diff options
author | Lukas Tönne <lukas.toenne@gmail.com> | 2018-04-15 13:16:55 +0300 |
---|---|---|
committer | Lukas Tönne <lukas.toenne@gmail.com> | 2018-04-15 13:16:55 +0300 |
commit | 7e1832c8d546ec13e752b7bd42ce13e3fc10ae86 (patch) | |
tree | 0fff9d878db69b288f909ff9a0f8aefe31ab8d80 /source/blender/editors | |
parent | c0c8df3f2cf3ab03cec1f660619b0fe2290caf2a (diff) | |
parent | 94959dba1b53640e2a36cf9b5ca46aaf49c5c74a (diff) |
Merge branch 'blender2.8' into hair_guides
Diffstat (limited to 'source/blender/editors')
285 files changed, 11671 insertions, 7695 deletions
diff --git a/source/blender/editors/CMakeLists.txt b/source/blender/editors/CMakeLists.txt index 00b514d1a15..e626636e1ab 100644 --- a/source/blender/editors/CMakeLists.txt +++ b/source/blender/editors/CMakeLists.txt @@ -30,6 +30,7 @@ if(WITH_BLENDER) add_subdirectory(groom) add_subdirectory(interface) add_subdirectory(io) + add_subdirectory(lattice) add_subdirectory(manipulator_library) add_subdirectory(mask) add_subdirectory(mesh) @@ -60,6 +61,7 @@ if(WITH_BLENDER) add_subdirectory(space_userpref) add_subdirectory(space_view3d) add_subdirectory(transform) + add_subdirectory(undo) add_subdirectory(util) add_subdirectory(uvedit) add_subdirectory(screen) diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index 9fb30dc8066..87fe002e536 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -3827,7 +3827,7 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float selected = 0; /* set blending again, as may not be set in previous step */ - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); /* step 1) draw backdrop ........................................... */ diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 0db465e583b..4af8089ffea 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -225,6 +225,33 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat ANIM_animdata_freelist(&anim_data); } +static void select_pchan_for_action_group(bAnimContext *ac, bActionGroup *agrp, bAnimListElem *ale) +{ + /* Armatures-Specific Feature: + * See mouse_anim_channels() -> ANIMTYPE_GROUP case for more details (T38737) + */ + if ((ac->ads->filterflag & ADS_FILTER_ONLYSEL) == 0) { + if ((ale->id) && (GS(ale->id->name) == ID_OB)) { + Object *ob = (Object *)ale->id; + if (ob->type == OB_ARMATURE) { + /* Assume for now that any group with corresponding name is what we want + * (i.e. for an armature whose location is animated, things would break + * if the user were to add a bone named "Location"). + * + * TODO: check the first F-Curve or so to be sure... + */ + bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, agrp->name); + if (agrp->flag & AGRP_SELECTED) { + ED_pose_bone_select(ob, pchan, true); + } + else { + ED_pose_bone_select(ob, pchan, false); + } + } + } + } +} + /* Deselect all animation channels * - data: pointer to datatype, as contained in bAnimContext * - datatype: the type of data that 'data' represents (eAnimCont_Types) @@ -345,8 +372,8 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d case ANIMTYPE_GROUP: { bActionGroup *agrp = (bActionGroup *)ale->data; - ACHANNEL_SET_FLAG(agrp, sel, AGRP_SELECTED); + select_pchan_for_action_group(ac, agrp, ale); agrp->flag &= ~AGRP_ACTIVE; break; } @@ -2398,33 +2425,7 @@ static void borderselect_anim_channels(bAnimContext *ac, rcti *rect, short selec case ANIMTYPE_GROUP: { bActionGroup *agrp = (bActionGroup *)ale->data; - - /* Armatures-Specific Feature: - * See mouse_anim_channels() -> ANIMTYPE_GROUP case for more details (T38737) - */ - if ((ac->ads->filterflag & ADS_FILTER_ONLYSEL) == 0) { - if ((ale->id) && (GS(ale->id->name) == ID_OB)) { - Object *ob = (Object *)ale->id; - - if (ob->type == OB_ARMATURE) { - /* Assume for now that any group with corresponding name is what we want - * (i.e. for an armature whose location is animated, things would break - * if the user were to add a bone named "Location"). - * - * TODO: check the first F-Curve or so to be sure... - */ - bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, agrp->name); - - if (agrp->flag & AGRP_SELECTED) { - ED_pose_bone_select(ob, pchan, true); - } - else { - ED_pose_bone_select(ob, pchan, false); - } - } - } - } - + select_pchan_for_action_group(ac, agrp, ale); /* always clear active flag after doing this */ agrp->flag &= ~AGRP_ACTIVE; break; @@ -2682,8 +2683,10 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index, } case ANIMTYPE_OBJECT: { +#if 0 bDopeSheet *ads = (bDopeSheet *)ac->data; Scene *sce = (Scene *)ads->source; +#endif ViewLayer *view_layer = ac->view_layer; Base *base = (Base *)ale->data; Object *ob = base->object; @@ -2722,8 +2725,8 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index, adt->flag |= ADT_UI_ACTIVE; /* ensure we exit editmode on whatever object was active before to avoid getting stuck there - T48747 */ - if (ob != sce->obedit) - ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO); + if (ob != CTX_data_edit_object(C)) + ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO); notifierFlags |= (ND_ANIMCHAN | NA_SELECTED); } @@ -3087,7 +3090,7 @@ static bool select_anim_channel_keys(bAnimContext *ac, int channel_index, bool e for (ale = anim_data.first; ale; ale = ale->next) { FCurve *fcu_inner = (FCurve *)ale->key_data; - if (fcu_inner) { + if (fcu_inner != NULL && fcu_inner->bezt != NULL) { for (i = 0, bezt = fcu_inner->bezt; i < fcu_inner->totvert; i++, bezt++) { bezt->f2 = bezt->f1 = bezt->f3 = 0; } diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c index 08851cebf51..9a07eaf896c 100644 --- a/source/blender/editors/animation/anim_draw.c +++ b/source/blender/editors/animation/anim_draw.c @@ -160,7 +160,7 @@ void ANIM_draw_previewrange(const bContext *C, View2D *v2d, int end_frame_width) /* only draw this if preview range is set */ if (PRVRANGEON) { - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); Gwn_VertFormat *format = immVertexFormat(); diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index bc901d7e13f..85bcfb603cd 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -116,7 +116,7 @@ static void animedit_get_yscale_factor(bAnimContext *ac) /* grab scale factor directly from action editor setting * NOTE: This theme setting doesn't have an ID, as it cannot be accessed normally - * since it is a float, and the theem settings methods can only handle chars. + * since it is a float, and the theme settings methods can only handle chars. */ ac->yscale_fac = btheme->tact.keyframe_scale_fac; @@ -880,6 +880,7 @@ static bAnimListElem *make_new_animlistelem(void *data, short datatype, ID *owne break; } case ANIMTYPE_FCURVE: + case ANIMTYPE_NLACURVE: /* practically the same as ANIMTYPE_FCURVE. Differences are applied post-creation */ { FCurve *fcu = (FCurve *)data; @@ -1089,13 +1090,14 @@ static bool name_matches_dopesheet_filter(bDopeSheet *ads, char *name) /* (Display-)Name-based F-Curve filtering * NOTE: when this function returns true, the F-Curve is to be skipped */ -static bool skip_fcurve_with_name(bDopeSheet *ads, FCurve *fcu, ID *owner_id) +static bool skip_fcurve_with_name(bDopeSheet *ads, FCurve *fcu, eAnim_ChannelType channel_type, void *owner, ID *owner_id) { bAnimListElem ale_dummy = {NULL}; const bAnimChannelType *acf; - /* create a dummy wrapper for the F-Curve */ - ale_dummy.type = ANIMTYPE_FCURVE; + /* create a dummy wrapper for the F-Curve, so we can get typeinfo for it */ + ale_dummy.type = channel_type; + ale_dummy.owner = owner; ale_dummy.id = owner_id; ale_dummy.data = fcu; @@ -1158,8 +1160,9 @@ static bool fcurve_has_errors(FCurve *fcu) } /* find the next F-Curve that is usable for inclusion */ -static FCurve *animfilter_fcurve_next(bDopeSheet *ads, FCurve *first, bActionGroup *grp, int filter_mode, ID *owner_id) +static FCurve *animfilter_fcurve_next(bDopeSheet *ads, FCurve *first, eAnim_ChannelType channel_type, int filter_mode, void *owner, ID *owner_id) { + bActionGroup *grp = (channel_type == ANIMTYPE_FCURVE) ? owner : NULL; FCurve *fcu = NULL; /* loop over F-Curves - assume that the caller of this has already checked that these should be included @@ -1193,7 +1196,7 @@ static FCurve *animfilter_fcurve_next(bDopeSheet *ads, FCurve *first, bActionGro if (!(filter_mode & ANIMFILTER_ACTIVE) || (fcu->flag & FCURVE_ACTIVE)) { /* name based filtering... */ if ( ((ads) && (ads->filterflag & ADS_FILTER_BY_FCU_NAME)) && (owner_id) ) { - if (skip_fcurve_with_name(ads, fcu, owner_id)) + if (skip_fcurve_with_name(ads, fcu, channel_type, owner, owner_id)) continue; } @@ -1216,7 +1219,10 @@ static FCurve *animfilter_fcurve_next(bDopeSheet *ads, FCurve *first, bActionGro return NULL; } -static size_t animfilter_fcurves(ListBase *anim_data, bDopeSheet *ads, FCurve *first, bActionGroup *grp, int filter_mode, ID *owner_id) +static size_t animfilter_fcurves(ListBase *anim_data, bDopeSheet *ads, + FCurve *first, eAnim_ChannelType fcurve_type, + int filter_mode, + void *owner, ID *owner_id) { FCurve *fcu; size_t items = 0; @@ -1230,8 +1236,18 @@ static size_t animfilter_fcurves(ListBase *anim_data, bDopeSheet *ads, FCurve *f * 4) the fcu pointer is set to the F-Curve after the one we just added, so that we can keep going through * the rest of the F-Curve list without an eternal loop. Back to step 2 :) */ - for (fcu = first; ( (fcu = animfilter_fcurve_next(ads, fcu, grp, filter_mode, owner_id)) ); fcu = fcu->next) { - ANIMCHANNEL_NEW_CHANNEL(fcu, ANIMTYPE_FCURVE, owner_id); + for (fcu = first; ( (fcu = animfilter_fcurve_next(ads, fcu, fcurve_type, filter_mode, owner, owner_id)) ); fcu = fcu->next) { + if (UNLIKELY(fcurve_type == ANIMTYPE_NLACURVE)) { + /* NLA Control Curve - Basically the same as normal F-Curves, except we need to set some stuff differently */ + ANIMCHANNEL_NEW_CHANNEL_FULL(fcu, ANIMTYPE_NLACURVE, owner_id, { + ale->owner = owner; /* strip */ + ale->adt = NULL; /* to prevent time mapping from causing problems */ + }); + } + else { + /* Normal FCurve */ + ANIMCHANNEL_NEW_CHANNEL(fcu, ANIMTYPE_FCURVE, owner_id); + } } /* return the number of items added to the list */ @@ -1282,10 +1298,10 @@ static size_t animfilter_act_group(bAnimContext *ac, ListBase *anim_data, bDopeS /* group must be editable for its children to be editable (if we care about this) */ if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_AGRP(agrp)) { /* get first F-Curve which can be used here */ - FCurve *first_fcu = animfilter_fcurve_next(ads, agrp->channels.first, agrp, filter_mode, owner_id); + FCurve *first_fcu = animfilter_fcurve_next(ads, agrp->channels.first, ANIMTYPE_FCURVE, filter_mode, agrp, owner_id); /* filter list, starting from this F-Curve */ - tmp_items += animfilter_fcurves(&tmp_data, ads, first_fcu, agrp, filter_mode, owner_id); + tmp_items += animfilter_fcurves(&tmp_data, ads, first_fcu, ANIMTYPE_FCURVE, filter_mode, agrp, owner_id); } } } @@ -1341,7 +1357,7 @@ static size_t animfilter_action(bAnimContext *ac, ListBase *anim_data, bDopeShee /* un-grouped F-Curves (only if we're not only considering those channels in the active group) */ if (!(filter_mode & ANIMFILTER_ACTGROUPED)) { FCurve *firstfcu = (lastchan) ? (lastchan->next) : (act->curves.first); - items += animfilter_fcurves(anim_data, ads, firstfcu, NULL, filter_mode, owner_id); + items += animfilter_fcurves(anim_data, ads, firstfcu, ANIMTYPE_FCURVE, filter_mode, NULL, owner_id); } /* return the number of items added to the list */ @@ -1463,36 +1479,8 @@ static size_t animfilter_nla_controls(ListBase *anim_data, bDopeSheet *ads, Anim /* for now, we only go one level deep - so controls on grouped FCurves are not handled */ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { for (strip = nlt->strips.first; strip; strip = strip->next) { - ListBase strip_curves = {NULL, NULL}; - size_t strip_items = 0; - - /* create the raw items */ - strip_items += animfilter_fcurves(&strip_curves, ads, strip->fcurves.first, NULL, filter_mode, owner_id); - - /* change their types and add extra data - * - There is no point making a separate copy of animfilter_fcurves for this now/yet, - * unless we later get per-element control curves for other stuff too - */ - if (strip_items) { - bAnimListElem *ale, *ale_n = NULL; - - for (ale = strip_curves.first; ale; ale = ale_n) { - ale_n = ale->next; - - /* change the type to being a FCurve for editing NLA strip controls */ - BLI_assert(ale->type == ANIMTYPE_FCURVE); - - ale->type = ANIMTYPE_NLACURVE; - ale->owner = strip; - - ale->adt = NULL; /* XXX: This way, there are no problems with time mapping errors */ - } - } - - /* add strip curves to the set of channels inside the group being collected */ - BLI_movelisttolist(&tmp_data, &strip_curves); - BLI_assert(BLI_listbase_is_empty(&strip_curves)); - tmp_items += strip_items; + /* pass strip as the "owner", so that the name lookups (used while filtering) will resolve */ + tmp_items += animfilter_fcurves(&tmp_data, ads, strip->fcurves.first, ANIMTYPE_NLACURVE, filter_mode, strip, owner_id); } } } @@ -1543,7 +1531,7 @@ static size_t animfilter_block_data(bAnimContext *ac, ListBase *anim_data, bDope items += animfilter_nla(ac, anim_data, ads, adt, filter_mode, id); }, { /* Drivers */ - items += animfilter_fcurves(anim_data, ads, adt->drivers.first, NULL, filter_mode, id); + items += animfilter_fcurves(anim_data, ads, adt->drivers.first, ANIMTYPE_FCURVE, filter_mode, NULL, id); }, { /* NLA Control Keyframes */ items += animfilter_nla_controls(anim_data, ads, adt, filter_mode, id); diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c index 107a46999f0..e43735c51fb 100644 --- a/source/blender/editors/animation/anim_markers.c +++ b/source/blender/editors/animation/anim_markers.c @@ -345,7 +345,7 @@ static void draw_marker( int icon_id; glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); /* vertical line - dotted */ #ifdef DURIAN_CAMERA_SWITCH @@ -462,7 +462,7 @@ void ED_markers_draw(const bContext *C, int flag) immUniformColor4ubv(shade); glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); immRectf(pos, v2d->cur.xmin, 0, v2d->cur.xmax, UI_MARKER_MARGIN_Y); @@ -1113,14 +1113,15 @@ static void select_timeline_marker_frame(ListBase *markers, int frame, bool exte } } - BLI_LISTBASE_CIRCULAR_FORWARD_BEGIN (markers, marker, marker_first) { + LISTBASE_CIRCULAR_FORWARD_BEGIN(markers, marker, marker_first) + { /* this way a not-extend select will always give 1 selected marker */ if (marker->frame == frame) { marker->flag ^= SELECT; break; } } - BLI_LISTBASE_CIRCULAR_FORWARD_END (markers, marker, marker_first); + LISTBASE_CIRCULAR_FORWARD_END(markers, marker, marker_first); } static int ed_marker_select(bContext *C, const wmEvent *event, bool extend, bool camera) diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c index 8d77460e197..8106be79521 100644 --- a/source/blender/editors/animation/fmodifier_ui.c +++ b/source/blender/editors/animation/fmodifier_ui.c @@ -62,7 +62,7 @@ #include "UI_resources.h" #include "ED_anim_api.h" -#include "ED_util.h" +#include "ED_undo.h" /* ********************************************** */ /* UI STUFF */ diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c index 9d25fc9e1a3..0ef6aa4bd4a 100644 --- a/source/blender/editors/animation/keyframes_edit.c +++ b/source/blender/editors/animation/keyframes_edit.c @@ -36,7 +36,7 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" -#include "BLI_lasso.h" +#include "BLI_lasso_2d.h" #include "BLI_math.h" #include "DNA_anim_types.h" diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 24f6a2dab2c..126e4b5f736 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -1358,7 +1358,7 @@ static int insert_key_exec(bContext *C, wmOperator *op) * updated since the last switching to the edit mode will be keyframed correctly */ if (obedit && ANIM_keyingset_find_id(ks, (ID *)obedit->data)) { - ED_object_toggle_modes(C, OB_MODE_EDIT); + ED_object_mode_toggle(C, OB_MODE_EDIT); ob_edit_mode = true; } @@ -1369,7 +1369,7 @@ static int insert_key_exec(bContext *C, wmOperator *op) /* restore the edit mode if necessary */ if (ob_edit_mode) { - ED_object_toggle_modes(C, OB_MODE_EDIT); + ED_object_mode_toggle(C, OB_MODE_EDIT); } /* report failure or do updates? */ diff --git a/source/blender/editors/armature/CMakeLists.txt b/source/blender/editors/armature/CMakeLists.txt index 5348298f57e..4301fe6582f 100644 --- a/source/blender/editors/armature/CMakeLists.txt +++ b/source/blender/editors/armature/CMakeLists.txt @@ -49,6 +49,7 @@ set(SRC editarmature_generate.c editarmature_retarget.c editarmature_sketch.c + editarmature_undo.c meshlaplacian.c pose_edit.c pose_lib.c diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c index 368d54fc3ad..bd3ddfe93c6 100644 --- a/source/blender/editors/armature/armature_add.c +++ b/source/blender/editors/armature/armature_add.c @@ -472,7 +472,7 @@ EditBone *duplicateEditBone(EditBone *curBone, const char *name, ListBase *editb return duplicateEditBoneObjects(curBone, name, editbones, ob, ob); } -static int armature_duplicate_selected_exec(bContext *C, wmOperator *UNUSED(op)) +static int armature_duplicate_selected_exec(bContext *C, wmOperator *op) { bArmature *arm; EditBone *ebone_iter; @@ -484,7 +484,9 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *UNUSED(op)) /* cancel if nothing selected */ if (CTX_DATA_COUNT(C, selected_bones) == 0) return OPERATOR_CANCELLED; - + + const bool do_flip_names = RNA_boolean_get(op->ptr, "do_flip_names"); + ED_armature_sync_selection(arm->edbo); // XXX why is this needed? preEditBoneDuplicate(arm->edbo); @@ -512,8 +514,20 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *UNUSED(op)) (ebone_iter->flag & BONE_SELECTED)) { EditBone *ebone; + char new_bone_name_buff[MAXBONENAME]; + char *new_bone_name = ebone_iter->name; + + if (do_flip_names) { + BLI_string_flip_side_name(new_bone_name_buff, ebone_iter->name, false, sizeof(new_bone_name_buff)); - ebone = duplicateEditBone(ebone_iter, ebone_iter->name, arm->edbo, obedit); + /* Only use flipped name if not yet in use. Otherwise we'd get again inconsistent namings + * (different numbers), better keep default behavior in this case. */ + if (ED_armature_bone_find_name(arm->edbo, new_bone_name_buff) == NULL) { + new_bone_name = new_bone_name_buff; + } + } + + ebone = duplicateEditBone(ebone_iter, new_bone_name, arm->edbo, obedit); if (!ebone_first_dupe) { ebone_first_dupe = ebone; @@ -590,6 +604,10 @@ void ARMATURE_OT_duplicate(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_boolean( + ot->srna, "do_flip_names", false, + "Flip Names", "Try to flip names of the bones, if possible, instead of adding a number extension"); } /** @@ -1011,7 +1029,7 @@ static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op) ED_armature_deselect_all(obedit); - /* Create a bone */ + /* Create a bone */ bone = ED_armature_edit_bone_add(obedit->data, name); copy_v3_v3(bone->head, curs); diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c index a2fbfe645f7..bb3c4164fc1 100644 --- a/source/blender/editors/armature/armature_edit.c +++ b/source/blender/editors/armature/armature_edit.c @@ -50,6 +50,7 @@ #include "BKE_context.h" #include "BKE_global.h" #include "BKE_report.h" +#include "BKE_object.h" #include "RNA_access.h" #include "RNA_define.h" @@ -138,17 +139,16 @@ void ED_armature_transform(struct bArmature *arm, float mat[4][4], const bool do /* exported for use in editors/object/ */ /* 0 == do center, 1 == center new, 2 == center cursor */ -void ED_armature_origin_set(Scene *scene, Object *ob, float cursor[3], int centermode, int around) +void ED_armature_origin_set(Object *ob, float cursor[3], int centermode, int around) { - Object *obedit = scene->obedit; // XXX get from context + const bool is_editmode = BKE_object_is_in_editmode(ob); EditBone *ebone; bArmature *arm = ob->data; float cent[3]; /* Put the armature into editmode */ - if (ob != obedit) { + if (is_editmode == false) { ED_armature_to_edit(arm); - obedit = NULL; /* we cant use this so behave as if there is no obedit */ } /* Find the centerpoint */ @@ -188,13 +188,13 @@ void ED_armature_origin_set(Scene *scene, Object *ob, float cursor[3], int cente } /* Turn the list into an armature */ - if (obedit == NULL) { + if (is_editmode == false) { ED_armature_from_edit(arm); ED_armature_edit_free(arm); } /* Adjust object location for new centerpoint */ - if (centermode && obedit == NULL) { + if (centermode && (is_editmode == false)) { mul_mat3_m4_v3(ob->obmat, cent); /* omit translation part */ add_v3_v3(ob->loc, cent); } @@ -1458,8 +1458,9 @@ static int armature_dissolve_selected_exec(bContext *C, wmOperator *UNUSED(op)) if (ebone->flag & BONE_DONE) { copy_v3_v3(ebone->parent->tail, ebone->tail); ebone->parent->rad_tail = ebone->rad_tail; + SET_FLAG_FROM_TEST(ebone->parent->flag, ebone->flag & BONE_TIPSEL, BONE_TIPSEL); - ED_armature_edit_bone_remove(arm, ebone); + ED_armature_edit_bone_remove_ex(arm, ebone, false); changed = true; } } @@ -1468,10 +1469,9 @@ static int armature_dissolve_selected_exec(bContext *C, wmOperator *UNUSED(op)) for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { if (ebone->parent && ebone->parent->temp.ebone && - (ebone->flag & BONE_CONNECTED) == 0) + (ebone->flag & BONE_CONNECTED)) { - ebone->flag |= BONE_CONNECTED; - ebone->rad_head = ebone->parent->rad_head; + ebone->rad_head = ebone->parent->rad_tail; } } diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h index 192bb8eea61..0ba720a17d0 100644 --- a/source/blender/editors/armature/armature_intern.h +++ b/source/blender/editors/armature/armature_intern.h @@ -250,7 +250,7 @@ void armature_tag_unselect(struct bArmature *arm); void *get_nearest_bone(struct bContext *C, const int xy[2], bool findunsel); void *get_bone_from_selectbuffer( - struct Scene *scene, struct Base *base, const unsigned int *buffer, short hits, + struct Base *base, struct Object *obedit, const unsigned int *buffer, short hits, bool findunsel, bool do_nearest); int bone_looper(struct Object *ob, struct Bone *bone, void *data, diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c index 0d114206c6b..52e9e424a85 100644 --- a/source/blender/editors/armature/armature_naming.c +++ b/source/blender/editors/armature/armature_naming.c @@ -314,8 +314,9 @@ typedef struct BoneFlipNameData { * * \param arm: Armature the bones belong to * \param bones_names: List of BoneConflict elems. + * \param do_strip_numbers: if set, try to get rid of dot-numbers at end of bone names. */ -void ED_armature_bones_flip_names(bArmature *arm, ListBase *bones_names) +void ED_armature_bones_flip_names(bArmature *arm, ListBase *bones_names, const bool do_strip_numbers) { ListBase bones_names_conflicts = {NULL}; BoneFlipNameData *bfn; @@ -327,9 +328,9 @@ void ED_armature_bones_flip_names(bArmature *arm, ListBase *bones_names) char name_flip[MAXBONENAME]; char *name = link->data; - /* Do not strip numbers, otherwise we'll end up with completely mismatched names in cases like + /* WARNING: if do_strip_numbers is set, expect completely mismatched names in cases like * Bone.R, Bone.R.001, Bone.R.002, etc. */ - BLI_string_flip_side_name(name_flip, name, false, sizeof(name_flip)); + BLI_string_flip_side_name(name_flip, name, do_strip_numbers, sizeof(name_flip)); ED_armature_bone_rename(arm, name, name_flip); @@ -352,7 +353,7 @@ void ED_armature_bones_flip_names(bArmature *arm, ListBase *bones_names) /* ************************************************** */ /* Bone Renaming - EditMode */ -static int armature_flip_names_exec(bContext *C, wmOperator *UNUSED(op)) +static int armature_flip_names_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_edit_object(C); bArmature *arm; @@ -361,6 +362,8 @@ static int armature_flip_names_exec(bContext *C, wmOperator *UNUSED(op)) if (ELEM(NULL, ob, ob->pose)) return OPERATOR_CANCELLED; + const bool do_strip_numbers = RNA_boolean_get(op->ptr, "do_strip_numbers"); + arm = ob->data; ListBase bones_names = {NULL}; @@ -371,7 +374,7 @@ static int armature_flip_names_exec(bContext *C, wmOperator *UNUSED(op)) } CTX_DATA_END; - ED_armature_bones_flip_names(arm, &bones_names); + ED_armature_bones_flip_names(arm, &bones_names, do_strip_numbers); BLI_freelistN(&bones_names); @@ -401,6 +404,10 @@ void ARMATURE_OT_flip_names(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, "do_strip_numbers", false, "Strip Numbers", + "Try to remove right-most dot-number from flipped names " + "(WARNING: may result in incoherent naming in some cases)"); } diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index ccaa9ecb8de..de2611f7092 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -130,46 +130,36 @@ typedef struct tJoinArmature_AdtFixData { /* FIXME: For now, we only care about drivers here. When editing rigs, it's very rare to have animation * on the rigs being edited already, so it should be safe to skip these. */ -static void joined_armature_fix_animdata_cb(ID *id, AnimData *adt, void *user_data) +static void joined_armature_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data) { tJoinArmature_AdtFixData *afd = (tJoinArmature_AdtFixData *)user_data; ID *src_id = &afd->srcArm->id; ID *dst_id = &afd->tarArm->id; GHashIterator gh_iter; - FCurve *fcu; /* Fix paths - If this is the target object, it will have some "dirty" paths */ - if (id == src_id) { - /* Fix drivers */ - for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { - /* skip driver if it doesn't affect the bones */ - if (strstr(fcu->rna_path, "pose.bones[") == NULL) { - continue; - } + if ((id == src_id) && strstr(fcu->rna_path, "pose.bones[")) { + GHASH_ITER(gh_iter, afd->names_map) { + const char *old_name = BLI_ghashIterator_getKey(&gh_iter); + const char *new_name = BLI_ghashIterator_getValue(&gh_iter); - // FIXME: this is too crude... it just does everything! - GHASH_ITER(gh_iter, afd->names_map) { - const char *old_name = BLI_ghashIterator_getKey(&gh_iter); - const char *new_name = BLI_ghashIterator_getValue(&gh_iter); + /* only remap if changed; this still means there will be some waste if there aren't many drivers/keys */ + if (!STREQ(old_name, new_name) && strstr(fcu->rna_path, old_name)) { + fcu->rna_path = BKE_animsys_fix_rna_path_rename(id, fcu->rna_path, "pose.bones", + old_name, new_name, 0, 0, false); - /* only remap if changed; this still means there will be some waste if there aren't many drivers/keys */ - if (!STREQ(old_name, new_name) && strstr(fcu->rna_path, old_name)) { - fcu->rna_path = BKE_animsys_fix_rna_path_rename(id, fcu->rna_path, "pose.bones", - old_name, new_name, 0, 0, false); - - /* we don't want to apply a second remapping on this driver now, - * so stop trying names, but keep fixing drivers - */ - break; - } + /* we don't want to apply a second remapping on this driver now, + * so stop trying names, but keep fixing drivers + */ + break; } } } /* Driver targets */ - for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { + if (fcu->driver) { ChannelDriver *driver = fcu->driver; DriverVar *dvar; @@ -373,7 +363,7 @@ int join_armature_exec(bContext *C, wmOperator *op) } /* Fix all the drivers (and animation data) */ - BKE_animdata_main_cb(bmain, joined_armature_fix_animdata_cb, &afd); + BKE_fcurves_main_cb(bmain, joined_armature_fix_animdata_cb, &afd); BLI_ghash_free(afd.names_map, MEM_freeN, NULL); /* Only copy over animdata now, after all the remapping has been done, diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c index b87942fed84..397691a409b 100644 --- a/source/blender/editors/armature/armature_select.c +++ b/source/blender/editors/armature/armature_select.c @@ -77,10 +77,9 @@ Bone *get_indexed_bone(Object *ob, int index) /* See if there are any selected bones in this buffer */ /* only bones from base are checked on */ void *get_bone_from_selectbuffer( - Scene *scene, Base *base, const unsigned int *buffer, short hits, + Base *base, Object *obedit, const unsigned int *buffer, short hits, bool findunsel, bool do_nearest) { - Object *obedit = scene->obedit; // XXX get from context Bone *bone; EditBone *ebone; void *firstunSel = NULL, *firstSel = NULL, *data; @@ -175,7 +174,7 @@ void *get_nearest_bone(bContext *C, const int xy[2], bool findunsel) short hits; CTX_data_eval_ctx(C, &eval_ctx); - view3d_set_viewcontext(C, &vc); + ED_view3d_viewcontext_init(C, &vc); // rect.xmin = ... mouseco! rect.xmin = rect.xmax = xy[0]; @@ -183,9 +182,9 @@ void *get_nearest_bone(bContext *C, const int xy[2], bool findunsel) hits = view3d_opengl_select(&eval_ctx, &vc, buffer, MAXPICKBUF, &rect, VIEW3D_SELECT_PICK_NEAREST); - if (hits > 0) - return get_bone_from_selectbuffer(vc.scene, vc.view_layer->basact, buffer, hits, findunsel, true); - + if (hits > 0) { + return get_bone_from_selectbuffer(vc.view_layer->basact, vc.obedit, buffer, hits, findunsel, true); + } return NULL; } @@ -492,7 +491,7 @@ bool ED_armature_select_pick(bContext *C, const int mval[2], bool extend, bool d int selmask; CTX_data_eval_ctx(C, &eval_ctx); - view3d_set_viewcontext(C, &vc); + ED_view3d_viewcontext_init(C, &vc); if (BIF_sk_selectStroke(C, mval, extend)) { return true; diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c index 72b4837c1b8..5c8e08a0d89 100644 --- a/source/blender/editors/armature/armature_skinning.c +++ b/source/blender/editors/armature/armature_skinning.c @@ -66,7 +66,7 @@ /* ********************************** Bone Skinning *********************************************** */ -static int bone_skinnable_cb(Object *ob, Bone *bone, void *datap) +static int bone_skinnable_cb(Object *UNUSED(ob), Bone *bone, void *datap) { /* Bones that are deforming * are regarded to be "skinnable" and are eligible for @@ -92,9 +92,9 @@ static int bone_skinnable_cb(Object *ob, Bone *bone, void *datap) */ Bone ***hbone; int a, segments; - struct { Object *armob; void *list; int heat; } *data = datap; + struct { Object *armob; void *list; int heat; bool is_weight_paint; } *data = datap; - if (!(ob->mode & OB_MODE_WEIGHT_PAINT) || !(bone->flag & BONE_HIDDEN_P)) { + if (!(data->is_weight_paint) || !(bone->flag & BONE_HIDDEN_P)) { if (!(bone->flag & BONE_NO_DEFORM)) { if (data->heat && data->armob->pose && BKE_pose_channel_find_name(data->armob->pose, bone->name)) segments = bone->segments; @@ -157,18 +157,17 @@ static int dgroup_skinnable_cb(Object *ob, Bone *bone, void *datap) */ bDeformGroup ***hgroup, *defgroup = NULL; int a, segments; - struct { Object *armob; void *list; int heat; } *data = datap; - int wpmode = (ob->mode & OB_MODE_WEIGHT_PAINT); + struct { Object *armob; void *list; int heat; bool is_weight_paint; } *data = datap; bArmature *arm = data->armob->data; - if (!wpmode || !(bone->flag & BONE_HIDDEN_P)) { + if (!data->is_weight_paint || !(bone->flag & BONE_HIDDEN_P)) { if (!(bone->flag & BONE_NO_DEFORM)) { if (data->heat && data->armob->pose && BKE_pose_channel_find_name(data->armob->pose, bone->name)) segments = bone->segments; else segments = 1; - if (!wpmode || ((arm->layer & bone->layer) && (bone->flag & BONE_SELECTED))) { + if (!data->is_weight_paint || ((arm->layer & bone->layer) && (bone->flag & BONE_SELECTED))) { if (!(defgroup = defgroup_find_name(ob, bone->name))) { defgroup = BKE_object_defgroup_add_name(ob, bone->name); } @@ -192,9 +191,10 @@ static int dgroup_skinnable_cb(Object *ob, Bone *bone, void *datap) return 0; } -static void envelope_bone_weighting(Object *ob, Mesh *mesh, float (*verts)[3], int numbones, Bone **bonelist, - bDeformGroup **dgrouplist, bDeformGroup **dgroupflip, - float (*root)[3], float (*tip)[3], const int *selected, float scale) +static void envelope_bone_weighting( + Object *ob, Mesh *mesh, float (*verts)[3], int numbones, Bone **bonelist, + bDeformGroup **dgrouplist, bDeformGroup **dgroupflip, + float (*root)[3], float (*tip)[3], const int *selected, float scale) { /* Create vertex group weights from envelopes */ @@ -276,12 +276,13 @@ static void add_verts_to_dgroups( float (*root)[3], (*tip)[3], (*verts)[3]; int *selected; int numbones, vertsfilled = 0, i, j, segments = 0; - int wpmode = (ob->mode & OB_MODE_WEIGHT_PAINT); - struct { Object *armob; void *list; int heat; } looper_data; + const bool wpmode = (ob->mode & OB_MODE_WEIGHT_PAINT); + struct { Object *armob; void *list; int heat; bool is_weight_paint; } looper_data; looper_data.armob = par; looper_data.heat = heat; looper_data.list = NULL; + looper_data.is_weight_paint = wpmode; /* count the number of skinnable bones */ numbones = bone_looper(ob, arm->bonebase.first, &looper_data, bone_skinnable_cb); @@ -404,15 +405,17 @@ static void add_verts_to_dgroups( if (heat) { const char *error = NULL; - heat_bone_weighting(ob, mesh, verts, numbones, dgrouplist, dgroupflip, - root, tip, selected, &error); + heat_bone_weighting( + ob, mesh, verts, numbones, dgrouplist, dgroupflip, + root, tip, selected, &error); if (error) { BKE_report(reports, RPT_WARNING, error); } } else { - envelope_bone_weighting(ob, mesh, verts, numbones, bonelist, dgrouplist, - dgroupflip, root, tip, selected, mat4_to_scale(par->obmat)); + envelope_bone_weighting( + ob, mesh, verts, numbones, bonelist, dgrouplist, + dgroupflip, root, tip, selected, mat4_to_scale(par->obmat)); } /* only generated in some cases but can call anyway */ diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c index f27c4fdd96f..aa0aa0e03ff 100644 --- a/source/blender/editors/armature/armature_utils.c +++ b/source/blender/editors/armature/armature_utils.c @@ -134,7 +134,10 @@ void bone_free(bArmature *arm, EditBone *bone) BLI_freelinkN(arm->edbo, bone); } -void ED_armature_edit_bone_remove(bArmature *arm, EditBone *exBone) +/** + * \param clear_connected: When false caller is responsible for keeping the flag in a valid state. + */ +void ED_armature_edit_bone_remove_ex(bArmature *arm, EditBone *exBone, bool clear_connected) { EditBone *curBone; @@ -142,13 +145,20 @@ void ED_armature_edit_bone_remove(bArmature *arm, EditBone *exBone) for (curBone = arm->edbo->first; curBone; curBone = curBone->next) { if (curBone->parent == exBone) { curBone->parent = exBone->parent; - curBone->flag &= ~BONE_CONNECTED; + if (clear_connected) { + curBone->flag &= ~BONE_CONNECTED; + } } } bone_free(arm, exBone); } +void ED_armature_edit_bone_remove(bArmature *arm, EditBone *exBone) +{ + ED_armature_edit_bone_remove_ex(arm, exBone, true); +} + bool ED_armature_ebone_is_child_recursive(EditBone *ebone_parent, EditBone *ebone_child) { for (ebone_child = ebone_child->parent; ebone_child; ebone_child = ebone_child->parent) { @@ -592,7 +602,7 @@ void ED_armature_from_edit(bArmature *arm) if (len_sq <= SQUARE(0.000001f)) { /* FLT_EPSILON is too large? */ EditBone *fBone; - /* Find any bones that refer to this bone */ + /* Find any bones that refer to this bone */ for (fBone = arm->edbo->first; fBone; fBone = fBone->next) { if (fBone->parent == eBone) fBone->parent = eBone->parent; @@ -711,11 +721,11 @@ void ED_armature_to_edit(bArmature *arm) } /* *************************************************************** */ -/* Undo for Armature EditMode*/ +/* Used by Undo for Armature EditMode*/ /* free's bones and their properties */ -static void ED_armature_ebone_listbase_free(ListBase *lb) +void ED_armature_ebone_listbase_free(ListBase *lb) { EditBone *ebone, *ebone_next; @@ -733,7 +743,7 @@ static void ED_armature_ebone_listbase_free(ListBase *lb) BLI_listbase_clear(lb); } -static void ED_armature_ebone_listbase_copy(ListBase *lb_dst, ListBase *lb_src) +void ED_armature_ebone_listbase_copy(ListBase *lb_dst, ListBase *lb_src) { EditBone *ebone_src; EditBone *ebone_dst; @@ -766,78 +776,6 @@ void ED_armature_ebone_listbase_temp_clear(ListBase *lb) } } -typedef struct UndoArmature { - EditBone *act_edbone; - ListBase lb; -} UndoArmature; - -static void undoBones_to_editBones(void *uarmv, void *armv, void *UNUSED(data)) -{ - UndoArmature *uarm = uarmv; - bArmature *arm = armv; - EditBone *ebone; - - ED_armature_ebone_listbase_free(arm->edbo); - ED_armature_ebone_listbase_copy(arm->edbo, &uarm->lb); - - /* active bone */ - if (uarm->act_edbone) { - ebone = uarm->act_edbone; - arm->act_edbone = ebone->temp.ebone; - } - else { - arm->act_edbone = NULL; - } - - ED_armature_ebone_listbase_temp_clear(arm->edbo); -} - -static void *editBones_to_undoBones(void *armv, void *UNUSED(obdata)) -{ - bArmature *arm = armv; - UndoArmature *uarm; - EditBone *ebone; - - uarm = MEM_callocN(sizeof(UndoArmature), "listbase undo"); - - ED_armature_ebone_listbase_copy(&uarm->lb, arm->edbo); - - /* active bone */ - if (arm->act_edbone) { - ebone = arm->act_edbone; - uarm->act_edbone = ebone->temp.ebone; - } - - ED_armature_ebone_listbase_temp_clear(&uarm->lb); - - return uarm; -} - -static void free_undoBones(void *uarmv) -{ - UndoArmature *uarm = uarmv; - - ED_armature_ebone_listbase_free(&uarm->lb); - - MEM_freeN(uarm); -} - -static void *get_armature_edit(bContext *C) -{ - Object *obedit = CTX_data_edit_object(C); - if (obedit && obedit->type == OB_ARMATURE) { - return obedit->data; - } - return NULL; -} - -/* and this is all the undo system needs to know */ -void undo_push_armature(bContext *C, const char *name) -{ - // XXX solve getdata() - undo_editmode_push(C, name, get_armature_edit, free_undoBones, undoBones_to_editBones, editBones_to_undoBones, NULL); -} - /* *************************************************************** */ /* Low level selection functions which hide connected-parent * flag behavior which gets tricky to handle in selection operators. diff --git a/source/blender/editors/armature/editarmature_retarget.c b/source/blender/editors/armature/editarmature_retarget.c index 2fb216c2ef8..3dd41f25e09 100644 --- a/source/blender/editors/armature/editarmature_retarget.c +++ b/source/blender/editors/armature/editarmature_retarget.c @@ -42,7 +42,7 @@ #include "BKE_context.h" #include "ED_armature.h" -#include "ED_util.h" +#include "ED_undo.h" #include "BIF_retarget.h" diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c index f4bebfd85e0..1f1468a8e41 100644 --- a/source/blender/editors/armature/editarmature_sketch.c +++ b/source/blender/editors/armature/editarmature_sketch.c @@ -158,7 +158,7 @@ void BIF_makeListTemplates(const bContext *C) TEMPLATES_HASH = BLI_ghash_int_new("makeListTemplates gh"); TEMPLATES_CURRENT = 0; - FOREACH_OBJECT(view_layer, ob) + FOREACH_OBJECT_BEGIN(view_layer, ob) { if (ob != obedit && ob->type == OB_ARMATURE) { index++; @@ -169,7 +169,7 @@ void BIF_makeListTemplates(const bContext *C) } } } - FOREACH_OBJECT_END + FOREACH_OBJECT_END; } #if 0 /* UNUSED */ @@ -178,7 +178,7 @@ const char *BIF_listTemplates(const bContext *UNUSED(C)) GHashIterator ghi; const char *menu_header = IFACE_("Template %t|None %x0|"); char *p; - const size_t template_size = (BLI_ghash_size(TEMPLATES_HASH) * 32 + 30); + const size_t template_size = (BLI_ghash_len(TEMPLATES_HASH) * 32 + 30); if (TEMPLATES_MENU != NULL) { MEM_freeN(TEMPLATES_MENU); @@ -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_type(C), 0, + CTX_data_main(C), CTX_data_scene(C), CTX_data_view_layer(C), 0, CTX_wm_region(C), CTX_wm_view3d(C)); float mvalf[2] = {UNPACK2(dd->mval)}; @@ -1932,7 +1932,7 @@ static bool sk_selectStroke(bContext *C, SK_Sketch *sketch, const int mval[2], c short hits; CTX_data_eval_ctx(C, &eval_ctx); - view3d_set_viewcontext(C, &vc); + ED_view3d_viewcontext_init(C, &vc); BLI_rcti_init_pt_radius(&rect, mval, 5); @@ -2031,7 +2031,7 @@ static void sk_drawSketch(Scene *scene, View3D *UNUSED(v3d), SK_Sketch *sketch, gpuPushMatrix(); glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); switch (sketch->next_point.mode) { case PT_SNAP: diff --git a/source/blender/editors/armature/editarmature_undo.c b/source/blender/editors/armature/editarmature_undo.c new file mode 100644 index 00000000000..217de06d99b --- /dev/null +++ b/source/blender/editors/armature/editarmature_undo.c @@ -0,0 +1,192 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Blender Foundation, 2002-2009 full recode. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/armature/editarmature_undo.c + * \ingroup edarmature + */ + +#include "DNA_armature_types.h" +#include "DNA_object_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_array_utils.h" + +#include "BKE_context.h" +#include "BKE_undo_system.h" + +#include "DEG_depsgraph.h" + +#include "ED_armature.h" +#include "ED_object.h" +#include "ED_util.h" + +#include "WM_types.h" +#include "WM_api.h" + +/* -------------------------------------------------------------------- */ +/** \name Undo Conversion + * \{ */ + +typedef struct UndoArmature { + EditBone *act_edbone; + ListBase lb; + size_t undo_size; +} UndoArmature; + +static void undoarm_to_editarm(UndoArmature *uarm, bArmature *arm) +{ + EditBone *ebone; + + ED_armature_ebone_listbase_free(arm->edbo); + ED_armature_ebone_listbase_copy(arm->edbo, &uarm->lb); + + /* active bone */ + if (uarm->act_edbone) { + ebone = uarm->act_edbone; + arm->act_edbone = ebone->temp.ebone; + } + else { + arm->act_edbone = NULL; + } + + ED_armature_ebone_listbase_temp_clear(arm->edbo); +} + +static void *undoarm_from_editarm(UndoArmature *uarm, bArmature *arm) +{ + BLI_assert(BLI_array_is_zeroed(uarm, 1)); + + /* TODO: include size of ID-properties. */ + uarm->undo_size = 0; + + ED_armature_ebone_listbase_copy(&uarm->lb, arm->edbo); + + /* active bone */ + if (arm->act_edbone) { + EditBone *ebone = arm->act_edbone; + uarm->act_edbone = ebone->temp.ebone; + } + + ED_armature_ebone_listbase_temp_clear(&uarm->lb); + + for (EditBone *ebone = uarm->lb.first; ebone; ebone = ebone->next) { + uarm->undo_size += sizeof(EditBone); + } + + return uarm; +} + +static void undoarm_free_data(UndoArmature *uarm) +{ + ED_armature_ebone_listbase_free(&uarm->lb); +} + +static Object *editarm_object_from_context(bContext *C) +{ + Object *obedit = CTX_data_edit_object(C); + if (obedit && obedit->type == OB_ARMATURE) { + bArmature *arm = obedit->data; + if (arm->edbo != NULL) { + return obedit; + } + } + return NULL; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Implements ED Undo System + * \{ */ + +typedef struct ArmatureUndoStep { + UndoStep step; + /* note: will split out into list for multi-object-editmode. */ + UndoRefID_Object obedit_ref; + UndoArmature data; +} ArmatureUndoStep; + +static bool armature_undosys_poll(bContext *C) +{ + return editarm_object_from_context(C) != NULL; +} + +static bool armature_undosys_step_encode(struct bContext *C, UndoStep *us_p) +{ + ArmatureUndoStep *us = (ArmatureUndoStep *)us_p; + us->obedit_ref.ptr = editarm_object_from_context(C); + bArmature *arm = us->obedit_ref.ptr->data; + undoarm_from_editarm(&us->data, arm); + us->step.data_size = us->data.undo_size; + return true; +} + +static void armature_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir)) +{ + /* TODO(campbell): undo_system: use low-level API to set mode. */ + ED_object_mode_set(C, OB_MODE_EDIT); + BLI_assert(armature_undosys_poll(C)); + + ArmatureUndoStep *us = (ArmatureUndoStep *)us_p; + Object *obedit = us->obedit_ref.ptr; + bArmature *arm = obedit->data; + undoarm_to_editarm(&us->data, arm); + DEG_id_tag_update(&obedit->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); +} + +static void armature_undosys_step_free(UndoStep *us_p) +{ + ArmatureUndoStep *us = (ArmatureUndoStep *)us_p; + undoarm_free_data(&us->data); +} + +static void armature_undosys_foreach_ID_ref( + UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data) +{ + ArmatureUndoStep *us = (ArmatureUndoStep *)us_p; + foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref)); +} + +/* Export for ED_undo_sys. */ +void ED_armature_undosys_type(UndoType *ut) +{ + ut->name = "Edit Armature"; + ut->poll = armature_undosys_poll; + ut->step_encode = armature_undosys_step_encode; + ut->step_decode = armature_undosys_step_decode; + ut->step_free = armature_undosys_step_free; + + ut->step_foreach_ID_ref = armature_undosys_foreach_ID_ref; + + ut->mode = BKE_UNDOTYPE_MODE_STORE; + ut->use_context = true; + + ut->step_size = sizeof(ArmatureUndoStep); +} + +/** \} */ diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c index 9500fd59b8b..489940007e4 100644 --- a/source/blender/editors/armature/meshlaplacian.c +++ b/source/blender/editors/armature/meshlaplacian.c @@ -46,6 +46,8 @@ #include "ED_mesh.h" #include "ED_armature.h" +#include "DEG_depsgraph.h" + #include "eigen_capi.h" #include "meshlaplacian.h" @@ -600,9 +602,10 @@ static float heat_limit_weight(float weight) return weight; } -void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource, - bDeformGroup **dgrouplist, bDeformGroup **dgroupflip, - float (*root)[3], float (*tip)[3], int *selected, const char **err_str) +void heat_bone_weighting( + Object *ob, Mesh *me, float (*verts)[3], int numsource, + bDeformGroup **dgrouplist, bDeformGroup **dgroupflip, + float (*root)[3], float (*tip)[3], int *selected, const char **err_str) { LaplacianSystem *sys; MLoopTri *mlooptri; diff --git a/source/blender/editors/armature/meshlaplacian.h b/source/blender/editors/armature/meshlaplacian.h index bba8c739abf..05ade4fc43e 100644 --- a/source/blender/editors/armature/meshlaplacian.h +++ b/source/blender/editors/armature/meshlaplacian.h @@ -52,10 +52,11 @@ float laplacian_system_get_solution(LaplacianSystem *sys, int v); /* Heat Weighting */ -void heat_bone_weighting(struct Object *ob, struct Mesh *me, float (*verts)[3], - int numbones, struct bDeformGroup **dgrouplist, - struct bDeformGroup **dgroupflip, float (*root)[3], float (*tip)[3], - int *selected, const char **error); +void heat_bone_weighting( + struct Object *ob, struct Mesh *me, float (*verts)[3], + int numbones, struct bDeformGroup **dgrouplist, + struct bDeformGroup **dgroupflip, float (*root)[3], float (*tip)[3], + int *selected, const char **error); #ifdef RIGID_DEFORM /* As-Rigid-As-Possible Deformation */ diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c index 74e29b2e8da..520ecc797aa 100644 --- a/source/blender/editors/armature/pose_edit.c +++ b/source/blender/editors/armature/pose_edit.c @@ -82,46 +82,62 @@ Object *ED_pose_object_from_context(bContext *C) } /* This function is used to process the necessary updates for */ -void ED_armature_enter_posemode(bContext *C, Base *base) +bool ED_object_posemode_enter_ex(struct Main *bmain, Object *ob) { - ReportList *reports = CTX_wm_reports(C); - Object *ob = base->object; - - if (ID_IS_LINKED(ob)) { - BKE_report(reports, RPT_WARNING, "Cannot pose libdata"); - return; - } + BLI_assert(!ID_IS_LINKED(ob)); + bool ok = false; switch (ob->type) { case OB_ARMATURE: ob->restore_mode = ob->mode; ob->mode |= OB_MODE_POSE; /* Inform all CoW versions that we changed the mode. */ - DEG_id_tag_update_ex(CTX_data_main(C), &ob->id, DEG_TAG_COPY_ON_WRITE); - WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_POSE, NULL); - + DEG_id_tag_update_ex(bmain, &ob->id, DEG_TAG_COPY_ON_WRITE); + ok = true; + break; default: - return; + break; } - - /* XXX: disabled as this would otherwise cause a nasty loop... */ - //ED_object_toggle_modes(C, ob->mode); + + return ok; +} +bool ED_object_posemode_enter(bContext *C, Object *ob) +{ + ReportList *reports = CTX_wm_reports(C); + if (ID_IS_LINKED(ob)) { + BKE_report(reports, RPT_WARNING, "Cannot pose libdata"); + return false; + } + struct Main *bmain = CTX_data_main(C); + bool ok = ED_object_posemode_enter_ex(bmain, ob); + if (ok) { + WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_POSE, NULL); + } + return ok; } -void ED_armature_exit_posemode(bContext *C, Base *base) +bool ED_object_posemode_exit_ex(struct Main *bmain, Object *ob) { - if (base) { - Object *ob = base->object; - + bool ok = false; + if (ob) { ob->restore_mode = ob->mode; ob->mode &= ~OB_MODE_POSE; /* Inform all CoW versions that we changed the mode. */ - DEG_id_tag_update_ex(CTX_data_main(C), &ob->id, DEG_TAG_COPY_ON_WRITE); - + DEG_id_tag_update_ex(bmain, &ob->id, DEG_TAG_COPY_ON_WRITE); + ok = true; + } + return ok; +} +bool ED_object_posemode_exit(bContext *C, Object *ob) +{ + struct Main *bmain = CTX_data_main(C); + bool ok = ED_object_posemode_exit_ex(bmain, ob); + if (ok) { WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL); } + return ok; } /* if a selected or active bone is protected, throw error (oonly if warn == 1) and return 1 */ @@ -597,7 +613,7 @@ static void pose_copy_menu(Scene *scene) /* ********************************************** */ -static int pose_flip_names_exec(bContext *C, wmOperator *UNUSED(op)) +static int pose_flip_names_exec(bContext *C, wmOperator *op) { Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); bArmature *arm; @@ -606,6 +622,8 @@ static int pose_flip_names_exec(bContext *C, wmOperator *UNUSED(op)) if (ELEM(NULL, ob, ob->pose)) return OPERATOR_CANCELLED; + const bool do_strip_numbers = RNA_boolean_get(op->ptr, "do_strip_numbers"); + arm = ob->data; ListBase bones_names = {NULL}; @@ -616,7 +634,7 @@ static int pose_flip_names_exec(bContext *C, wmOperator *UNUSED(op)) } CTX_DATA_END; - ED_armature_bones_flip_names(arm, &bones_names); + ED_armature_bones_flip_names(arm, &bones_names, do_strip_numbers); BLI_freelistN(&bones_names); @@ -642,6 +660,10 @@ void POSE_OT_flip_names(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, "do_strip_numbers", false, "Strip Numbers", + "Try to remove right-most dot-number from flipped names " + "(WARNING: may result in incoherent naming in some cases)"); } /* ------------------ */ diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c index d89b2fcfe84..54c40621a14 100644 --- a/source/blender/editors/armature/pose_lib.c +++ b/source/blender/editors/armature/pose_lib.c @@ -834,7 +834,6 @@ typedef struct tPoseLib_PreviewData { bAction *act; /* poselib to use */ TimeMarker *marker; /* 'active' pose */ - int selcount; /* number of selected elements to work on */ int totcount; /* total number of elements to work on */ short state; /* state of main loop */ @@ -867,7 +866,8 @@ enum { /* defines for tPoseLib_PreviewData->flag values */ enum { PL_PREVIEW_FIRSTTIME = (1 << 0), - PL_PREVIEW_SHOWORIGINAL = (1 << 1) + PL_PREVIEW_SHOWORIGINAL = (1 << 1), + PL_PREVIEW_ANY_BONE_SELECTED = (1 << 2), }; /* ---------------------------- */ @@ -887,7 +887,20 @@ static void poselib_backup_posecopy(tPoseLib_PreviewData *pld) { bActionGroup *agrp; bPoseChannel *pchan; - + bool selected = false; + + /* determine whether any bone is selected. */ + LISTBASE_FOREACH (bPoseChannel *, bchan, &pld->pose->chanbase) { + selected = bchan->bone != NULL && bchan->bone->flag & BONE_SELECTED; + if (selected) { + pld->flag |= PL_PREVIEW_ANY_BONE_SELECTED; + break; + } + } + if (!selected) { + pld->flag &= ~PL_PREVIEW_ANY_BONE_SELECTED; + } + /* for each posechannel that has an actionchannel in */ for (agrp = pld->act->groups.first; agrp; agrp = agrp->next) { /* try to find posechannel */ @@ -909,8 +922,6 @@ static void poselib_backup_posecopy(tPoseLib_PreviewData *pld) BLI_addtail(&pld->backups, plb); /* mark as being affected */ - if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED)) - pld->selcount++; pld->totcount++; } } @@ -971,6 +982,7 @@ static void poselib_apply_pose(tPoseLib_PreviewData *pld) KeyframeEditData ked = {{NULL}}; KeyframeEditFunc group_ok_cb; int frame = 1; + const bool any_bone_selected = pld->flag & PL_PREVIEW_ANY_BONE_SELECTED; /* get the frame */ if (pld->marker) @@ -983,8 +995,7 @@ static void poselib_apply_pose(tPoseLib_PreviewData *pld) group_ok_cb = ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE); ked.f1 = ((float)frame) - 0.5f; ked.f2 = ((float)frame) + 0.5f; - - + /* start applying - only those channels which have a key at this point in time! */ for (agrp = act->groups.first; agrp; agrp = agrp->next) { /* check if group has any keyframes */ @@ -996,7 +1007,7 @@ static void poselib_apply_pose(tPoseLib_PreviewData *pld) bool ok = 0; /* check if this bone should get any animation applied */ - if (pld->selcount == 0) { + if (!any_bone_selected) { /* if no bones are selected, then any bone is ok */ ok = 1; } @@ -1009,7 +1020,7 @@ static void poselib_apply_pose(tPoseLib_PreviewData *pld) ok = 1; } } - + if (ok) animsys_evaluate_action_group(ptr, act, agrp, NULL, (float)frame); } @@ -1028,14 +1039,15 @@ static void poselib_keytag_pose(bContext *C, Scene *scene, tPoseLib_PreviewData KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_WHOLE_CHARACTER_ID); ListBase dsources = {NULL, NULL}; bool autokey = autokeyframe_cfra_can_key(scene, &pld->ob->id); - + const bool any_bone_selected = pld->flag & PL_PREVIEW_ANY_BONE_SELECTED; + /* start tagging/keying */ for (agrp = act->groups.first; agrp; agrp = agrp->next) { /* only for selected bones unless there aren't any selected, in which case all are included */ pchan = BKE_pose_channel_find_name(pose, agrp->name); if (pchan) { - if ((pld->selcount == 0) || ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED))) { + if (!any_bone_selected || ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED))) { if (autokey) { /* add datasource override for the PoseChannel, to be used later */ ANIM_relative_keyingset_add_source(&dsources, &pld->ob->id, &RNA_PoseBone, pchan); diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c index 9bc678cd9e6..a66cedd8d4f 100644 --- a/source/blender/editors/armature/pose_select.c +++ b/source/blender/editors/armature/pose_select.c @@ -134,7 +134,7 @@ void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select) /* called from editview.c, for mode-less pose selection */ /* assumes scene obact and basact is still on old situation */ bool ED_do_pose_selectbuffer( - Scene *scene, ViewLayer *view_layer, Base *base, const unsigned int *buffer, short hits, + ViewLayer *view_layer, Base *base, const unsigned int *buffer, short hits, bool extend, bool deselect, bool toggle, bool do_nearest) { Object *ob = base->object; @@ -142,11 +142,13 @@ bool ED_do_pose_selectbuffer( if (!ob || !ob->pose) return 0; - nearBone = get_bone_from_selectbuffer(scene, base, buffer, hits, 1, do_nearest); + Object *ob_act = OBACT(view_layer); + Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer); + + nearBone = get_bone_from_selectbuffer(base, obedit, buffer, hits, 1, do_nearest); /* if the bone cannot be affected, don't do anything */ if ((nearBone) && !(nearBone->flag & BONE_UNSELECTABLE)) { - Object *ob_act = OBACT(view_layer); bArmature *arm = ob->data; /* since we do unified select, we don't shift+select a bone if the @@ -228,7 +230,7 @@ void ED_pose_de_selectall(Object *ob, int select_mode, const bool ignore_visibil return; } - /* Determine if we're selecting or deselecting */ + /* Determine if we're selecting or deselecting */ if (select_mode == SEL_TOGGLE) { select_mode = SEL_SELECT; for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c index 18d6408f026..c49591be5d1 100644 --- a/source/blender/editors/armature/pose_transform.c +++ b/source/blender/editors/armature/pose_transform.c @@ -158,6 +158,28 @@ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op) curbone->roll = eul[1]; } + /* combine pose and rest values for bendy bone settings, + * then clear the pchan values (so we don't get a double-up) + */ + if (pchan->bone->segments > 1) { + curbone->curveInX += pchan->curveInX; + curbone->curveInY += pchan->curveInY; + curbone->curveOutX += pchan->curveOutX; + curbone->curveOutY += pchan->curveOutY; + curbone->roll1 += pchan->roll1; + curbone->roll2 += pchan->roll2; + curbone->ease1 += pchan->ease1; + curbone->ease2 += pchan->ease2; + curbone->scaleIn += pchan->scaleIn; + curbone->scaleOut += pchan->scaleOut; + + pchan->curveInX = pchan->curveOutX = 0.0f; + pchan->curveInY = pchan->curveOutY = 0.0f; + pchan->roll1 = pchan->roll2 = 0.0f; + pchan->ease1 = pchan->ease2 = 0.0f; + pchan->scaleIn = pchan->scaleOut = 1.0f; + } + /* clear transform values for pchan */ zero_v3(pchan->loc); zero_v3(pchan->eul); @@ -510,7 +532,7 @@ static int pose_paste_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } /* Make sure data from this file is usable for pose paste. */ - if (BLI_listbase_count_ex(&tmp_bmain->object, 2) != 1) { + if (BLI_listbase_count_at_most(&tmp_bmain->object, 2) != 1) { BKE_report(op->reports, RPT_ERROR, "Copy buffer is not from pose mode"); BKE_main_free(tmp_bmain); return OPERATOR_CANCELLED; diff --git a/source/blender/editors/armature/reeb.c b/source/blender/editors/armature/reeb.c index 0eb44085bae..fda7012e955 100644 --- a/source/blender/editors/armature/reeb.c +++ b/source/blender/editors/armature/reeb.c @@ -546,7 +546,7 @@ void verifyFaces(ReebGraph *rg) int total = 0; ReebArc *arc = NULL; for (arc = rg->arcs.first; arc; arc = arc->next) { - total += BLI_ghash_size(arc->faces); + total += BLI_ghash_len(arc->faces); } #endif @@ -1656,7 +1656,7 @@ int filterSmartReebGraph(ReebGraph *UNUSED(rg), float UNUSED(threshold)) { GHashIterator ghi; int merging = 0; - int total = BLI_ghash_size(arc->faces); + int total = BLI_ghash_len(arc->faces); float avg_angle = 0; float avg_vec[3] = {0, 0, 0}; @@ -1932,7 +1932,7 @@ void REEB_exportGraph(ReebGraph *rg, int count) add_v3_v3v3(p, arc->tail->p, arc->head->p); mul_v3_fl(p, 0.5f); - fprintf(f, "angle %0.3f %0.3f %0.3f %0.3f %i\n", p[0], p[1], p[2], arc->angle, BLI_ghash_size(arc->faces)); + fprintf(f, "angle %0.3f %0.3f %0.3f %0.3f %i\n", p[0], p[1], p[2], arc->angle, BLI_ghash_len(arc->faces)); exportNode(f, "v2", arc->tail); } @@ -2678,7 +2678,7 @@ static void shortestPathsFromVert(EditMesh *em, EditVert *starting_vert, EdgeInd eed->f1 = 0; } - while (BLI_heap_size(edge_heap) > 0) { + while (BLI_heap_len(edge_heap) > 0) { float current_weight; current_eve->f1 = 1; /* mark vertex as selected */ @@ -2695,7 +2695,7 @@ static void shortestPathsFromVert(EditMesh *em, EditVert *starting_vert, EdgeInd /* Find next shortest edge with unselected verts */ do { current_weight = BLI_heap_node_value(BLI_heap_top(edge_heap)); - select_eed = BLI_heap_popmin(edge_heap); + select_eed = BLI_heap_pop_min(edge_heap); } while (select_eed != NULL && select_eed->v1->f1 != 0 && select_eed->v2->f1); if (select_eed != NULL) { diff --git a/source/blender/editors/curve/CMakeLists.txt b/source/blender/editors/curve/CMakeLists.txt index ae5c0a13ced..85daa7e44e5 100644 --- a/source/blender/editors/curve/CMakeLists.txt +++ b/source/blender/editors/curve/CMakeLists.txt @@ -43,6 +43,7 @@ set(SRC editcurve_add.c editcurve_paint.c editcurve_select.c + editcurve_undo.c editfont.c editfont_undo.c diff --git a/source/blender/editors/curve/curve_intern.h b/source/blender/editors/curve/curve_intern.h index bf1e22ae170..020d34f2767 100644 --- a/source/blender/editors/curve/curve_intern.h +++ b/source/blender/editors/curve/curve_intern.h @@ -35,6 +35,7 @@ /* internal exports only */ struct ListBase; struct EditNurb; +struct GHash; struct Object; struct wmOperatorType; struct ViewContext; @@ -129,6 +130,10 @@ void CURVE_OT_cyclic_toggle(struct wmOperatorType *ot); void CURVE_OT_match_texture_space(struct wmOperatorType *ot); +/* exported for editcurve_undo.c */ +struct GHash *ED_curve_keyindex_hash_duplicate(struct GHash *keyindex); +void ED_curve_keyindex_update_nurb(struct EditNurb *editnurb, struct Nurb *nu, struct Nurb *newnu); + bool ED_curve_pick_vert( struct ViewContext *vc, short sel, const int mval[2], struct Nurb **r_nurb, struct BezTriple **r_bezt, struct BPoint **r_bp, short *r_handle); diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 4b578ba389e..3ea8592ac3e 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -84,16 +84,6 @@ #include "RNA_define.h" #include "RNA_enum_types.h" -/* Undo stuff */ -typedef struct { - ListBase nubase; - int actvert; - GHash *undoIndex; - ListBase fcurves, drivers; - int actnu; - int flag; -} UndoCurve; - void selectend_nurb(Object *obedit, enum eEndPoint_Types selfirst, bool doswap, bool selstatus); static void adduplicateflagNurb(Object *obedit, ListBase *newnurb, const short flag, const bool split); static int curve_delete_segments(Object *obedit, const bool split); @@ -346,7 +336,7 @@ static void keyIndex_updateBP(EditNurb *editnurb, BPoint *bp, keyIndex_updateCV(editnurb, (char *)bp, (char *)newbp, count, sizeof(BPoint)); } -static void keyIndex_updateNurb(EditNurb *editnurb, Nurb *nu, Nurb *newnu) +void ED_curve_keyindex_update_nurb(EditNurb *editnurb, Nurb *nu, Nurb *newnu) { if (nu->bezt) { keyIndex_updateBezt(editnurb, nu->bezt, newnu->bezt, newnu->pntsu); @@ -525,12 +515,12 @@ static void keyData_switchDirectionNurb(Curve *cu, Nurb *nu) switch_keys_direction(cu, nu); } -static GHash *dupli_keyIndexHash(GHash *keyindex) +GHash *ED_curve_keyindex_hash_duplicate(GHash *keyindex) { GHash *gh; GHashIterator gh_iter; - gh = BLI_ghash_ptr_new_ex("dupli_keyIndex gh", BLI_ghash_size(keyindex)); + gh = BLI_ghash_ptr_new_ex("dupli_keyIndex gh", BLI_ghash_len(keyindex)); GHASH_ITER (gh_iter, keyindex) { void *cv = BLI_ghashIterator_getKey(&gh_iter); @@ -1242,7 +1232,10 @@ void ED_curve_editnurb_make(Object *obedit) if (actkey) { // XXX strcpy(G.editModeTitleExtra, "(Key) "); + /* TODO(campbell): undo_system: investigate why this was needed. */ +#if 0 undo_editmode_clear(); +#endif } if (editnurb) { @@ -4312,7 +4305,7 @@ bool ED_curve_editnurb_select_pick(bContext *C, const int mval[2], bool extend, short hand; view3d_operator_needs_opengl(C); - view3d_set_viewcontext(C, &vc); + ED_view3d_viewcontext_init(C, &vc); location[0] = mval[0]; location[1] = mval[1]; @@ -4988,7 +4981,7 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ViewContext vc; - view3d_set_viewcontext(C, &vc); + ED_view3d_viewcontext_init(C, &vc); if (vc.rv3d && !RNA_struct_property_is_set(op->ptr, "location")) { Curve *cu; @@ -5020,14 +5013,13 @@ 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_type, 0, - vc.ar, vc.v3d); + CTX_data_main(C), vc.scene, vc.view_layer, 0, vc.ar, vc.v3d); ED_transform_snap_object_project_view3d_mixed( snap_context, SCE_SELECT_FACE, &(const struct SnapObjectParams){ - .snap_select = (vc.scene->obedit != NULL) ? SNAP_NOT_ACTIVE : SNAP_ALL, + .snap_select = (vc.obedit != NULL) ? SNAP_NOT_ACTIVE : SNAP_ALL, .use_object_edit_cage = false, }, mval, NULL, true, @@ -6202,119 +6194,6 @@ void CURVE_OT_tilt_clear(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/****************** undo for curves ****************/ - -static void undoCurve_to_editCurve(void *ucu, void *UNUSED(edata), void *cu_v) -{ - Curve *cu = cu_v; - UndoCurve *undoCurve = ucu; - ListBase *undobase = &undoCurve->nubase; - ListBase *editbase = BKE_curve_editNurbs_get(cu); - Nurb *nu, *newnu; - EditNurb *editnurb = cu->editnurb; - AnimData *ad = BKE_animdata_from_id(&cu->id); - - BKE_nurbList_free(editbase); - - if (undoCurve->undoIndex) { - BKE_curve_editNurb_keyIndex_free(&editnurb->keyindex); - editnurb->keyindex = dupli_keyIndexHash(undoCurve->undoIndex); - } - - if (ad) { - if (ad->action) { - free_fcurves(&ad->action->curves); - copy_fcurves(&ad->action->curves, &undoCurve->fcurves); - } - - free_fcurves(&ad->drivers); - copy_fcurves(&ad->drivers, &undoCurve->drivers); - } - - /* copy */ - for (nu = undobase->first; nu; nu = nu->next) { - newnu = BKE_nurb_duplicate(nu); - - if (editnurb->keyindex) { - keyIndex_updateNurb(editnurb, nu, newnu); - } - - BLI_addtail(editbase, newnu); - } - - cu->actvert = undoCurve->actvert; - cu->actnu = undoCurve->actnu; - cu->flag = undoCurve->flag; - ED_curve_updateAnimPaths(cu); -} - -static void *editCurve_to_undoCurve(void *UNUSED(edata), void *cu_v) -{ - Curve *cu = cu_v; - ListBase *nubase = BKE_curve_editNurbs_get(cu); - UndoCurve *undoCurve; - EditNurb *editnurb = cu->editnurb, tmpEditnurb; - Nurb *nu, *newnu; - AnimData *ad = BKE_animdata_from_id(&cu->id); - - undoCurve = MEM_callocN(sizeof(UndoCurve), "undoCurve"); - - if (editnurb->keyindex) { - undoCurve->undoIndex = dupli_keyIndexHash(editnurb->keyindex); - tmpEditnurb.keyindex = undoCurve->undoIndex; - } - - if (ad) { - if (ad->action) - copy_fcurves(&undoCurve->fcurves, &ad->action->curves); - - copy_fcurves(&undoCurve->drivers, &ad->drivers); - } - - /* copy */ - for (nu = nubase->first; nu; nu = nu->next) { - newnu = BKE_nurb_duplicate(nu); - - if (undoCurve->undoIndex) { - keyIndex_updateNurb(&tmpEditnurb, nu, newnu); - } - - BLI_addtail(&undoCurve->nubase, newnu); - } - - undoCurve->actvert = cu->actvert; - undoCurve->actnu = cu->actnu; - undoCurve->flag = cu->flag; - - return undoCurve; -} - -static void free_undoCurve(void *ucv) -{ - UndoCurve *undoCurve = ucv; - - BKE_nurbList_free(&undoCurve->nubase); - - BKE_curve_editNurb_keyIndex_free(&undoCurve->undoIndex); - - free_fcurves(&undoCurve->fcurves); - free_fcurves(&undoCurve->drivers); - - MEM_freeN(undoCurve); -} - -static void *get_data(bContext *C) -{ - Object *obedit = CTX_data_edit_object(C); - return obedit; -} - -/* and this is all the undo system needs to know */ -void undo_push_curve(bContext *C, const char *name) -{ - undo_editmode_push(C, name, get_data, free_undoCurve, undoCurve_to_editCurve, editCurve_to_undoCurve, NULL); -} - void ED_curve_beztcpy(EditNurb *editnurb, BezTriple *dst, BezTriple *src, int count) { memcpy(dst, src, count * sizeof(BezTriple)); diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c index 281f6c3c22e..f269799973f 100644 --- a/source/blender/editors/curve/editcurve_add.c +++ b/source/blender/editors/curve/editcurve_add.c @@ -53,7 +53,7 @@ #include "ED_object.h" #include "ED_screen.h" -#include "ED_util.h" +#include "ED_undo.h" #include "ED_view3d.h" #include "ED_curve.h" diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c index 062b9c94a1b..36eb4c6c5bc 100644 --- a/source/blender/editors/curve/editcurve_paint.c +++ b/source/blender/editors/curve/editcurve_paint.c @@ -365,7 +365,7 @@ static void curve_draw_stroke_3d(const struct bContext *UNUSED(C), ARegion *UNUS wmOperator *op = arg; struct CurveDrawData *cdd = op->customdata; - const int stroke_len = BLI_mempool_count(cdd->stroke_elem_pool); + const int stroke_len = BLI_mempool_len(cdd->stroke_elem_pool); if (stroke_len == 0) { return; @@ -608,7 +608,7 @@ static bool curve_draw_init(bContext *C, wmOperator *op, bool is_invoke) cdd->depsgraph = CTX_data_depsgraph(C); if (is_invoke) { - view3d_set_viewcontext(C, &cdd->vc); + ED_view3d_viewcontext_init(C, &cdd->vc); if (ELEM(NULL, cdd->vc.ar, cdd->vc.rv3d, cdd->vc.v3d, cdd->vc.win, cdd->vc.scene)) { MEM_freeN(cdd); BKE_report(op->reports, RPT_ERROR, "Unable to access 3D viewport"); @@ -706,7 +706,7 @@ static void curve_draw_exec_precalc(wmOperator *op) if (!RNA_property_is_set(op->ptr, prop)) { bool use_cyclic = false; - if (BLI_mempool_count(cdd->stroke_elem_pool) > 2) { + if (BLI_mempool_len(cdd->stroke_elem_pool) > 2) { BLI_mempool_iter iter; const struct StrokeElem *selem, *selem_first, *selem_last; @@ -732,7 +732,7 @@ static void curve_draw_exec_precalc(wmOperator *op) (cps->radius_taper_end != 0.0f)) { /* note, we could try to de-duplicate the length calculations above */ - const int stroke_len = BLI_mempool_count(cdd->stroke_elem_pool); + const int stroke_len = BLI_mempool_len(cdd->stroke_elem_pool); BLI_mempool_iter iter; struct StrokeElem *selem, *selem_prev; @@ -788,18 +788,18 @@ static int curve_draw_exec(bContext *C, wmOperator *op) struct CurveDrawData *cdd = op->customdata; const CurvePaintSettings *cps = &cdd->vc.scene->toolsettings->curve_paint_settings; - Object *obedit = cdd->vc.scene->obedit; + Object *obedit = cdd->vc.obedit; Curve *cu = obedit->data; ListBase *nurblist = object_editcurve_get(obedit); - int stroke_len = BLI_mempool_count(cdd->stroke_elem_pool); + int stroke_len = BLI_mempool_len(cdd->stroke_elem_pool); const bool is_3d = (cu->flag & CU_3D) != 0; invert_m4_m4(obedit->imat, obedit->obmat); - if (BLI_mempool_count(cdd->stroke_elem_pool) == 0) { + if (BLI_mempool_len(cdd->stroke_elem_pool) == 0) { curve_draw_stroke_from_operator(op); - stroke_len = BLI_mempool_count(cdd->stroke_elem_pool); + stroke_len = BLI_mempool_len(cdd->stroke_elem_pool); } ED_curve_deselect_all(cu->editnurb); diff --git a/source/blender/editors/curve/editcurve_select.c b/source/blender/editors/curve/editcurve_select.c index 02b8970731c..673faa37f2a 100644 --- a/source/blender/editors/curve/editcurve_select.c +++ b/source/blender/editors/curve/editcurve_select.c @@ -559,7 +559,7 @@ static int select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent const bool select = !RNA_boolean_get(op->ptr, "deselect"); view3d_operator_needs_opengl(C); - view3d_set_viewcontext(C, &vc); + ED_view3d_viewcontext_init(C, &vc); if (!ED_curve_pick_vert(&vc, 1, event->mval, &nu, &bezt, &bp, NULL)) { return OPERATOR_CANCELLED; @@ -1607,7 +1607,7 @@ static void curve_select_shortest_path_surf(Nurb *nu, int vert_src, int vert_dst int axis, sign; int u, v; - vert_curr = *((int *)BLI_heap_popmin(heap)); + vert_curr = *((int *)BLI_heap_pop_min(heap)); if (vert_curr == vert_dst) { break; } @@ -1677,7 +1677,7 @@ static int edcu_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmE } view3d_operator_needs_opengl(C); - view3d_set_viewcontext(C, &vc); + ED_view3d_viewcontext_init(C, &vc); if (!ED_curve_pick_vert(&vc, 1, event->mval, &nu_dst, &bezt_dst, &bp_dst, NULL)) { return OPERATOR_PASS_THROUGH; diff --git a/source/blender/editors/curve/editcurve_undo.c b/source/blender/editors/curve/editcurve_undo.c new file mode 100644 index 00000000000..4eb2abaefad --- /dev/null +++ b/source/blender/editors/curve/editcurve_undo.c @@ -0,0 +1,257 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/curve/editcurve_undo.c + * \ingroup edcurve + */ + +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_anim_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_ghash.h" +#include "BLI_array_utils.h" + +#include "BKE_context.h" +#include "BKE_curve.h" +#include "BKE_fcurve.h" +#include "BKE_library.h" +#include "BKE_animsys.h" +#include "BKE_undo_system.h" + +#include "DEG_depsgraph.h" + +#include "ED_object.h" +#include "ED_util.h" +#include "ED_curve.h" + +#include "WM_types.h" +#include "WM_api.h" + +#include "curve_intern.h" + +/* -------------------------------------------------------------------- */ +/** \name Undo Conversion + * \{ */ + +typedef struct { + ListBase nubase; + int actvert; + GHash *undoIndex; + ListBase fcurves, drivers; + int actnu; + int flag; + + /* Stored in the object, needed since users may change the active key while in edit-mode. */ + struct { + short shapenr; + } obedit; + + size_t undo_size; +} UndoCurve; + +static void undocurve_to_editcurve(UndoCurve *ucu, Curve *cu, short *r_shapenr) +{ + ListBase *undobase = &ucu->nubase; + ListBase *editbase = BKE_curve_editNurbs_get(cu); + Nurb *nu, *newnu; + EditNurb *editnurb = cu->editnurb; + AnimData *ad = BKE_animdata_from_id(&cu->id); + + BKE_nurbList_free(editbase); + + if (ucu->undoIndex) { + BKE_curve_editNurb_keyIndex_free(&editnurb->keyindex); + editnurb->keyindex = ED_curve_keyindex_hash_duplicate(ucu->undoIndex); + } + + if (ad) { + if (ad->action) { + free_fcurves(&ad->action->curves); + copy_fcurves(&ad->action->curves, &ucu->fcurves); + } + + free_fcurves(&ad->drivers); + copy_fcurves(&ad->drivers, &ucu->drivers); + } + + /* copy */ + for (nu = undobase->first; nu; nu = nu->next) { + newnu = BKE_nurb_duplicate(nu); + + if (editnurb->keyindex) { + ED_curve_keyindex_update_nurb(editnurb, nu, newnu); + } + + BLI_addtail(editbase, newnu); + } + + cu->actvert = ucu->actvert; + cu->actnu = ucu->actnu; + cu->flag = ucu->flag; + *r_shapenr = ucu->obedit.shapenr; + ED_curve_updateAnimPaths(cu); +} + +static void undocurve_from_editcurve(UndoCurve *ucu, Curve *cu, const short shapenr) +{ + BLI_assert(BLI_array_is_zeroed(ucu, 1)); + ListBase *nubase = BKE_curve_editNurbs_get(cu); + EditNurb *editnurb = cu->editnurb, tmpEditnurb; + Nurb *nu, *newnu; + AnimData *ad = BKE_animdata_from_id(&cu->id); + + /* TODO: include size of fcurve & undoIndex */ + // ucu->undo_size = 0; + + if (editnurb->keyindex) { + ucu->undoIndex = ED_curve_keyindex_hash_duplicate(editnurb->keyindex); + tmpEditnurb.keyindex = ucu->undoIndex; + } + + if (ad) { + if (ad->action) + copy_fcurves(&ucu->fcurves, &ad->action->curves); + + copy_fcurves(&ucu->drivers, &ad->drivers); + } + + /* copy */ + for (nu = nubase->first; nu; nu = nu->next) { + newnu = BKE_nurb_duplicate(nu); + + if (ucu->undoIndex) { + ED_curve_keyindex_update_nurb(&tmpEditnurb, nu, newnu); + } + + BLI_addtail(&ucu->nubase, newnu); + + ucu->undo_size += ( + (nu->bezt ? (sizeof(BezTriple) * nu->pntsu) : 0) + + (nu->bp ? (sizeof(BPoint) * (nu->pntsu * nu->pntsv)) : 0) + + (nu->knotsu ? (sizeof(float) * KNOTSU(nu)) : 0) + + (nu->knotsv ? (sizeof(float) * KNOTSV(nu)) : 0) + + sizeof(Nurb)); + } + + ucu->actvert = cu->actvert; + ucu->actnu = cu->actnu; + ucu->flag = cu->flag; + + ucu->obedit.shapenr = shapenr; +} + +static void undocurve_free_data(UndoCurve *uc) +{ + BKE_nurbList_free(&uc->nubase); + + BKE_curve_editNurb_keyIndex_free(&uc->undoIndex); + + free_fcurves(&uc->fcurves); + free_fcurves(&uc->drivers); +} + +static Object *editcurve_object_from_context(bContext *C) +{ + Object *obedit = CTX_data_edit_object(C); + if (obedit && ELEM(obedit->type, OB_CURVE, OB_SURF)) { + Curve *cu = obedit->data; + if (BKE_curve_editNurbs_get(cu) != NULL) { + return obedit; + } + } + return NULL; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Implements ED Undo System + * \{ */ + +typedef struct CurveUndoStep { + UndoStep step; + /* note: will split out into list for multi-object-editmode. */ + UndoRefID_Object obedit_ref; + UndoCurve data; +} CurveUndoStep; + +static bool curve_undosys_poll(bContext *C) +{ + Object *obedit = editcurve_object_from_context(C); + return (obedit != NULL); +} + +static bool curve_undosys_step_encode(struct bContext *C, UndoStep *us_p) +{ + CurveUndoStep *us = (CurveUndoStep *)us_p; + us->obedit_ref.ptr = editcurve_object_from_context(C); + undocurve_from_editcurve(&us->data, us->obedit_ref.ptr->data, us->obedit_ref.ptr->shapenr); + us->step.data_size = us->data.undo_size; + return true; +} + +static void curve_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir)) +{ + /* TODO(campbell): undo_system: use low-level API to set mode. */ + ED_object_mode_set(C, OB_MODE_EDIT); + BLI_assert(curve_undosys_poll(C)); + + CurveUndoStep *us = (CurveUndoStep *)us_p; + Object *obedit = us->obedit_ref.ptr; + undocurve_to_editcurve(&us->data, obedit->data, &obedit->shapenr); + DEG_id_tag_update(&obedit->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); +} + +static void curve_undosys_step_free(UndoStep *us_p) +{ + CurveUndoStep *us = (CurveUndoStep *)us_p; + undocurve_free_data(&us->data); +} + +static void curve_undosys_foreach_ID_ref( + UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data) +{ + CurveUndoStep *us = (CurveUndoStep *)us_p; + foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref)); +} + +/* Export for ED_undo_sys. */ +void ED_curve_undosys_type(UndoType *ut) +{ + ut->name = "Edit Curve"; + ut->poll = curve_undosys_poll; + ut->step_encode = curve_undosys_step_encode; + ut->step_decode = curve_undosys_step_decode; + ut->step_free = curve_undosys_step_free; + + ut->step_foreach_ID_ref = curve_undosys_foreach_ID_ref; + + ut->mode = BKE_UNDOTYPE_MODE_STORE; + ut->use_context = true; + + ut->step_size = sizeof(CurveUndoStep); +} + +/** \} */ diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c index cbb5abf1309..b72ac8c63c8 100644 --- a/source/blender/editors/curve/editfont.c +++ b/source/blender/editors/curve/editfont.c @@ -1857,7 +1857,7 @@ bool ED_curve_editfont_select_pick(bContext *C, const int mval[2], bool extend, const float dist = ED_view3d_select_dist_px(); float dist_sq_best = dist * dist; - view3d_set_viewcontext(C, &vc); + ED_view3d_viewcontext_init(C, &vc); ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); diff --git a/source/blender/editors/curve/editfont_undo.c b/source/blender/editors/curve/editfont_undo.c index a61f863b61e..d4d48e93f43 100644 --- a/source/blender/editors/curve/editfont_undo.c +++ b/source/blender/editors/curve/editfont_undo.c @@ -29,6 +29,8 @@ #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" +#include "BLI_array_utils.h" + #include "DNA_curve_types.h" #include "DNA_object_types.h" @@ -36,10 +38,17 @@ #include "BKE_context.h" #include "BKE_font.h" +#include "BKE_undo_system.h" + +#include "DEG_depsgraph.h" +#include "ED_object.h" #include "ED_curve.h" #include "ED_util.h" +#include "WM_types.h" +#include "WM_api.h" + #define USE_ARRAY_STORE #ifdef USE_ARRAY_STORE @@ -50,6 +59,10 @@ # define ARRAY_CHUNK_SIZE 32 #endif +/* -------------------------------------------------------------------- */ +/** \name Undo Conversion + * \{ */ + typedef struct UndoFont { wchar_t *textbuf; struct CharInfo *textbufinfo; @@ -62,6 +75,8 @@ typedef struct UndoFont { BArrayState *textbufinfo; } store; #endif + + size_t undo_size; } UndoFont; @@ -202,23 +217,20 @@ static void uf_arraystore_free(UndoFont *uf) BLI_array_store_at_size_clear(&uf_arraystore.bs_stride); } - } /** \} */ #endif /* USE_ARRAY_STORE */ -static void undoFont_to_editFont(void *uf_v, void *ecu, void *UNUSED(obdata)) +static void undofont_to_editfont(UndoFont *uf, Curve *cu) { - Curve *cu = (Curve *)ecu; EditFont *ef = cu->editfont; - const UndoFont *uf = uf_v; size_t final_size; #ifdef USE_ARRAY_STORE - uf_arraystore_expand(uf_v); + uf_arraystore_expand(uf); #endif final_size = sizeof(wchar_t) * (uf->len + 1); @@ -233,16 +245,17 @@ static void undoFont_to_editFont(void *uf_v, void *ecu, void *UNUSED(obdata)) ef->selstart = ef->selend = 0; #ifdef USE_ARRAY_STORE - uf_arraystore_expand_clear(uf_v); + uf_arraystore_expand_clear(uf); #endif } -static void *editFont_to_undoFont(void *ecu, void *UNUSED(obdata)) +static void *undofont_from_editfont(UndoFont *uf, Curve *cu) { - Curve *cu = (Curve *)ecu; + BLI_assert(BLI_array_is_zeroed(uf, 1)); + EditFont *ef = cu->editfont; - UndoFont *uf = MEM_callocN(sizeof(*uf), __func__); + size_t mem_used_prev = MEM_get_memory_in_use(); size_t final_size; @@ -269,13 +282,15 @@ static void *editFont_to_undoFont(void *ecu, void *UNUSED(obdata)) } #endif + size_t mem_used_curr = MEM_get_memory_in_use(); + + uf->undo_size = mem_used_prev < mem_used_curr ? mem_used_curr - mem_used_prev : sizeof(UndoFont); + return uf; } -static void free_undoFont(void *uf_v) +static void undofont_free_data(UndoFont *uf) { - UndoFont *uf = uf_v; - #ifdef USE_ARRAY_STORE { LinkData *link = BLI_findptr(&uf_arraystore.local_links, uf, offsetof(LinkData, data)); @@ -291,21 +306,91 @@ static void free_undoFont(void *uf_v) if (uf->textbufinfo) { MEM_freeN(uf->textbufinfo); } - - MEM_freeN(uf); } -static void *get_undoFont(bContext *C) +static Object *editfont_object_from_context(bContext *C) { Object *obedit = CTX_data_edit_object(C); if (obedit && obedit->type == OB_FONT) { - return obedit->data; + Curve *cu = obedit->data; + EditFont *ef = cu->editfont; + if (ef != NULL) { + return obedit; + } } return NULL; } -/* and this is all the undo system needs to know */ -void undo_push_font(bContext *C, const char *name) +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Implements ED Undo System + * \{ */ + +typedef struct FontUndoStep { + UndoStep step; + /* note: will split out into list for multi-object-editmode. */ + UndoRefID_Object obedit_ref; + UndoFont data; +} FontUndoStep; + +static bool font_undosys_poll(bContext *C) { - undo_editmode_push(C, name, get_undoFont, free_undoFont, undoFont_to_editFont, editFont_to_undoFont, NULL); + return editfont_object_from_context(C) != NULL; } + +static bool font_undosys_step_encode(struct bContext *C, UndoStep *us_p) +{ + FontUndoStep *us = (FontUndoStep *)us_p; + us->obedit_ref.ptr = editfont_object_from_context(C); + Curve *cu = us->obedit_ref.ptr->data; + undofont_from_editfont(&us->data, cu); + us->step.data_size = us->data.undo_size; + return true; +} + +static void font_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir)) +{ + /* TODO(campbell): undo_system: use low-level API to set mode. */ + ED_object_mode_set(C, OB_MODE_EDIT); + BLI_assert(font_undosys_poll(C)); + + FontUndoStep *us = (FontUndoStep *)us_p; + Object *obedit = us->obedit_ref.ptr; + Curve *cu = obedit->data; + undofont_to_editfont(&us->data, cu); + DEG_id_tag_update(&obedit->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); +} + +static void font_undosys_step_free(UndoStep *us_p) +{ + FontUndoStep *us = (FontUndoStep *)us_p; + undofont_free_data(&us->data); +} + +static void font_undosys_foreach_ID_ref( + UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data) +{ + FontUndoStep *us = (FontUndoStep *)us_p; + foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref)); +} + +/* Export for ED_undo_sys. */ +void ED_font_undosys_type(UndoType *ut) +{ + ut->name = "Edit Font"; + ut->poll = font_undosys_poll; + ut->step_encode = font_undosys_step_encode; + ut->step_decode = font_undosys_step_decode; + ut->step_free = font_undosys_step_free; + + ut->step_foreach_ID_ref = font_undosys_foreach_ID_ref; + + ut->mode = BKE_UNDOTYPE_MODE_STORE; + ut->use_context = true; + + ut->step_size = sizeof(FontUndoStep); +} + +/** \} */ diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index 4a95027528b..942aa861cec 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -41,7 +41,7 @@ #include "BLI_math.h" #include "BLI_utildefines.h" -#include "BLI_polyfill2d.h" +#include "BLI_polyfill_2d.h" #include "BLF_api.h" #include "BLT_translation.h" @@ -1479,7 +1479,7 @@ static void gp_draw_status_text(const bGPdata *gpd, ARegion *ar) /* grease pencil icon... */ // XXX: is this too intrusive? - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); xco -= U.widget_unit; diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c index 38927cf91e1..533ab21dbb6 100644 --- a/source/blender/editors/gpencil/gpencil_brush.c +++ b/source/blender/editors/gpencil/gpencil_brush.c @@ -54,7 +54,6 @@ #include "DNA_object_types.h" #include "BKE_context.h" -#include "BKE_global.h" #include "BKE_gpencil.h" #include "BKE_library.h" #include "BKE_report.h" diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c index d2ae8bc3ce7..2c3c9f4f9b9 100644 --- a/source/blender/editors/gpencil/gpencil_convert.c +++ b/source/blender/editors/gpencil/gpencil_convert.c @@ -55,6 +55,7 @@ #include "DNA_space_types.h" #include "DNA_view3d_types.h" #include "DNA_gpencil_types.h" +#include "DNA_workspace_types.h" #include "BKE_collection.h" #include "BKE_context.h" @@ -1293,6 +1294,7 @@ static int gp_convert_poll(bContext *C) bGPDframe *gpf = NULL; ScrArea *sa = CTX_wm_area(C); Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); /* only if the current view is 3D View, if there's valid data (i.e. at least one stroke!), * and if we are not in edit mode! @@ -1301,7 +1303,7 @@ static int gp_convert_poll(bContext *C) (gpl = BKE_gpencil_layer_getactive(gpd)) && (gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0)) && (gpf->strokes.first) && - (scene->obedit == NULL)); + (OBEDIT_FROM_VIEW_LAYER(view_layer) == NULL)); } static int gp_convert_layer_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index 5bd5c9c74b9..9d183222c2d 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -53,7 +53,6 @@ #include "DNA_gpencil_types.h" #include "BKE_context.h" -#include "BKE_global.h" #include "BKE_gpencil.h" #include "BKE_library.h" #include "BKE_object.h" @@ -1063,7 +1062,7 @@ static int gp_brush_remove_exec(bContext *C, wmOperator *op) if (ELEM(NULL, ts, brush)) return OPERATOR_CANCELLED; - if (BLI_listbase_count_ex(&ts->gp_brushes, 2) < 2) { + if (BLI_listbase_count_at_most(&ts->gp_brushes, 2) < 2) { BKE_report(op->reports, RPT_ERROR, "Grease Pencil needs a brush, unable to delete the last one"); return OPERATOR_CANCELLED; } @@ -1421,7 +1420,7 @@ static int gp_palette_remove_exec(bContext *C, wmOperator *op) if (ELEM(NULL, gpd, palette)) return OPERATOR_CANCELLED; - if (BLI_listbase_count_ex(&gpd->palettes, 2) < 2) { + if (BLI_listbase_count_at_most(&gpd->palettes, 2) < 2) { BKE_report(op->reports, RPT_ERROR, "Grease Pencil needs a palette, unable to delete the last one"); return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 22a3224e563..1eee774fd3e 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -55,7 +55,6 @@ #include "DNA_gpencil_types.h" #include "BKE_context.h" -#include "BKE_global.h" #include "BKE_gpencil.h" #include "BKE_library.h" #include "BKE_report.h" diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 472b88cb18b..77e5dc8fe5d 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -46,7 +46,6 @@ #include "PIL_time.h" -#include "BKE_main.h" #include "BKE_paint.h" #include "BKE_gpencil.h" #include "BKE_context.h" @@ -1862,7 +1861,7 @@ static void gpencil_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_ptr) glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); immUniformColor4ub(255, 100, 100, 20); imm_draw_circle_fill_2d(shdr_pos, x, y, p->radius, 40); diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c index 07abab8af2e..dc3483163bf 100644 --- a/source/blender/editors/gpencil/gpencil_select.c +++ b/source/blender/editors/gpencil/gpencil_select.c @@ -37,7 +37,7 @@ #include "BLI_blenlib.h" #include "BLI_ghash.h" -#include "BLI_lasso.h" +#include "BLI_lasso_2d.h" #include "BLI_utildefines.h" #include "BLI_math_vector.h" diff --git a/source/blender/editors/gpencil/gpencil_undo.c b/source/blender/editors/gpencil/gpencil_undo.c index 7a9ad2b32c0..202d7630ae0 100644 --- a/source/blender/editors/gpencil/gpencil_undo.c +++ b/source/blender/editors/gpencil/gpencil_undo.c @@ -45,7 +45,6 @@ #include "BKE_context.h" #include "BKE_global.h" #include "BKE_gpencil.h" -#include "BKE_main.h" #include "ED_gpencil.h" diff --git a/source/blender/editors/groom/editgroom_select.c b/source/blender/editors/groom/editgroom_select.c index 190e121ea2b..9592d3e21fe 100644 --- a/source/blender/editors/groom/editgroom_select.c +++ b/source/blender/editors/groom/editgroom_select.c @@ -324,7 +324,7 @@ static void groom_set_section_select_flags(Groom *groom, int flag) bool ED_groom_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle) { ViewContext vc; - view3d_set_viewcontext(C, &vc); + ED_view3d_viewcontext_init(C, &vc); Groom *groom = vc.obedit->data; struct diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h index 3184ebee4d9..863d817d19a 100644 --- a/source/blender/editors/include/BIF_glutil.h +++ b/source/blender/editors/include/BIF_glutil.h @@ -107,38 +107,6 @@ void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state, float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect, float scaleX, float scaleY, float clip_min_x, float clip_min_y, float clip_max_x, float clip_max_y, float xzoom, float yzoom, float color[4]); -/* 2D Drawing Assistance */ - -/** Define a 2D area (viewport, scissor, matrices) for OpenGL rendering. - * - * glaDefine2DArea and glaBegin2DDraw set up an OpenGL state appropriate - * for drawing using both vertex (Vertex, etc) and raster (RasterPos, Rect) - * commands. All coordinates should be at integer positions. There is little - * to no reason to use glVertex2f etc. functions during 2D rendering, and - * thus no reason to +-0.5 the coordinates or perform other silly - * tricks. - * - * \param screen_rect The screen rectangle to be defined for 2D drawing. - */ -void glaDefine2DArea(struct rcti *screen_rect); - -/* TODO(merwin): put the following 2D code to use, or build new 2D code inspired & informd by it */ - -#if 0 /* UNUSED */ - -typedef struct gla2DDrawInfo gla2DDrawInfo; - -gla2DDrawInfo *glaBegin2DDraw(struct rcti *screen_rect, struct rctf *world_rect); -void gla2DDrawTranslatePt(gla2DDrawInfo *di, float wo_x, float wo_y, int *r_sc_x, int *r_sc_y); -void gla2DDrawTranslatePtv(gla2DDrawInfo *di, float world[2], int r_screen[2]); - -void glaEnd2DDraw(gla2DDrawInfo *di); - -/** Adjust the transformation mapping of a 2d area */ -void gla2DGetMap(gla2DDrawInfo *di, struct rctf *rect); -void gla2DSetMap(gla2DDrawInfo *di, struct rctf *rect); - -#endif /* UNUSED */ void set_inverted_drawing(int enable); void setlinestyle(int nr); diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index 4595bcfa86d..0dcc4f32e43 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -52,6 +52,7 @@ struct ViewContext; struct wmKeyConfig; struct wmOperator; struct Main; +struct UndoType; typedef struct EditBone { struct EditBone *next, *prev; @@ -137,25 +138,26 @@ void ED_keymap_armature(struct wmKeyConfig *keyconf); void ED_armature_from_edit(struct bArmature *arm); void ED_armature_to_edit(struct bArmature *arm); void ED_armature_edit_free(struct bArmature *arm); -void ED_armature_ebone_listbase_temp_clear(struct ListBase *lb); void ED_armature_deselect_all(struct Object *obedit); void ED_armature_deselect_all_visible(struct Object *obedit); bool ED_do_pose_selectbuffer( - struct Scene *scene, struct ViewLayer *view_layer, struct Base *base, const unsigned int *buffer, short hits, + struct ViewLayer *view_layer, struct Base *base, const unsigned int *buffer, short hits, bool extend, bool deselect, bool toggle, bool do_nearest); bool ED_armature_select_pick(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle); int join_armature_exec(struct bContext *C, struct wmOperator *op); struct Bone *get_indexed_bone(struct Object *ob, int index); float ED_rollBoneToVector(EditBone *bone, const float new_up_axis[3], const bool axis_only); -EditBone *ED_armature_bone_find_name(const ListBase *edbo, const char *name); +EditBone *ED_armature_bone_find_name(const struct ListBase *edbo, const char *name); EditBone *ED_armature_bone_get_mirrored(const struct ListBase *edbo, EditBone *ebo); void ED_armature_sync_selection(struct ListBase *edbo); void ED_armature_validate_active(struct bArmature *arm); EditBone *ED_armature_edit_bone_add_primitive(struct Object *obedit_arm, float length, bool view_aligned); EditBone *ED_armature_edit_bone_add(struct bArmature *arm, const char *name); + +void ED_armature_edit_bone_remove_ex(struct bArmature *arm, EditBone *exBone, bool clear_connected); void ED_armature_edit_bone_remove(struct bArmature *arm, EditBone *exBone); bool ED_armature_ebone_is_child_recursive(EditBone *ebone_parent, EditBone *ebone_child); @@ -168,7 +170,7 @@ void ED_armature_ebone_from_mat3(EditBone *ebone, float mat[3][3]); void ED_armature_ebone_from_mat4(EditBone *ebone, float mat[4][4]); void transform_armature_mirror_update(struct Object *obedit); -void ED_armature_origin_set(struct Scene *scene, struct Object *ob, float cursor[3], int centermode, int around); +void ED_armature_origin_set(struct Object *ob, float cursor[3], int centermode, int around); void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4], const bool do_props); void ED_armature_apply_transform(struct Object *ob, float mat[4][4], const bool do_props); @@ -185,9 +187,7 @@ void create_vgroups_from_armature( /* if bone is already in list, pass it as param to ignore it */ void unique_editbone_name(struct ListBase *ebones, char *name, EditBone *bone); void ED_armature_bone_rename(struct bArmature *arm, const char *oldnamep, const char *newnamep); -void ED_armature_bones_flip_names(struct bArmature *arm, struct ListBase *bones_names); - -void undo_push_armature(struct bContext *C, const char *name); +void ED_armature_bones_flip_names(struct bArmature *arm, struct ListBase *bones_names, const bool do_strip_numbers); /* low level selection functions which handle */ int ED_armature_ebone_selectflag_get(const EditBone *ebone); @@ -196,9 +196,19 @@ void ED_armature_ebone_select_set(EditBone *ebone, bool select); void ED_armature_ebone_selectflag_enable(EditBone *ebone, int flag); void ED_armature_ebone_selectflag_disable(EditBone *ebone, int flag); +/* editarmature_undo.c */ +void ED_armature_undosys_type(struct UndoType *ut); + +/* armature_utils.c */ +void ED_armature_ebone_listbase_temp_clear(struct ListBase *lb); +void ED_armature_ebone_listbase_free(struct ListBase *lb); +void ED_armature_ebone_listbase_copy(struct ListBase *lb_dst, struct ListBase *lb_src); + /* poseobject.c */ -void ED_armature_exit_posemode(struct bContext *C, struct Base *base); -void ED_armature_enter_posemode(struct bContext *C, struct Base *base); +bool ED_object_posemode_exit_ex(struct Main *bmain, struct Object *ob); +bool ED_object_posemode_exit(struct bContext *C, struct Object *ob); +bool ED_object_posemode_enter_ex(struct Main *bmain, struct Object *ob); +bool ED_object_posemode_enter(struct bContext *C, struct Object *ob); void ED_pose_de_selectall(struct Object *ob, int select_mode, const bool ignore_visibility); void ED_pose_bone_select(struct Object *ob, struct bPoseChannel *pchan, bool select); void ED_pose_recalculate_paths(struct bContext *C, struct Scene *scene, struct Object *ob); diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h index 859d45e9c86..da726cb8000 100644 --- a/source/blender/editors/include/ED_curve.h +++ b/source/blender/editors/include/ED_curve.h @@ -41,6 +41,7 @@ struct Curve; struct EditNurb; struct BezTriple; struct BPoint; +struct UndoType; /* curve_ops.c */ void ED_operatortypes_curve(void); @@ -48,8 +49,7 @@ void ED_operatormacros_curve(void); void ED_keymap_curve(struct wmKeyConfig *keyconf); /* editcurve.c */ -void undo_push_curve(struct bContext *C, const char *name); -ListBase *object_editcurve_get(struct Object *ob); +struct ListBase *object_editcurve_get(struct Object *ob); void ED_curve_editnurb_load(struct Object *obedit); void ED_curve_editnurb_make(struct Object *obedit); @@ -72,6 +72,9 @@ void ED_curve_deselect_all(struct EditNurb *editnurb); void ED_curve_select_all(struct EditNurb *editnurb); void ED_curve_select_swap(struct EditNurb *editnurb, bool hide_handles); +/* editcurve_undo.c */ +void ED_curve_undosys_type(struct UndoType *ut); + /* editfont.c */ void ED_curve_editfont_load(struct Object *obedit); void ED_curve_editfont_make(struct Object *obedit); @@ -89,7 +92,8 @@ bool ED_curve_active_center(struct Curve *cu, float center[3]); bool ED_curve_editfont_select_pick(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle); /* editfont_undo.c */ -void undo_push_font(struct bContext *C, const char *name); +void ED_font_undosys_type(struct UndoType *ut); + #if 0 /* debug only */ diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h index 95ba6095517..cb824b3c9b7 100644 --- a/source/blender/editors/include/ED_image.h +++ b/source/blender/editors/include/ED_image.h @@ -75,7 +75,7 @@ bool ED_space_image_show_uvedit(struct SpaceImage *sima, struct Object *obedit); bool ED_space_image_paint_curve(const struct bContext *C); -bool ED_space_image_check_show_maskedit(struct ViewLayer *view_layer, struct SpaceImage *sima); +bool ED_space_image_check_show_maskedit(struct SpaceImage *sima, struct ViewLayer *view_layer); int ED_space_image_maskedit_poll(struct bContext *C); int ED_space_image_maskedit_mask_poll(struct bContext *C); diff --git a/source/blender/editors/include/ED_lattice.h b/source/blender/editors/include/ED_lattice.h index 30d66577770..b30929f5307 100644 --- a/source/blender/editors/include/ED_lattice.h +++ b/source/blender/editors/include/ED_lattice.h @@ -4,7 +4,7 @@ * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -18,7 +18,6 @@ * The Original Code is Copyright (C) 2008 Blender Foundation. * All rights reserved. * - * * Contributor(s): Blender Foundation * * ***** END GPL LICENSE BLOCK ***** @@ -31,10 +30,19 @@ #ifndef __ED_LATTICE_H__ #define __ED_LATTICE_H__ +struct wmKeyConfig; +struct UndoType; struct Object; -void ED_lattice_editlatt_free(struct Object *ob); -void ED_lattice_editlatt_make(struct Object *obedit); -void ED_lattice_editlatt_load(struct Object *obedit); +/* lattice_ops.c */ +void ED_operatortypes_lattice(void); +void ED_keymap_lattice(struct wmKeyConfig *keyconf); + +/* editlattice_select.c */ +void ED_lattice_flags_set(struct Object *obedit, int flag); +bool ED_lattice_select_pick(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle); + +/* editlattice_undo.c */ +void ED_lattice_undosys_type(struct UndoType *ut); #endif /* __ED_LATTICE_H__ */ diff --git a/source/blender/editors/include/ED_mball.h b/source/blender/editors/include/ED_mball.h index 232d7d1d234..9982c87a764 100644 --- a/source/blender/editors/include/ED_mball.h +++ b/source/blender/editors/include/ED_mball.h @@ -34,6 +34,7 @@ struct bContext; struct Object; struct wmKeyConfig; +struct UndoType; void ED_operatortypes_metaball(void); void ED_operatormacros_metaball(void); @@ -47,6 +48,7 @@ void ED_mball_editmball_free(struct Object *obedit); void ED_mball_editmball_make(struct Object *obedit); void ED_mball_editmball_load(struct Object *obedit); -void undo_push_mball(struct bContext *C, const char *name); +/* editmball_undo.c */ +void ED_mball_undosys_type(struct UndoType *ut); #endif /* __ED_MBALL_H__ */ diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 78497b29313..3217433204e 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -36,7 +36,6 @@ extern "C" { #endif struct ID; -struct EvaluationContext; struct View3D; struct ARegion; struct bContext; @@ -63,6 +62,7 @@ struct UvMapVert; struct ToolSettings; struct Object; struct rcti; +struct UndoType; /* editmesh_utils.c */ void EDBM_verts_mirror_cache_begin_ex(struct BMEditMesh *em, const int axis, @@ -81,7 +81,7 @@ void EDBM_mesh_normals_update(struct BMEditMesh *em); void EDBM_mesh_clear(struct BMEditMesh *em); void EDBM_selectmode_to_scene(struct bContext *C); -void EDBM_mesh_make(struct ToolSettings *ts, struct Object *ob, const bool add_key_index); +void EDBM_mesh_make(struct Object *ob, const int select_mode, const bool add_key_index); void EDBM_mesh_free(struct BMEditMesh *em); void EDBM_mesh_load(struct Object *ob); struct DerivedMesh *EDBM_mesh_deform_dm_get(struct BMEditMesh *em); @@ -99,8 +99,6 @@ void EDBM_selectmode_flush(struct BMEditMesh *em); void EDBM_deselect_flush(struct BMEditMesh *em); void EDBM_select_flush(struct BMEditMesh *em); -void undo_push_mesh(struct bContext *C, const char *name); - bool EDBM_vert_color_check(struct BMEditMesh *em); void EDBM_mesh_hide(struct BMEditMesh *em, bool swap); @@ -115,7 +113,8 @@ void BM_uv_element_map_free(struct UvElementMap *vmap); struct UvElement *BM_uv_element_get(struct UvElementMap *map, struct BMFace *efa, struct BMLoop *l); bool EDBM_uv_check(struct BMEditMesh *em); -struct BMFace *EDBM_uv_active_face_get(struct BMEditMesh *em, const bool sloppy, const bool selected); +struct BMFace *EDBM_uv_active_face_get( + struct BMEditMesh *em, const bool sloppy, const bool selected); void BM_uv_vert_map_free(struct UvVertMap *vmap); struct UvMapVert *BM_uv_vert_map_at_index(struct UvVertMap *vmap, unsigned int v); @@ -130,6 +129,9 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree, struct BMEdge *e, const struct Depsgraph *depsgraph, struct ARegion *ar, struct View3D *v3d, struct Object *obedit); +/* editmesh_undo.c */ +void ED_mesh_undosys_type(struct UndoType *ut); + /* editmesh_select.c */ void EDBM_select_mirrored( struct BMEditMesh *em, const int axis, const bool extend, @@ -219,12 +221,14 @@ typedef struct MirrTopoStore_t { intptr_t *index_lookup; int prev_vert_tot; int prev_edge_tot; - int prev_ob_mode; + bool prev_is_editmode; } MirrTopoStore_t; -bool ED_mesh_mirrtopo_recalc_check(struct Mesh *me, struct DerivedMesh *dm, const int ob_mode, MirrTopoStore_t *mesh_topo_store); -void ED_mesh_mirrtopo_init(struct Mesh *me, struct DerivedMesh *dm, const int ob_mode, MirrTopoStore_t *mesh_topo_store, - const bool skip_em_vert_array_init); +bool ED_mesh_mirrtopo_recalc_check( + struct Mesh *me, struct DerivedMesh *dm, MirrTopoStore_t *mesh_topo_store); +void ED_mesh_mirrtopo_init( + struct Mesh *me, struct DerivedMesh *dm, MirrTopoStore_t *mesh_topo_store, + const bool skip_em_vert_array_init); void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store); diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 8d2ff327c51..83119062203 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -52,9 +52,14 @@ struct wmKeyConfig; struct wmKeyMap; struct wmOperator; struct wmOperatorType; +struct wmWindow; +struct wmWindowManager; struct PointerRNA; struct PropertyRNA; struct EnumPropertyItem; +struct EvaluationContext; + +#include "DNA_object_enums.h" /* object_edit.c */ struct Object *ED_object_context(struct bContext *C); /* context.object */ @@ -113,21 +118,46 @@ struct Base *ED_object_add_duplicate(struct Main *bmain, struct Scene *scene, st void ED_object_parent(struct Object *ob, struct Object *parent, const int type, const char *substr); -bool ED_object_mode_compat_set(struct bContext *C, struct Object *ob, int mode, struct ReportList *reports); -void ED_object_toggle_modes(struct bContext *C, int mode); - /* bitflags for enter/exit editmode */ -#define EM_FREEDATA 1 -#define EM_FREEUNDO 2 -#define EM_WAITCURSOR 4 -#define EM_DO_UNDO 8 -#define EM_IGNORE_LAYER 16 +enum { + EM_FREEDATA = (1 << 0), + EM_WAITCURSOR = (1 << 1), + EM_DO_UNDO = (1 << 2), + EM_IGNORE_LAYER = (1 << 3), +}; +void ED_object_editmode_exit_ex( + struct bContext *C, struct Scene *scene, struct Object *obedit, int flag); void ED_object_editmode_exit(struct bContext *C, int flag); void ED_object_editmode_enter(struct bContext *C, int flag); bool ED_object_editmode_load(struct Object *obedit); bool ED_object_editmode_calc_active_center(struct Object *obedit, const bool select_only, float r_center[3]); + +void ED_object_vpaintmode_enter_ex( + const struct EvaluationContext *eval_ctx, struct wmWindowManager *wm, + struct Scene *scene, struct Object *ob); +void ED_object_vpaintmode_enter(struct bContext *C); +void ED_object_wpaintmode_enter_ex( + const struct EvaluationContext *eval_ctx, struct wmWindowManager *wm, + struct Scene *scene, struct Object *ob); +void ED_object_wpaintmode_enter(struct bContext *C); + +void ED_object_vpaintmode_exit_ex(struct Object *ob); +void ED_object_vpaintmode_exit(struct bContext *C); +void ED_object_wpaintmode_exit_ex(struct Object *ob); +void ED_object_wpaintmode_exit(struct bContext *C); + +void ED_object_sculptmode_enter_ex( + const struct EvaluationContext *eval_ctx, + struct Scene *scene, struct Object *ob, + struct ReportList *reports); +void ED_object_sculptmode_enter(struct bContext *C, struct ReportList *reports); +void ED_object_sculptmode_exit_ex( + const struct EvaluationContext *eval_ctx, + struct Scene *scene, struct Object *ob); +void ED_object_sculptmode_exit(struct bContext *C); + void ED_object_location_from_view(struct bContext *C, float loc[3]); void ED_object_rotation_from_view(struct bContext *C, float rot[3], const char align_axis); void ED_object_base_init_transform(struct bContext *C, struct Base *base, const float loc[3], const float rot[3]); @@ -173,13 +203,25 @@ void ED_object_constraint_dependency_update(struct Main *bmain, struct Object *o void ED_object_constraint_tag_update(struct Object *ob, struct bConstraint *con); void ED_object_constraint_dependency_tag_update(struct Main *bmain, struct Object *ob, struct bConstraint *con); -/* object_lattice.c */ -bool ED_lattice_select_pick(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle); -void undo_push_lattice(struct bContext *C, const char *name); +/* object_modes.c */ +bool ED_object_mode_compat_test(const struct Object *ob, eObjectMode mode); +bool ED_object_mode_compat_set(struct bContext *C, struct Object *ob, eObjectMode mode, struct ReportList *reports); +void ED_object_mode_toggle(struct bContext *C, eObjectMode mode); +void ED_object_mode_set(struct bContext *C, eObjectMode mode); -/* object_lattice.c */ - -void ED_lattice_flags_set(struct Object *obedit, int flag); +bool ED_object_mode_generic_enter( + struct bContext *C, + eObjectMode object_mode); +void ED_object_mode_generic_exit( + const struct EvaluationContext *eval_ctx, + struct Scene *scene, struct Object *ob); +bool ED_object_mode_generic_has_data( + const struct EvaluationContext *eval_ctx, + struct Object *ob); + +bool ED_object_mode_generic_exists( + struct wmWindowManager *wm, struct Object *ob, + eObjectMode object_mode); /* object_modifier.c */ enum { @@ -196,13 +238,14 @@ int ED_object_modifier_move_down(struct ReportList *reports, struct Object *ob, int ED_object_modifier_move_up(struct ReportList *reports, struct Object *ob, struct ModifierData *md); int ED_object_modifier_convert(struct ReportList *reports, struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, struct Object *ob, struct ModifierData *md); -int ED_object_modifier_apply(struct ReportList *reports, const struct bContext *C, struct Scene *scene, +int ED_object_modifier_apply(struct ReportList *reports, const struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob, struct ModifierData *md, int mode); int ED_object_modifier_copy(struct ReportList *reports, struct Object *ob, struct ModifierData *md); -bool ED_object_iter_other(struct Main *bmain, struct Object *orig_ob, const bool include_orig, - bool (*callback)(struct Object *ob, void *callback_data), - void *callback_data); +bool ED_object_iter_other( + struct Main *bmain, struct Object *orig_ob, const bool include_orig, + bool (*callback)(struct Object *ob, void *callback_data), + void *callback_data); bool ED_object_multires_update_totlevels_cb(struct Object *ob, void *totlevel_v); diff --git a/source/blender/editors/include/ED_paint.h b/source/blender/editors/include/ED_paint.h index e46f4b966c0..246419d64aa 100644 --- a/source/blender/editors/include/ED_paint.h +++ b/source/blender/editors/include/ED_paint.h @@ -28,37 +28,32 @@ struct bContext; struct wmKeyConfig; struct wmOperator; +struct ImBuf; +struct Image; +struct UndoStep; +struct UndoType; /* paint_ops.c */ void ED_operatortypes_paint(void); void ED_operatormacros_paint(void); void ED_keymap_paint(struct wmKeyConfig *keyconf); -/* paint_undo.c */ -enum { - UNDO_PAINT_IMAGE = 0, - UNDO_PAINT_MESH = 1, -}; - -typedef void (*UndoRestoreCb)(struct bContext *C, struct ListBase *lb); -typedef void (*UndoFreeCb)(struct ListBase *lb); -typedef bool (*UndoCleanupCb)(struct bContext *C, struct ListBase *lb); - -int ED_undo_paint_step(struct bContext *C, int type, int step, const char *name); -void ED_undo_paint_step_num(struct bContext *C, int type, int num); -const char *ED_undo_paint_get_name(struct bContext *C, int type, int nr, bool *r_active); -void ED_undo_paint_free(void); -bool ED_undo_paint_is_valid(int type, const char *name); -bool ED_undo_paint_empty(int type); -void ED_undo_paint_push_begin(int type, const char *name, UndoRestoreCb restore, UndoFreeCb free, UndoCleanupCb cleanup); -void ED_undo_paint_push_end(int type); - /* paint_image.c */ -/* image painting specific undo */ -void ED_image_undo_restore(struct bContext *C, struct ListBase *lb); -void ED_image_undo_free(struct ListBase *lb); void ED_imapaint_clear_partial_redraw(void); void ED_imapaint_dirty_region(struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h, bool find_old); void ED_imapaint_bucket_fill(struct bContext *C, float color[3], struct wmOperator *op); +/* paint_image_undo.c */ +void ED_image_undo_push_begin(const char *name); +void ED_image_undo_push_end(void); +void ED_image_undo_restore(struct UndoStep *us); + +void ED_image_undosys_type(struct UndoType *ut); + +/* paint_curve_undo.c */ +void ED_paintcurve_undo_push_begin(const char *name); +void ED_paintcurve_undo_push_end(void); + +void ED_paintcurve_undosys_type(struct UndoType *ut); + #endif /* __ED_PAINT_H__ */ diff --git a/source/blender/editors/include/ED_particle.h b/source/blender/editors/include/ED_particle.h index ffa6db18caa..b3e274a235a 100644 --- a/source/blender/editors/include/ED_particle.h +++ b/source/blender/editors/include/ED_particle.h @@ -39,13 +39,14 @@ struct rcti; struct PTCacheEdit; struct Scene; struct ViewLayer; +struct UndoType; /* particle edit mode */ void PE_free_ptcache_edit(struct PTCacheEdit *edit); int PE_start_edit(struct PTCacheEdit *edit); /* access */ -struct PTCacheEdit *PE_get_current(struct Scene *scene, struct ViewLayer *view_layer, struct Object *ob); +struct PTCacheEdit *PE_get_current(struct Scene *scene, struct Object *ob); struct PTCacheEdit *PE_create_current(const struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob); void PE_current_changed(const struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob); int PE_minmax(struct Scene *scene, struct ViewLayer *view_layer, float min[3], float max[3]); @@ -55,7 +56,7 @@ struct ParticleEditSettings *PE_settings(struct Scene *scene); void PE_hide_keys_time(struct Scene *scene, struct PTCacheEdit *edit, float cfra); void PE_update_object( const struct EvaluationContext *eval_ctx, struct Scene *scene, - struct ViewLayer *view_layer, struct Object *ob, int useflag); + struct Object *ob, int useflag); /* selection tools */ int PE_mouse_particles(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle); @@ -64,14 +65,8 @@ int PE_circle_select(struct bContext *C, int selecting, const int mval[2], float int PE_lasso_select(struct bContext *C, const int mcords[][2], const short moves, bool extend, bool select); void PE_deselect_all_visible(struct PTCacheEdit *edit); -/* undo */ -void PE_undo_push(struct Scene *scene, struct ViewLayer *view_layer, const char *str); -void PE_undo_step(struct Scene *scene, struct ViewLayer *view_layer, int step); -void PE_undo(struct Scene *scene, struct ViewLayer *view_layer); -void PE_redo(struct Scene *scene, struct ViewLayer *view_layer); -bool PE_undo_is_valid(struct Scene *scene, struct ViewLayer *view_layer); -void PE_undo_number(struct Scene *scene, struct ViewLayer *view_layer, int nr); -const char *PE_undo_get_name(struct Scene *scene, struct ViewLayer *view_layer, int nr, bool *r_active); +/* particle_edit_undo.c */ +void ED_particle_undosys_type(struct UndoType *ut); #endif /* __ED_PARTICLE_H__ */ diff --git a/source/blender/editors/include/ED_scene.h b/source/blender/editors/include/ED_scene.h index 647a8dda1b9..9b48187e541 100644 --- a/source/blender/editors/include/ED_scene.h +++ b/source/blender/editors/include/ED_scene.h @@ -31,9 +31,10 @@ enum eSceneCopyMethod; struct Scene *ED_scene_add(struct Main *bmain, struct bContext *C, struct wmWindow *win, enum eSceneCopyMethod method) ATTR_NONNULL(); bool ED_scene_delete(struct bContext *C, struct Main *bmain, struct wmWindow *win, struct Scene *scene) ATTR_NONNULL(); -void ED_scene_exit(struct bContext *C) ATTR_NONNULL(); -void ED_scene_changed_update(struct Main *bmain, struct bContext *C, struct Scene *scene_new, - const struct bScreen *active_screen) ATTR_NONNULL(); +void ED_scene_change_update( + struct Main *bmain, struct bContext *C, + struct wmWindow *win, const struct bScreen *screen, + struct Scene *scene_old, struct Scene *scene_new) ATTR_NONNULL(); bool ED_scene_view_layer_delete( struct Main *bmain, struct Scene *scene, struct ViewLayer *layer, struct ReportList *reports) ATTR_NONNULL(1, 2, 3); diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index fdf22cd0f53..ea8a7c217a2 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -37,6 +37,8 @@ #include "DNA_view3d_types.h" #include "DNA_workspace_types.h" +#include "DNA_object_enums.h" + #include "BLI_compiler_attrs.h" struct Depsgraph; @@ -66,7 +68,6 @@ void ED_region_do_listen( void ED_region_do_draw(struct bContext *C, struct ARegion *ar); void ED_region_exit(struct bContext *C, struct ARegion *ar); void ED_region_pixelspace(struct ARegion *ar); -void ED_region_set(const struct bContext *C, struct ARegion *ar); void ED_region_update_rect(struct bContext *C, struct ARegion *ar); void ED_region_init(struct bContext *C, struct ARegion *ar); void ED_region_tag_redraw(struct ARegion *ar); @@ -135,7 +136,7 @@ void ED_screen_update_after_scene_change( const struct bScreen *screen, struct Scene *scene_new, struct ViewLayer *view_layer); -void ED_screen_set_subwinactive(struct bContext *C, const struct wmEvent *event); +void ED_screen_set_active_region(struct bContext *C, const struct wmEvent *event); void ED_screen_exit(struct bContext *C, struct wmWindow *window, struct bScreen *screen); void ED_screen_animation_timer(struct bContext *C, int redraws, int refresh, int sync, int enable); void ED_screen_animation_timer_update(struct bScreen *screen, int redraws, int refresh); @@ -147,6 +148,8 @@ struct ScrArea *ED_screen_state_toggle(struct bContext *C, struct wmWindow *win, void ED_screens_header_tools_menu_create(struct bContext *C, struct uiLayout *layout, void *arg); bool ED_screen_stereo3d_required(const struct bScreen *screen, const struct Scene *scene); Scene *ED_screen_scene_find(const struct bScreen *screen, const struct wmWindowManager *wm); +Scene *ED_screen_scene_find_with_window(const struct bScreen *screen, const struct wmWindowManager *wm, struct wmWindow **r_window); +struct wmWindow *ED_screen_window_find(const struct bScreen *screen, const struct wmWindowManager *wm); void ED_screen_preview_render(const struct bScreen *screen, int size_x, int size_y, unsigned int *r_rect) ATTR_NONNULL(); /* workspaces */ @@ -186,8 +189,13 @@ bool ED_workspace_layout_cycle( struct WorkSpace *workspace, const short direction, struct bContext *C) ATTR_NONNULL(); +void ED_workspace_object_mode_sync_from_object( + struct wmWindowManager *wm, WorkSpace *workspace, struct Object *obact); +void ED_workspace_object_mode_sync_from_scene( + struct wmWindowManager *wm, WorkSpace *workspace, struct Scene *scene); + /* anim */ -void ED_update_for_newframe(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, struct Depsgraph *depsgraph); +void ED_update_for_newframe(struct Main *bmain, struct Depsgraph *depsgraph); void ED_refresh_viewport_fps(struct bContext *C); int ED_screen_animation_play(struct bContext *C, int sync, int mode); diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h index a81d63d9f25..574523696f5 100644 --- a/source/blender/editors/include/ED_sculpt.h +++ b/source/blender/editors/include/ED_sculpt.h @@ -36,10 +36,16 @@ struct Object; struct RegionView3D; struct ViewContext; struct rcti; +struct UndoStep; +struct UndoType; +struct ListBase; /* sculpt.c */ void ED_operatortypes_sculpt(void); void ED_sculpt_redraw_planes_get(float planes[4][4], struct ARegion *ar, struct Object *ob); int ED_sculpt_mask_box_select(struct bContext *C, struct ViewContext *vc, const struct rcti *rect, bool select, bool extend); +/* sculpt_undo.c */ +void ED_sculpt_undosys_type(struct UndoType *ut); + #endif /* __ED_SCULPT_H__ */ diff --git a/source/blender/editors/include/ED_text.h b/source/blender/editors/include/ED_text.h index 5df7d9cfaef..763fbe3bac5 100644 --- a/source/blender/editors/include/ED_text.h +++ b/source/blender/editors/include/ED_text.h @@ -30,12 +30,16 @@ #ifndef __ED_TEXT_H__ #define __ED_TEXT_H__ -struct bContext; struct SpaceText; struct ARegion; +struct UndoType; +struct TextUndoBuf; -void ED_text_undo_step(struct bContext *C, int step); bool ED_text_region_location_from_cursor(struct SpaceText *st, struct ARegion *ar, const int cursor_co[2], int r_pixel_co[2]); -#endif /* __ED_TEXT_H__ */ +/* text_undo.c */ +void ED_text_undosys_type(struct UndoType *ut); + +struct TextUndoBuf *ED_text_undo_push_init(struct bContext *C); +#endif /* __ED_TEXT_H__ */ 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 8761f2c5361..26cef2599bd 100644 --- a/source/blender/editors/include/ED_transform_snap_object_context.h +++ b/source/blender/editors/include/ED_transform_snap_object_context.h @@ -30,7 +30,6 @@ struct BMEdge; struct BMFace; struct ListBase; -struct RenderEngineType; struct Scene; struct ViewLayer; struct Main; @@ -76,9 +75,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_type, int flag); + struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, int flag); SnapObjectContext *ED_transform_snap_object_context_create_view3d( - struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, struct RenderEngineType *engine_type, int flag, + struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, 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_undo.h b/source/blender/editors/include/ED_undo.h new file mode 100644 index 00000000000..b3814ab5899 --- /dev/null +++ b/source/blender/editors/include/ED_undo.h @@ -0,0 +1,64 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ED_undo.h + * \ingroup editors + */ + +#ifndef __ED_UNDO_H__ +#define __ED_UNDO_H__ + +struct bContext; +struct wmOperator; +struct wmOperatorType; +struct UndoStack; + +/* undo.c */ +void ED_undo_push(struct bContext *C, const char *str); +void ED_undo_push_op(struct bContext *C, struct wmOperator *op); +void ED_undo_grouped_push(struct bContext *C, const char *str); +void ED_undo_grouped_push_op(struct bContext *C, struct wmOperator *op); +void ED_undo_pop_op(struct bContext *C, struct wmOperator *op); +void ED_undo_pop(struct bContext *C); +void ED_undo_redo(struct bContext *C); +void ED_OT_undo(struct wmOperatorType *ot); +void ED_OT_undo_push(struct wmOperatorType *ot); +void ED_OT_redo(struct wmOperatorType *ot); +void ED_OT_undo_redo(struct wmOperatorType *ot); +void ED_OT_undo_history(struct wmOperatorType *ot); + +int ED_undo_operator_repeat(struct bContext *C, struct wmOperator *op); +/* convenience since UI callbacks use this mostly*/ +void ED_undo_operator_repeat_cb(struct bContext *C, void *arg_op, void *arg_unused); +void ED_undo_operator_repeat_cb_evt(struct bContext *C, void *arg_op, int arg_unused); + +bool ED_undo_is_valid(const struct bContext *C, const char *undoname); + +struct UndoStack *ED_undo_stack_get(void); + +/* undo_system_types.c */ +void ED_undosys_type_init(void); +void ED_undosys_type_free(void); + +/* memfile_undo.c */ +struct MemFile *ED_undosys_stack_memfile_get_active(struct UndoStack *ustack); + +#endif /* __ED_UNDO_H__ */ + diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h index 60c4b3593aa..2653585dacc 100644 --- a/source/blender/editors/include/ED_util.h +++ b/source/blender/editors/include/ED_util.h @@ -32,9 +32,10 @@ #define __ED_UTIL_H__ struct bContext; -struct SpaceLink; -struct wmOperator; struct wmOperatorType; +struct ScrArea; +struct SpaceLink; +struct PackedFile; /* ed_util.c */ @@ -47,40 +48,6 @@ void ED_spacedata_id_remap(struct ScrArea *sa, struct SpaceLink *sl, struct I void ED_OT_flush_edits(struct wmOperatorType *ot); -/* ************** Undo ************************ */ - -/* undo.c */ -void ED_undo_push(struct bContext *C, const char *str); -void ED_undo_push_op(struct bContext *C, struct wmOperator *op); -void ED_undo_grouped_push(struct bContext *C, const char *str); -void ED_undo_grouped_push_op(struct bContext *C, struct wmOperator *op); -void ED_undo_pop_op(struct bContext *C, struct wmOperator *op); -void ED_undo_pop(struct bContext *C); -void ED_undo_redo(struct bContext *C); -void ED_OT_undo(struct wmOperatorType *ot); -void ED_OT_undo_push(struct wmOperatorType *ot); -void ED_OT_redo(struct wmOperatorType *ot); -void ED_OT_undo_redo(struct wmOperatorType *ot); -void ED_OT_undo_history(struct wmOperatorType *ot); - -int ED_undo_operator_repeat(struct bContext *C, struct wmOperator *op); -/* convenience since UI callbacks use this mostly*/ -void ED_undo_operator_repeat_cb(struct bContext *C, void *arg_op, void *arg_unused); -void ED_undo_operator_repeat_cb_evt(struct bContext *C, void *arg_op, int arg_unused); - -bool ED_undo_is_valid(const struct bContext *C, const char *undoname); - -/* undo_editmode.c */ -void undo_editmode_push(struct bContext *C, const char *name, - void * (*getdata)(struct bContext *C), - void (*freedata)(void *), - void (*to_editmode)(void *, void *, void *), - void *(*from_editmode)(void *, void *), - int (*validate_undo)(void *, void *)); - - -void undo_editmode_clear(void); - /* ************** XXX OLD CRUFT WARNING ************* */ void apply_keyb_grid(int shift, int ctrl, float *val, float fac1, float fac2, float fac3, int invert); diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h index 96b4004b6a6..2a5ad494643 100644 --- a/source/blender/editors/include/ED_uvedit.h +++ b/source/blender/editors/include/ED_uvedit.h @@ -50,49 +50,65 @@ struct wmKeyConfig; void ED_operatortypes_uvedit(void); void ED_keymap_uvedit(struct wmKeyConfig *keyconf); -void ED_uvedit_assign_image(struct Main *bmain, struct Scene *scene, struct Object *obedit, struct Image *ima, struct Image *previma); +void ED_uvedit_assign_image( + struct Main *bmain, struct Scene *scene, struct Object *obedit, struct Image *ima, struct Image *previma); bool ED_uvedit_minmax(struct Scene *scene, struct Image *ima, struct Object *obedit, float min[2], float max[2]); bool ED_uvedit_center(Scene *scene, Image *ima, struct Object *obedit, float cent[2], char mode); void ED_uvedit_select_all(struct BMesh *bm); -bool ED_object_get_active_image(struct Object *ob, int mat_nr, - struct Image **r_ima, struct ImageUser **r_iuser, struct bNode **r_node, struct bNodeTree **r_ntree); +bool ED_object_get_active_image( + struct Object *ob, int mat_nr, + struct Image **r_ima, struct ImageUser **r_iuser, struct bNode **r_node, struct bNodeTree **r_ntree); void ED_object_assign_active_image(struct Main *bmain, struct Object *ob, int mat_nr, struct Image *ima); bool ED_uvedit_test(struct Object *obedit); /* visibility and selection */ -bool uvedit_face_visible_test(struct Scene *scene, struct Image *ima, struct BMFace *efa); -bool uvedit_face_select_test(struct Scene *scene, struct BMFace *efa, - const int cd_loop_uv_offset); -bool uvedit_edge_select_test(struct Scene *scene, struct BMLoop *l, - const int cd_loop_uv_offset); -bool uvedit_uv_select_test(struct Scene *scene, struct BMLoop *l, - const int cd_loop_uv_offset); +bool uvedit_face_visible_test( + struct Scene *scene, struct Object *obedit, struct Image *ima, struct BMFace *efa); +bool uvedit_face_select_test( + struct Scene *scene, struct BMFace *efa, + const int cd_loop_uv_offset); +bool uvedit_edge_select_test( + struct Scene *scene, struct BMLoop *l, + const int cd_loop_uv_offset); +bool uvedit_uv_select_test( + struct Scene *scene, struct BMLoop *l, + const int cd_loop_uv_offset); /* uv face */ -bool uvedit_face_select_set(struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa, const bool select, - const bool do_history, const int cd_loop_uv_offset); -bool uvedit_face_select_enable(struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa, - const bool do_history, const int cd_loop_uv_offset); -bool uvedit_face_select_disable(struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa, - const int cd_loop_uv_offset); +bool uvedit_face_select_set( + struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa, const bool select, + const bool do_history, const int cd_loop_uv_offset); +bool uvedit_face_select_enable( + struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa, + const bool do_history, const int cd_loop_uv_offset); +bool uvedit_face_select_disable( + struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa, + const int cd_loop_uv_offset); /* uv edge */ -void uvedit_edge_select_set(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l, const bool select, - const bool do_history, const int cd_loop_uv_offset); -void uvedit_edge_select_enable(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l, - const bool do_history, const int cd_loop_uv_offset); -void uvedit_edge_select_disable(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l, - const int cd_loop_uv_offset); +void uvedit_edge_select_set( + struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l, const bool select, + const bool do_history, const int cd_loop_uv_offset); +void uvedit_edge_select_enable( + struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l, + const bool do_history, const int cd_loop_uv_offset); +void uvedit_edge_select_disable( + struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l, + const int cd_loop_uv_offset); /* uv vert */ -void uvedit_uv_select_set(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l, const bool select, - const bool do_history, const int cd_loop_uv_offset); -void uvedit_uv_select_enable(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l, - const bool do_history, const int cd_loop_uv_offset); -void uvedit_uv_select_disable(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l, - const int cd_loop_uv_offset); - -bool ED_uvedit_nearest_uv(struct Scene *scene, struct Object *obedit, struct Image *ima, - const float co[2], float r_uv[2]); +void uvedit_uv_select_set( + struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l, const bool select, + const bool do_history, const int cd_loop_uv_offset); +void uvedit_uv_select_enable( + struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l, + const bool do_history, const int cd_loop_uv_offset); +void uvedit_uv_select_disable( + struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l, + const int cd_loop_uv_offset); + +bool ED_uvedit_nearest_uv( + struct Scene *scene, struct Object *obedit, struct Image *ima, + const float co[2], float r_uv[2]); void ED_uvedit_get_aspect(struct Scene *scene, struct Object *ob, struct BMesh *em, float *aspx, float *aspy); @@ -102,7 +118,8 @@ void ED_uvedit_live_unwrap_re_solve(void); void ED_uvedit_live_unwrap_end(short cancel); void ED_uvedit_live_unwrap(struct Scene *scene, struct Object *obedit); -void ED_uvedit_pack_islands(struct Scene *scene, struct Object *ob, struct BMesh *bm, bool selected, bool correct_aspect, bool do_rotate); +void ED_uvedit_pack_islands( +struct Scene *scene, struct Object *ob, struct BMesh *bm, bool selected, bool correct_aspect, bool do_rotate); void ED_uvedit_unwrap_cube_project( struct BMesh *bm, float cube_size, bool use_select, const float center[3]); @@ -111,8 +128,12 @@ void ED_unwrap_lscm(struct Scene *scene, struct Object *obedit, const short sel) /* uvedit_draw.c */ -void ED_image_draw_cursor(struct ARegion *ar, const float cursor[2]); -void ED_uvedit_draw_main(struct SpaceImage *sima, struct ARegion *ar, struct Scene *scene, struct ViewLayer *view_layer, struct Object *obedit, struct Object *obact, struct Depsgraph *depsgraph); +void ED_image_draw_cursor( +struct ARegion *ar, const float cursor[2]); +void ED_uvedit_draw_main( + struct SpaceImage *sima, + struct ARegion *ar, struct Scene *scene, struct ViewLayer *view_layer, + struct Object *obedit, struct Object *obact, struct Depsgraph *depsgraph); /* uvedit_buttons.c */ void ED_uvedit_buttons_register(struct ARegionType *art); diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 8201401296a..1d4fc8891f5 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -363,7 +363,7 @@ int view3d_opengl_select( /* view3d_select.c */ float ED_view3d_select_dist_px(void); -void view3d_set_viewcontext(struct bContext *C, struct ViewContext *vc); +void ED_view3d_viewcontext_init(struct bContext *C, struct ViewContext *vc); void view3d_operator_needs_opengl(const struct bContext *C); void view3d_region_operator_needs_opengl(struct wmWindow *win, struct ARegion *ar); void view3d_opengl_read_pixels(struct ARegion *ar, int x, int y, int w, int h, int format, int type, void *data); @@ -395,12 +395,14 @@ void ED_draw_object_facemap(const struct EvaluationContext *eval_ctx, struct Sc bool ED_view3d_context_activate(struct bContext *C); void ED_view3d_draw_offscreen_init( const struct EvaluationContext *eval_ctx, struct Scene *scene, - struct ViewLayer *view_layer, struct View3D *v3d); + struct ViewLayer *view_layer, struct RenderEngineType *engine_type, + struct View3D *v3d); void ED_view3d_draw_offscreen( const struct EvaluationContext *eval_ctx, struct Scene *scene, - struct ViewLayer *view_layer, struct View3D *v3d, struct ARegion *ar, int winx, int winy, float viewmat[4][4], + struct ViewLayer *view_layer, struct RenderEngineType *engine_type, + struct View3D *v3d, struct ARegion *ar, int winx, int winy, float viewmat[4][4], float winmat[4][4], bool do_bgpic, bool do_sky, bool is_persp, const char *viewname, - struct GPUFX *fx, struct GPUFXSettings *fx_settings, + struct GPUFXSettings *fx_settings, struct GPUOffScreen *ofs, struct GPUViewport *viewport); void ED_view3d_draw_setup_view( struct wmWindow *win, const struct EvaluationContext *eval_ctx, struct Scene *scene, struct ARegion *ar, struct View3D *v3d, @@ -420,16 +422,18 @@ enum { struct ImBuf *ED_view3d_draw_offscreen_imbuf( const struct EvaluationContext *eval_ctx, struct Scene *scene, - struct ViewLayer *view_layer, struct View3D *v3d, struct ARegion *ar, + struct ViewLayer *view_layer, struct RenderEngineType *engine_type, + struct View3D *v3d, struct ARegion *ar, int sizex, int sizey, unsigned int flag, unsigned int draw_flags, int alpha_mode, int samples, const char *viewname, - struct GPUFX *fx, struct GPUOffScreen *ofs, char err_out[256]); + struct GPUOffScreen *ofs, char err_out[256]); struct ImBuf *ED_view3d_draw_offscreen_imbuf_simple( const struct EvaluationContext *eval_ctx, struct Scene *scene, - struct ViewLayer *view_layer, struct Object *camera, int width, int height, + struct ViewLayer *view_layer, struct RenderEngineType *engine_type, + struct Object *camera, int width, int height, unsigned int flag, unsigned int draw_flags, int drawtype, int alpha_mode, int samples, const char *viewname, - struct GPUFX *fx, struct GPUOffScreen *ofs, char err_out[256]); + struct GPUOffScreen *ofs, char err_out[256]); struct Base *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2]); void ED_view3d_quadview_update(struct ScrArea *sa, struct ARegion *ar, bool do_clip); @@ -488,7 +492,7 @@ void ED_view3d_operator_properties_viewmat_get(struct wmOperator *op, int *winx, /* render */ void ED_view3d_stop_render_preview(struct wmWindowManager *wm, struct ARegion *ar); -void ED_view3d_shade_update(struct Main *bmain, struct Scene *scene, struct View3D *v3d, struct ScrArea *sa); +void ED_view3d_shade_update(struct Main *bmain, struct View3D *v3d, struct ScrArea *sa); #define V3D_IS_ZBUF(v3d) \ (((v3d)->flag & V3D_ZBUF_SELECT) && ((v3d)->drawtype > OB_WIRE)) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 6e09318314d..edf15d02e73 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -64,7 +64,6 @@ struct Image; struct ImageUser; struct wmKeyConfig; struct wmOperatorType; -struct uiWidgetColors; struct MTex; struct ImBuf; struct bNodeTree; @@ -1168,4 +1167,9 @@ void UI_tooltip_free(struct bContext *C, struct bScreen *sc, struct ARegion *ar) int UI_calc_float_precision(int prec, double value); +/* widget batched drawing */ +void UI_widgetbase_draw_cache_begin(void); +void UI_widgetbase_draw_cache_flush(void); +void UI_widgetbase_draw_cache_end(void); + #endif /* __UI_INTERFACE_H__ */ diff --git a/source/blender/editors/include/UI_interface_icons.h b/source/blender/editors/include/UI_interface_icons.h index cee68ed361c..8b436942fdd 100644 --- a/source/blender/editors/include/UI_interface_icons.h +++ b/source/blender/editors/include/UI_interface_icons.h @@ -77,6 +77,9 @@ void UI_icon_draw_size(float x, float y, int size, int icon_id, float alpha); void UI_icons_free(void); void UI_icons_free_drawinfo(void *drawinfo); +void UI_icon_draw_cache_begin(void); +void UI_icon_draw_cache_end(void); + struct ListBase *UI_iconfile_list(void); int UI_iconfile_get_index(const char *filename); diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt index 94f377fb35e..c023816b52c 100644 --- a/source/blender/editors/interface/CMakeLists.txt +++ b/source/blender/editors/interface/CMakeLists.txt @@ -70,7 +70,9 @@ set(SRC view2d.c view2d_ops.c + interface_eyedropper_intern.h interface_intern.h + interface_regions_intern.h ) if(WITH_INTERNATIONAL) @@ -81,6 +83,10 @@ if(WITH_HEADLESS) add_definitions(-DWITH_HEADLESS) endif() +if(WITH_CYCLES) + add_definitions(-DWITH_CYCLES) +endif() + if(WITH_PYTHON) add_definitions(-DWITH_PYTHON) endif() diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 9e6d9f23442..12ee1ad35a1 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -64,12 +64,12 @@ #include "BLT_translation.h" #include "UI_interface.h" +#include "UI_interface_icons.h" #include "IMB_imbuf.h" #include "WM_api.h" #include "WM_types.h" -#include "wm_subwindow.h" #include "WM_message.h" #include "RNA_access.h" @@ -1222,11 +1222,9 @@ static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block) void ui_but_override_flag(uiBut *but) { - bool is_overridden; + const int override_status = RNA_property_override_status(&but->rnapoin, but->rnaprop, but->rnaindex); - RNA_property_override_status(&but->rnapoin, but->rnaprop, but->rnaindex, NULL, &is_overridden, NULL, NULL); - - if (is_overridden) { + if (override_status & RNA_OVERRIDE_STATUS_OVERRIDDEN) { but->flag |= UI_BUT_OVERRIDEN; } else { @@ -1393,7 +1391,6 @@ void UI_block_draw(const bContext *C, uiBlock *block) ARegion *ar; uiBut *but; rcti rect; - int multisample_enabled; /* get menu region or area region */ ar = CTX_wm_menu(C); @@ -1403,13 +1400,8 @@ void UI_block_draw(const bContext *C, uiBlock *block) if (!block->endblock) UI_block_end(C, block); - /* disable AA, makes widgets too blurry */ - multisample_enabled = glIsEnabled(GL_MULTISAMPLE); - if (multisample_enabled) - glDisable(GL_MULTISAMPLE); - /* we set this only once */ - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); /* scale fonts */ ui_fontscale(&style.paneltitle.points, block->aspect); @@ -1435,6 +1427,10 @@ void UI_block_draw(const bContext *C, uiBlock *block) else if (block->panel) ui_draw_aligned_panel(&style, block, &rect, UI_panel_category_is_visible(ar)); + BLF_batch_draw_begin(); + UI_icon_draw_cache_begin(); + UI_widgetbase_draw_cache_begin(); + /* widgets */ for (but = block->buttons.first; but; but = but->next) { if (!(but->flag & (UI_HIDDEN | UI_SCROLLED))) { @@ -1446,14 +1442,15 @@ void UI_block_draw(const bContext *C, uiBlock *block) ui_draw_but(C, ar, &style, but, &rect); } } + + UI_widgetbase_draw_cache_end(); + UI_icon_draw_cache_end(); + BLF_batch_draw_end(); /* restore matrix */ gpuPopProjectionMatrix(); gpuPopMatrix(); - if (multisample_enabled) - glEnable(GL_MULTISAMPLE); - ui_draw_links(block); } @@ -2862,7 +2859,6 @@ uiBlock *UI_block_begin(const bContext *C, ARegion *region, const char *name, sh uiBlock *block; wmWindow *window; Scene *scn; - int getsizex, getsizey; window = CTX_wm_window(C); scn = CTX_data_scene(C); @@ -2893,22 +2889,22 @@ uiBlock *UI_block_begin(const bContext *C, ARegion *region, const char *name, sh UI_block_region_set(block, region); /* window matrix and aspect */ - if (region && region->swinid) { - wm_subwindow_matrix_get(window, region->swinid, block->winmat); - wm_subwindow_size_get(window, region->swinid, &getsizex, &getsizey); + if (region && region->visible) { + gpuGetProjectionMatrix(block->winmat); - block->aspect = 2.0f / fabsf(getsizex * block->winmat[0][0]); + block->aspect = 2.0f / fabsf(region->winx * block->winmat[0][0]); } else { - const bScreen *screen = WM_window_get_active_screen(window); - /* no subwindow created yet, for menus for example, so we * use the main window instead, since buttons are created * there anyway */ - wm_subwindow_matrix_get(window, screen->mainwin, block->winmat); - wm_subwindow_size_get(window, screen->mainwin, &getsizex, &getsizey); + int width = WM_window_pixels_x(window); + int height = WM_window_pixels_y(window); + rcti winrct = {0, width -1, 0, height - 1}; + + wmGetProjectionMatrix(block->winmat, &winrct); - block->aspect = 2.0f / fabsf(getsizex * block->winmat[0][0]); + block->aspect = 2.0f / fabsf(width * block->winmat[0][0]); block->auto_open = true; block->flag |= UI_BLOCK_LOOP; /* tag as menu */ } diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c index 3ecb72353bc..f84347b97a4 100644 --- a/source/blender/editors/interface/interface_draw.c +++ b/source/blender/editors/interface/interface_draw.c @@ -64,6 +64,7 @@ /* own include */ #include "interface_intern.h" + static int roundboxtype = UI_CNR_ALL; void UI_draw_roundbox_corner_set(int type) @@ -101,12 +102,58 @@ void UI_draw_roundbox_3fvAlpha(bool filled, float minx, float miny, float maxx, UI_draw_roundbox_4fv(filled, minx, miny, maxx, maxy, rad, colv); } +void UI_draw_roundbox_aa(bool filled, float minx, float miny, float maxx, float maxy, float rad, const float color[4]) +{ + uiWidgetBaseParameters widget_params = { + .recti.xmin = minx, .recti.ymin = miny, + .recti.xmax = maxx, .recti.ymax = maxy, + .radi = rad, + .round_corners[0] = (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 1.0f : 0.0f, + .round_corners[1] = (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 1.0f : 0.0f, + .round_corners[2] = (roundboxtype & UI_CNR_TOP_RIGHT) ? 1.0f : 0.0f, + .round_corners[3] = (roundboxtype & UI_CNR_TOP_LEFT) ? 1.0f : 0.0f, + .color_inner1[0] = color[0], .color_inner2[0] = color[0], + .color_inner1[1] = color[1], .color_inner2[1] = color[1], + .color_inner1[2] = color[2], .color_inner2[2] = color[2], + .color_inner1[3] = color[3], .color_inner2[3] = color[3], + }; + + glEnable(GL_BLEND); + + if (filled) { + /* plain antialiased filled box */ + widget_params.color_inner1[3] *= 0.125f; + widget_params.color_inner2[3] *= 0.125f; + + /* WATCH: This is assuming the ModelViewProjectionMatrix is area pixel space. + * If it has been scaled, then it's no longer valid. */ + Gwn_Batch *batch = ui_batch_roundbox_get(filled, true); + GWN_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE); + GWN_batch_uniform_4fv_array(batch, "parameters", 11, (float *)&widget_params); + GWN_batch_draw(batch); + } + else { + /* plain antialiased unfilled box */ + glEnable(GL_LINE_SMOOTH); + + Gwn_Batch *batch = ui_batch_roundbox_get(filled, false); + GWN_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE); + GWN_batch_uniform_4fv_array(batch, "parameters", 11, (float *)&widget_params); + GWN_batch_draw(batch); + + glDisable(GL_LINE_SMOOTH); + } + + glDisable(GL_BLEND); +} + void UI_draw_roundbox_4fv(bool filled, float minx, float miny, float maxx, float maxy, float rad, const float col[4]) { +#if 0 float vec[7][2] = {{0.195, 0.02}, {0.383, 0.067}, {0.55, 0.169}, {0.707, 0.293}, {0.831, 0.45}, {0.924, 0.617}, {0.98, 0.805}}; int a; - + Gwn_VertFormat *format = immVertexFormat(); unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); @@ -175,8 +222,29 @@ void UI_draw_roundbox_4fv(bool filled, float minx, float miny, float maxx, float immEnd(); immUnbindProgram(); +#endif + + uiWidgetBaseParameters widget_params = { + .recti.xmin = minx, .recti.ymin = miny, + .recti.xmax = maxx, .recti.ymax = maxy, + .radi = rad, + .round_corners[0] = (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 1.0f : 0.0f, + .round_corners[1] = (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 1.0f : 0.0f, + .round_corners[2] = (roundboxtype & UI_CNR_TOP_RIGHT) ? 1.0f : 0.0f, + .round_corners[3] = (roundboxtype & UI_CNR_TOP_LEFT) ? 1.0f : 0.0f, + .color_inner1[0] = col[0], .color_inner2[0] = col[0], + .color_inner1[1] = col[1], .color_inner2[1] = col[1], + .color_inner1[2] = col[2], .color_inner2[2] = col[2], + .color_inner1[3] = col[3], .color_inner2[3] = col[3], + }; + + Gwn_Batch *batch = ui_batch_roundbox_get(filled, false); + GWN_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE); + GWN_batch_uniform_4fv_array(batch, "parameters", 11, (float *)&widget_params); + GWN_batch_draw(batch); } +#if 0 static void round_box_shade_col(unsigned attrib, const float col1[3], float const col2[3], const float fac) { float col[4] = { @@ -187,6 +255,7 @@ static void round_box_shade_col(unsigned attrib, const float col1[3], float cons }; immAttrib4fv(attrib, col); } +#endif /* linear horizontal shade within button or in outline */ /* view2d scrollers use it */ @@ -194,6 +263,7 @@ void UI_draw_roundbox_shade_x( bool filled, float minx, float miny, float maxx, float maxy, float rad, float shadetop, float shadedown, const float col[4]) { +#if 0 float vec[7][2] = {{0.195, 0.02}, {0.383, 0.067}, {0.55, 0.169}, {0.707, 0.293}, {0.831, 0.45}, {0.924, 0.617}, {0.98, 0.805}}; const float div = maxy - miny; @@ -305,6 +375,30 @@ void UI_draw_roundbox_shade_x( immEnd(); immUnbindProgram(); +#endif + + uiWidgetBaseParameters widget_params = { + .recti.xmin = minx, .recti.ymin = miny, + .recti.xmax = maxx, .recti.ymax = maxy, + .radi = rad, + .round_corners[0] = (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 1.0f : 0.0f, + .round_corners[1] = (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 1.0f : 0.0f, + .round_corners[2] = (roundboxtype & UI_CNR_TOP_RIGHT) ? 1.0f : 0.0f, + .round_corners[3] = (roundboxtype & UI_CNR_TOP_LEFT) ? 1.0f : 0.0f, + .color_inner1[0] = min_ff(1.0f, col[0] + shadetop), + .color_inner2[0] = max_ff(0.0f, col[0] + shadedown), + .color_inner1[1] = min_ff(1.0f, col[1] + shadetop), + .color_inner2[1] = max_ff(0.0f, col[1] + shadedown), + .color_inner1[2] = min_ff(1.0f, col[2] + shadetop), + .color_inner2[2] = max_ff(0.0f, col[2] + shadedown), + .color_inner1[3] = 1.0f, + .color_inner2[3] = 1.0f, + }; + + Gwn_Batch *batch = ui_batch_roundbox_get(filled, false); + GWN_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE); + GWN_batch_uniform_4fv_array(batch, "parameters", 11, (float *)&widget_params); + GWN_batch_draw(batch); } #if 0 /* unused */ @@ -615,7 +709,7 @@ static void draw_scope_end(const rctf *rect, GLint *scissor) /* restore scissortest */ glScissor(scissor[0], scissor[1], scissor[2], scissor[3]); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); /* outline */ UI_draw_roundbox_corner_set(UI_CNR_ALL); @@ -635,7 +729,7 @@ static void histogram_draw_one( return; glEnable(GL_LINE_SMOOTH); - glBlendFunc(GL_SRC_ALPHA, GL_ONE); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ONE, GL_ONE); immUniformColor4fv(color); @@ -665,7 +759,7 @@ static void histogram_draw_one( /* curve outline */ immUniformColor4f(0.0f, 0.0f, 0.0f, 0.25f); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); immBegin(GWN_PRIM_LINE_STRIP, res); for (int i = 0; i < res; i++) { float x2 = x + i * (w / (float)res); @@ -696,7 +790,7 @@ void ui_draw_but_HISTOGRAM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol) float h = BLI_rctf_size_y(&rect) * hist->ymax; glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); float color[4]; UI_GetThemeColor4fv(TH_PREVIEW_BACK, color); @@ -705,7 +799,7 @@ void ui_draw_but_HISTOGRAM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol) /* need scissor test, histogram can draw outside of boundary */ GLint scissor[4]; - glGetIntegerv(GL_VIEWPORT, scissor); + glGetIntegerv(GL_SCISSOR_BOX, scissor); glScissor(ar->winrct.xmin + (rect.xmin - 1), ar->winrct.ymin + (rect.ymin - 1), (rect.xmax + 1) - (rect.xmin - 1), @@ -816,8 +910,11 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol), } } + /* Flush text cache before changing scissors. */ + BLF_batch_draw_flush(); + glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); float color[4]; UI_GetThemeColor4fv(TH_PREVIEW_BACK, color); @@ -825,7 +922,7 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol), UI_draw_roundbox_4fv(true, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f, color); /* need scissor test, waveform can draw outside of boundary */ - glGetIntegerv(GL_VIEWPORT, scissor); + glGetIntegerv(GL_SCISSOR_BOX, scissor); glScissor(ar->winrct.xmin + (rect.xmin - 1), ar->winrct.ymin + (rect.ymin - 1), (rect.xmax + 1) - (rect.xmin - 1), @@ -840,8 +937,11 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol), BLF_draw_default(rect.xmin + 1, yofs - 5 + (i * 0.2f) * h, 0, str, sizeof(str) - 1); } + /* Flush text cache before drawing things on top. */ + BLF_batch_draw_flush(); + glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); Gwn_VertFormat *format = immVertexFormat(); unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); @@ -1085,7 +1185,7 @@ void ui_draw_but_VECTORSCOPE(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wco float alpha = scopes->vecscope_alpha * scopes->vecscope_alpha * scopes->vecscope_alpha; glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); float color[4]; UI_GetThemeColor4fv(TH_PREVIEW_BACK, color); @@ -1094,7 +1194,7 @@ void ui_draw_but_VECTORSCOPE(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wco /* need scissor test, hvectorscope can draw outside of boundary */ GLint scissor[4]; - glGetIntegerv(GL_VIEWPORT, scissor); + glGetIntegerv(GL_SCISSOR_BOX, scissor); glScissor(ar->winrct.xmin + (rect.xmin - 1), ar->winrct.ymin + (rect.ymin - 1), (rect.xmax + 1) - (rect.xmin - 1), @@ -1520,7 +1620,7 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, uiWidgetColors *wcol, const rcti /* need scissor test, curve can draw outside of boundary */ GLint scissor[4]; - glGetIntegerv(GL_VIEWPORT, scissor); + glGetIntegerv(GL_SCISSOR_BOX, scissor); rcti scissor_new = { .xmin = ar->winrct.xmin + rect->xmin, .ymin = ar->winrct.ymin + rect->ymin, @@ -1564,7 +1664,7 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, uiWidgetColors *wcol, const rcti if (but->a1 == UI_GRAD_H) { /* grid, hsv uses different grid */ glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); immUniformColor4ub(0, 0, 0, 48); ui_draw_but_curve_grid(pos, rect, zoomx, zoomy, offsx, offsy, 0.1666666f); glDisable(GL_BLEND); @@ -1738,11 +1838,11 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wc int height = BLI_rctf_size_y(&rect); glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); /* need scissor test, preview image can draw outside of boundary */ GLint scissor[4]; - glGetIntegerv(GL_VIEWPORT, scissor); + glGetIntegerv(GL_SCISSOR_BOX, scissor); glScissor(ar->winrct.xmin + (rect.xmin - 1), ar->winrct.ymin + (rect.ymin - 1), (rect.xmax + 1) - (rect.xmin - 1), @@ -1874,7 +1974,7 @@ void ui_draw_but_NODESOCKET(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol GLint scissor[4]; /* need scissor test, can draw outside of boundary */ - glGetIntegerv(GL_VIEWPORT, scissor); + glGetIntegerv(GL_SCISSOR_BOX, scissor); rcti scissor_new = { .xmin = ar->winrct.xmin + recti->xmin, @@ -2031,16 +2131,40 @@ void ui_draw_dropshadow(const rctf *rct, float radius, float aspect, float alpha } glEnable(GL_BLEND); - const float dalpha = alpha * 2.0f / 255.0f; float calpha = dalpha; - for (; i--; a -= aspect) { + float visibility = 1.0f; + for (; i--;) { /* alpha ranges from 2 to 20 or so */ +#if 0 /* Old Method (pre 2.8) */ float color[4] = {0.0f, 0.0f, 0.0f, calpha}; UI_draw_roundbox_4fv(true, rct->xmin - a, rct->ymin - a, rct->xmax + a, rct->ymax - 10.0f + a, rad + a, color); +#endif + /* Compute final visibility to match old method result. */ + /* TODO we could just find a better fit function inside the shader instead of this. */ + visibility = visibility * (1.0f - calpha); calpha += dalpha; } + uiWidgetBaseParameters widget_params = { + .recti.xmin = rct->xmin, .recti.ymin = rct->ymin, + .recti.xmax = rct->xmax, .recti.ymax = rct->ymax - 10.0f, + .rect.xmin = rct->xmin - a, .rect.ymin = rct->ymin - a, + .rect.xmax = rct->xmax + a, .rect.ymax = rct->ymax - 10.0f + a, + .radi = rad, + .rad = rad + a, + .round_corners[0] = (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 1.0f : 0.0f, + .round_corners[1] = (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 1.0f : 0.0f, + .round_corners[2] = (roundboxtype & UI_CNR_TOP_RIGHT) ? 1.0f : 0.0f, + .round_corners[3] = (roundboxtype & UI_CNR_TOP_LEFT) ? 1.0f : 0.0f, + }; + + Gwn_Batch *batch = ui_batch_roundbox_shadow_get(); + GWN_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_SHADOW); + GWN_batch_uniform_4fv_array(batch, "parameters", 4, (float *)&widget_params); + GWN_batch_uniform_1f(batch, "alpha", 1.0f - visibility); + GWN_batch_draw(batch); + /* outline emphasis */ glEnable(GL_LINE_SMOOTH); float color[4] = {0.0f, 0.0f, 0.0f, 0.4f}; diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 3af64c8c5a6..11f78967315 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -74,7 +74,7 @@ #include "BKE_paint.h" #include "ED_screen.h" -#include "ED_util.h" +#include "ED_undo.h" #include "ED_keyframing.h" #include "UI_interface.h" @@ -185,6 +185,7 @@ typedef struct uiSelectContextStore { uiSelectContextElem *elems; int elems_len; bool do_free; + bool is_enabled; /* When set, simply copy values (don't apply difference). * Rules are: * - dragging numbers uses delta. @@ -200,9 +201,7 @@ static void ui_selectcontext_apply( bContext *C, uiBut *but, struct uiSelectContextStore *selctx_data, const double value, const double value_orig); -#if 0 #define IS_ALLSELECT_EVENT(event) ((event)->alt != 0) -#endif /** just show a tinted color so users know its activated */ #define UI_BUT_IS_SELECT_CONTEXT UI_BUT_NODE_ACTIVE @@ -1180,11 +1179,14 @@ static void ui_multibut_states_apply(bContext *C, uiHandleButtonData *data, uiBl ui_but_execute_begin(C, ar, but, &active_back); #ifdef USE_ALLSELECT - if (mbut_state->select_others.elems_len == 0) { - ui_selectcontext_begin(C, but, &mbut_state->select_others); - } - if (mbut_state->select_others.elems_len == 0) { - mbut_state->select_others.elems_len = -1; + if (data->select_others.is_enabled) { + /* init once! */ + if (mbut_state->select_others.elems_len == 0) { + ui_selectcontext_begin(C, but, &mbut_state->select_others); + } + if (mbut_state->select_others.elems_len == 0) { + mbut_state->select_others.elems_len = -1; + } } /* needed so we apply the right deltas */ @@ -2067,7 +2069,12 @@ static void ui_apply_but(bContext *C, uiBlock *block, uiBut *but, uiHandleButton else # endif if (data->select_others.elems_len == 0) { - ui_selectcontext_begin(C, but, &data->select_others); + wmWindow *win = CTX_wm_window(C); + /* may have been enabled before activating */ + if (data->select_others.is_enabled || IS_ALLSELECT_EVENT(win->eventstate)) { + ui_selectcontext_begin(C, but, &data->select_others); + data->select_others.is_enabled = true; + } } if (data->select_others.elems_len == 0) { /* dont check again */ @@ -3070,7 +3077,11 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data) #ifdef USE_ALLSELECT if (is_num_but) { - data->select_others.is_copy = true; + if (IS_ALLSELECT_EVENT(win->eventstate)) { + data->select_others.is_enabled = true; + data->select_others.is_copy = true; + + } } #endif @@ -3675,6 +3686,15 @@ static void ui_block_open_begin(bContext *C, uiBut *but, uiHandleButtonData *dat data->menu->popup = but->block->handle->popup; } +#ifdef USE_ALLSELECT + { + wmWindow *win = CTX_wm_window(C); + if (IS_ALLSELECT_EVENT(win->eventstate)) { + data->select_others.is_enabled = true; + } + } +#endif + /* this makes adjacent blocks auto open from now on */ //if (but->block->auto_open == 0) but->block->auto_open = 1; } @@ -3859,7 +3879,7 @@ static int ui_do_but_KEYEVT( static int ui_do_but_TAB(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { - if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_RELEASE) { + if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) { button_activate_state(C, but, BUTTON_STATE_EXIT); return WM_UI_HANDLER_CONTINUE; } @@ -6793,11 +6813,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); - RNA_property_override_status(ptr, prop, -1, &is_overridable, NULL, NULL, NULL); + const int override_status = RNA_property_override_status(ptr, prop, -1); + const bool is_overridable = (override_status & RNA_OVERRIDE_STATUS_OVERRIDABLE) != 0; /* second slower test, saved people finding keyframe items in menus when its not possible */ if (is_anim) @@ -7762,7 +7782,10 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s /* highlight has timers for tooltips and auto open */ if (state == BUTTON_STATE_HIGHLIGHT) { - but->flag &= ~UI_SELECT; + /* for list-items (that are not drawn with regular emboss), don't change selection based on hovering */ + if (((but->flag & UI_BUT_LIST_ITEM) == 0) && (but->dragflag & UI_EMBOSS_NONE)) { + but->flag &= ~UI_SELECT; + } button_tooltip_timer_reset(C, but); diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index d048324d35e..682eac6a352 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -34,11 +34,13 @@ #include "MEM_guardedalloc.h" #include "GPU_draw.h" +#include "GPU_matrix.h" #include "GPU_immediate.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" #include "BLI_fileops_types.h" +#include "BLI_math_vector.h" #include "DNA_brush_types.h" #include "DNA_curve_types.h" @@ -46,6 +48,7 @@ #include "DNA_object_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" +#include "DNA_workspace_types.h" #include "RNA_access.h" #include "RNA_enum_types.h" @@ -61,6 +64,8 @@ #include "BIF_glutil.h" +#include "DEG_depsgraph.h" + #include "ED_datafiles.h" #include "ED_keyframes_draw.h" #include "ED_render.h" @@ -1004,6 +1009,9 @@ static void icon_draw_rect(float x, float y, int w, int h, float UNUSED(aspect), rect = ima->rect; } + /* We need to flush widget base first to ensure correct ordering. */ + UI_widgetbase_draw_cache_flush(); + /* draw */ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR); immDrawPixelsTex(&state, draw_x, draw_y, draw_w, draw_h, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST, rect, @@ -1013,10 +1021,122 @@ static void icon_draw_rect(float x, float y, int w, int h, float UNUSED(aspect), IMB_freeImBuf(ima); } -static void icon_draw_texture( +/* High enough to make a difference, low enough so that + * small draws are still efficient with the use of glUniform. + * NOTE TODO: We could use UBO but we would need some triple + * buffer system + persistent mapping for this to be more + * efficient than simple glUniform calls. */ +#define ICON_DRAW_CACHE_SIZE 16 + +typedef struct IconDrawCall{ + rctf pos; + rctf tex; + float color[4]; +} IconDrawCall; + +static struct { + IconDrawCall drawcall_cache[ICON_DRAW_CACHE_SIZE]; + int calls; /* Number of calls batched together */ + bool enabled; + float mat[4][4]; +} g_icon_draw_cache = {0}; + +void UI_icon_draw_cache_begin(void) +{ + BLI_assert(g_icon_draw_cache.enabled == false); + g_icon_draw_cache.enabled = true; +} + +static void icon_draw_cache_flush_ex(void) +{ + if (g_icon_draw_cache.calls == 0) + return; + + /* We need to flush widget base first to ensure correct ordering. */ + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + UI_widgetbase_draw_cache_flush(); + + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, icongltex.id); + + GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR); + GPU_shader_bind(shader); + + int img_loc = GPU_shader_get_uniform(shader, "image"); + int data_loc = GPU_shader_get_uniform(shader, "calls_data[0]"); + + glUniform1i(img_loc, 0); + glUniform4fv(data_loc, ICON_DRAW_CACHE_SIZE * 3, (float *)g_icon_draw_cache.drawcall_cache); + + GWN_draw_primitive(GWN_PRIM_TRIS, 6 * g_icon_draw_cache.calls); + + glBindTexture(GL_TEXTURE_2D, 0); + + g_icon_draw_cache.calls = 0; +} + +void UI_icon_draw_cache_end(void) +{ + BLI_assert(g_icon_draw_cache.enabled == true); + g_icon_draw_cache.enabled = false; + + /* Don't change blend state if it's not needed. */ + if (g_icon_draw_cache.calls == 0) + return; + + glEnable(GL_BLEND); + + icon_draw_cache_flush_ex(); + + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_BLEND); +} + +static void icon_draw_texture_cached( float x, float y, float w, float h, int ix, int iy, int UNUSED(iw), int ih, float alpha, const float rgb[3]) { + + float mvp[4][4]; + gpuGetModelViewProjectionMatrix(mvp); + + IconDrawCall *call = &g_icon_draw_cache.drawcall_cache[g_icon_draw_cache.calls]; + g_icon_draw_cache.calls++; + + /* Manual mat4*vec2 */ + call->pos.xmin = x * mvp[0][0] + y * mvp[1][0] + mvp[3][0]; + call->pos.ymin = x * mvp[0][1] + y * mvp[1][1] + mvp[3][1]; + call->pos.xmax = call->pos.xmin + w * mvp[0][0] + h * mvp[1][0]; + call->pos.ymax = call->pos.ymin + w * mvp[0][1] + h * mvp[1][1]; + + call->tex.xmin = ix * icongltex.invw; + call->tex.xmax = (ix + ih) * icongltex.invw; + call->tex.ymin = iy * icongltex.invh; + call->tex.ymax = (iy + ih) * icongltex.invh; + + if (rgb) copy_v4_fl4(call->color, rgb[0], rgb[1], rgb[2], alpha); + else copy_v4_fl(call->color, alpha); + + if (g_icon_draw_cache.calls == ICON_DRAW_CACHE_SIZE) { + icon_draw_cache_flush_ex(); + } +} + +static void icon_draw_texture( + float x, float y, float w, float h, int ix, int iy, + int iw, int ih, float alpha, const float rgb[3]) +{ + if (g_icon_draw_cache.enabled) { + icon_draw_texture_cached(x, y, w, h, ix, iy, iw, ih, alpha, rgb); + return; + } + + /* We need to flush widget base first to ensure correct ordering. */ + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + UI_widgetbase_draw_cache_flush(); + float x1, x2, y1, y2; x1 = ix * icongltex.invw; @@ -1024,32 +1144,20 @@ static void icon_draw_texture( y1 = iy * icongltex.invh; y2 = (iy + ih) * icongltex.invh; + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, icongltex.id); - Gwn_VertFormat *format = immVertexFormat(); - unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - unsigned int texCoord = GWN_vertformat_attr_add(format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_COLOR); - if (rgb) immUniformColor3fvAlpha(rgb, alpha); - else immUniformColor4f(alpha, alpha, alpha, alpha); + GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_RECT_COLOR); + GPU_shader_bind(shader); - immUniform1i("image", 0); + if (rgb) glUniform4f(GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_COLOR), rgb[0], rgb[1], rgb[2], alpha); + else glUniform4f(GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_COLOR), alpha, alpha, alpha, alpha); - immBegin(GWN_PRIM_TRI_STRIP, 4); - immAttrib2f(texCoord, x1, y2); - immVertex2f(pos, x, y + h); + glUniform1i(GPU_shader_get_uniform(shader, "image"), 0); + glUniform4f(GPU_shader_get_uniform(shader, "rect_icon"), x1, y1, x2, y2); + glUniform4f(GPU_shader_get_uniform(shader, "rect_geom"), x, y, x + w, y + h); - immAttrib2f(texCoord, x1, y1); - immVertex2f(pos, x, y); - - immAttrib2f(texCoord, x2, y2); - immVertex2f(pos, x + w, y + h); - - immAttrib2f(texCoord, x2, y1); - immVertex2f(pos, x + w, y); - immEnd(); - - immUnbindProgram(); + GWN_draw_primitive(GWN_PRIM_TRI_STRIP, 4); glBindTexture(GL_TEXTURE_2D, 0); } @@ -1112,7 +1220,7 @@ static void icon_draw_size( glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); icon_draw_texture(x, y, (float)w, (float)h, di->data.texture.x, di->data.texture.y, di->data.texture.w, di->data.texture.h, alpha, rgb); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } else if (di->type == ICON_TYPE_BUFFER) { /* it is a builtin icon */ @@ -1122,9 +1230,9 @@ static void icon_draw_size( #endif if (!iimg->rect) return; /* something has gone wrong! */ - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); icon_draw_rect(x, y, w, h, aspect, iimg->w, iimg->h, iimg->rect, alpha, rgb, is_preview); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } else if (di->type == ICON_TYPE_PREVIEW) { PreviewImage *pi = (icon->type != 0) ? BKE_previewimg_id_ensure((ID *)icon->obj) : icon->obj; @@ -1137,7 +1245,7 @@ static void icon_draw_size( glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); icon_draw_rect(x, y, w, h, aspect, pi->w[size], pi->h[size], pi->rect[size], alpha, rgb, is_preview); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } } } @@ -1316,7 +1424,7 @@ int UI_idcode_icon_get(const int idcode) { switch (idcode) { case ID_AC: - return ICON_ANIM_DATA; + return ICON_ACTION; case ID_AR: return ICON_ARMATURE_DATA; case ID_BR: diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 8d7f9d47ab5..043dfc9fd99 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -700,6 +700,35 @@ struct wmIMEData *ui_but_ime_data_get(uiBut *but); #endif /* interface_widgets.c */ + +/* Widget shader parameters, must match the shader layout. */ +typedef struct uiWidgetBaseParameters { + rctf recti, rect; + float radi, rad; + float facxi, facyi; + float round_corners[4]; + float color_inner1[4], color_inner2[4]; + float color_outline[4], color_emboss[4]; + float color_tria[4]; + float tria1_center[2], tria2_center[2]; + float tria1_size, tria2_size; + float shade_dir, do_alpha_check; +} uiWidgetBaseParameters; + +enum { + ROUNDBOX_TRIA_NONE = 0, + ROUNDBOX_TRIA_ARROWS, + ROUNDBOX_TRIA_SCROLL, + ROUNDBOX_TRIA_MENU, + ROUNDBOX_TRIA_CHECK, + + ROUNDBOX_TRIA_MAX, /* don't use */ +}; + +struct Gwn_Batch *ui_batch_roundbox_get(bool filled, bool antialiased); +struct Gwn_Batch *ui_batch_roundbox_widget_get(int tria); +struct Gwn_Batch *ui_batch_roundbox_shadow_get(void); + void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3, const float color[4]); void ui_draw_anti_roundbox(int mode, float minx, float miny, float maxx, float maxy, float rad, bool use_alpha, const float color[4]); diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 30a18ddc8bc..969367f485c 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -1488,7 +1488,7 @@ void uiItemFullR(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index } /* Mark non-embossed textfields inside a listbox. */ - if (but && (block->flag & UI_BLOCK_LIST_ITEM) && (but->type == UI_BTYPE_TEXT) && (but->dt & UI_EMBOSS_NONE)) { + if (but && (block->flag & UI_BLOCK_LIST_ITEM) && (but->dt & UI_EMBOSS_NONE)) { UI_but_flag_enable(but, UI_BUT_LIST_ITEM); } diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 16525dfbc9e..9e31e8729d5 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -482,13 +482,12 @@ 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); + const int override_status = RNA_property_override_status(&ptr, prop, index); - return (ptr.data && prop && is_overridable); + return (ptr.data && prop && (override_status & RNA_OVERRIDE_STATUS_OVERRIDABLE)); } static int override_type_set_button_exec(bContext *C, wmOperator *op) @@ -572,13 +571,12 @@ 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); + const int override_status = RNA_property_override_status(&ptr, prop, index); - return (ptr.data && ptr.id.data && prop && is_overridden); + return (ptr.data && ptr.id.data && prop && (override_status & RNA_OVERRIDE_STATUS_OVERRIDDEN)); } static int override_remove_button_exec(bContext *C, wmOperator *op) @@ -945,7 +943,8 @@ static int reports_to_text_exec(bContext *C, wmOperator *UNUSED(op)) str = BKE_reports_string(reports, (G.debug & G_DEBUG) ? RPT_DEBUG : RPT_INFO); if (str) { - BKE_text_write(txt, str); + TextUndoBuf *utxt = NULL; // FIXME + BKE_text_write(txt, utxt, str); MEM_freeN(str); return OPERATOR_FINISHED; diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index c3759e232b0..bb086d63917 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -501,9 +501,28 @@ static void ui_draw_panel_scalewidget(unsigned int pos, const rcti *rect) glDisable(GL_BLEND); } -static void ui_draw_panel_dragwidget(unsigned int pos, const rctf *rect) + +static void immRectf_tris_color_ex(unsigned int pos, float x1, float y1, float x2, float y2, + unsigned int col, const float color[3]) +{ + immAttrib4fv(col, color); + immVertex2f(pos, x1, y1); + immAttrib4fv(col, color); + immVertex2f(pos, x2, y1); + immAttrib4fv(col, color); + immVertex2f(pos, x2, y2); + + immAttrib4fv(col, color); + immVertex2f(pos, x1, y1); + immAttrib4fv(col, color); + immVertex2f(pos, x2, y2); + immAttrib4fv(col, color); + immVertex2f(pos, x1, y2); +} + +static void ui_draw_panel_dragwidget(unsigned int pos, unsigned int col, const rctf *rect) { - unsigned char col_back[3], col_high[3], col_dark[3]; + float col_high[4], col_dark[4]; const int col_tint = 84; const int px = (int)U.pixelsize; @@ -518,24 +537,24 @@ static void ui_draw_panel_dragwidget(unsigned int pos, const rctf *rect) const int x_ofs = y_ofs; int i_x, i_y; - - UI_GetThemeColor3ubv(UI_GetThemeValue(TH_PANEL_SHOW_HEADER) ? TH_PANEL_HEADER : TH_PANEL_BACK, col_back); - UI_GetColorPtrShade3ubv(col_back, col_high, col_tint); - UI_GetColorPtrShade3ubv(col_back, col_dark, -col_tint); - + int col_id = UI_GetThemeValue(TH_PANEL_SHOW_HEADER) ? TH_PANEL_HEADER : TH_PANEL_BACK; + UI_GetThemeColorShade4fv(col_id, col_tint, col_high); + UI_GetThemeColorShade4fv(col_id, -col_tint, col_dark); /* draw multiple boxes */ + immBegin(GWN_PRIM_TRIS, 4 * 2 * (6 * 2)); for (i_x = 0; i_x < 4; i_x++) { for (i_y = 0; i_y < 2; i_y++) { const int x_co = (x_min + x_ofs) + (i_x * (box_size + box_margin)); const int y_co = (y_min + y_ofs) + (i_y * (box_size + box_margin)); - immUniformColor3ubv(col_dark); - immRectf(pos, x_co - box_size, y_co - px_zoom, x_co, (y_co + box_size) - px_zoom); - immUniformColor3ubv(col_high); - immRectf(pos, x_co - box_size, y_co, x_co, y_co + box_size); + immRectf_tris_color_ex(pos, x_co - box_size, y_co - px_zoom, x_co, (y_co + box_size) - px_zoom, + col, col_dark); + immRectf_tris_color_ex(pos, x_co - box_size, y_co, x_co, y_co + box_size, + col, col_high); } } + immEnd(); } @@ -662,8 +681,11 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con /* horizontal title */ if (is_closed_x == false) { + unsigned int col; ui_draw_aligned_panel_header(style, block, &headrect, 'h'); - pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + Gwn_VertFormat *format = immVertexFormat(); + pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + col = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 4, GWN_FETCH_FLOAT); /* itemrect smaller */ itemrect.xmax = headrect.xmax - 5.0f / block->aspect; @@ -672,9 +694,12 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con itemrect.ymax = headrect.ymax; BLI_rctf_scale(&itemrect, 0.7f); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - ui_draw_panel_dragwidget(pos, &itemrect); + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + ui_draw_panel_dragwidget(pos, col, &itemrect); immUnbindProgram(); + + /* Restore format for the following draws. */ + pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); } /* if the panel is minimized vertically: @@ -1594,30 +1619,36 @@ static void ui_panel_category_draw_tab( immBegin(filled ? GWN_PRIM_TRI_FAN : GWN_PRIM_LINE_STRIP, vert_ct); - immAttrib3ubv(color, col); - /* start with corner right-top */ if (use_highlight) { if (roundboxtype & UI_CNR_TOP_RIGHT) { + immAttrib3ubv(color, col); immVertex2f(pos, maxx, maxy - rad); for (a = 0; a < 4; a++) { + immAttrib3ubv(color, col); immVertex2f(pos, maxx - vec[a][1], maxy - rad + vec[a][0]); } + immAttrib3ubv(color, col); immVertex2f(pos, maxx - rad, maxy); } else { + immAttrib3ubv(color, col); immVertex2f(pos, maxx, maxy); } /* corner left-top */ if (roundboxtype & UI_CNR_TOP_LEFT) { + immAttrib3ubv(color, col); immVertex2f(pos, minx + rad, maxy); for (a = 0; a < 4; a++) { + immAttrib3ubv(color, col); immVertex2f(pos, minx + rad - vec[a][0], maxy - vec[a][1]); } + immAttrib3ubv(color, col); immVertex2f(pos, minx, maxy - rad); } else { + immAttrib3ubv(color, col); immVertex2f(pos, minx, maxy); } } @@ -1626,6 +1657,9 @@ static void ui_panel_category_draw_tab( if (highlight_fade) { immAttrib3ubv(color, highlight_fade); } + else { + immAttrib3ubv(color, col); + } immVertex2f(pos, minx, miny + rad); immEnd(); immUnbindProgram(); @@ -1634,25 +1668,33 @@ static void ui_panel_category_draw_tab( /* corner left-bottom */ if (roundboxtype & UI_CNR_BOTTOM_LEFT) { + immAttrib3ubv(color, col); immVertex2f(pos, minx, miny + rad); for (a = 0; a < 4; a++) { + immAttrib3ubv(color, col); immVertex2f(pos, minx + vec[a][1], miny + rad - vec[a][0]); } + immAttrib3ubv(color, col); immVertex2f(pos, minx + rad, miny); } else { + immAttrib3ubv(color, col); immVertex2f(pos, minx, miny); } /* corner right-bottom */ if (roundboxtype & UI_CNR_BOTTOM_RIGHT) { + immAttrib3ubv(color, col); immVertex2f(pos, maxx - rad, miny); for (a = 0; a < 4; a++) { + immAttrib3ubv(color, col); immVertex2f(pos, maxx - rad + vec[a][0], miny + vec[a][1]); } + immAttrib3ubv(color, col); immVertex2f(pos, maxx, miny + rad); } else { + immAttrib3ubv(color, col); immVertex2f(pos, maxx, miny); } diff --git a/source/blender/editors/interface/interface_region_menu_pie.c b/source/blender/editors/interface/interface_region_menu_pie.c index b3d5c74f77a..37a603d967f 100644 --- a/source/blender/editors/interface/interface_region_menu_pie.c +++ b/source/blender/editors/interface/interface_region_menu_pie.c @@ -214,9 +214,10 @@ int UI_pie_menu_invoke(struct bContext *C, const char *idname, const wmEvent *ev return OPERATOR_CANCELLED; } - if (mt->poll && mt->poll(C, mt) == 0) + if (WM_menutype_poll(C, mt) == false) { /* cancel but allow event to pass through, just like operators do */ return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); + } pie = UI_pie_menu_begin(C, IFACE_(mt->label), ICON_NONE, event); layout = UI_pie_menu_layout(pie); diff --git a/source/blender/editors/interface/interface_region_menu_popup.c b/source/blender/editors/interface/interface_region_menu_popup.c index a0aecb12b84..d4fe0f5a5ee 100644 --- a/source/blender/editors/interface/interface_region_menu_popup.c +++ b/source/blender/editors/interface/interface_region_menu_popup.c @@ -518,9 +518,10 @@ int UI_popup_menu_invoke(bContext *C, const char *idname, ReportList *reports) return OPERATOR_CANCELLED; } - if (mt->poll && mt->poll(C, mt) == 0) + if (WM_menutype_poll(C, mt) == false) { /* cancel but allow event to pass through, just like operators do */ return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); + } pup = UI_popup_menu_begin(C, IFACE_(mt->label), ICON_NONE); layout = UI_popup_menu_layout(pup); diff --git a/source/blender/editors/interface/interface_region_popup.c b/source/blender/editors/interface/interface_region_popup.c index 24990c593ac..67383ec73a6 100644 --- a/source/blender/editors/interface/interface_region_popup.c +++ b/source/blender/editors/interface/interface_region_popup.c @@ -48,7 +48,6 @@ #include "WM_api.h" #include "WM_types.h" -#include "wm_subwindow.h" #include "UI_interface.h" @@ -303,19 +302,36 @@ static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but, static void ui_block_region_draw(const bContext *C, ARegion *ar) { + ScrArea *ctx_area = CTX_wm_area(C); + ARegion *ctx_region = CTX_wm_region(C); uiBlock *block; if (ar->do_draw & RGN_DRAW_REFRESH_UI) { + ScrArea *handle_ctx_area; + ARegion *handle_ctx_region; uiBlock *block_next; + ar->do_draw &= ~RGN_DRAW_REFRESH_UI; for (block = ar->uiblocks.first; block; block = block_next) { block_next = block->next; if (block->handle->can_refresh) { + handle_ctx_area = block->handle->ctx_area; + handle_ctx_region = block->handle->ctx_region; + + if (handle_ctx_area) { + CTX_wm_area_set((bContext *)C, handle_ctx_area); + } + if (handle_ctx_region) { + CTX_wm_region_set((bContext *)C, handle_ctx_region); + } ui_popup_block_refresh((bContext *)C, block->handle, NULL, NULL); } } } + CTX_wm_area_set((bContext *)C, ctx_area); + CTX_wm_region_set((bContext *)C, ctx_region); + for (block = ar->uiblocks.first; block; block = block->next) UI_block_draw(C, block); } @@ -589,9 +605,7 @@ uiBlock *ui_popup_block_refresh( ED_region_init(C, ar); /* get winmat now that we actually have the subwindow */ - wmSubWindowSet(window, ar->swinid); - - wm_subwindow_matrix_get(window, ar->swinid, block->winmat); + wmGetProjectionMatrix(block->winmat, &ar->winrct); /* notify change and redraw */ ED_region_tag_redraw(ar); diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c index 07fbefa42e1..449e783b03e 100644 --- a/source/blender/editors/interface/interface_region_tooltip.c +++ b/source/blender/editors/interface/interface_region_tooltip.c @@ -175,12 +175,7 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *ar) float background_color[3]; float tone_bg; - int i, multisample_enabled; - - /* disable AA, makes widgets too blurry */ - multisample_enabled = glIsEnabled(GL_MULTISAMPLE); - if (multisample_enabled) - glDisable(GL_MULTISAMPLE); + int i; wmOrtho2_region_pixelspace(ar); @@ -285,9 +280,6 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *ar) BLF_disable(data->fstyle.uifont_id, BLF_WORD_WRAP); BLF_disable(blf_mono_font, BLF_WORD_WRAP); - - if (multisample_enabled) - glEnable(GL_MULTISAMPLE); } static void ui_tooltip_region_free_cb(ARegion *ar) diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 32758b7935a..375027a84d0 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -36,7 +36,7 @@ #include "DNA_node_types.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" -#include "DNA_object_force.h" +#include "DNA_object_force_types.h" #include "DNA_brush_types.h" #include "DNA_texture_types.h" @@ -79,7 +79,7 @@ #include "ED_screen.h" #include "ED_object.h" #include "ED_render.h" -#include "ED_util.h" +#include "ED_undo.h" #include "RNA_access.h" @@ -351,11 +351,11 @@ static void id_search_cb_objects_from_scene(const bContext *C, void *arg_templat BKE_main_id_flag_listbase(lb, LIB_TAG_DOIT, false); - FOREACH_SCENE_OBJECT(scene, ob_iter) + FOREACH_SCENE_OBJECT_BEGIN(scene, ob_iter) { ob_iter->id.tag |= LIB_TAG_DOIT; } - FOREACH_SCENE_OBJECT_END + FOREACH_SCENE_OBJECT_END; id_search_cb_tagged(C, arg_template, str, items); } diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 3afae5ed8d4..5a210d01f27 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -55,6 +55,7 @@ #include "interface_intern.h" #include "GPU_basic_shader.h" +#include "GPU_batch.h" #include "GPU_immediate.h" #include "GPU_immediate_util.h" #include "GPU_matrix.h" @@ -79,6 +80,7 @@ enum { #define UI_BUT_UPDATE_DELAY ((void)0) #define UI_BUT_UNDO ((void)0) + /* ************** widget base functions ************** */ /** * - in: roundbox codes for corner types and radius @@ -98,6 +100,8 @@ enum { typedef struct uiWidgetTrias { unsigned int tot; + int type; + float size, center[2]; float vec[16][2]; const unsigned int (*index)[3]; @@ -105,21 +109,24 @@ typedef struct uiWidgetTrias { } uiWidgetTrias; /* max as used by round_box__edges */ +/* Make sure to change widget_base_vert.glsl accordingly. */ #define WIDGET_CURVE_RESOLU 9 #define WIDGET_SIZE_MAX (WIDGET_CURVE_RESOLU * 4) typedef struct uiWidgetBase { - + /* TODO remove these completely */ int totvert, halfwayvert; float outer_v[WIDGET_SIZE_MAX][2]; float inner_v[WIDGET_SIZE_MAX][2]; float inner_uv[WIDGET_SIZE_MAX][2]; - bool draw_inner, draw_outline, draw_emboss, draw_shadedir; + bool draw_inner, draw_outline, draw_emboss; uiWidgetTrias tria1; uiWidgetTrias tria2; - + + /* Widget shader parameters, must match the shader layout. */ + uiWidgetBaseParameters uniform_params; } uiWidgetBase; /** uiWidgetType: for time being only for visual appearance, @@ -206,6 +213,270 @@ static const uint g_shape_preset_hold_action_face[2][3] = {{2, 0, 1}, {3, 5, 4}} /** \} */ +/* **************** Batch creations ****************** */ +/** + * In order to speed up UI drawing we create some batches that are then + * modified by specialized shaders to draw certain elements really fast. + * TODO: find a better place. Maybe it's own file? + **/ + +/* offset in triavec[] in shader per type */ +static const int tria_ofs[ROUNDBOX_TRIA_MAX] = {0, 0, 6, 22, 28}; +static const int tria_vcount[ROUNDBOX_TRIA_MAX] = {0, 3, 16, 3, 6}; + +static struct { + Gwn_Batch *roundbox_widget[ROUNDBOX_TRIA_MAX]; + + Gwn_Batch *roundbox_simple; + Gwn_Batch *roundbox_simple_aa; + Gwn_Batch *roundbox_simple_outline; + Gwn_Batch *roundbox_shadow; + + Gwn_VertFormat format; + uint vflag_id; +} g_ui_batch_cache = {{0}}; + +static Gwn_VertFormat *vflag_format(void) +{ + if (g_ui_batch_cache.format.attrib_ct == 0) { + Gwn_VertFormat *format = &g_ui_batch_cache.format; + g_ui_batch_cache.vflag_id = GWN_vertformat_attr_add(format, "vflag", GWN_COMP_U32, 1, GWN_FETCH_INT); + } + return &g_ui_batch_cache.format; +} + +#define INNER 0 +#define OUTLINE 1 +#define EMBOSS 2 +#define NO_AA WIDGET_AA_JITTER + +static void set_roundbox_vertex_data( + Gwn_VertBufRaw *vflag_step, uint32_t d) +{ + uint32_t *data = GWN_vertbuf_raw_step(vflag_step); + *data = d; +} + +static uint32_t set_roundbox_vertex( + Gwn_VertBufRaw *vflag_step, + int corner_id, int corner_v, int jit_v, bool inner, bool emboss, int color) +{ + uint32_t *data = GWN_vertbuf_raw_step(vflag_step); + *data = corner_id; + *data |= corner_v << 2; + *data |= jit_v << 6; + *data |= color << 12; + *data |= (inner) ? (1 << 10) : 0; /* is inner vert */ + *data |= (emboss) ? (1 << 11) : 0; /* is emboss vert */ + return *data; +} + +static uint32_t set_tria_vertex( + Gwn_VertBufRaw *vflag_step, + int tria_type, int tria_v, int tria_id, int jit_v) +{ + uint32_t *data = GWN_vertbuf_raw_step(vflag_step); + if (ELEM(tria_type, ROUNDBOX_TRIA_ARROWS, ROUNDBOX_TRIA_MENU)) { + tria_v += tria_id * 3; + } + *data = tria_ofs[tria_type] + tria_v; + *data |= jit_v << 6; + *data |= (tria_id == 0) ? (1 << 10) : 0; /* is first tria */ + *data |= 1 << 14; /* is tria vert */ + return *data; +} + +static void roundbox_batch_add_tria(Gwn_VertBufRaw *vflag_step, int tria, uint32_t last_data) +{ + const int tria_num = (tria == ROUNDBOX_TRIA_CHECK) ? 1 : 2; + /* for each tria */ + for (int t = 0; t < tria_num; ++t) { + for (int j = 0; j < WIDGET_AA_JITTER; j++) { + /* restart */ + set_roundbox_vertex_data(vflag_step, last_data); + set_tria_vertex(vflag_step, tria, 0, t, j); + for (int v = 0; v < tria_vcount[tria]; v++) { + last_data = set_tria_vertex(vflag_step, tria, v, t, j); + } + } + } +} + +Gwn_Batch *ui_batch_roundbox_widget_get(int tria) +{ + if (g_ui_batch_cache.roundbox_widget[tria] == NULL) { + uint32_t last_data; + Gwn_VertBufRaw vflag_step; + Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(vflag_format()); + int vcount = WIDGET_SIZE_MAX; /* inner */ + vcount += 2; /* restart */ + vcount += ((WIDGET_SIZE_MAX + 1) * 2) * WIDGET_AA_JITTER; /* outline (edges) */ + vcount += 2; /* restart */ + vcount += ((WIDGET_CURVE_RESOLU * 2) * 2) * WIDGET_AA_JITTER; /* emboss */ + if (tria) { + vcount += (tria_vcount[tria] + 2) * WIDGET_AA_JITTER; /* tria1 */ + if (tria != ROUNDBOX_TRIA_CHECK) { + vcount += (tria_vcount[tria] + 2) * WIDGET_AA_JITTER; /* tria2 */ + } + } + GWN_vertbuf_data_alloc(vbo, vcount); + GWN_vertbuf_attr_get_raw_data(vbo, g_ui_batch_cache.vflag_id, &vflag_step); + /* Inner */ + for (int c1 = 0, c2 = 3; c1 < 2; c1++, c2--) { + for (int a1 = 0, a2 = WIDGET_CURVE_RESOLU -1; a2 >= 0; a1++, a2--) { + last_data = set_roundbox_vertex(&vflag_step, c1, a1, NO_AA, true, false, INNER); + last_data = set_roundbox_vertex(&vflag_step, c2, a2, NO_AA, true, false, INNER); + } + } + /* restart */ + set_roundbox_vertex_data(&vflag_step, last_data); + set_roundbox_vertex(&vflag_step, 0, 0, 0, true, false, OUTLINE); + /* Outlines */ + for (int j = 0; j < WIDGET_AA_JITTER; j++) { + for (int c = 0; c < 4; c++) { + for (int a = 0; a < WIDGET_CURVE_RESOLU; a++) { + set_roundbox_vertex(&vflag_step, c, a, j, true, false, OUTLINE); + set_roundbox_vertex(&vflag_step, c, a, j, false, false, OUTLINE); + } + } + /* Close the loop. */ + set_roundbox_vertex(&vflag_step, 0, 0, j, true, false, OUTLINE); + last_data = set_roundbox_vertex(&vflag_step, 0, 0, j, false, false, OUTLINE); + } + /* restart */ + set_roundbox_vertex_data(&vflag_step, last_data); + set_roundbox_vertex(&vflag_step, 0, 0, 0, false, false, EMBOSS); + /* Emboss */ + bool rev = false; /* go back and forth : avoid degenerate triangle (but beware of backface cull) */ + for (int j = 0; j < WIDGET_AA_JITTER; j++, rev = !rev) { + for (int c = (rev) ? 1 : 0; (rev) ? c >= 0 : c < 2; (rev) ? c-- : c++) { + int sta = (rev) ? WIDGET_CURVE_RESOLU - 1 : 0; + int end = WIDGET_CURVE_RESOLU; + for (int a = sta; (rev) ? a >= 0 : a < end; (rev) ? a-- : a++) { + set_roundbox_vertex(&vflag_step, c, a, j, false, false, EMBOSS); + last_data = set_roundbox_vertex(&vflag_step, c, a, j, false, true, EMBOSS); + } + } + } + if (tria) { + roundbox_batch_add_tria(&vflag_step, tria, last_data); + } + g_ui_batch_cache.roundbox_widget[tria] = GWN_batch_create_ex(GWN_PRIM_TRI_STRIP, vbo, NULL, GWN_BATCH_OWNS_VBO); + gpu_batch_presets_register(g_ui_batch_cache.roundbox_widget[tria]); + } + return g_ui_batch_cache.roundbox_widget[tria]; +} + +Gwn_Batch *ui_batch_roundbox_get(bool filled, bool antialiased) +{ + Gwn_Batch **batch = NULL; + + if (filled) { + if (antialiased) + batch = &g_ui_batch_cache.roundbox_simple_aa; + else + batch = &g_ui_batch_cache.roundbox_simple; + } + else { + if (antialiased) + BLI_assert(0); /* Use GL_LINE_SMOOTH instead!!: */ + else + batch = &g_ui_batch_cache.roundbox_simple_outline; + } + + if (*batch == NULL) { + uint32_t last_data; + Gwn_VertBufRaw vflag_step; + Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(vflag_format()); + int vcount = WIDGET_SIZE_MAX; + vcount += (filled) ? 2 : 0; + vcount *= (antialiased) ? WIDGET_AA_JITTER : 1; + GWN_vertbuf_data_alloc(vbo, vcount); + GWN_vertbuf_attr_get_raw_data(vbo, g_ui_batch_cache.vflag_id, &vflag_step); + + if (filled) { + for (int j = 0; j < WIDGET_AA_JITTER; j++) { + if (!antialiased) { + j = NO_AA; + } + /* restart */ + set_roundbox_vertex(&vflag_step, 0, 0, j, true, false, INNER); + for (int c1 = 0, c2 = 3; c1 < 2; c1++, c2--) { + for (int a1 = 0, a2 = WIDGET_CURVE_RESOLU -1; a2 >= 0; a1++, a2--) { + last_data = set_roundbox_vertex(&vflag_step, c1, a1, j, true, false, INNER); + last_data = set_roundbox_vertex(&vflag_step, c2, a2, j, true, false, INNER); + } + } + /* restart */ + set_roundbox_vertex_data(&vflag_step, last_data); + if (!antialiased) { + break; + } + } + *batch = GWN_batch_create_ex(GWN_PRIM_TRI_STRIP, vbo, NULL, GWN_BATCH_OWNS_VBO); + } + else { + for (int j = 0; j < WIDGET_AA_JITTER; j++) { + if (!antialiased) { + j = NO_AA; + } + for (int c = 0; c < 4; c++) { + for (int a = 0; a < WIDGET_CURVE_RESOLU; a++) { + set_roundbox_vertex(&vflag_step, c, a, j, true, false, INNER); + } + } + if (!antialiased) { + break; + } + } + *batch = GWN_batch_create_ex(GWN_PRIM_LINE_LOOP, vbo, NULL, GWN_BATCH_OWNS_VBO); + } + + gpu_batch_presets_register(*batch); + } + return *batch; +} + +Gwn_Batch *ui_batch_roundbox_shadow_get(void) +{ + if (g_ui_batch_cache.roundbox_shadow == NULL) { + uint32_t last_data; + Gwn_VertBufRaw vflag_step; + Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(vflag_format()); + int vcount = (WIDGET_SIZE_MAX + 1) * 2 + 2 + WIDGET_SIZE_MAX; + GWN_vertbuf_data_alloc(vbo, vcount); + GWN_vertbuf_attr_get_raw_data(vbo, g_ui_batch_cache.vflag_id, &vflag_step); + + for (int c = 0; c < 4; c++) { + for (int a = 0; a < WIDGET_CURVE_RESOLU; a++) { + set_roundbox_vertex(&vflag_step, c, a, NO_AA, true, false, INNER); + set_roundbox_vertex(&vflag_step, c, a, NO_AA, false, false, INNER); + } + } + /* close loop */ + last_data = set_roundbox_vertex(&vflag_step, 0, 0, NO_AA, true, false, INNER); + last_data = set_roundbox_vertex(&vflag_step, 0, 0, NO_AA, false, false, INNER); + /* restart */ + set_roundbox_vertex_data(&vflag_step, last_data); + set_roundbox_vertex(&vflag_step, 0, 0, NO_AA, true, false, INNER); + /* filled */ + for (int c1 = 0, c2 = 3; c1 < 2; c1++, c2--) { + for (int a1 = 0, a2 = WIDGET_CURVE_RESOLU -1; a2 >= 0; a1++, a2--) { + set_roundbox_vertex(&vflag_step, c1, a1, NO_AA, true, false, INNER); + set_roundbox_vertex(&vflag_step, c2, a2, NO_AA, true, false, INNER); + } + } + g_ui_batch_cache.roundbox_shadow = GWN_batch_create_ex(GWN_PRIM_TRI_STRIP, vbo, NULL, GWN_BATCH_OWNS_VBO); + gpu_batch_presets_register(g_ui_batch_cache.roundbox_shadow); + } + return g_ui_batch_cache.roundbox_shadow; +} + +#undef INNER +#undef OUTLINE +#undef EMBOSS +#undef NO_AA + /* ************************************************* */ void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3, @@ -239,42 +510,20 @@ void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y glDisable(GL_BLEND); } -/* belongs in interface_draw.c, but needs WIDGET_AA_JITTER from this file */ -void UI_draw_roundbox_aa(bool filled, float minx, float miny, float maxx, float maxy, float rad, const float color[4]) -{ - glEnable(GL_BLEND); - - if (filled) { - /* plain antialiased filled box */ - const float alpha = color[3] * 0.125f; - - for (int j = 0; j < WIDGET_AA_JITTER; j++) { - gpuPushMatrix(); - gpuTranslate2fv(jit[j]); - UI_draw_roundbox_3fvAlpha(true, minx, miny, maxx, maxy, rad, color, alpha); - gpuPopMatrix(); - } - } - else { - /* plain antialiased unfilled box */ - glEnable(GL_LINE_SMOOTH); - UI_draw_roundbox_4fv(false, minx, miny, maxx, maxy, rad, color); - glDisable(GL_LINE_SMOOTH); - } - - glDisable(GL_BLEND); -} - static void widget_init(uiWidgetBase *wtb) { wtb->totvert = wtb->halfwayvert = 0; wtb->tria1.tot = 0; wtb->tria2.tot = 0; + wtb->tria1.type = ROUNDBOX_TRIA_NONE; + wtb->tria1.size = 0; + wtb->tria2.size = 0; wtb->draw_inner = true; wtb->draw_outline = true; wtb->draw_emboss = true; - wtb->draw_shadedir = true; + + wtb->uniform_params.shade_dir = 1.0f; } /* helper call, makes shadow rect, with 'sun' above menu, so only shadow to left/right/bottom */ @@ -381,7 +630,18 @@ static void round_box__edges(uiWidgetBase *wt, int roundboxalign, const rcti *re if (2.0f * (radi + 1.0f) > minsize) radi = 0.5f * minsize - U.pixelsize; - + + wt->uniform_params.rad = rad; + wt->uniform_params.radi = radi; + wt->uniform_params.facxi = facxi; + wt->uniform_params.facyi = facyi; + wt->uniform_params.round_corners[0] = (roundboxalign & UI_CNR_BOTTOM_LEFT) ? 1.0f : 0.0f; + wt->uniform_params.round_corners[1] = (roundboxalign & UI_CNR_BOTTOM_RIGHT) ? 1.0f : 0.0f; + wt->uniform_params.round_corners[2] = (roundboxalign & UI_CNR_TOP_RIGHT) ? 1.0f : 0.0f; + wt->uniform_params.round_corners[3] = (roundboxalign & UI_CNR_TOP_LEFT) ? 1.0f : 0.0f; + BLI_rctf_rcti_copy(&wt->uniform_params.rect, rect); + BLI_rctf_init(&wt->uniform_params.recti, minxi, maxxi, minyi, maxyi); + /* mult */ for (a = 0; a < WIDGET_CURVE_RESOLU; a++) { veci[a][0] = radi * cornervec[a][0]; @@ -531,18 +791,20 @@ static void shape_preset_init_trias_ex( /* center position and size */ centx = (float)rect->xmin + 0.4f * minsize; centy = (float)rect->ymin + 0.5f * minsize; - sizex = sizey = -0.5f * triasize * minsize; + tria->size = sizex = sizey = -0.5f * triasize * minsize; if (where == 'r') { centx = (float)rect->xmax - 0.4f * minsize; sizex = -sizex; } else if (where == 't') { + centx = (float)rect->xmin + 0.5f * minsize; centy = (float)rect->ymax - 0.5f * minsize; sizey = -sizey; i2 = 0; i1 = 1; } else if (where == 'b') { + centx = (float)rect->xmin + 0.5f * minsize; sizex = -sizex; i2 = 0; i1 = 1; } @@ -552,12 +814,16 @@ static void shape_preset_init_trias_ex( tria->vec[a][1] = sizey * verts[a][i2] + centy; } + tria->center[0] = centx; + tria->center[1] = centy; + tria->tot = tris_tot; tria->index = tris; } static void shape_preset_init_number_arrows(uiWidgetTrias *tria, const rcti *rect, float triasize, char where) { + tria->type = ROUNDBOX_TRIA_ARROWS; shape_preset_init_trias_ex( tria, rect, triasize, where, g_shape_preset_number_arrow_vert, ARRAY_SIZE(g_shape_preset_number_arrow_vert), @@ -574,19 +840,22 @@ static void shape_preset_init_hold_action(uiWidgetTrias *tria, const rcti *rect, static void shape_preset_init_scroll_circle(uiWidgetTrias *tria, const rcti *rect, float triasize, char where) { + tria->type = ROUNDBOX_TRIA_SCROLL; shape_preset_init_trias_ex( tria, rect, triasize, where, g_shape_preset_scroll_circle_vert, ARRAY_SIZE(g_shape_preset_scroll_circle_vert), g_shape_preset_scroll_circle_face, ARRAY_SIZE(g_shape_preset_scroll_circle_face)); } -static void shape_preset_draw_trias(uiWidgetTrias *tria, uint pos) +static void shape_preset_draw_trias_aa(uiWidgetTrias *tria, uint pos) { - immBegin(GWN_PRIM_TRIS, tria->tot * 3); - for (int i = 0; i < tria->tot; ++i) - for (int j = 0; j < 3; ++j) - immVertex2fv(pos, tria->vec[tria->index[i][j]]); - immEnd(); + for (int k = 0; k < WIDGET_AA_JITTER; k++) { + for (int i = 0; i < tria->tot; ++i) + for (int j = 0; j < 3; ++j) + immVertex2f(pos, + tria->vec[tria->index[i][j]][0] + jit[k][0], + tria->vec[tria->index[i][j]][1] + jit[k][1]); + } } static void widget_draw_vertex_buffer(unsigned int pos, unsigned int col, int mode, @@ -607,11 +876,12 @@ static void shape_preset_trias_from_rect_menu(uiWidgetTrias *tria, const rcti *r { float centx, centy, size; int a; + tria->type = ROUNDBOX_TRIA_MENU; /* center position and size */ - centx = rect->xmax - 0.32f * BLI_rcti_size_y(rect); - centy = rect->ymin + 0.50f * BLI_rcti_size_y(rect); - size = 0.4f * BLI_rcti_size_y(rect); + tria->center[0] = centx = rect->xmax - 0.32f * BLI_rcti_size_y(rect); + tria->center[1] = centy = rect->ymin + 0.50f * BLI_rcti_size_y(rect); + tria->size = size = 0.4f * BLI_rcti_size_y(rect); for (a = 0; a < 6; a++) { tria->vec[a][0] = size * g_shape_preset_menu_arrow_vert[a][0] + centx; @@ -626,11 +896,12 @@ static void shape_preset_trias_from_rect_checkmark(uiWidgetTrias *tria, const rc { float centx, centy, size; int a; + tria->type = ROUNDBOX_TRIA_CHECK; /* center position and size */ - centx = rect->xmin + 0.5f * BLI_rcti_size_y(rect); - centy = rect->ymin + 0.5f * BLI_rcti_size_y(rect); - size = 0.5f * BLI_rcti_size_y(rect); + tria->center[0] = centx = rect->xmin + 0.5f * BLI_rcti_size_y(rect); + tria->center[1] = centy = rect->ymin + 0.5f * BLI_rcti_size_y(rect); + tria->size = size = 0.5f * BLI_rcti_size_y(rect); for (a = 0; a < 6; a++) { tria->vec[a][0] = size * g_shape_preset_checkmark_vert[a][0] + centx; @@ -680,17 +951,6 @@ static void widget_verts_to_triangle_strip(uiWidgetBase *wtb, const int totvert, copy_v2_v2(triangle_strip[a * 2 + 1], wtb->inner_v[0]); } -static void widget_verts_to_triangle_strip_open(uiWidgetBase *wtb, const int totvert, float triangle_strip[WIDGET_SIZE_MAX * 2][2]) -{ - int a; - for (a = 0; a < totvert; a++) { - triangle_strip[a * 2][0] = wtb->outer_v[a][0]; - triangle_strip[a * 2][1] = wtb->outer_v[a][1]; - triangle_strip[a * 2 + 1][0] = wtb->outer_v[a][0]; - triangle_strip[a * 2 + 1][1] = wtb->outer_v[a][1] - 1.0f; - } -} - static void widgetbase_outline(uiWidgetBase *wtb, unsigned int pos) { float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */ @@ -699,135 +959,178 @@ static void widgetbase_outline(uiWidgetBase *wtb, unsigned int pos) widget_draw_vertex_buffer(pos, 0, GL_TRIANGLE_STRIP, triangle_strip, NULL, wtb->totvert * 2 + 2); } -static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol) +static void widgetbase_set_uniform_colors_ubv( + uiWidgetBase *wtb, + const unsigned char *col1, const unsigned char *col2, + const unsigned char *outline, + const unsigned char *emboss, + const unsigned char *tria, + const bool alpha_check) { - int j, a; - - glEnable(GL_BLEND); - - /* backdrop non AA */ - if (wtb->draw_inner) { - BLI_assert(wtb->totvert != 0); - if (wcol->shaded == 0) { - if (wcol->alpha_check) { - float inner_v_half[WIDGET_SIZE_MAX][2]; - float x_mid = 0.0f; /* used for dumb clamping of values */ - - unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_CHECKER); + wtb->uniform_params.do_alpha_check = (float)alpha_check; + rgba_float_args_set_ch(wtb->uniform_params.color_inner1, col1[0], col1[1], col1[2], col1[3]); + rgba_float_args_set_ch(wtb->uniform_params.color_inner2, col2[0], col2[1], col2[2], col2[3]); + rgba_float_args_set_ch(wtb->uniform_params.color_outline, outline[0], outline[1], outline[2], outline[3]); + rgba_float_args_set_ch(wtb->uniform_params.color_emboss, emboss[0], emboss[1], emboss[2], emboss[3]); + rgba_float_args_set_ch(wtb->uniform_params.color_tria, tria[0], tria[1], tria[2], tria[3]); +} - /* checkers */ - immUniform4f("color1", UI_ALPHA_CHECKER_DARK / 255.0f, UI_ALPHA_CHECKER_DARK / 255.0f, UI_ALPHA_CHECKER_DARK / 255.0f, 1.0f); - immUniform4f("color2", UI_ALPHA_CHECKER_LIGHT / 255.0f, UI_ALPHA_CHECKER_LIGHT / 255.0f, UI_ALPHA_CHECKER_LIGHT / 255.0f, 1.0f); - immUniform1i("size", 8); +/* keep in sync with shader */ +#define MAX_WIDGET_BASE_BATCH 6 - widget_draw_vertex_buffer(pos, 0, GL_TRIANGLE_FAN, wtb->inner_v, NULL, wtb->totvert); +struct { + Gwn_Batch *batch; /* Batch type */ + uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]; + int count; + bool enabled; +} g_widget_base_batch = {0}; - immUnbindProgram(); +void UI_widgetbase_draw_cache_flush(void) +{ + float checker_params[3] = {UI_ALPHA_CHECKER_DARK / 255.0f, UI_ALPHA_CHECKER_LIGHT / 255.0f, 8.0f}; - /* alpha fill */ - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformColor4ubv((unsigned char *)wcol->inner); + if (g_widget_base_batch.count == 0) + return; - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + Gwn_Batch *batch = g_widget_base_batch.batch; + if (g_widget_base_batch.count == 1) { + /* draw single */ + GWN_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE); + GWN_batch_uniform_4fv_array(batch, "parameters", 11, (float *)g_widget_base_batch.params); + GWN_batch_uniform_3fv(batch, "checkerColorAndSize", checker_params); + GWN_batch_draw(batch); + } + else { + GWN_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE_INST); + GWN_batch_uniform_4fv_array(batch, "parameters", 11 * MAX_WIDGET_BASE_BATCH, (float *)g_widget_base_batch.params); + GWN_batch_uniform_3fv(batch, "checkerColorAndSize", checker_params); + gpuBindMatrices(batch->interface); + GWN_batch_draw_range_ex(batch, 0, g_widget_base_batch.count, true); + GWN_batch_program_use_end(batch); + } + g_widget_base_batch.count = 0; +} - for (a = 0; a < wtb->totvert; a++) { - x_mid += wtb->inner_v[a][0]; - } - x_mid /= wtb->totvert; +void UI_widgetbase_draw_cache_begin(void) +{ + BLI_assert(g_widget_base_batch.enabled == false); + g_widget_base_batch.enabled = true; +} - widget_draw_vertex_buffer(pos, 0, GL_TRIANGLE_FAN, wtb->inner_v, NULL, wtb->totvert); +void UI_widgetbase_draw_cache_end(void) +{ + BLI_assert(g_widget_base_batch.enabled == true); + g_widget_base_batch.enabled = false; - /* 1/2 solid color */ - immUniformColor3ubv((unsigned char *)wcol->inner); + glEnable(GL_BLEND); - for (a = 0; a < wtb->totvert; a++) { - inner_v_half[a][0] = MIN2(wtb->inner_v[a][0], x_mid); - inner_v_half[a][1] = wtb->inner_v[a][1]; - } + UI_widgetbase_draw_cache_flush(); - widget_draw_vertex_buffer(pos, 0, GL_TRIANGLE_FAN, inner_v_half, NULL, wtb->totvert); + glDisable(GL_BLEND); +} - immUnbindProgram(); - } - else { - /* simple fill */ - unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformColor4ubv((unsigned char *)wcol->inner); +static void draw_widgetbase_batch(Gwn_Batch *batch, uiWidgetBase *wtb) +{ + wtb->uniform_params.tria1_size = wtb->tria1.size; + wtb->uniform_params.tria2_size = wtb->tria2.size; + copy_v2_v2(wtb->uniform_params.tria1_center, wtb->tria1.center); + copy_v2_v2(wtb->uniform_params.tria2_center, wtb->tria2.center); + + if (g_widget_base_batch.enabled) { + if (g_widget_base_batch.batch == NULL) { + g_widget_base_batch.batch = ui_batch_roundbox_widget_get(ROUNDBOX_TRIA_ARROWS); + } - widget_draw_vertex_buffer(pos, 0, GL_TRIANGLE_FAN, wtb->inner_v, NULL, wtb->totvert); + /* draw multi */ + if (batch != g_ui_batch_cache.roundbox_widget[ROUNDBOX_TRIA_NONE] && + batch != g_widget_base_batch.batch) + { + /* issue previous calls before changing batch type. */ + UI_widgetbase_draw_cache_flush(); + g_widget_base_batch.batch = batch; + } - immUnbindProgram(); - } + /* No need to change batch if tria is not visible. Just scale it to 0. */ + if (batch == g_ui_batch_cache.roundbox_widget[ROUNDBOX_TRIA_NONE]) { + wtb->uniform_params.tria1_size = wtb->uniform_params.tria2_size = 0; } - else { - char col1[4], col2[4]; - unsigned char col_array[WIDGET_SIZE_MAX][4]; - unsigned char *col_pt = &col_array[0][0]; - Gwn_VertFormat *format = immVertexFormat(); - unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - unsigned int col = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT); + g_widget_base_batch.params[g_widget_base_batch.count] = wtb->uniform_params; + g_widget_base_batch.count++; - immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); + if (g_widget_base_batch.count == MAX_WIDGET_BASE_BATCH) { + UI_widgetbase_draw_cache_flush(); + } + } + else { + float checker_params[3] = {UI_ALPHA_CHECKER_DARK / 255.0f, UI_ALPHA_CHECKER_LIGHT / 255.0f, 8.0f}; + /* draw single */ + GWN_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE); + GWN_batch_uniform_4fv_array(batch, "parameters", 11, (float *)&wtb->uniform_params); + GWN_batch_uniform_3fv(batch, "checkerColorAndSize", checker_params); + GWN_batch_draw(batch); + } +} - shadecolors4(col1, col2, wcol->inner, wcol->shadetop, wcol->shadedown); +static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol) +{ + unsigned char inner_col1[4] = {0}; + unsigned char inner_col2[4] = {0}; + unsigned char emboss_col[4] = {0}; + unsigned char outline_col[4] = {0}; + unsigned char tria_col[4] = {0}; + /* For color widget. */ + bool alpha_check = (wcol->alpha_check && (wcol->shaded == 0)); - for (a = 0; a < wtb->totvert; a++, col_pt += 4) { - round_box_shade_col4_r(col_pt, col1, col2, wtb->inner_uv[a][wtb->draw_shadedir ? 1 : 0]); - } + glEnable(GL_BLEND); - widget_draw_vertex_buffer(pos, col, GL_TRIANGLE_FAN, wtb->inner_v, col_array, wtb->totvert); - immUnbindProgram(); + /* backdrop non AA */ + if (wtb->draw_inner) { + if (wcol->shaded == 0) { + /* simple fill */ + inner_col1[0] = inner_col2[0] = (unsigned char)wcol->inner[0]; + inner_col1[1] = inner_col2[1] = (unsigned char)wcol->inner[1]; + inner_col1[2] = inner_col2[2] = (unsigned char)wcol->inner[2]; + inner_col1[3] = inner_col2[3] = (unsigned char)wcol->inner[3]; + } + else { + /* gradient fill */ + shadecolors4((char *)inner_col1, (char *)inner_col2, wcol->inner, wcol->shadetop, wcol->shadedown); } } - /* for each AA step */ if (wtb->draw_outline) { - BLI_assert(wtb->totvert != 0); - float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */ - float triangle_strip_emboss[WIDGET_SIZE_MAX * 2][2]; /* only for emboss */ - - const unsigned char tcol[4] = {wcol->outline[0], - wcol->outline[1], - wcol->outline[2], - wcol->outline[3] / WIDGET_AA_JITTER}; - unsigned char emboss[4]; - - widget_verts_to_triangle_strip(wtb, wtb->totvert, triangle_strip); + outline_col[0] = wcol->outline[0]; + outline_col[1] = wcol->outline[1]; + outline_col[2] = wcol->outline[2]; + outline_col[3] = wcol->outline[3] / WIDGET_AA_JITTER; + /* emboss bottom shadow */ if (wtb->draw_emboss) { - widget_verts_to_triangle_strip_open(wtb, wtb->halfwayvert, triangle_strip_emboss); - UI_GetThemeColor4ubv(TH_WIDGET_EMBOSS, emboss); + UI_GetThemeColor4ubv(TH_WIDGET_EMBOSS, emboss_col); } + } - unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - for (j = 0; j < WIDGET_AA_JITTER; j++) { - gpuTranslate2fv(jit[j]); - - /* outline */ - immUniformColor4ubv(tcol); + if (wtb->tria1.type != ROUNDBOX_TRIA_NONE) + { + tria_col[0] = wcol->item[0]; + tria_col[1] = wcol->item[1]; + tria_col[2] = wcol->item[2]; + tria_col[3] = (unsigned char)((float)wcol->item[3] / WIDGET_AA_JITTER); + } - widget_draw_vertex_buffer(pos, 0, GL_TRIANGLE_STRIP, triangle_strip, NULL, wtb->totvert * 2 + 2); + /* Draw everything in one drawcall */ + if (inner_col1[3] || inner_col2[3] || outline_col[3] || emboss_col[3] || tria_col[3] || alpha_check) { + widgetbase_set_uniform_colors_ubv(wtb, inner_col1, inner_col2, outline_col, emboss_col, tria_col, alpha_check); - /* emboss bottom shadow */ - if (wtb->draw_emboss) { - if (emboss[3]) { - immUniformColor4ubv(emboss); - widget_draw_vertex_buffer(pos, 0, GL_TRIANGLE_STRIP, triangle_strip_emboss, NULL, wtb->halfwayvert * 2); - } - } - - gpuTranslate2f(-jit[j][0], -jit[j][1]); - } - immUnbindProgram(); + Gwn_Batch *roundbox_batch = ui_batch_roundbox_widget_get(wtb->tria1.type); + draw_widgetbase_batch(roundbox_batch, wtb); } - /* decoration */ - if (wtb->tria1.tot || wtb->tria2.tot) { + /* DEPRECATED: should be removed at some point. */ + if ((wtb->tria1.type == ROUNDBOX_TRIA_NONE) && + (wtb->tria1.tot || wtb->tria2.tot)) + { const unsigned char tcol[4] = {wcol->item[0], wcol->item[1], wcol->item[2], @@ -838,17 +1141,14 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol) immUniformColor4ubv(tcol); /* for each AA step */ - for (j = 0; j < WIDGET_AA_JITTER; j++) { - gpuTranslate2fv(jit[j]); - - if (wtb->tria1.tot) - shape_preset_draw_trias(&wtb->tria1, pos); - - if (wtb->tria2.tot) - shape_preset_draw_trias(&wtb->tria2, pos); - - gpuTranslate2f(-jit[j][0], -jit[j][1]); + immBegin(GWN_PRIM_TRIS, (wtb->tria1.tot + wtb->tria2.tot) * 3 * WIDGET_AA_JITTER); + if (wtb->tria1.tot){ + shape_preset_draw_trias_aa(&wtb->tria1, pos); + } + if (wtb->tria2.tot) { + shape_preset_draw_trias_aa(&wtb->tria2, pos); } + immEnd(); immUnbindProgram(); } @@ -1411,6 +1711,10 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b int selsta_draw, selwidth_draw; if (drawstr[0] != 0) { + /* We are drawing on top of widget bases. Flush cache. */ + glEnable(GL_BLEND); + UI_widgetbase_draw_cache_flush(); + glDisable(GL_BLEND); if (but->selsta >= but->ofs) { selsta_draw = BLF_width(fstyle->uifont_id, drawstr + but->ofs, but->selsta - but->ofs); @@ -1452,6 +1756,10 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b else { t = 0; } + /* We are drawing on top of widget bases. Flush cache. */ + glEnable(GL_BLEND); + UI_widgetbase_draw_cache_flush(); + glDisable(GL_BLEND); unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); @@ -1591,6 +1899,7 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB rcti temp = *rect; temp.xmin = rect->xmax - BLI_rcti_size_y(rect) - 1; widget_draw_icon(but, ICON_LAYER_USED, alpha, &temp, false); + rect->xmax = temp.xmin; } /* If there's an icon too (made with uiDefIconTextBut) then draw the icon @@ -2734,6 +3043,11 @@ static void ui_draw_but_HSV_v(uiBut *but, const rcti *rect) widgetbase_draw(&wtb, &wcol_tmp); + /* We are drawing on top of widget bases. Flush cache. */ + glEnable(GL_BLEND); + UI_widgetbase_draw_cache_flush(); + glDisable(GL_BLEND); + /* cursor */ x = rect->xmin + 0.5f * BLI_rcti_size_x(rect); y = rect->ymin + v * BLI_rcti_size_y(rect); @@ -2891,7 +3205,7 @@ void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *s else rad = 0.5f * BLI_rcti_size_x(rect); - wtb.draw_shadedir = (horizontal) ? true : false; + wtb.uniform_params.shade_dir = (horizontal) ? 1.0f : 0.0; /* draw back part, colors swapped and shading inverted */ if (horizontal) @@ -3204,7 +3518,6 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat } widgetbase_draw(&wtb, wcol); - if (but->a1 == UI_PALETTE_COLOR && ((Palette *)but->rnapoin.id.data)->active_color == (int)but->a2) { float width = rect->xmax - rect->xmin; float height = rect->ymax - rect->ymin; @@ -3213,6 +3526,11 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat bw += (bw < 0.5f) ? 0.5f : -0.5f; + /* We are drawing on top of widget bases. Flush cache. */ + glEnable(GL_BLEND); + UI_widgetbase_draw_cache_flush(); + glDisable(GL_BLEND); + unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); @@ -3285,6 +3603,8 @@ static void widget_menubut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), /* decoration */ shape_preset_trias_from_rect_menu(&wtb.tria1, rect); + /* copy size and center to 2nd tria */ + wtb.tria2 = wtb.tria1; widgetbase_draw(&wtb, wcol); @@ -3568,6 +3888,11 @@ static void widget_tab(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED( wtb.draw_outline = 0; widgetbase_draw(&wtb, wcol); + /* We are drawing on top of widget bases. Flush cache. */ + glEnable(GL_BLEND); + UI_widgetbase_draw_cache_flush(); + glDisable(GL_BLEND); + /* draw outline (3d look) */ ui_draw_but_TAB_outline(rect, rad, theme_col_tab_highlight, (unsigned char *)wcol->inner); diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index 2eae452debb..687b225b838 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -45,6 +45,7 @@ #include "BLI_utildefines.h" #include "BLI_math.h" +#include "BKE_addon.h" #include "BKE_appdir.h" #include "BKE_colorband.h" #include "BKE_DerivedMesh.h" @@ -2307,13 +2308,9 @@ void init_userdef_do_versions(void) if (btheme->tipo.handle_sel_auto_clamped[3] == 0) rgba_char_args_set(btheme->tipo.handle_sel_auto_clamped, 0xf0, 0xaf, 0x90, 255); } - + /* enable (Cycles) addon by default */ - if (!BLI_findstring(&U.addons, "cycles", offsetof(bAddon, module))) { - bAddon *baddon = MEM_callocN(sizeof(bAddon), "bAddon"); - BLI_strncpy(baddon->module, "cycles", sizeof(baddon->module)); - BLI_addtail(&U.addons, baddon); - } + BKE_addon_ensure(&U.addons, "cycles"); } if (!USER_VERSION_ATLEAST(260, 5)) { @@ -2974,6 +2971,15 @@ void init_userdef_do_versions(void) // we default to the first audio device U.audiodevice = 0; + /* Not versioning, just avoid errors. */ +#ifndef WITH_CYCLES + bAddon *addon = BLI_findstring(&U.addons, "cycles", offsetof(bAddon, module)); + if (addon) { + BLI_remlink(&U.addons, addon); + BKE_addon_free(addon); + } +#endif + /* funny name, but it is GE stuff, moves userdef stuff to engine */ // XXX space_set_commmandline_options(); /* this timer uses U */ diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index a94ef0d1d5b..375711194a3 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -1027,6 +1027,13 @@ bool UI_view2d_tab_set(View2D *v2d, int tab) void UI_view2d_zoom_cache_reset(void) { + /* TODO(sergey): This way we avoid threading conflict with VSE rendering + * text strip. But ideally we want to make glyph cache to be fully safe + * for threading. + */ + if (G.is_rendering) { + return; + } /* While scaling we can accumulate fonts at many sizes (~20 or so). * Not an issue with embedded font, but can use over 500Mb with i18n ones! See [#38244]. */ @@ -1204,10 +1211,10 @@ static void step_to_grid(float *step, int *power, int unit) * - Units + clamping args will be checked, to make sure they are valid values that can be used * so it is very possible that we won't return grid at all! * - * - xunits,yunits = V2D_UNIT_* grid steps in seconds or frames - * - xclamp,yclamp = V2D_CLAMP_* only show whole-number intervals - * - winx = width of region we're drawing to, note: not used but keeping for completeness. - * - winy = height of region we're drawing into + * - xunits,yunits = V2D_UNIT_* grid steps in seconds or frames + * - xclamp,yclamp = V2D_CLAMP_* only show whole-number intervals + * - winx = width of region we're drawing to, note: not used but keeping for completeness. + * - winy = height of region we're drawing into */ View2DGrid *UI_view2d_grid_calc( Scene *scene, View2D *v2d, @@ -1885,7 +1892,9 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v /* draw numbers in the appropriate range */ if (dfac > 0.0f) { float h = 0.1f * UI_UNIT_Y + (float)(hor.ymin); - + + BLF_batch_draw_begin(); + for (; fac < hor.xmax - 0.5f * U.widget_unit; fac += dfac, val += grid->dx) { /* make prints look nicer for scrollers */ @@ -1912,6 +1921,8 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v break; } } + + BLF_batch_draw_end(); } } } diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c index ca4ab30a08d..b584782e183 100644 --- a/source/blender/editors/io/io_alembic.c +++ b/source/blender/editors/io/io_alembic.c @@ -59,6 +59,8 @@ #include "RNA_define.h" #include "RNA_enum_types.h" +#include "ED_object.h" + #include "UI_interface.h" #include "UI_resources.h" @@ -543,6 +545,12 @@ static int wm_alembic_import_exec(bContext *C, wmOperator *op) } } + /* Switch out of edit mode to avoid being stuck in it (T54326). */ + Object *obedit = CTX_data_edit_object(C); + if (obedit) { + ED_object_mode_toggle(C, OB_MODE_EDIT); + } + bool ok = ABC_import(C, filename, scale, is_sequence, set_frame_range, sequence_len, offset, validate_meshes, as_background_job); diff --git a/source/blender/editors/io/io_cache.c b/source/blender/editors/io/io_cache.c index 975bbddd893..eb79d0bec13 100644 --- a/source/blender/editors/io/io_cache.c +++ b/source/blender/editors/io/io_cache.c @@ -33,7 +33,6 @@ #include "BKE_cachefile.h" #include "BKE_context.h" -#include "BKE_global.h" #include "BKE_library.h" #include "BKE_main.h" #include "BKE_report.h" diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c index 1b7fd319da0..4d0d59ae42c 100644 --- a/source/blender/editors/io/io_collada.c +++ b/source/blender/editors/io/io_collada.c @@ -28,7 +28,7 @@ * \ingroup collada */ #ifdef WITH_COLLADA -#include "DNA_scene_types.h" +#include "DNA_space_types.h" #include "BLT_translation.h" @@ -39,6 +39,7 @@ #include "BKE_global.h" #include "BKE_main.h" #include "BKE_report.h" +#include "BKE_object.h" #include "DEG_depsgraph.h" @@ -92,6 +93,10 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op) int include_shapekeys; int deform_bones_only; + int include_animations; + int sample_animations; + int sampling_rate; + int include_material_textures; int use_texture_copies; int active_uv_only; @@ -143,6 +148,11 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op) include_children = RNA_boolean_get(op->ptr, "include_children"); include_armatures = RNA_boolean_get(op->ptr, "include_armatures"); include_shapekeys = RNA_boolean_get(op->ptr, "include_shapekeys"); + + include_animations = RNA_boolean_get(op->ptr, "include_animations"); + sample_animations = RNA_boolean_get(op->ptr, "sample_animations"); + sampling_rate = (sample_animations) ? RNA_int_get(op->ptr, "sampling_rate") : 0; + deform_bones_only = RNA_boolean_get(op->ptr, "deform_bones_only"); include_material_textures = RNA_boolean_get(op->ptr, "include_material_textures"); @@ -162,32 +172,42 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op) /* get editmode results */ ED_object_editmode_load(CTX_data_edit_object(C)); + Scene *scene = CTX_data_scene(C); + CTX_data_eval_ctx(C, &eval_ctx); + + ExportSettings export_settings; + + export_settings.filepath = filepath; + + export_settings.apply_modifiers = apply_modifiers != 0; + export_settings.export_mesh_type = export_mesh_type; + export_settings.selected = selected != 0; + export_settings.include_children = include_children != 0; + export_settings.include_armatures = include_armatures != 0; + export_settings.include_shapekeys = include_shapekeys != 0; + export_settings.deform_bones_only = deform_bones_only != 0; + export_settings.include_animations = include_animations; + export_settings.sampling_rate = sampling_rate; + + export_settings.active_uv_only = active_uv_only != 0; + export_settings.use_texture_copies = use_texture_copies != 0; + + export_settings.triangulate = triangulate != 0; + export_settings.use_object_instantiation = use_object_instantiation != 0; + export_settings.use_blender_profile = use_blender_profile != 0; + export_settings.sort_by_name = sort_by_name != 0; + export_settings.export_transformation_type = export_transformation_type; + export_settings.open_sim = open_sim != 0; + export_settings.limit_precision = limit_precision != 0; + export_settings.keep_bind_info = keep_bind_info != 0; + + int includeFilter = OB_REL_NONE; + if (export_settings.include_armatures) includeFilter |= OB_REL_MOD_ARMATURE; + if (export_settings.include_children) includeFilter |= OB_REL_CHILDREN_RECURSIVE; export_count = collada_export(&eval_ctx, - CTX_data_scene(C), - CTX_data_view_layer(C), - filepath, - apply_modifiers, - export_mesh_type, - selected, - include_children, - include_armatures, - include_shapekeys, - deform_bones_only, - - active_uv_only, - include_material_textures, - use_texture_copies, - - triangulate, - use_object_instantiation, - use_blender_profile, - sort_by_name, - export_transformation_type, - - open_sim, - limit_precision, - keep_bind_info + scene, + &export_settings ); if (export_count == 0) { @@ -209,6 +229,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op) static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr) { uiLayout *box, *row, *col, *split; + bool include_animations = RNA_boolean_get(imfptr, "include_animations"); /* Export Options: */ box = uiLayoutBox(layout); @@ -238,6 +259,16 @@ static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr) uiItemR(row, imfptr, "include_shapekeys", 0, NULL, ICON_NONE); uiLayoutSetEnabled(row, RNA_boolean_get(imfptr, "selected")); + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "include_animations", 0, NULL, ICON_NONE); + row = uiLayoutRow(box, false); + if (include_animations) { + uiItemR(row, imfptr, "sample_animations", 0, NULL, ICON_NONE); + row = uiLayoutColumn(box, false); + uiItemR(row, imfptr, "sampling_rate", 0, NULL, ICON_NONE); + uiLayoutSetEnabled(row, RNA_boolean_get(imfptr, "sample_animations")); + } + /* Texture options */ box = uiLayoutBox(layout); row = uiLayoutRow(box, false); @@ -260,6 +291,7 @@ static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr) row = uiLayoutRow(box, false); uiItemR(row, imfptr, "deform_bones_only", 0, NULL, ICON_NONE); + row = uiLayoutRow(box, false); uiItemR(row, imfptr, "open_sim", 0, NULL, ICON_NONE); @@ -279,7 +311,6 @@ static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr) split = uiLayoutSplit(row, 0.6f, UI_LAYOUT_ALIGN_RIGHT); uiItemL(split, IFACE_("Transformation Type"), ICON_NONE); uiItemR(split, imfptr, "export_transformation_type_selection", 0, "", ICON_NONE); - row = uiLayoutRow(box, false); uiItemR(row, imfptr, "sort_by_name", 0, NULL, ICON_NONE); @@ -356,20 +387,29 @@ void WM_OT_collada_export(wmOperatorType *ot) RNA_def_enum(func, "export_mesh_type_selection", prop_bc_export_mesh_type, 0, "Resolution", "Modifier resolution for export"); - RNA_def_boolean(func, "selected", 0, "Selection Only", + RNA_def_boolean(func, "selected", false, "Selection Only", "Export only selected elements"); - RNA_def_boolean(func, "include_children", 0, "Include Children", + RNA_def_boolean(func, "include_children", false, "Include Children", "Export all children of selected objects (even if not selected)"); - RNA_def_boolean(func, "include_armatures", 0, "Include Armatures", + RNA_def_boolean(func, "include_armatures", false, "Include Armatures", "Export related armatures (even if not selected)"); - RNA_def_boolean(func, "include_shapekeys", 1, "Include Shape Keys", + RNA_def_boolean(func, "include_shapekeys", false, "Include Shape Keys", "Export all Shape Keys from Mesh Objects"); - RNA_def_boolean(func, "deform_bones_only", 0, "Deform Bones only", - "Only export deforming bones with armatures"); + RNA_def_boolean(func, "deform_bones_only", false, "Deform Bones only", + "Only export deforming bones with armatures"); + + RNA_def_boolean(func, "include_animations", true, + "Include Animations", "Export Animations if available.\nExporting Animations will enforce the decomposition of node transforms\ninto <translation> <rotation> and <scale> components"); + + RNA_def_boolean(func, "sample_animations", 0, + "Sample Animations", "Auto-generate keyframes with a frame distance set by 'Sampling Rate'.\nWhen disabled, export only the keyframes defined in the animation f-curves (may be less accurate)"); + + RNA_def_int(func, "sampling_rate", 1, 1, INT_MAX, + "Sampling Rate", "The distance between 2 keyframes. 1 means: Every frame is keyed", 1, INT_MAX); RNA_def_boolean(func, "active_uv_only", 0, "Only Selected UV Map", @@ -423,6 +463,7 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op) int min_chain_length; int keep_bind_info; + ImportSettings import_settings; if (!RNA_struct_property_is_set(op->ptr, "filepath")) { BKE_report(op->reports, RPT_ERROR, "No filename given"); @@ -440,15 +481,16 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op) min_chain_length = RNA_int_get(op->ptr, "min_chain_length"); RNA_string_get(op->ptr, "filepath", filename); - if (collada_import( - C, filename, - import_units, - find_chains, - auto_connect, - fix_orientation, - min_chain_length, - keep_bind_info) ) - { + + import_settings.filepath = filename; + import_settings.import_units = import_units != 0; + import_settings.auto_connect = auto_connect != 0; + import_settings.find_chains = find_chains != 0; + import_settings.fix_orientation = fix_orientation != 0; + import_settings.min_chain_length = min_chain_length; + import_settings.keep_bind_info = keep_bind_info != 0; + + if (collada_import(C, &import_settings)) { DEG_id_tag_update(&CTX_data_scene(C)->id, DEG_TAG_BASE_FLAGS_UPDATE); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/lattice/CMakeLists.txt b/source/blender/editors/lattice/CMakeLists.txt new file mode 100644 index 00000000000..eaf837cf978 --- /dev/null +++ b/source/blender/editors/lattice/CMakeLists.txt @@ -0,0 +1,46 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL LICENSE BLOCK ***** + +set(INC + ../include + ../../blenkernel + ../../blenlib + ../../depsgraph + ../../makesdna + ../../makesrna + ../../render/extern/include + ../../windowmanager + ../../../../intern/guardedalloc +) + +set(INC_SYS + +) + +set(SRC + editlattice_select.c + editlattice_tools.c + editlattice_undo.c + lattice_ops.c + + lattice_intern.h +) + +blender_add_lib(bf_editor_lattice "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/editors/object/object_lattice.c b/source/blender/editors/lattice/editlattice_select.c index b2f9bee27ff..d0d64b85195 100644 --- a/source/blender/editors/object/object_lattice.c +++ b/source/blender/editors/lattice/editlattice_select.c @@ -23,14 +23,11 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/editors/object/object_lattice.c - * \ingroup edobj +/** \file blender/editors/lattice/editlattice_select.c + * \ingroup edlattice */ - #include <stdlib.h> -#include <string.h> -#include <math.h> #include "MEM_guardedalloc.h" @@ -41,7 +38,6 @@ #include "BLI_bitmap.h" #include "DNA_curve_types.h" -#include "DNA_key_types.h" #include "DNA_lattice_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" @@ -52,127 +48,21 @@ #include "RNA_enum_types.h" #include "BKE_context.h" -#include "BKE_key.h" #include "BKE_lattice.h" -#include "BKE_deform.h" #include "BKE_report.h" -#include "DEG_depsgraph.h" - -#include "ED_lattice.h" -#include "ED_object.h" #include "ED_screen.h" +#include "ED_lattice.h" #include "ED_view3d.h" -#include "ED_util.h" #include "WM_api.h" #include "WM_types.h" -#include "object_intern.h" - -/********************** Load/Make/Free ********************/ - -void ED_lattice_editlatt_free(Object *ob) -{ - Lattice *lt = ob->data; - - if (lt->editlatt) { - Lattice *editlt = lt->editlatt->latt; - - if (editlt->def) - MEM_freeN(editlt->def); - if (editlt->dvert) - BKE_defvert_array_free(editlt->dvert, editlt->pntsu * editlt->pntsv * editlt->pntsw); - - MEM_freeN(editlt); - MEM_freeN(lt->editlatt); - - lt->editlatt = NULL; - } -} - -void ED_lattice_editlatt_make(Object *obedit) -{ - Lattice *lt = obedit->data; - KeyBlock *actkey; - - ED_lattice_editlatt_free(obedit); - - actkey = BKE_keyblock_from_object(obedit); - if (actkey) - BKE_keyblock_convert_to_lattice(actkey, lt); - - lt->editlatt = MEM_callocN(sizeof(EditLatt), "editlatt"); - lt->editlatt->latt = MEM_dupallocN(lt); - lt->editlatt->latt->def = MEM_dupallocN(lt->def); - - if (lt->dvert) { - int tot = lt->pntsu * lt->pntsv * lt->pntsw; - lt->editlatt->latt->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert"); - BKE_defvert_array_copy(lt->editlatt->latt->dvert, lt->dvert, tot); - } - - if (lt->key) lt->editlatt->shapenr = obedit->shapenr; -} - -void ED_lattice_editlatt_load(Object *obedit) -{ - Lattice *lt, *editlt; - KeyBlock *actkey; - BPoint *bp; - float *fp; - int tot; - - lt = obedit->data; - editlt = lt->editlatt->latt; - - if (lt->editlatt->shapenr) { - actkey = BLI_findlink(<->key->block, lt->editlatt->shapenr - 1); - - /* active key: vertices */ - tot = editlt->pntsu * editlt->pntsv * editlt->pntsw; - - if (actkey->data) MEM_freeN(actkey->data); - - fp = actkey->data = MEM_callocN(lt->key->elemsize * tot, "actkey->data"); - actkey->totelem = tot; - - bp = editlt->def; - while (tot--) { - copy_v3_v3(fp, bp->vec); - fp += 3; - bp++; - } - } - else { - MEM_freeN(lt->def); - - lt->def = MEM_dupallocN(editlt->def); - - lt->flag = editlt->flag; - - lt->pntsu = editlt->pntsu; - lt->pntsv = editlt->pntsv; - lt->pntsw = editlt->pntsw; - - lt->typeu = editlt->typeu; - lt->typev = editlt->typev; - lt->typew = editlt->typew; - lt->actbp = editlt->actbp; - } - - if (lt->dvert) { - BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); - lt->dvert = NULL; - } +#include "lattice_intern.h" - if (editlt->dvert) { - tot = lt->pntsu * lt->pntsv * lt->pntsw; - - lt->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert"); - BKE_defvert_array_copy(lt->dvert, editlt->dvert, tot); - } -} +/* -------------------------------------------------------------------- */ +/** \name Utility Functions + * \{ */ static void bpoint_select_set(BPoint *bp, bool select) { @@ -186,7 +76,11 @@ static void bpoint_select_set(BPoint *bp, bool select) } } -/************************** Select Random Operator **********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Random Operator + * \{ */ static int lattice_select_random_exec(bContext *C, wmOperator *op) { @@ -242,9 +136,11 @@ void LATTICE_OT_select_random(wmOperatorType *ot) WM_operator_properties_select_random(ot); } +/** \} */ /* -------------------------------------------------------------------- */ -/* Select Mirror Operator */ +/** \name Select Mirror Operator + * \{ */ static void ed_lattice_select_mirrored(Lattice *lt, const int axis, const bool extend) { @@ -323,8 +219,11 @@ void LATTICE_OT_select_mirror(wmOperatorType *ot) RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection"); } +/** \} */ -/************************** Select More/Less Operator *************************/ +/* -------------------------------------------------------------------- */ +/** \name Select More/Less Operator + * \{ */ static bool lattice_test_bitmap_uvw(Lattice *lt, BLI_bitmap *selpoints, int u, int v, int w, const bool selected) { @@ -423,16 +322,20 @@ void LATTICE_OT_select_less(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/************************** Select All Operator *************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select All Operator + * \{ */ void ED_lattice_flags_set(Object *obedit, int flag) { Lattice *lt = obedit->data; BPoint *bp; int a; - + bp = lt->editlatt->latt->def; - + a = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw; lt->editlatt->latt->actbp = LT_ACTBP_NONE; @@ -501,18 +404,22 @@ void LATTICE_OT_select_all(wmOperatorType *ot) ot->name = "(De)select All"; ot->description = "Change selection of all UVW control points"; ot->idname = "LATTICE_OT_select_all"; - + /* api callbacks */ ot->exec = lattice_select_all_exec; ot->poll = ED_operator_editlattice; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; WM_operator_properties_select_all(ot); } -/************************** Select Ungrouped Verts Operator *************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Ungrouped Verts Operator + * \{ */ static int lattice_select_ungrouped_exec(bContext *C, wmOperator *op) { @@ -564,291 +471,22 @@ void LATTICE_OT_select_ungrouped(wmOperatorType *ot) RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection"); } -/************************** Make Regular Operator *************************/ - -static int make_regular_poll(bContext *C) -{ - Object *ob; - - if (ED_operator_editlattice(C)) return 1; - - ob = CTX_data_active_object(C); - return (ob && ob->type == OB_LATTICE); -} - -static int make_regular_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *ob = CTX_data_edit_object(C); - Lattice *lt; - - if (ob) { - lt = ob->data; - BKE_lattice_resize(lt->editlatt->latt, lt->pntsu, lt->pntsv, lt->pntsw, NULL); - } - else { - ob = CTX_data_active_object(C); - lt = ob->data; - BKE_lattice_resize(lt, lt->pntsu, lt->pntsv, lt->pntsw, NULL); - } - - DEG_id_tag_update(&ob->id, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); - - return OPERATOR_FINISHED; -} - -void LATTICE_OT_make_regular(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Make Regular"; - ot->description = "Set UVW control points a uniform distance apart"; - ot->idname = "LATTICE_OT_make_regular"; - - /* api callbacks */ - ot->exec = make_regular_exec; - ot->poll = make_regular_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -/************************** Flip Verts Operator *************************/ - -/* flipping options */ -typedef enum eLattice_FlipAxes { - LATTICE_FLIP_U = 0, - LATTICE_FLIP_V = 1, - LATTICE_FLIP_W = 2 -} eLattice_FlipAxes; - -/* Flip midpoint value so that relative distances between midpoint and neighbor-pair is maintained - * ! Assumes that uvw <=> xyz (i.e. axis-aligned index-axes with coordinate-axes) - * - Helper for lattice_flip_exec() - */ -static void lattice_flip_point_value(Lattice *lt, int u, int v, int w, float mid, eLattice_FlipAxes axis) -{ - BPoint *bp; - float diff; - - /* just the point in the middle (unpaired) */ - bp = <->def[BKE_lattice_index_from_uvw(lt, u, v, w)]; - - /* flip over axis */ - diff = mid - bp->vec[axis]; - bp->vec[axis] = mid + diff; -} +/** \} */ -/* Swap pairs of lattice points along a specified axis - * - Helper for lattice_flip_exec() - */ -static void lattice_swap_point_pairs(Lattice *lt, int u, int v, int w, float mid, eLattice_FlipAxes axis) -{ - BPoint *bpA, *bpB; - - int numU = lt->pntsu; - int numV = lt->pntsv; - int numW = lt->pntsw; - - int u0 = u, u1 = u; - int v0 = v, v1 = v; - int w0 = w, w1 = w; - - /* get pair index by just overriding the relevant pair-value - * - "-1" else buffer overflow - */ - switch (axis) { - case LATTICE_FLIP_U: - u1 = numU - u - 1; - break; - case LATTICE_FLIP_V: - v1 = numV - v - 1; - break; - case LATTICE_FLIP_W: - w1 = numW - w - 1; - break; - } - - /* get points to operate on */ - bpA = <->def[BKE_lattice_index_from_uvw(lt, u0, v0, w0)]; - bpB = <->def[BKE_lattice_index_from_uvw(lt, u1, v1, w1)]; - - /* Swap all coordinates, so that flipped coordinates belong to - * the indices on the correct side of the lattice. - * - * Coords: (-2 4) |0| (3 4) --> (3 4) |0| (-2 4) - * Indices: (0,L) (1,R) --> (0,L) (1,R) - */ - swap_v3_v3(bpA->vec, bpB->vec); - - /* However, we need to mirror the coordinate values on the axis we're dealing with, - * otherwise we'd have effectively only rotated the points around. If we don't do this, - * we'd just be reimplementing the naive mirroring algorithm, which causes unwanted deforms - * such as flipped normals, etc. - * - * Coords: (3 4) |0| (-2 4) --\ - * \-> (-3 4) |0| (2 4) - * Indices: (0,L) (1,R) --> (0,L) (1,R) - */ - lattice_flip_point_value(lt, u0, v0, w0, mid, axis); - lattice_flip_point_value(lt, u1, v1, w1, mid, axis); -} - -static int lattice_flip_exec(bContext *C, wmOperator *op) -{ - Object *obedit = CTX_data_edit_object(C); - Lattice *lt; - - eLattice_FlipAxes axis = RNA_enum_get(op->ptr, "axis"); - int numU, numV, numW; - int totP; - - float mid = 0.0f; - short isOdd = 0; - - /* get lattice - we need the "edit lattice" from the lattice... confusing... */ - lt = (Lattice *)obedit->data; - lt = lt->editlatt->latt; - - numU = lt->pntsu; - numV = lt->pntsv; - numW = lt->pntsw; - totP = numU * numV * numW; - - /* First Pass: determine midpoint - used for flipping center verts if there are odd number of points on axis */ - switch (axis) { - case LATTICE_FLIP_U: - isOdd = numU & 1; - break; - case LATTICE_FLIP_V: - isOdd = numV & 1; - break; - case LATTICE_FLIP_W: - isOdd = numW & 1; - break; - - default: - printf("lattice_flip(): Unknown flipping axis (%u)\n", axis); - return OPERATOR_CANCELLED; - } - - if (isOdd) { - BPoint *bp; - float avgInv = 1.0f / (float)totP; - int i; - - /* midpoint calculation - assuming that u/v/w are axis-aligned */ - for (i = 0, bp = lt->def; i < totP; i++, bp++) { - mid += bp->vec[axis] * avgInv; - } - } - - /* Second Pass: swap pairs of vertices per axis, assuming they are all sorted */ - switch (axis) { - case LATTICE_FLIP_U: - { - int u, v, w; - - /* v/w strips - front to back, top to bottom */ - for (w = 0; w < numW; w++) { - for (v = 0; v < numV; v++) { - /* swap coordinates of pairs of vertices on u */ - for (u = 0; u < (numU / 2); u++) { - lattice_swap_point_pairs(lt, u, v, w, mid, axis); - } - - /* flip u-coordinate of midpoint (i.e. unpaired point on u) */ - if (isOdd) { - u = (numU / 2); - lattice_flip_point_value(lt, u, v, w, mid, axis); - } - } - } - break; - } - case LATTICE_FLIP_V: - { - int u, v, w; - - /* u/w strips - front to back, left to right */ - for (w = 0; w < numW; w++) { - for (u = 0; u < numU; u++) { - /* swap coordinates of pairs of vertices on v */ - for (v = 0; v < (numV / 2); v++) { - lattice_swap_point_pairs(lt, u, v, w, mid, axis); - } - - /* flip v-coordinate of midpoint (i.e. unpaired point on v) */ - if (isOdd) { - v = (numV / 2); - lattice_flip_point_value(lt, u, v, w, mid, axis); - } - } - } - break; - } - case LATTICE_FLIP_W: - { - int u, v, w; - - for (v = 0; v < numV; v++) { - for (u = 0; u < numU; u++) { - /* swap coordinates of pairs of vertices on w */ - for (w = 0; w < (numW / 2); w++) { - lattice_swap_point_pairs(lt, u, v, w, mid, axis); - } - - /* flip w-coordinate of midpoint (i.e. unpaired point on w) */ - if (isOdd) { - w = (numW / 2); - lattice_flip_point_value(lt, u, v, w, mid, axis); - } - } - } - break; - } - default: /* shouldn't happen, but just in case */ - break; - } - - /* updates */ - DEG_id_tag_update(&obedit->id, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - - return OPERATOR_FINISHED; -} -void LATTICE_OT_flip(wmOperatorType *ot) -{ - static const EnumPropertyItem flip_items[] = { - {LATTICE_FLIP_U, "U", 0, "U (X) Axis", ""}, - {LATTICE_FLIP_V, "V", 0, "V (Y) Axis", ""}, - {LATTICE_FLIP_W, "W", 0, "W (Z) Axis", ""}, - {0, NULL, 0, NULL, NULL}}; - - /* identifiers */ - ot->name = "Flip (Distortion Free)"; - ot->description = "Mirror all control points without inverting the lattice deform"; - ot->idname = "LATTICE_OT_flip"; - - /* api callbacks */ - ot->poll = ED_operator_editlattice; - ot->invoke = WM_menu_invoke; - ot->exec = lattice_flip_exec; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - ot->prop = RNA_def_enum(ot->srna, "axis", flip_items, LATTICE_FLIP_U, "Flip Axis", "Coordinates along this axis get flipped"); -} +/* -------------------------------------------------------------------- */ +/** \name Select Picking API + * + * Here actual select happens, + * Gets called via generic mouse select operator. + * \{ */ -/****************************** Mouse Selection *************************/ static void findnearestLattvert__doClosest(void *userData, BPoint *bp, const float screen_co[2]) { struct { BPoint *bp; float dist; int select; float mval_fl[2]; } *data = userData; float dist_test = len_manhattan_v2v2(data->mval_fl, screen_co); - + if ((bp->f1 & SELECT) && data->select) dist_test += 5.0f; @@ -883,7 +521,7 @@ bool ED_lattice_select_pick(bContext *C, const int mval[2], bool extend, bool de BPoint *bp = NULL; Lattice *lt; - view3d_set_viewcontext(C, &vc); + ED_view3d_viewcontext_init(C, &vc); lt = ((Lattice *)vc.obedit->data)->editlatt->latt; bp = findnearestLattvert(&vc, mval, true); @@ -917,70 +555,4 @@ bool ED_lattice_select_pick(bContext *C, const int mval[2], bool extend, bool de return false; } -/******************************** Undo *************************/ - -typedef struct UndoLattice { - BPoint *def; - int pntsu, pntsv, pntsw, actbp; -} UndoLattice; - -static void undoLatt_to_editLatt(void *data, void *edata, void *UNUSED(obdata)) -{ - UndoLattice *ult = (UndoLattice *)data; - EditLatt *editlatt = (EditLatt *)edata; - int a = editlatt->latt->pntsu * editlatt->latt->pntsv * editlatt->latt->pntsw; - - memcpy(editlatt->latt->def, ult->def, a * sizeof(BPoint)); - editlatt->latt->actbp = ult->actbp; -} - -static void *editLatt_to_undoLatt(void *edata, void *UNUSED(obdata)) -{ - UndoLattice *ult = MEM_callocN(sizeof(UndoLattice), "UndoLattice"); - EditLatt *editlatt = (EditLatt *)edata; - - ult->def = MEM_dupallocN(editlatt->latt->def); - ult->pntsu = editlatt->latt->pntsu; - ult->pntsv = editlatt->latt->pntsv; - ult->pntsw = editlatt->latt->pntsw; - ult->actbp = editlatt->latt->actbp; - - return ult; -} - -static void free_undoLatt(void *data) -{ - UndoLattice *ult = (UndoLattice *)data; - - if (ult->def) MEM_freeN(ult->def); - MEM_freeN(ult); -} - -static int validate_undoLatt(void *data, void *edata) -{ - UndoLattice *ult = (UndoLattice *)data; - EditLatt *editlatt = (EditLatt *)edata; - - return (ult->pntsu == editlatt->latt->pntsu && - ult->pntsv == editlatt->latt->pntsv && - ult->pntsw == editlatt->latt->pntsw); -} - -static void *get_editlatt(bContext *C) -{ - Object *obedit = CTX_data_edit_object(C); - - if (obedit && obedit->type == OB_LATTICE) { - Lattice *lt = obedit->data; - return lt->editlatt; - } - - return NULL; -} - -/* and this is all the undo system needs to know */ -void undo_push_lattice(bContext *C, const char *name) -{ - undo_editmode_push(C, name, get_editlatt, free_undoLatt, undoLatt_to_editLatt, editLatt_to_undoLatt, validate_undoLatt); -} - +/** \} */ diff --git a/source/blender/editors/lattice/editlattice_tools.c b/source/blender/editors/lattice/editlattice_tools.c new file mode 100644 index 00000000000..bf60c1e7da6 --- /dev/null +++ b/source/blender/editors/lattice/editlattice_tools.c @@ -0,0 +1,341 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/lattice/editlattice_tools.c + * \ingroup edlattice + */ + +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "DNA_curve_types.h" +#include "DNA_lattice_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "BKE_context.h" +#include "BKE_lattice.h" + +#include "DEG_depsgraph.h" + +#include "ED_screen.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "lattice_intern.h" + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Make Regular Operator + * \{ */ + +static int make_regular_poll(bContext *C) +{ + Object *ob; + + if (ED_operator_editlattice(C)) return 1; + + ob = CTX_data_active_object(C); + return (ob && ob->type == OB_LATTICE); +} + +static int make_regular_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *ob = CTX_data_edit_object(C); + Lattice *lt; + + if (ob) { + lt = ob->data; + BKE_lattice_resize(lt->editlatt->latt, lt->pntsu, lt->pntsv, lt->pntsw, NULL); + } + else { + ob = CTX_data_active_object(C); + lt = ob->data; + BKE_lattice_resize(lt, lt->pntsu, lt->pntsv, lt->pntsw, NULL); + } + + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); + + return OPERATOR_FINISHED; +} + +void LATTICE_OT_make_regular(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Make Regular"; + ot->description = "Set UVW control points a uniform distance apart"; + ot->idname = "LATTICE_OT_make_regular"; + + /* api callbacks */ + ot->exec = make_regular_exec; + ot->poll = make_regular_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Flip Verts Operator + * \{ */ + +/* flipping options */ +typedef enum eLattice_FlipAxes { + LATTICE_FLIP_U = 0, + LATTICE_FLIP_V = 1, + LATTICE_FLIP_W = 2 +} eLattice_FlipAxes; + +/** + * Flip midpoint value so that relative distances between midpoint and neighbor-pair is maintained + * ! Assumes that uvw <=> xyz (i.e. axis-aligned index-axes with coordinate-axes) + * - Helper for lattice_flip_exec() + */ +static void lattice_flip_point_value(Lattice *lt, int u, int v, int w, float mid, eLattice_FlipAxes axis) +{ + BPoint *bp; + float diff; + + /* just the point in the middle (unpaired) */ + bp = <->def[BKE_lattice_index_from_uvw(lt, u, v, w)]; + + /* flip over axis */ + diff = mid - bp->vec[axis]; + bp->vec[axis] = mid + diff; +} + +/** + * Swap pairs of lattice points along a specified axis + * - Helper for lattice_flip_exec() + */ +static void lattice_swap_point_pairs(Lattice *lt, int u, int v, int w, float mid, eLattice_FlipAxes axis) +{ + BPoint *bpA, *bpB; + + int numU = lt->pntsu; + int numV = lt->pntsv; + int numW = lt->pntsw; + + int u0 = u, u1 = u; + int v0 = v, v1 = v; + int w0 = w, w1 = w; + + /* get pair index by just overriding the relevant pair-value + * - "-1" else buffer overflow + */ + switch (axis) { + case LATTICE_FLIP_U: + u1 = numU - u - 1; + break; + case LATTICE_FLIP_V: + v1 = numV - v - 1; + break; + case LATTICE_FLIP_W: + w1 = numW - w - 1; + break; + } + + /* get points to operate on */ + bpA = <->def[BKE_lattice_index_from_uvw(lt, u0, v0, w0)]; + bpB = <->def[BKE_lattice_index_from_uvw(lt, u1, v1, w1)]; + + /* Swap all coordinates, so that flipped coordinates belong to + * the indices on the correct side of the lattice. + * + * Coords: (-2 4) |0| (3 4) --> (3 4) |0| (-2 4) + * Indices: (0,L) (1,R) --> (0,L) (1,R) + */ + swap_v3_v3(bpA->vec, bpB->vec); + + /* However, we need to mirror the coordinate values on the axis we're dealing with, + * otherwise we'd have effectively only rotated the points around. If we don't do this, + * we'd just be reimplementing the naive mirroring algorithm, which causes unwanted deforms + * such as flipped normals, etc. + * + * Coords: (3 4) |0| (-2 4) --\ + * \-> (-3 4) |0| (2 4) + * Indices: (0,L) (1,R) --> (0,L) (1,R) + */ + lattice_flip_point_value(lt, u0, v0, w0, mid, axis); + lattice_flip_point_value(lt, u1, v1, w1, mid, axis); +} + +static int lattice_flip_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + Lattice *lt; + + eLattice_FlipAxes axis = RNA_enum_get(op->ptr, "axis"); + int numU, numV, numW; + int totP; + + float mid = 0.0f; + short isOdd = 0; + + /* get lattice - we need the "edit lattice" from the lattice... confusing... */ + lt = (Lattice *)obedit->data; + lt = lt->editlatt->latt; + + numU = lt->pntsu; + numV = lt->pntsv; + numW = lt->pntsw; + totP = numU * numV * numW; + + /* First Pass: determine midpoint - used for flipping center verts if there are odd number of points on axis */ + switch (axis) { + case LATTICE_FLIP_U: + isOdd = numU & 1; + break; + case LATTICE_FLIP_V: + isOdd = numV & 1; + break; + case LATTICE_FLIP_W: + isOdd = numW & 1; + break; + + default: + printf("lattice_flip(): Unknown flipping axis (%u)\n", axis); + return OPERATOR_CANCELLED; + } + + if (isOdd) { + BPoint *bp; + float avgInv = 1.0f / (float)totP; + int i; + + /* midpoint calculation - assuming that u/v/w are axis-aligned */ + for (i = 0, bp = lt->def; i < totP; i++, bp++) { + mid += bp->vec[axis] * avgInv; + } + } + + /* Second Pass: swap pairs of vertices per axis, assuming they are all sorted */ + switch (axis) { + case LATTICE_FLIP_U: + { + int u, v, w; + + /* v/w strips - front to back, top to bottom */ + for (w = 0; w < numW; w++) { + for (v = 0; v < numV; v++) { + /* swap coordinates of pairs of vertices on u */ + for (u = 0; u < (numU / 2); u++) { + lattice_swap_point_pairs(lt, u, v, w, mid, axis); + } + + /* flip u-coordinate of midpoint (i.e. unpaired point on u) */ + if (isOdd) { + u = (numU / 2); + lattice_flip_point_value(lt, u, v, w, mid, axis); + } + } + } + break; + } + case LATTICE_FLIP_V: + { + int u, v, w; + + /* u/w strips - front to back, left to right */ + for (w = 0; w < numW; w++) { + for (u = 0; u < numU; u++) { + /* swap coordinates of pairs of vertices on v */ + for (v = 0; v < (numV / 2); v++) { + lattice_swap_point_pairs(lt, u, v, w, mid, axis); + } + + /* flip v-coordinate of midpoint (i.e. unpaired point on v) */ + if (isOdd) { + v = (numV / 2); + lattice_flip_point_value(lt, u, v, w, mid, axis); + } + } + } + break; + } + case LATTICE_FLIP_W: + { + int u, v, w; + + for (v = 0; v < numV; v++) { + for (u = 0; u < numU; u++) { + /* swap coordinates of pairs of vertices on w */ + for (w = 0; w < (numW / 2); w++) { + lattice_swap_point_pairs(lt, u, v, w, mid, axis); + } + + /* flip w-coordinate of midpoint (i.e. unpaired point on w) */ + if (isOdd) { + w = (numW / 2); + lattice_flip_point_value(lt, u, v, w, mid, axis); + } + } + } + break; + } + default: /* shouldn't happen, but just in case */ + break; + } + + /* updates */ + DEG_id_tag_update(&obedit->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + + return OPERATOR_FINISHED; +} + +void LATTICE_OT_flip(wmOperatorType *ot) +{ + static const EnumPropertyItem flip_items[] = { + {LATTICE_FLIP_U, "U", 0, "U (X) Axis", ""}, + {LATTICE_FLIP_V, "V", 0, "V (Y) Axis", ""}, + {LATTICE_FLIP_W, "W", 0, "W (Z) Axis", ""}, + {0, NULL, 0, NULL, NULL}}; + + /* identifiers */ + ot->name = "Flip (Distortion Free)"; + ot->description = "Mirror all control points without inverting the lattice deform"; + ot->idname = "LATTICE_OT_flip"; + + /* api callbacks */ + ot->poll = ED_operator_editlattice; + ot->invoke = WM_menu_invoke; + ot->exec = lattice_flip_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + ot->prop = RNA_def_enum(ot->srna, "axis", flip_items, LATTICE_FLIP_U, "Flip Axis", "Coordinates along this axis get flipped"); +} + +/** \} */ diff --git a/source/blender/editors/lattice/editlattice_undo.c b/source/blender/editors/lattice/editlattice_undo.c new file mode 100644 index 00000000000..58fa08e5aa9 --- /dev/null +++ b/source/blender/editors/lattice/editlattice_undo.c @@ -0,0 +1,196 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/lattice/editlattice_undo.c + * \ingroup edlattice + */ + +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" +#include "BLI_array_utils.h" + +#include "DNA_curve_types.h" +#include "DNA_lattice_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BKE_context.h" +#include "BKE_undo_system.h" + +#include "DEG_depsgraph.h" + +#include "ED_object.h" +#include "ED_lattice.h" +#include "ED_util.h" + +#include "WM_types.h" +#include "WM_api.h" + +#include "lattice_intern.h" + +/* -------------------------------------------------------------------- */ +/** \name Undo Conversion + * \{ */ + +typedef struct UndoLattice { + BPoint *def; + int pntsu, pntsv, pntsw, actbp; + size_t undo_size; +} UndoLattice; + +static void undolatt_to_editlatt(UndoLattice *ult, EditLatt *editlatt) +{ + int len = editlatt->latt->pntsu * editlatt->latt->pntsv * editlatt->latt->pntsw; + + memcpy(editlatt->latt->def, ult->def, sizeof(BPoint) * len); + editlatt->latt->actbp = ult->actbp; +} + +static void *undolatt_from_editlatt(UndoLattice *ult, EditLatt *editlatt) +{ + BLI_assert(BLI_array_is_zeroed(ult, 1)); + + ult->def = MEM_dupallocN(editlatt->latt->def); + ult->pntsu = editlatt->latt->pntsu; + ult->pntsv = editlatt->latt->pntsv; + ult->pntsw = editlatt->latt->pntsw; + ult->actbp = editlatt->latt->actbp; + + ult->undo_size += sizeof(*ult->def) * ult->pntsu * ult->pntsv * ult->pntsw; + + return ult; +} + +static void undolatt_free_data(UndoLattice *ult) +{ + if (ult->def) { + MEM_freeN(ult->def); + } +} + +#if 0 +static int validate_undoLatt(void *data, void *edata) +{ + UndoLattice *ult = (UndoLattice *)data; + EditLatt *editlatt = (EditLatt *)edata; + + return (ult->pntsu == editlatt->latt->pntsu && + ult->pntsv == editlatt->latt->pntsv && + ult->pntsw == editlatt->latt->pntsw); +} +#endif + +static Object *editlatt_object_from_context(bContext *C) +{ + Object *obedit = CTX_data_edit_object(C); + if (obedit && obedit->type == OB_LATTICE) { + Lattice *lt = obedit->data; + if (lt->editlatt != NULL) { + return obedit; + } + } + + return NULL; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Implements ED Undo System + * \{ */ + +typedef struct LatticeUndoStep { + UndoStep step; + /* note: will split out into list for multi-object-editmode. */ + UndoRefID_Object obedit_ref; + UndoLattice data; +} LatticeUndoStep; + +static bool lattice_undosys_poll(bContext *C) +{ + return editlatt_object_from_context(C) != NULL; +} + +static bool lattice_undosys_step_encode(struct bContext *C, UndoStep *us_p) +{ + LatticeUndoStep *us = (LatticeUndoStep *)us_p; + us->obedit_ref.ptr = editlatt_object_from_context(C); + Lattice *lt = us->obedit_ref.ptr->data; + undolatt_from_editlatt(&us->data, lt->editlatt); + us->step.data_size = us->data.undo_size; + return true; +} + +static void lattice_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir)) +{ + /* TODO(campbell): undo_system: use low-level API to set mode. */ + ED_object_mode_set(C, OB_MODE_EDIT); + BLI_assert(lattice_undosys_poll(C)); + + LatticeUndoStep *us = (LatticeUndoStep *)us_p; + Object *obedit = us->obedit_ref.ptr; + Lattice *lt = obedit->data; + EditLatt *editlatt = lt->editlatt; + undolatt_to_editlatt(&us->data, editlatt); + DEG_id_tag_update(&obedit->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); +} + +static void lattice_undosys_step_free(UndoStep *us_p) +{ + LatticeUndoStep *us = (LatticeUndoStep *)us_p; + undolatt_free_data(&us->data); +} + +static void lattice_undosys_foreach_ID_ref( + UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data) +{ + LatticeUndoStep *us = (LatticeUndoStep *)us_p; + foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref)); +} + +/* Export for ED_undo_sys. */ +void ED_lattice_undosys_type(UndoType *ut) +{ + ut->name = "Edit Lattice"; + ut->poll = lattice_undosys_poll; + ut->step_encode = lattice_undosys_step_encode; + ut->step_decode = lattice_undosys_step_decode; + ut->step_free = lattice_undosys_step_free; + + ut->step_foreach_ID_ref = lattice_undosys_foreach_ID_ref; + + ut->mode = BKE_UNDOTYPE_MODE_STORE; + ut->use_context = true; + + ut->step_size = sizeof(LatticeUndoStep); +} + +/** \} */ diff --git a/source/blender/editors/lattice/lattice_intern.h b/source/blender/editors/lattice/lattice_intern.h new file mode 100644 index 00000000000..7902b992270 --- /dev/null +++ b/source/blender/editors/lattice/lattice_intern.h @@ -0,0 +1,44 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2008 Blender Foundation. + * All rights reserved. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/lattice/lattice_intern.h + * \ingroup edlattice + */ + + +#ifndef __LATTICE_INTERN_H__ +#define __LATTICE_INTERN_H__ + +/* editlattice_select.c */ +void LATTICE_OT_select_all(struct wmOperatorType *ot); +void LATTICE_OT_select_more(struct wmOperatorType *ot); +void LATTICE_OT_select_less(struct wmOperatorType *ot); +void LATTICE_OT_select_ungrouped(struct wmOperatorType *ot); +void LATTICE_OT_select_random(struct wmOperatorType *ot); +void LATTICE_OT_select_mirror(struct wmOperatorType *ot); + +/* editlattice_tools.c */ +void LATTICE_OT_make_regular(struct wmOperatorType *ot); +void LATTICE_OT_flip(struct wmOperatorType *ot); + +#endif /* __LATTICE_INTERN_H__ */ diff --git a/source/blender/editors/lattice/lattice_ops.c b/source/blender/editors/lattice/lattice_ops.c new file mode 100644 index 00000000000..d3d57a0b510 --- /dev/null +++ b/source/blender/editors/lattice/lattice_ops.c @@ -0,0 +1,80 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2008 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/lattice/lattice_ops.c + * \ingroup edlattice + */ + +#include "DNA_scene_types.h" + +#include "RNA_access.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_screen.h" +#include "ED_object.h" +#include "ED_lattice.h" + +#include "lattice_intern.h" + +void ED_operatortypes_lattice(void) +{ + WM_operatortype_append(LATTICE_OT_select_all); + WM_operatortype_append(LATTICE_OT_select_more); + WM_operatortype_append(LATTICE_OT_select_less); + WM_operatortype_append(LATTICE_OT_select_ungrouped); + WM_operatortype_append(LATTICE_OT_select_random); + WM_operatortype_append(LATTICE_OT_select_mirror); + WM_operatortype_append(LATTICE_OT_make_regular); + WM_operatortype_append(LATTICE_OT_flip); +} + +void ED_keymap_lattice(wmKeyConfig *keyconf) +{ + wmKeyMap *keymap; + wmKeyMapItem *kmi; + + keymap = WM_keymap_find(keyconf, "Lattice", 0, 0); + keymap->poll = ED_operator_editlattice; + + kmi = WM_keymap_add_item(keymap, "LATTICE_OT_select_all", AKEY, KM_PRESS, 0, 0); + RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE); + kmi = WM_keymap_add_item(keymap, "LATTICE_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0); + RNA_enum_set(kmi->ptr, "action", SEL_INVERT); + WM_keymap_add_item(keymap, "LATTICE_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0); + WM_keymap_add_item(keymap, "LATTICE_OT_select_less", PADMINUS, KM_PRESS, KM_CTRL, 0); + + WM_keymap_add_item(keymap, "OBJECT_OT_vertex_parent_set", PKEY, KM_PRESS, KM_CTRL, 0); + + WM_keymap_add_item(keymap, "LATTICE_OT_flip", FKEY, KM_PRESS, KM_CTRL, 0); + + /* menus */ + WM_keymap_add_menu(keymap, "VIEW3D_MT_hook", HKEY, KM_PRESS, KM_CTRL, 0); + + ED_keymap_proportional_cycle(keyconf, keymap); + ED_keymap_proportional_editmode(keyconf, keymap, false); +} diff --git a/source/blender/editors/manipulator_library/manipulator_types/cage2d_manipulator.c b/source/blender/editors/manipulator_library/manipulator_types/cage2d_manipulator.c index 0299a33d0fe..23c6030f091 100644 --- a/source/blender/editors/manipulator_library/manipulator_types/cage2d_manipulator.c +++ b/source/blender/editors/manipulator_library/manipulator_types/cage2d_manipulator.c @@ -37,7 +37,7 @@ #include "MEM_guardedalloc.h" #include "BLI_math.h" -#include "BLI_dial.h" +#include "BLI_dial_2d.h" #include "BLI_rect.h" #include "BKE_context.h" diff --git a/source/blender/editors/manipulator_library/manipulator_types/cage3d_manipulator.c b/source/blender/editors/manipulator_library/manipulator_types/cage3d_manipulator.c index d58cdb4b187..67fb2419931 100644 --- a/source/blender/editors/manipulator_library/manipulator_types/cage3d_manipulator.c +++ b/source/blender/editors/manipulator_library/manipulator_types/cage3d_manipulator.c @@ -37,7 +37,7 @@ #include "MEM_guardedalloc.h" #include "BLI_math.h" -#include "BLI_dial.h" +#include "BLI_dial_2d.h" #include "BLI_rect.h" #include "BKE_context.h" diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c index c60b673ec69..689a96a3dec 100644 --- a/source/blender/editors/mask/mask_draw.c +++ b/source/blender/editors/mask/mask_draw.c @@ -555,7 +555,7 @@ static void draw_masklays(const bContext *C, Mask *mask, const char draw_flag, c const int width, const int height) { glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); GPU_enable_program_point_size(); MaskLayer *masklay; diff --git a/source/blender/editors/mask/mask_select.c b/source/blender/editors/mask/mask_select.c index 9f2f6de8a09..7ffd82e262c 100644 --- a/source/blender/editors/mask/mask_select.c +++ b/source/blender/editors/mask/mask_select.c @@ -33,7 +33,7 @@ #include "BLI_utildefines.h" #include "BLI_rect.h" -#include "BLI_lasso.h" +#include "BLI_lasso_2d.h" #include "BLI_math.h" #include "BKE_context.h" diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt index 80e1187609c..3877838ec54 100644 --- a/source/blender/editors/mesh/CMakeLists.txt +++ b/source/blender/editors/mesh/CMakeLists.txt @@ -60,6 +60,7 @@ set(SRC editmesh_undo.c editmesh_utils.c mesh_data.c + mesh_mirror.c mesh_ops.c meshtools.c diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c index 992d0fada5e..1b9ee70ccf5 100644 --- a/source/blender/editors/mesh/editface.c +++ b/source/blender/editors/mesh/editface.c @@ -24,7 +24,6 @@ * \ingroup edmesh */ - #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" @@ -41,7 +40,6 @@ #include "BKE_global.h" #include "BKE_mesh.h" #include "BKE_context.h" -#include "BKE_editmesh.h" #include "BIF_gl.h" @@ -609,258 +607,3 @@ void paintvert_select_ungrouped(Object *ob, bool extend, bool flush_flags) paintvert_flush_flags(ob); } } - -/* ********************* MESH VERTEX MIRR TOPO LOOKUP *************** */ -/* note, this is not the best place for the function to be but moved - * here for the purpose of syncing with bmesh */ - -typedef unsigned int MirrTopoHash_t; - -typedef struct MirrTopoVert_t { - MirrTopoHash_t hash; - int v_index; -} MirrTopoVert_t; - -static int mirrtopo_hash_sort(const void *l1, const void *l2) -{ - if ((MirrTopoHash_t)(intptr_t)l1 > (MirrTopoHash_t)(intptr_t)l2) return 1; - else if ((MirrTopoHash_t)(intptr_t)l1 < (MirrTopoHash_t)(intptr_t)l2) return -1; - return 0; -} - -static int mirrtopo_vert_sort(const void *v1, const void *v2) -{ - if (((MirrTopoVert_t *)v1)->hash > ((MirrTopoVert_t *)v2)->hash) return 1; - else if (((MirrTopoVert_t *)v1)->hash < ((MirrTopoVert_t *)v2)->hash) return -1; - return 0; -} - -bool ED_mesh_mirrtopo_recalc_check(Mesh *me, DerivedMesh *dm, const int ob_mode, MirrTopoStore_t *mesh_topo_store) -{ - int totvert; - int totedge; - - if (dm) { - totvert = dm->getNumVerts(dm); - totedge = dm->getNumEdges(dm); - } - else if (me->edit_btmesh) { - totvert = me->edit_btmesh->bm->totvert; - totedge = me->edit_btmesh->bm->totedge; - } - else { - totvert = me->totvert; - totedge = me->totedge; - } - - if ((mesh_topo_store->index_lookup == NULL) || - (mesh_topo_store->prev_ob_mode != ob_mode) || - (totvert != mesh_topo_store->prev_vert_tot) || - (totedge != mesh_topo_store->prev_edge_tot)) - { - return true; - } - else { - return false; - } - -} - -void ED_mesh_mirrtopo_init(Mesh *me, DerivedMesh *dm, const int ob_mode, MirrTopoStore_t *mesh_topo_store, - const bool skip_em_vert_array_init) -{ - MEdge *medge = NULL, *med; - BMEditMesh *em = dm ? NULL : me->edit_btmesh; - - /* editmode*/ - BMEdge *eed; - BMIter iter; - - int a, last; - int totvert, totedge; - int tot_unique = -1, tot_unique_prev = -1; - int tot_unique_edges = 0, tot_unique_edges_prev; - - MirrTopoHash_t *topo_hash = NULL; - MirrTopoHash_t *topo_hash_prev = NULL; - MirrTopoVert_t *topo_pairs; - MirrTopoHash_t topo_pass = 1; - - intptr_t *index_lookup; /* direct access to mesh_topo_store->index_lookup */ - - /* reallocate if needed */ - ED_mesh_mirrtopo_free(mesh_topo_store); - - mesh_topo_store->prev_ob_mode = ob_mode; - - if (em) { - BM_mesh_elem_index_ensure(em->bm, BM_VERT); - - totvert = em->bm->totvert; - } - else { - totvert = dm ? dm->getNumVerts(dm) : me->totvert; - } - - topo_hash = MEM_callocN(totvert * sizeof(MirrTopoHash_t), "TopoMirr"); - - /* Initialize the vert-edge-user counts used to detect unique topology */ - if (em) { - totedge = me->edit_btmesh->bm->totedge; - - BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { - const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2); - topo_hash[i1]++; - topo_hash[i2]++; - } - } - else { - totedge = dm ? dm->getNumEdges(dm) : me->totedge; - medge = dm ? dm->getEdgeArray(dm) : me->medge; - - for (a = 0, med = medge; a < totedge; a++, med++) { - const unsigned int i1 = med->v1, i2 = med->v2; - topo_hash[i1]++; - topo_hash[i2]++; - } - } - - topo_hash_prev = MEM_dupallocN(topo_hash); - - tot_unique_prev = -1; - tot_unique_edges_prev = -1; - while (1) { - /* use the number of edges per vert to give verts unique topology IDs */ - - tot_unique_edges = 0; - - /* This can make really big numbers, wrapping around here is fine */ - if (em) { - BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { - const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2); - topo_hash[i1] += topo_hash_prev[i2] * topo_pass; - topo_hash[i2] += topo_hash_prev[i1] * topo_pass; - tot_unique_edges += (topo_hash[i1] != topo_hash[i2]); - } - } - else { - for (a = 0, med = medge; a < totedge; a++, med++) { - const unsigned int i1 = med->v1, i2 = med->v2; - topo_hash[i1] += topo_hash_prev[i2] * topo_pass; - topo_hash[i2] += topo_hash_prev[i1] * topo_pass; - tot_unique_edges += (topo_hash[i1] != topo_hash[i2]); - } - } - memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * totvert); - - /* sort so we can count unique values */ - qsort(topo_hash_prev, totvert, sizeof(MirrTopoHash_t), mirrtopo_hash_sort); - - tot_unique = 1; /* account for skiping the first value */ - for (a = 1; a < totvert; a++) { - if (topo_hash_prev[a - 1] != topo_hash_prev[a]) { - tot_unique++; - } - } - - if ((tot_unique <= tot_unique_prev) && (tot_unique_edges <= tot_unique_edges_prev)) { - /* Finish searching for unique values when 1 loop dosnt give a - * higher number of unique values compared to the previous loop */ - break; - } - else { - tot_unique_prev = tot_unique; - tot_unique_edges_prev = tot_unique_edges; - } - /* Copy the hash calculated this iter, so we can use them next time */ - memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * totvert); - - topo_pass++; - } - - /* Hash/Index pairs are needed for sorting to find index pairs */ - topo_pairs = MEM_callocN(sizeof(MirrTopoVert_t) * totvert, "MirrTopoPairs"); - - /* since we are looping through verts, initialize these values here too */ - index_lookup = MEM_mallocN(totvert * sizeof(*index_lookup), "mesh_topo_lookup"); - - if (em) { - if (skip_em_vert_array_init == false) { - BM_mesh_elem_table_ensure(em->bm, BM_VERT); - } - } - - for (a = 0; a < totvert; a++) { - topo_pairs[a].hash = topo_hash[a]; - topo_pairs[a].v_index = a; - - /* initialize lookup */ - index_lookup[a] = -1; - } - - qsort(topo_pairs, totvert, sizeof(MirrTopoVert_t), mirrtopo_vert_sort); - - last = 0; - - /* Get the pairs out of the sorted hashes, note, totvert+1 means we can use the previous 2, - * but you cant ever access the last 'a' index of MirrTopoPairs */ - if (em) { - BMVert **vtable = em->bm->vtable; - for (a = 1; a <= totvert; a++) { - /* printf("I %d %ld %d\n", (a - last), MirrTopoPairs[a].hash, MirrTopoPairs[a].v_indexs); */ - if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) { - const int match_count = a - last; - if (match_count == 2) { - const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index; - index_lookup[j] = (intptr_t)vtable[k]; - index_lookup[k] = (intptr_t)vtable[j]; - } - else if (match_count == 1) { - /* Center vertex. */ - const int j = topo_pairs[a - 1].v_index; - index_lookup[j] = (intptr_t)vtable[j]; - } - last = a; - } - } - } - else { - /* same as above, for mesh */ - for (a = 1; a <= totvert; a++) { - if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) { - const int match_count = a - last; - if (match_count == 2) { - const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index; - index_lookup[j] = k; - index_lookup[k] = j; - } - else if (match_count == 1) { - /* Center vertex. */ - const int j = topo_pairs[a - 1].v_index; - index_lookup[j] = j; - } - last = a; - } - } - } - - MEM_freeN(topo_pairs); - topo_pairs = NULL; - - MEM_freeN(topo_hash); - MEM_freeN(topo_hash_prev); - - mesh_topo_store->index_lookup = index_lookup; - mesh_topo_store->prev_vert_tot = totvert; - mesh_topo_store->prev_edge_tot = totedge; -} - -void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store) -{ - if (mesh_topo_store->index_lookup) { - MEM_freeN(mesh_topo_store->index_lookup); - } - mesh_topo_store->index_lookup = NULL; - mesh_topo_store->prev_vert_tot = -1; - mesh_topo_store->prev_edge_tot = -1; -} diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c index a21fc2fffde..292b28c772c 100644 --- a/source/blender/editors/mesh/editmesh_add.c +++ b/source/blender/editors/mesh/editmesh_add.c @@ -65,9 +65,10 @@ typedef struct MakePrimitiveData { bool was_editmode; } MakePrimitiveData; -static Object *make_prim_init(bContext *C, const char *idname, - const float loc[3], const float rot[3], const unsigned int layer, - MakePrimitiveData *r_creation_data) +static Object *make_prim_init( + bContext *C, const char *idname, + const float loc[3], const float rot[3], const unsigned int layer, + MakePrimitiveData *r_creation_data) { Object *obedit = CTX_data_edit_object(C); diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index d4d7d92d5ad..c8d33a9cc60 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -139,6 +139,10 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal) return false; } + if (is_modal) { + RNA_float_set(op->ptr, "offset", 0.0f); + } + op->customdata = opdata = MEM_mallocN(sizeof(BevelData), "beveldata_mesh_operator"); opdata->em = em; @@ -622,7 +626,6 @@ 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_bisect.c b/source/blender/editors/mesh/editmesh_bisect.c index 1937a9f6891..741d16206cd 100644 --- a/source/blender/editors/mesh/editmesh_bisect.c +++ b/source/blender/editors/mesh/editmesh_bisect.c @@ -58,7 +58,7 @@ #ifdef USE_MANIPULATOR #include "ED_manipulator_library.h" -#include "ED_util.h" +#include "ED_undo.h" #endif static int mesh_bisect_exec(bContext *C, wmOperator *op); diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c index 18320ec65f5..41b3ab0079b 100644 --- a/source/blender/editors/mesh/editmesh_extrude.c +++ b/source/blender/editors/mesh/editmesh_extrude.c @@ -36,8 +36,6 @@ #include "BLI_listbase.h" #include "BKE_context.h" -#include "BKE_global.h" -#include "BKE_main.h" #include "BKE_object.h" #include "BKE_report.h" #include "BKE_editmesh.h" @@ -63,9 +61,13 @@ #ifdef USE_MANIPULATOR #include "ED_manipulator_library.h" -#include "ED_util.h" +#include "ED_undo.h" #endif +/* -------------------------------------------------------------------- */ +/** \name Extrude Internal Utilities + * \{ */ + static void edbm_extrude_edge_exclude_mirror( Object *obedit, BMEditMesh *em, const char hflag, @@ -154,7 +156,7 @@ static bool edbm_extrude_discrete_faces(BMEditMesh *em, wmOperator *op, const ch EDBM_flag_disable_all(em, BM_ELEM_SELECT); BMO_op_exec(em->bm, &bmop); - + BMO_ITER (f, &siter, bmop.slots_out, "faces.out", BM_FACE) { BM_face_select_set(em->bm, f, true); @@ -254,7 +256,7 @@ static bool edbm_extrude_ex( BMOIter siter; BMOperator extop; BMElem *ele; - + /* needed to remove the faces left behind */ if (htype & BM_FACE) { htype |= BM_EDGE; @@ -276,7 +278,7 @@ static bool edbm_extrude_ex( BM_SELECT_HISTORY_RESTORE(bm); BMO_op_exec(bm, &extop); - + BMO_ITER (ele, &siter, extop.slots_out, "geom.out", BM_ALL_NOLOOP) { BM_elem_select_set(bm, ele, true); } @@ -286,14 +288,20 @@ static bool edbm_extrude_ex( return true; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Extrude Repeat Operator + * \{ */ + static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); RegionView3D *rv3d = CTX_wm_region_view3d(C); - + const int steps = RNA_int_get(op->ptr, "steps"); - + const float offs = RNA_float_get(op->ptr, "offset"); float dvec[3], tmat[3][3], bmat[3][3]; short a; @@ -314,7 +322,7 @@ static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op) "translate vec=%v verts=%hv", dvec, BM_ELEM_SELECT); } - + EDBM_mesh_normals_update(em); EDBM_update_generic(em, true, true); @@ -328,19 +336,25 @@ void MESH_OT_extrude_repeat(wmOperatorType *ot) ot->name = "Extrude Repeat Mesh"; ot->description = "Extrude selected vertices, edges or faces repeatedly"; ot->idname = "MESH_OT_extrude_repeat"; - + /* api callbacks */ ot->exec = edbm_extrude_repeat_exec; ot->poll = ED_operator_editmesh_view3d; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* props */ RNA_def_float_distance(ot->srna, "offset", 2.0f, 0.0f, 1e12f, "Offset", "", 0.0f, 100.0f); RNA_def_int(ot->srna, "steps", 10, 0, 1000000, "Steps", "", 0, 180); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Extrude Operator + * \{ */ + /* generic extern called extruder */ static bool edbm_extrude_mesh(Object *obedit, BMEditMesh *em, wmOperator *op) { @@ -377,7 +391,7 @@ static bool edbm_extrude_mesh(Object *obedit, BMEditMesh *em, wmOperator *op) changed = edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT); break; } - + if (changed) { return true; } @@ -392,7 +406,7 @@ static int edbm_extrude_region_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); - + edbm_extrude_mesh(obedit, em, op); /* This normally happens when pushing undo but modal operators @@ -401,7 +415,7 @@ static int edbm_extrude_region_exec(bContext *C, wmOperator *op) EDBM_mesh_normals_update(em); EDBM_update_generic(em, true, true); - + return OPERATOR_FINISHED; } @@ -411,27 +425,33 @@ void MESH_OT_extrude_region(wmOperatorType *ot) ot->name = "Extrude Region"; ot->idname = "MESH_OT_extrude_region"; ot->description = "Extrude region of faces"; - + /* api callbacks */ //ot->invoke = mesh_extrude_region_invoke; ot->exec = edbm_extrude_region_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Extrude Verts Operator + * \{ */ + static int edbm_extrude_verts_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); edbm_extrude_verts_indiv(em, op, BM_ELEM_SELECT); - + EDBM_update_generic(em, true, true); - + return OPERATOR_FINISHED; } @@ -441,11 +461,11 @@ void MESH_OT_extrude_verts_indiv(wmOperatorType *ot) ot->name = "Extrude Only Vertices"; ot->idname = "MESH_OT_extrude_verts_indiv"; ot->description = "Extrude individual vertices only"; - + /* api callbacks */ ot->exec = edbm_extrude_verts_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -453,15 +473,21 @@ void MESH_OT_extrude_verts_indiv(wmOperatorType *ot) Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Extrude Edges Operator + * \{ */ + static int edbm_extrude_edges_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT); - + EDBM_update_generic(em, true, true); - + return OPERATOR_FINISHED; } @@ -471,11 +497,11 @@ void MESH_OT_extrude_edges_indiv(wmOperatorType *ot) ot->name = "Extrude Only Edges"; ot->idname = "MESH_OT_extrude_edges_indiv"; ot->description = "Extrude individual edges only"; - + /* api callbacks */ ot->exec = edbm_extrude_edges_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -483,15 +509,21 @@ void MESH_OT_extrude_edges_indiv(wmOperatorType *ot) Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Extrude Faces Operator + * \{ */ + static int edbm_extrude_faces_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); edbm_extrude_discrete_faces(em, op, BM_ELEM_SELECT); - + EDBM_update_generic(em, true, true); - + return OPERATOR_FINISHED; } @@ -501,18 +533,25 @@ void MESH_OT_extrude_faces_indiv(wmOperatorType *ot) ot->name = "Extrude Individual Faces"; ot->idname = "MESH_OT_extrude_faces_indiv"; ot->description = "Extrude individual faces only"; - + /* api callbacks */ ot->exec = edbm_extrude_faces_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY); } -/* *************** add-click-mesh (extrude) operator ************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Dupli-Extrude Operator + * + * Add-click-mesh (extrude) operator. + * \{ */ + static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ViewContext vc; @@ -533,7 +572,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w zero_v3(center); verts_len = 0; - + BM_ITER_MESH (v1, &iter, vc.em->bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(v1, BM_ELEM_SELECT)) { add_v3_v3(center, v1->co); @@ -596,7 +635,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w cross_v3_v3v3(nor, view_vec, cross); normalize_v3(nor); } - + /* center */ copy_v3_v3(ofs, center); @@ -605,7 +644,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w mul_m4_v3(vc.obedit->imat, ofs); // back in object space sub_v3_v3(ofs, center); - + /* calculate rotation */ unit_m3(mat); if (done) { @@ -628,7 +667,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w axis_angle_to_mat3(mat, axis, angle); } } - + if (rot_src) { EDBM_op_callf(vc.em, op, "rotate verts=%hv cent=%v matrix=%m3", BM_ELEM_SELECT, center, mat); @@ -653,7 +692,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w ED_view3d_win_to_3d_int(vc.v3d, vc.ar, center, event->mval, center); mul_m4_v3(vc.obedit->imat, center); // back in object space - + EDBM_op_init(vc.em, &bmop, op, "create_vert co=%v", center); BMO_op_exec(vc.em->bm, &bmop); @@ -685,17 +724,22 @@ void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot) ot->name = "Duplicate or Extrude to Cursor"; ot->idname = "MESH_OT_dupli_extrude_cursor"; ot->description = "Duplicate and extrude selected vertices, edges or faces towards the mouse cursor"; - + /* api callbacks */ ot->invoke = edbm_dupli_extrude_cursor_invoke; ot->poll = ED_operator_editmesh_region_view3d; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; RNA_def_boolean(ot->srna, "rotate_source", true, "Rotate Source", "Rotate initial selection giving better shape"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Spin Operator + * \{ */ static int edbm_spin_exec(bContext *C, wmOperator *op) { @@ -815,8 +859,7 @@ void MESH_OT_spin(wmOperatorType *ot) #ifdef USE_MANIPULATOR /* -------------------------------------------------------------------- */ - -/** \name Spin Manipulator +/** \name Screw Operator * \{ */ typedef struct ManipulatorSpinGroup { @@ -1315,3 +1358,5 @@ void MESH_OT_screw(wmOperatorType *ot) RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -1.0f, 1.0f); } + +/** \} */ diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c index 6fd4203e085..3833b84b5d2 100644 --- a/source/blender/editors/mesh/editmesh_inset.c +++ b/source/blender/editors/mesh/editmesh_inset.c @@ -122,6 +122,11 @@ static bool edbm_inset_init(bContext *C, wmOperator *op, const bool is_modal) return false; } + if (is_modal) { + RNA_float_set(op->ptr, "thickness", 0.01f); + RNA_float_set(op->ptr, "depth", 0.0f); + } + op->customdata = opdata = MEM_mallocN(sizeof(InsetData), "inset_operator_data"); opdata->old_thickness = 0.01; @@ -527,11 +532,9 @@ void MESH_OT_inset(wmOperatorType *ot) 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_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c index 3498c6246d7..d681d904e74 100644 --- a/source/blender/editors/mesh/editmesh_intersect.c +++ b/source/blender/editors/mesh/editmesh_intersect.c @@ -400,7 +400,7 @@ static void bm_face_split_by_edges( bm, f, edge_net_temp_buf->data, edge_net_temp_buf->count, &face_arr, &face_arr_len); - BLI_buffer_empty(edge_net_temp_buf); + BLI_buffer_clear(edge_net_temp_buf); if (face_arr_len) { int i; diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 5d5e54edf56..0a12291c128 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -860,7 +860,7 @@ static void knife_cut_face(KnifeTool_OpData *kcd, BMFace *f, ListBase *hits) { Ref *r; - if (BLI_listbase_count_ex(hits, 2) != 2) + if (BLI_listbase_count_at_most(hits, 2) != 2) return; for (r = hits->first; r->next; r = r->next) { @@ -1116,7 +1116,7 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg) int i; glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); /* draw any snapped verts first */ immUniformColor4ubv(kcd->colors.point_a); @@ -1158,7 +1158,7 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg) immUniformColor3ubv(kcd->colors.line); glLineWidth(1.0); - immBeginAtMost(GWN_PRIM_LINES, BLI_mempool_count(kcd->kedges) * 2); + immBeginAtMost(GWN_PRIM_LINES, BLI_mempool_len(kcd->kedges) * 2); BLI_mempool_iternew(kcd->kedges, &iter); for (kfe = BLI_mempool_iterstep(&iter); kfe; kfe = BLI_mempool_iterstep(&iter)) { @@ -1179,7 +1179,7 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg) immUniformColor3ubv(kcd->colors.point); glPointSize(5.0); - immBeginAtMost(GWN_PRIM_POINTS, BLI_mempool_count(kcd->kverts)); + immBeginAtMost(GWN_PRIM_POINTS, BLI_mempool_len(kcd->kverts)); BLI_mempool_iternew(kcd->kverts, &iter); for (kfv = BLI_mempool_iterstep(&iter); kfv; kfv = BLI_mempool_iterstep(&iter)) { @@ -1782,7 +1782,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) } kcd->linehits = linehits; - kcd->totlinehit = BLI_array_count(linehits); + kcd->totlinehit = BLI_array_len(linehits); /* find position along screen line, used for sorting */ for (i = 0; i < kcd->totlinehit; i++) { @@ -2300,7 +2300,7 @@ static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfe /* point to knife edges we've created edges in, edge_array aligned */ KnifeEdge **kfe_array = BLI_array_alloca(kfe_array, edge_array_len); - BLI_assert(BLI_gset_size(kcd->edgenet.edge_visit) == 0); + BLI_assert(BLI_gset_len(kcd->edgenet.edge_visit) == 0); i = 0; for (ref = kfedges->first; ref; ref = ref->next) { diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c index b71dd029bf2..2ae48bee095 100644 --- a/source/blender/editors/mesh/editmesh_path.c +++ b/source/blender/editors/mesh/editmesh_path.c @@ -63,6 +63,10 @@ #include "mesh_intern.h" /* own include */ +/* -------------------------------------------------------------------- */ +/** \name Path Select Struct & Properties + * \{ */ + struct PathSelectParams { bool track_active; /* ensure the active element is the last selected item (handy for picking) */ bool use_topology_distance; @@ -102,8 +106,11 @@ struct UserData { const struct PathSelectParams *op_params; }; +/** \} */ + /* -------------------------------------------------------------------- */ -/* Vert Path */ +/** \name Vert Path + * \{ */ /* callbacks */ static bool verttag_filter_cb(BMVert *v, void *UNUSED(user_data_v)) @@ -121,10 +128,9 @@ static void verttag_set_cb(BMVert *v, bool val, void *user_data_v) } static void mouse_mesh_shortest_path_vert( - Scene *scene, const struct PathSelectParams *op_params, + Scene *UNUSED(scene), Object *obedit, const struct PathSelectParams *op_params, BMVert *v_act, BMVert *v_dst) { - Object *obedit = scene->obedit; BMEditMesh *em = BKE_editmesh_from_object(obedit); BMesh *bm = em->bm; @@ -206,10 +212,11 @@ static void mouse_mesh_shortest_path_vert( EDBM_update_generic(em, false, false); } - +/** \} */ /* -------------------------------------------------------------------- */ -/* Edge Path */ +/** \name Edge Path + * \{ */ /* callbacks */ static bool edgetag_filter_cb(BMEdge *e, void *UNUSED(user_data_v)) @@ -280,11 +287,11 @@ static void edgetag_set_cb(BMEdge *e, bool val, void *user_data_v) } } -static void edgetag_ensure_cd_flag(Scene *scene, Mesh *me) +static void edgetag_ensure_cd_flag(Mesh *me, const char edge_mode) { BMesh *bm = me->edit_btmesh->bm; - switch (scene->toolsettings->edge_mode) { + switch (edge_mode) { case EDGE_MODE_TAG_CREASE: BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_CREASE); break; @@ -307,10 +314,9 @@ static void edgetag_ensure_cd_flag(Scene *scene, Mesh *me) /* since you want to create paths with multiple selects, it doesn't have extend option */ static void mouse_mesh_shortest_path_edge( - Scene *scene, const struct PathSelectParams *op_params, + Scene *scene, Object *obedit, const struct PathSelectParams *op_params, BMEdge *e_act, BMEdge *e_dst) { - Object *obedit = scene->obedit; BMEditMesh *em = BKE_editmesh_from_object(obedit); BMesh *bm = em->bm; @@ -319,7 +325,7 @@ static void mouse_mesh_shortest_path_edge( Mesh *me = obedit->data; bool is_path_ordered = false; - edgetag_ensure_cd_flag(scene, obedit->data); + edgetag_ensure_cd_flag(obedit->data, op_params->edge_mode); if (e_act && (e_act != e_dst)) { if (op_params->use_fill) { @@ -377,7 +383,7 @@ static void mouse_mesh_shortest_path_edge( } else { const bool is_act = !edgetag_test_cb(e_dst, &user_data); - edgetag_ensure_cd_flag(scene, obedit->data); + edgetag_ensure_cd_flag(obedit->data, op_params->edge_mode); edgetag_set_cb(e_dst, is_act, &user_data); /* switch the edge option */ } @@ -429,10 +435,11 @@ static void mouse_mesh_shortest_path_edge( EDBM_update_generic(em, false, false); } - +/** \} */ /* -------------------------------------------------------------------- */ -/* Face Path */ +/** \name Face Path + * \{ */ /* callbacks */ static bool facetag_filter_cb(BMFace *f, void *UNUSED(user_data_v)) @@ -452,10 +459,9 @@ static void facetag_set_cb(BMFace *f, bool val, void *user_data_v) } static void mouse_mesh_shortest_path_face( - Scene *scene, const struct PathSelectParams *op_params, + Scene *UNUSED(scene), Object *obedit, const struct PathSelectParams *op_params, BMFace *f_act, BMFace *f_dst) { - Object *obedit = scene->obedit; BMEditMesh *em = BKE_editmesh_from_object(obedit); BMesh *bm = em->bm; @@ -480,7 +486,6 @@ static void mouse_mesh_shortest_path_face( facetag_filter_cb, &user_data); } - if (f_act != f_dst) { if (path) { if (op_params->track_active) { @@ -541,13 +546,14 @@ static void mouse_mesh_shortest_path_face( EDBM_update_generic(em, false, false); } - +/** \} */ /* -------------------------------------------------------------------- */ -/* Main Operator for vert/edge/face tag */ +/** \name Main Operator for vert/edge/face tag + * \{ */ static bool edbm_shortest_path_pick_ex( - Scene *scene, const struct PathSelectParams *op_params, + Scene *scene, Object *obedit, const struct PathSelectParams *op_params, BMElem *ele_src, BMElem *ele_dst) { @@ -555,15 +561,15 @@ static bool edbm_shortest_path_pick_ex( /* pass */ } else if (ele_src->head.htype == BM_VERT) { - mouse_mesh_shortest_path_vert(scene, op_params, (BMVert *)ele_src, (BMVert *)ele_dst); + mouse_mesh_shortest_path_vert(scene, obedit, op_params, (BMVert *)ele_src, (BMVert *)ele_dst); return true; } else if (ele_src->head.htype == BM_EDGE) { - mouse_mesh_shortest_path_edge(scene, op_params, (BMEdge *)ele_src, (BMEdge *)ele_dst); + mouse_mesh_shortest_path_edge(scene, obedit, op_params, (BMEdge *)ele_src, (BMEdge *)ele_dst); return true; } else if (ele_src->head.htype == BM_FACE) { - mouse_mesh_shortest_path_face(scene, op_params, (BMFace *)ele_src, (BMFace *)ele_dst); + mouse_mesh_shortest_path_face(scene, obedit, op_params, (BMFace *)ele_src, (BMFace *)ele_dst); return true; } @@ -644,7 +650,7 @@ static int edbm_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmE op_params.track_active = track_active; op_params.edge_mode = vc.scene->toolsettings->edge_mode; - if (!edbm_shortest_path_pick_ex(vc.scene, &op_params, ele_src, ele_dst)) { + if (!edbm_shortest_path_pick_ex(vc.scene, vc.obedit, &op_params, ele_src, ele_dst)) { return OPERATOR_PASS_THROUGH; } @@ -681,7 +687,7 @@ static int edbm_shortest_path_pick_exec(bContext *C, wmOperator *op) op_params.track_active = true; op_params.edge_mode = scene->toolsettings->edge_mode; - if (!edbm_shortest_path_pick_ex(scene, &op_params, ele_src, ele_dst)) { + if (!edbm_shortest_path_pick_ex(scene, obedit, &op_params, ele_src, ele_dst)) { return OPERATOR_CANCELLED; } @@ -713,15 +719,17 @@ void MESH_OT_shortest_path_pick(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } +/** \} */ /* -------------------------------------------------------------------- */ -/* Select path between existing selection */ +/** \name Select Path Between Existing Selection + * \{ */ static int edbm_shortest_path_select_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Object *ob = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(ob); + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); BMesh *bm = em->bm; BMIter iter; BMEditSelection *ese_src, *ese_dst; @@ -773,7 +781,7 @@ static int edbm_shortest_path_select_exec(bContext *C, wmOperator *op) struct PathSelectParams op_params; path_select_params_from_op(op, &op_params); - edbm_shortest_path_pick_ex(scene, &op_params, ele_src, ele_dst); + edbm_shortest_path_pick_ex(scene, obedit, &op_params, ele_src, ele_dst); return OPERATOR_FINISHED; } @@ -800,3 +808,5 @@ void MESH_OT_shortest_path_select(wmOperatorType *ot) /* properties */ path_select_properties(ot); } + +/** \} */ diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 3e0afd3095e..87937fd4146 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -75,7 +75,9 @@ /* use bmesh operator flags for a few operators */ #define BMO_ELE_TAG 1 -/* ****************************** MIRROR **************** */ +/* -------------------------------------------------------------------- */ +/** \name Select Mirror + * \{ */ void EDBM_select_mirrored( BMEditMesh *em, const int axis, const bool extend, @@ -168,21 +170,34 @@ void EDBM_select_mirrored( *r_totfail = totfail; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Auto-Merge + * + * Used after transform operations. + * \{ */ + void EDBM_automerge(Scene *scene, Object *obedit, bool update, const char hflag) { bool ok; BMEditMesh *em = BKE_editmesh_from_object(obedit); - ok = BMO_op_callf(em->bm, BMO_FLAG_DEFAULTS, - "automerge verts=%hv dist=%f", - hflag, scene->toolsettings->doublimit); + ok = BMO_op_callf( + em->bm, BMO_FLAG_DEFAULTS, + "automerge verts=%hv dist=%f", + hflag, scene->toolsettings->doublimit); if (LIKELY(ok) && update) { EDBM_update_generic(em, true, true); } } -/* ****************************** SELECTION ROUTINES **************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Back-Buffer OpenGL Selection + * \{ */ unsigned int bm_solidoffs = 0, bm_wireoffs = 0, bm_vertoffs = 0; /* set in drawobject.c ... for colorindices */ @@ -203,21 +218,21 @@ bool EDBM_backbuf_border_init( struct ImBuf *buf; unsigned int *dr; int a; - + if (vc->obedit == NULL || !V3D_IS_ZBUF(vc->v3d)) { return false; } - + buf = ED_view3d_backbuf_read(eval_ctx, vc, xmin, ymin, xmax, ymax); if ((buf == NULL) || (bm_vertoffs == 0)) { return false; } dr = buf->rect; - + /* build selection lookup */ selbuf = edbm_backbuf_alloc(bm_vertoffs + 1); - + a = (xmax - xmin + 1) * (ymax - ymin + 1); while (a--) { if (*dr > 0 && *dr <= bm_vertoffs) { @@ -267,9 +282,9 @@ static void edbm_mask_lasso_px_cb(int x, int x_end, int y, void *user_data) /* mcords is a polygon mask * - grab backbuffer, - * - draw with black in backbuffer, + * - draw with black in backbuffer, * - grab again and compare - * returns 'OK' + * returns 'OK' */ bool EDBM_backbuf_border_mask_init(const struct EvaluationContext *eval_ctx, ViewContext *vc, const int mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax) { @@ -277,7 +292,7 @@ bool EDBM_backbuf_border_mask_init(const struct EvaluationContext *eval_ctx, Vie struct ImBuf *buf; int a; struct LassoMaskData lasso_mask_data; - + /* method in use for face selecting too */ if (vc->obedit == NULL) { if (!BKE_paint_select_elem_test(vc->obact)) { @@ -306,7 +321,7 @@ bool EDBM_backbuf_border_mask_init(const struct EvaluationContext *eval_ctx, Vie /* build selection lookup */ selbuf = edbm_backbuf_alloc(bm_vertoffs + 1); - + a = (xmax - xmin + 1) * (ymax - ymin + 1); while (a--) { if (*dr > 0 && *dr <= bm_vertoffs && *dr_mask == true) { @@ -329,7 +344,7 @@ bool EDBM_backbuf_circle_init( unsigned int *dr; short xmin, ymin, xmax, ymax, xc, yc; int radsq; - + /* method in use for face selecting too */ if (vc->obedit == NULL) { if (!BKE_paint_select_elem_test(vc->obact)) { @@ -348,7 +363,7 @@ bool EDBM_backbuf_circle_init( } dr = buf->rect; - + /* build selection lookup */ selbuf = edbm_backbuf_alloc(bm_vertoffs + 1); radsq = rads * rads; @@ -364,12 +379,12 @@ bool EDBM_backbuf_circle_init( IMB_freeImBuf(buf); return true; - + } +/** \} */ /* -------------------------------------------------------------------- */ - /** \name Find Nearest Vert/Edge/Face * * \note Screen-space manhatten distances are used here, @@ -451,14 +466,14 @@ BMVert *EDBM_vert_find_nearest_ex( float dist_test; unsigned int index; BMVert *eve; - + /* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */ ED_view3d_backbuf_validate(eval_ctx, vc); index = ED_view3d_backbuf_sample_rect( eval_ctx, vc, vc->mval, dist_px, bm_wireoffs, 0xFFFFFF, &dist_test); eve = index ? BM_vert_at_index_find_or_table(bm, index - 1) : NULL; - + if (eve) { if (dist_test < *r_dist) { *r_dist = dist_test; @@ -817,7 +832,7 @@ BMFace *EDBM_face_find_nearest_ex( index = ED_view3d_backbuf_sample(eval_ctx, vc, vc->mval[0], vc->mval[1]); efa = index ? BM_face_at_index_find_or_table(bm, index - 1) : NULL; - + if (r_efa_zbuf) { *r_efa_zbuf = efa; } @@ -895,8 +910,8 @@ BMFace *EDBM_face_find_nearest(const struct EvaluationContext *eval_ctx, ViewCon #undef FIND_NEAR_CYCLE_THRESHOLD_MIN -/* best distance based on screen coords. - * use em->selectmode to define how to use +/* best distance based on screen coords. + * use em->selectmode to define how to use * selected vertices and edges get disadvantage * return 1 if found one */ @@ -914,7 +929,7 @@ static int unified_findnearest( float dist = dist_init; BMFace *efa_zbuf = NULL; BMEdge *eed_zbuf = NULL; - + BMVert *eve = NULL; BMEdge *eed = NULL; BMFace *efa = NULL; @@ -976,8 +991,10 @@ static int unified_findnearest( /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Select Similar (Vert/Edge/Face) Operator + * \{ */ -/* **************** SIMILAR "group" SELECTS. FACE, EDGE AND VERTEX ************** */ static const EnumPropertyItem prop_similar_compare_types[] = { {SIM_CMP_EQ, "EQUAL", 0, "Equal", ""}, {SIM_CMP_GT, "GREATER", 0, "Greater", ""}, @@ -1054,7 +1071,7 @@ static int similar_face_select_exec(bContext *C, wmOperator *op) EDBM_update_generic(em, false, false); return OPERATOR_FINISHED; -} +} /* ***************************************************** */ @@ -1160,8 +1177,9 @@ static int edbm_select_similar_exec(bContext *C, wmOperator *op) else return similar_face_select_exec(C, op); } -static const EnumPropertyItem *select_similar_type_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), - bool *r_free) +static const EnumPropertyItem *select_similar_type_itemf( + bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), + bool *r_free) { Object *obedit; @@ -1213,15 +1231,15 @@ void MESH_OT_select_similar(wmOperatorType *ot) ot->name = "Select Similar"; ot->idname = "MESH_OT_select_similar"; ot->description = "Select similar vertices, edges or faces by property types"; - + /* api callbacks */ ot->invoke = WM_menu_invoke; ot->exec = edbm_select_similar_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* properties */ prop = ot->prop = RNA_def_enum(ot->srna, "type", prop_similar_types, SIMVERT_NORMAL, "Type", ""); RNA_def_enum_funcs(prop, select_similar_type_itemf); @@ -1231,9 +1249,11 @@ void MESH_OT_select_similar(wmOperatorType *ot) RNA_def_float(ot->srna, "threshold", 0.0f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f); } +/** \} */ /* -------------------------------------------------------------------- */ -/* Select Similar Regions */ +/** \name Select Similar Region Operator + * \{ */ static int edbm_select_similar_region_exec(bContext *C, wmOperator *op) { @@ -1254,9 +1274,10 @@ static int edbm_select_similar_region_exec(bContext *C, wmOperator *op) } groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totfacesel, __func__); - group_tot = BM_mesh_calc_face_groups(bm, groups_array, &group_index, - NULL, NULL, - BM_ELEM_SELECT, BM_VERT); + group_tot = BM_mesh_calc_face_groups( + bm, groups_array, &group_index, + NULL, NULL, + BM_ELEM_SELECT, BM_VERT); BM_mesh_elem_table_ensure(bm, BM_FACE); @@ -1297,7 +1318,7 @@ static int edbm_select_similar_region_exec(bContext *C, wmOperator *op) MEM_freeN(group_index); if (changed) { - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } else { BKE_report(op->reports, RPT_WARNING, "No matching face regions found"); @@ -1321,8 +1342,11 @@ void MESH_OT_select_similar_region(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ -/* **************** Mode Select *************** */ +/* -------------------------------------------------------------------- */ +/** \name Select Mode Vert/Edge/Face Operator + * \{ */ static int edbm_select_mode_exec(bContext *C, wmOperator *op) { @@ -1393,12 +1417,15 @@ void MESH_OT_select_mode(wmOperatorType *ot) RNA_def_enum(ot->srna, "action", actions_items, 2, "Action", "Selection action to execute"); } -/* ***************************************************** */ +/** \} */ -/* **************** LOOP SELECTS *************** */ +/* -------------------------------------------------------------------- */ +/** \name Select Loop (Non Modal) Operator + * \{ */ -static void walker_select_count(BMEditMesh *em, int walkercode, void *start, const bool select, const bool select_mix, - int *r_totsel, int *r_totunsel) +static void walker_select_count( + BMEditMesh *em, int walkercode, void *start, const bool select, const bool select_mix, + int *r_totsel, int *r_totunsel) { BMesh *bm = em->bm; BMElem *ele; @@ -1453,7 +1480,7 @@ static int edbm_loop_multiselect_exec(bContext *C, wmOperator *op) BMEdge **edarray; int edindex; const bool is_ring = RNA_boolean_get(op->ptr, "ring"); - + BMIter iter; int totedgesel = 0; @@ -1462,17 +1489,17 @@ static int edbm_loop_multiselect_exec(bContext *C, wmOperator *op) totedgesel++; } } - + edarray = MEM_mallocN(sizeof(BMEdge *) * totedgesel, "edge array"); edindex = 0; - + BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { edarray[edindex] = eed; edindex++; } } - + if (is_ring) { for (edindex = 0; edindex < totedgesel; edindex += 1) { eed = edarray[edindex]; @@ -1489,8 +1516,8 @@ static int edbm_loop_multiselect_exec(bContext *C, wmOperator *op) } MEM_freeN(edarray); // if (EM_texFaceCheck()) - - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit); + + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; } @@ -1501,23 +1528,23 @@ void MESH_OT_loop_multi_select(wmOperatorType *ot) ot->name = "Multi Select Loops"; ot->idname = "MESH_OT_loop_multi_select"; ot->description = "Select a loop of connected edges by connection type"; - + /* api callbacks */ ot->exec = edbm_loop_multiselect_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* properties */ RNA_def_boolean(ot->srna, "ring", 0, "Ring", ""); } - -/* ***************** MAIN MOUSE SELECTION ************** */ - +/** \} */ -/* ***************** loop select (non modal) ************** */ +/* -------------------------------------------------------------------- */ +/** \name Select Loop (Cursor Pick) Operator + * \{ */ static void mouse_mesh_loop_face(BMEditMesh *em, BMEdge *eed, bool select, bool select_clear) { @@ -1572,7 +1599,6 @@ static void mouse_mesh_loop_edge(BMEditMesh *em, BMEdge *eed, bool select, bool } } - static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle, bool ring) { EvaluationContext eval_ctx; @@ -1651,11 +1677,15 @@ static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool de /* We can't be sure this has already been set... */ ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); - if (ED_view3d_project_float_object(vc.ar, eed->v1->co, v1_co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) { + if (ED_view3d_project_float_object( + vc.ar, eed->v1->co, v1_co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) + { length_1 = len_squared_v2v2(mvalf, v1_co); } - if (ED_view3d_project_float_object(vc.ar, eed->v2->co, v2_co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) { + if (ED_view3d_project_float_object( + vc.ar, eed->v2->co, v2_co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) + { length_2 = len_squared_v2v2(mvalf, v2_co); } #if 0 @@ -1682,7 +1712,9 @@ static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool de float co[2], tdist; BM_face_calc_center_mean(f, cent); - if (ED_view3d_project_float_object(vc.ar, cent, co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) { + if (ED_view3d_project_float_object( + vc.ar, cent, co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) + { tdist = len_squared_v2v2(mvalf, co); if (tdist < best_dist) { /* printf("Best face: %p (%f)\n", f, tdist);*/ @@ -1699,21 +1731,22 @@ static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool de } } - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); return true; } static int edbm_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - + view3d_operator_needs_opengl(C); - - if (mouse_mesh_loop(C, event->mval, - RNA_boolean_get(op->ptr, "extend"), - RNA_boolean_get(op->ptr, "deselect"), - RNA_boolean_get(op->ptr, "toggle"), - RNA_boolean_get(op->ptr, "ring"))) + + if (mouse_mesh_loop( + C, event->mval, + RNA_boolean_get(op->ptr, "extend"), + RNA_boolean_get(op->ptr, "deselect"), + RNA_boolean_get(op->ptr, "toggle"), + RNA_boolean_get(op->ptr, "ring"))) { return OPERATOR_FINISHED; } @@ -1728,14 +1761,14 @@ void MESH_OT_loop_select(wmOperatorType *ot) ot->name = "Loop Select"; ot->idname = "MESH_OT_loop_select"; ot->description = "Select a loop of connected edges"; - + /* api callbacks */ ot->invoke = edbm_select_loop_invoke; ot->poll = ED_operator_editmesh_region_view3d; - + /* flags */ ot->flag = OPTYPE_UNDO; - + /* properties */ RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "Extend the selection"); RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Remove from the selection"); @@ -1749,11 +1782,11 @@ void MESH_OT_edgering_select(wmOperatorType *ot) ot->name = "Edge Ring Select"; ot->idname = "MESH_OT_edgering_select"; ot->description = "Select an edge ring"; - + /* callbacks */ ot->invoke = edbm_select_loop_invoke; ot->poll = ED_operator_editmesh_region_view3d; - + /* flags */ ot->flag = OPTYPE_UNDO; @@ -1763,7 +1796,12 @@ void MESH_OT_edgering_select(wmOperatorType *ot) RNA_def_boolean(ot->srna, "ring", 1, "Select Ring", "Select ring"); } -/* ******************** (de)select all operator **************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name (De)Select All Operator + * \{ */ + static int edbm_select_all_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -1786,7 +1824,7 @@ static int edbm_select_all_exec(bContext *C, wmOperator *op) break; } - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; } @@ -1808,13 +1846,19 @@ void MESH_OT_select_all(wmOperatorType *ot) WM_operator_properties_select_all(ot); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Interior Faces Operator + * \{ */ + static int edbm_faces_select_interior_exec(bContext *C, wmOperator *UNUSED(op)) { Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); if (EDBM_select_interior_faces(em)) { - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; } @@ -1839,10 +1883,15 @@ void MESH_OT_select_interior_faces(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Picking API + * + * Here actual select happens, + * Gets called via generic mouse select operator. + * \{ */ -/* ************************************************** */ -/* here actual select happens */ -/* gets called via generic mouse select operator */ bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle) { EvaluationContext eval_ctx; @@ -1957,7 +2006,7 @@ bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect const int cd_fmap_offset = CustomData_get_offset(&vc.em->bm->pdata, CD_FACEMAP); if (cd_fmap_offset != -1) { int map = *((int *)BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset)); - if ((map < -1) || (map > BLI_listbase_count_ex(&vc.obedit->fmaps, map))) { + if ((map < -1) || (map > BLI_listbase_count_at_most(&vc.obedit->fmaps, map))) { map = -1; } map += 1; @@ -1971,13 +2020,19 @@ bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect } - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); return true; } return false; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Mode Utilities + * \{ */ + static void edbm_strip_selections(BMEditMesh *em) { BMEditSelection *ese, *nextese; @@ -2016,11 +2071,11 @@ void EDBM_selectmode_set(BMEditMesh *em) BMEdge *eed; BMFace *efa; BMIter iter; - + em->bm->selectmode = em->selectmode; edbm_strip_selections(em); /* strip BMEditSelections from em->selected that are not relevant to new mode */ - + if (em->bm->totvertsel == 0 && em->bm->totedgesel == 0 && em->bm->totfacesel == 0) @@ -2183,8 +2238,9 @@ void EDBM_selectmode_convert(BMEditMesh *em, const short selectmode_old, const s } /* user facing function, does notification */ -bool EDBM_selectmode_toggle(bContext *C, const short selectmode_new, - const int action, const bool use_extend, const bool use_expand) +bool EDBM_selectmode_toggle( + bContext *C, const short selectmode_new, + const int action, const bool use_extend, const bool use_expand) { ToolSettings *ts = CTX_data_tool_settings(C); Object *obedit = CTX_data_edit_object(C); @@ -2280,9 +2336,10 @@ bool EDBM_selectmode_toggle(bContext *C, const short selectmode_new, * * \return true if the mode is changed. */ -bool EDBM_selectmode_disable(Scene *scene, BMEditMesh *em, - const short selectmode_disable, - const short selectmode_fallback) +bool EDBM_selectmode_disable( + Scene *scene, BMEditMesh *em, + const short selectmode_disable, + const short selectmode_fallback) { /* note essential, but switch out of vertex mode since the * selected regions wont be nicely isolated after flushing */ @@ -2305,6 +2362,12 @@ bool EDBM_selectmode_disable(Scene *scene, BMEditMesh *em, } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Toggle + * \{ */ + void EDBM_deselect_by_material(BMEditMesh *em, const short index, const bool select) { BMIter iter; @@ -2333,7 +2396,7 @@ void EDBM_select_swap(BMEditMesh *em) /* exported for UV */ BMVert *eve; BMEdge *eed; BMFace *efa; - + if (em->bm->selectmode & SCE_SELECT_VERTEX) { BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) @@ -2356,9 +2419,17 @@ void EDBM_select_swap(BMEditMesh *em) /* exported for UV */ } } -// if (EM_texFaceCheck()) } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Interior Faces + * + * \note This algorithm is limited to single faces and could be improved, see: + * https://blender.stackexchange.com/questions/18916 + * \{ */ + bool EDBM_select_interior_faces(BMEditMesh *em) { BMesh *bm = em->bm; @@ -2391,8 +2462,13 @@ bool EDBM_select_interior_faces(BMEditMesh *em) return changed; } +/** \} */ -/************************ Select Linked Operator *************************/ +/* -------------------------------------------------------------------- */ +/** \name Select Linked Operator + * + * Support delimiting on different edge properties. + * \{ */ /* so we can have last-used default depend on selection mode (rare exception!) */ #define USE_LINKED_SELECT_DEFAULT_HACK @@ -2452,10 +2528,10 @@ static bool select_linked_delimit_test( * Gets the default from the operator fallback to own last-used value * (selected based on mode) */ -static int select_linked_delimit_default_from_op(wmOperator *op, BMEditMesh *em) +static int select_linked_delimit_default_from_op(wmOperator *op, int select_mode) { static char delimit_last_store[2] = {0, BMO_DELIM_SEAM}; - int delimit_last_index = (em->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0; + int delimit_last_index = (select_mode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0; char *delimit_last = &delimit_last_store[delimit_last_index]; PropertyRNA *prop_delimit = RNA_struct_find_property(op->ptr, "delimit"); int delimit; @@ -2525,7 +2601,7 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op) BMWalker walker; #ifdef USE_LINKED_SELECT_DEFAULT_HACK - int delimit = select_linked_delimit_default_from_op(op, em); + int delimit = select_linked_delimit_default_from_op(op, em->selectmode); #else int delimit = RNA_enum_get(op->ptr, "delimit"); #endif @@ -2683,7 +2759,7 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op) select_linked_delimit_end(em); } - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; } @@ -2713,6 +2789,12 @@ void MESH_OT_select_linked(wmOperatorType *ot) #endif } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Linked (Cursor Pick) Operator + * \{ */ + static int edbm_select_linked_pick_exec(bContext *C, wmOperator *op); static void edbm_select_linked_pick_ex(BMEditMesh *em, BMElem *ele, bool sel, int delimit) @@ -2853,13 +2935,13 @@ static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmE /* return warning! */ if (unified_findnearest(&eval_ctx, &vc, &eve, &eed, &efa) == 0) { - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_CANCELLED; } #ifdef USE_LINKED_SELECT_DEFAULT_HACK - int delimit = select_linked_delimit_default_from_op(op, em); + int delimit = select_linked_delimit_default_from_op(op, em->selectmode); #else int delimit = RNA_enum_get(op->ptr, "delimit"); #endif @@ -2874,7 +2956,7 @@ static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmE RNA_int_set(op->ptr, "index", index); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; } @@ -2896,14 +2978,14 @@ static int edbm_select_linked_pick_exec(bContext *C, wmOperator *op) BMElem *ele = EDBM_elem_from_index_any(em, index); #ifdef USE_LINKED_SELECT_DEFAULT_HACK - int delimit = select_linked_delimit_default_from_op(op, em); + int delimit = select_linked_delimit_default_from_op(op, em->selectmode); #else int delimit = RNA_enum_get(op->ptr, "delimit"); #endif edbm_select_linked_pick_ex(em, ele, sel, delimit); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; } @@ -2916,15 +2998,15 @@ void MESH_OT_select_linked_pick(wmOperatorType *ot) ot->name = "Select Linked"; ot->idname = "MESH_OT_select_linked_pick"; ot->description = "(De)select all vertices linked to the edge under the mouse cursor"; - + /* api callbacks */ ot->invoke = edbm_select_linked_pick_invoke; ot->exec = edbm_select_linked_pick_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", ""); prop = RNA_def_enum_flag(ot->srna, "delimit", rna_enum_mesh_delimit_mode_items, BMO_DELIM_SEAM, "Delimit", "Delimit selected region"); @@ -2937,6 +3019,11 @@ void MESH_OT_select_linked_pick(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Face by Sides Operator + * \{ */ static int edbm_select_face_by_sides_exec(bContext *C, wmOperator *op) { @@ -3012,6 +3099,11 @@ void MESH_OT_select_face_by_sides(wmOperatorType *ot) RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend the selection"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Loose Operator + * \{ */ static int edbm_select_loose_exec(bContext *C, wmOperator *op) { @@ -3083,6 +3175,11 @@ void MESH_OT_select_loose(wmOperatorType *ot) RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Mirror Operator + * \{ */ static int edbm_select_mirror_exec(bContext *C, wmOperator *op) { @@ -3131,7 +3228,11 @@ void MESH_OT_select_mirror(wmOperatorType *ot) RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the existing selection"); } -/* ******************** **************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select More Operator + * \{ */ static int edbm_select_more_exec(bContext *C, wmOperator *op) { @@ -3141,7 +3242,7 @@ static int edbm_select_more_exec(bContext *C, wmOperator *op) EDBM_select_more(em, use_face_step); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; } @@ -3155,13 +3256,19 @@ void MESH_OT_select_more(wmOperatorType *ot) /* api callbacks */ ot->exec = edbm_select_more_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; RNA_def_boolean(ot->srna, "use_face_step", true, "Face Step", "Connected faces (instead of edges)"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select More Operator + * \{ */ + static int edbm_select_less_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -3170,7 +3277,7 @@ static int edbm_select_less_exec(bContext *C, wmOperator *op) EDBM_select_less(em, use_face_step); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; } @@ -3184,13 +3291,19 @@ void MESH_OT_select_less(wmOperatorType *ot) /* api callbacks */ ot->exec = edbm_select_less_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; RNA_def_boolean(ot->srna, "use_face_step", true, "Face Step", "Connected faces (instead of edges)"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select N'th Operator + * \{ */ + /** * Check if we're connected to another selected efge. */ @@ -3413,13 +3526,18 @@ void MESH_OT_select_nth(wmOperatorType *ot) void em_setup_viewcontext(bContext *C, ViewContext *vc) { - view3d_set_viewcontext(C, vc); - + ED_view3d_viewcontext_init(C, vc); + if (vc->obedit) { vc->em = BKE_editmesh_from_object(vc->obedit); } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Sharp Edges Operator + * \{ */ static int edbm_select_sharp_edges_exec(bContext *C, wmOperator *op) { @@ -3460,20 +3578,26 @@ void MESH_OT_edges_select_sharp(wmOperatorType *ot) ot->name = "Select Sharp Edges"; ot->description = "Select all sharp-enough edges"; ot->idname = "MESH_OT_edges_select_sharp"; - + /* api callbacks */ ot->exec = edbm_select_sharp_edges_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* props */ prop = RNA_def_float_rotation(ot->srna, "sharpness", 0, NULL, DEG2RADF(0.01f), DEG2RADF(180.0f), "Sharpness", "", DEG2RADF(1.0f), DEG2RADF(180.0f)); RNA_def_property_float_default(prop, DEG2RADF(30.0f)); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Linked Flat Faces Operator + * \{ */ + static int edbm_select_linked_flat_faces_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -3541,20 +3665,26 @@ void MESH_OT_faces_select_linked_flat(wmOperatorType *ot) ot->name = "Select Linked Flat Faces"; ot->description = "Select linked faces by angle"; ot->idname = "MESH_OT_faces_select_linked_flat"; - + /* api callbacks */ ot->exec = edbm_select_linked_flat_faces_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* props */ prop = RNA_def_float_rotation(ot->srna, "sharpness", 0, NULL, DEG2RADF(0.01f), DEG2RADF(180.0f), "Sharpness", "", DEG2RADF(1.0f), DEG2RADF(180.0f)); RNA_def_property_float_default(prop, DEG2RADF(1.0f)); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Non-Manifold Operator + * \{ */ + static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -3576,12 +3706,12 @@ static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op) /* Selects isolated verts, and edges that do not have 2 neighboring * faces */ - + if (em->selectmode == SCE_SELECT_FACE) { BKE_report(op->reports, RPT_ERROR, "Does not work in face selection mode"); return OPERATOR_CANCELLED; } - + if (use_verts) { BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) { @@ -3591,7 +3721,7 @@ static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op) } } } - + if (use_wire || use_boundary || use_multi_face || use_non_contiguous) { BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { @@ -3622,11 +3752,11 @@ void MESH_OT_select_non_manifold(wmOperatorType *ot) ot->name = "Select Non Manifold"; ot->description = "Select all non-manifold vertices or edges"; ot->idname = "MESH_OT_select_non_manifold"; - + /* api callbacks */ ot->exec = edbm_select_non_manifold_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -3646,6 +3776,12 @@ void MESH_OT_select_non_manifold(wmOperatorType *ot) "Vertices connecting multiple face regions"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Random Operator + * \{ */ + static int edbm_select_random_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -3692,9 +3828,9 @@ static int edbm_select_random_exec(bContext *C, wmOperator *op) else { EDBM_deselect_flush(em); } - + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - + return OPERATOR_FINISHED; } @@ -3711,11 +3847,17 @@ void MESH_OT_select_random(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* props */ WM_operator_properties_select_random(ot); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Ungrouped Operator + * \{ */ + static int edbm_select_ungrouped_poll(bContext *C) { if (ED_operator_editmesh(C)) { @@ -3782,6 +3924,11 @@ void MESH_OT_select_ungrouped(wmOperatorType *ot) RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Axis Operator + * \{ */ /* BMESH_TODO - some way to select on an arbitrary axis */ static int edbm_select_axis_exec(bContext *C, wmOperator *op) @@ -3868,6 +4015,12 @@ void MESH_OT_select_axis(wmOperatorType *ot) RNA_def_float(ot->srna, "threshold", 0.0001f, 0.000001f, 50.0f, "Threshold", "", 0.00001f, 10.0f); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Region to Loop Operator + * \{ */ + static int edbm_region_to_loop_exec(bContext *C, wmOperator *UNUSED(op)) { Object *obedit = CTX_data_edit_object(C); @@ -3881,22 +4034,22 @@ static int edbm_region_to_loop_exec(bContext *C, wmOperator *UNUSED(op)) BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { BMLoop *l1, *l2; BMIter liter1, liter2; - + BM_ITER_ELEM (l1, &liter1, f, BM_LOOPS_OF_FACE) { int tot = 0, totsel = 0; - + BM_ITER_ELEM (l2, &liter2, l1->e, BM_LOOPS_OF_EDGE) { tot++; totsel += BM_elem_flag_test(l2->f, BM_ELEM_SELECT) != 0; } - + if ((tot != totsel && totsel > 0) || (totsel == 1 && tot == 1)) BM_elem_flag_enable(l1->e, BM_ELEM_TAG); } } EDBM_flag_disable_all(em, BM_ELEM_SELECT); - + BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { if (BM_elem_flag_test(e, BM_ELEM_TAG)) { BM_edge_select_set(em->bm, e, true); @@ -3931,29 +4084,36 @@ void MESH_OT_region_to_loop(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -static int loop_find_region(BMLoop *l, int flag, - GSet *visit_face_set, BMFace ***region_out) +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Loop to Region Operator + * \{ */ + +static int loop_find_region( + BMLoop *l, int flag, + GSet *visit_face_set, BMFace ***region_out) { BMFace **region = NULL; BMFace **stack = NULL; BLI_array_declare(region); BLI_array_declare(stack); BMFace *f; - + BLI_array_append(stack, l->f); BLI_gset_insert(visit_face_set, l->f); - - while (BLI_array_count(stack) > 0) { + + while (BLI_array_len(stack) > 0) { BMIter liter1, liter2; BMLoop *l1, *l2; - + f = BLI_array_pop(stack); BLI_array_append(region, f); - + BM_ITER_ELEM (l1, &liter1, f, BM_LOOPS_OF_FACE) { if (BM_elem_flag_test(l1->e, flag)) continue; - + BM_ITER_ELEM (l2, &liter2, l1->e, BM_LOOPS_OF_EDGE) { /* avoids finding same region twice * (otherwise) the logic works fine without */ @@ -3967,11 +4127,11 @@ static int loop_find_region(BMLoop *l, int flag, } } } - + BLI_array_free(stack); - + *region_out = region; - return BLI_array_count(region); + return BLI_array_len(region); } static int verg_radial(const void *va, const void *vb) @@ -3979,10 +4139,9 @@ static int verg_radial(const void *va, const void *vb) const BMEdge *e_a = *((const BMEdge **)va); const BMEdge *e_b = *((const BMEdge **)vb); - int a, b; - a = BM_edge_face_count(e_a); - b = BM_edge_face_count(e_b); - + const int a = BM_edge_face_count(e_a); + const int b = BM_edge_face_count(e_b); + if (a > b) return -1; if (a < b) return 1; return 0; @@ -4001,7 +4160,7 @@ static int loop_find_regions(BMEditMesh *em, const bool selbigger) const int edges_len = em->bm->totedgesel; BMEdge *e, **edges; int count = 0, i; - + visit_face_set = BLI_gset_ptr_new_ex(__func__, edges_len); edges = MEM_mallocN(sizeof(*edges) * edges_len, __func__); @@ -4015,21 +4174,21 @@ static int loop_find_regions(BMEditMesh *em, const bool selbigger) BM_elem_flag_disable(e, BM_ELEM_TAG); } } - + /* sort edges by radial cycle length */ qsort(edges, edges_len, sizeof(*edges), verg_radial); - + for (i = 0; i < edges_len; i++) { BMIter liter; BMLoop *l; BMFace **region = NULL, **region_out; int c, tot = 0; - + e = edges[i]; - + if (!BM_elem_flag_test(e, BM_ELEM_TAG)) continue; - + BM_ITER_ELEM (l, &liter, e, BM_LOOPS_OF_EDGE) { if (BLI_gset_haskey(visit_face_set, l->f)) continue; @@ -4051,26 +4210,26 @@ static int loop_find_regions(BMEditMesh *em, const bool selbigger) MEM_freeN(region_out); } } - + if (region) { int j; - + for (j = 0; j < tot; j++) { BM_elem_flag_enable(region[j], BM_ELEM_TAG); BM_ITER_ELEM (l, &liter, region[j], BM_LOOPS_OF_FACE) { BM_elem_flag_disable(l->e, BM_ELEM_TAG); } } - + count += tot; - + MEM_freeN(region); } } - + MEM_freeN(edges); BLI_gset_free(visit_face_set, NULL); - + return count; } @@ -4081,25 +4240,23 @@ static int edbm_loop_to_region_exec(bContext *C, wmOperator *op) BMIter iter; BMFace *f; const bool select_bigger = RNA_boolean_get(op->ptr, "select_bigger"); - int a, b; - /* find the set of regions with smallest number of total faces */ BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); - a = loop_find_regions(em, select_bigger); - b = loop_find_regions(em, !select_bigger); + const int a = loop_find_regions(em, select_bigger); + const int b = loop_find_regions(em, !select_bigger); BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); loop_find_regions(em, ((a <= b) != select_bigger) ? select_bigger : !select_bigger); - + EDBM_flag_disable_all(em, BM_ELEM_SELECT); - + BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { if (BM_elem_flag_test(f, BM_ELEM_TAG) && !BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { BM_face_select_set(em->bm, f, true); } } - + EDBM_selectmode_flush(em); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); @@ -4119,9 +4276,8 @@ void MESH_OT_loop_to_region(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + RNA_def_boolean(ot->srna, "select_bigger", 0, "Select Bigger", "Select bigger regions instead of smaller ones"); } - -/************************ Select Path Operator *************************/ +/** \} */ diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index ff1cd7224cd..bf70cc3fa7e 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -87,6 +87,10 @@ #define USE_FACE_CREATE_SEL_EXTEND +/* -------------------------------------------------------------------- */ +/** \name Subdivide Operator + * \{ */ + static int edbm_subdivide_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -96,19 +100,20 @@ static int edbm_subdivide_exec(bContext *C, wmOperator *op) const float fractal = RNA_float_get(op->ptr, "fractal") / 2.5f; const float along_normal = RNA_float_get(op->ptr, "fractal_along_normal"); - if (RNA_boolean_get(op->ptr, "quadtri") && + if (RNA_boolean_get(op->ptr, "quadtri") && RNA_enum_get(op->ptr, "quadcorner") == SUBD_CORNER_STRAIGHT_CUT) { RNA_enum_set(op->ptr, "quadcorner", SUBD_CORNER_INNERVERT); } - - BM_mesh_esubdivide(em->bm, BM_ELEM_SELECT, - smooth, SUBD_FALLOFF_LIN, false, - fractal, along_normal, - cuts, - SUBDIV_SELECT_ORIG, RNA_enum_get(op->ptr, "quadcorner"), - RNA_boolean_get(op->ptr, "quadtri"), true, false, - RNA_int_get(op->ptr, "seed")); + + BM_mesh_esubdivide( + em->bm, BM_ELEM_SELECT, + smooth, SUBD_FALLOFF_LIN, false, + fractal, along_normal, + cuts, + SUBDIV_SELECT_ORIG, RNA_enum_get(op->ptr, "quadcorner"), + RNA_boolean_get(op->ptr, "quadtri"), true, false, + RNA_int_get(op->ptr, "seed")); EDBM_update_generic(em, true, true); @@ -159,10 +164,14 @@ void MESH_OT_subdivide(wmOperatorType *ot) RNA_def_int(ot->srna, "seed", 0, 0, INT_MAX, "Random Seed", "Seed for the random number generator", 0, 255); } +/** \} */ + /* -------------------------------------------------------------------- */ -/* Edge Ring Subdiv - * (bridge code shares props) - */ +/** \name Edge Ring Subdivide Operator + * + * Bridge code shares props. + * + * \{ */ struct EdgeRingOpSubdProps { int interp_mode; @@ -224,11 +233,12 @@ static int edbm_subdivide_edge_ring_exec(bContext *C, wmOperator *op) mesh_operator_edgering_props_get(op, &op_props); - if (!EDBM_op_callf(em, op, - "subdivide_edgering edges=%he interp_mode=%i cuts=%i smooth=%f " - "profile_shape=%i profile_shape_factor=%f", - BM_ELEM_SELECT, op_props.interp_mode, op_props.cuts, op_props.smooth, - op_props.profile_shape, op_props.profile_shape_factor)) + if (!EDBM_op_callf( + em, op, + "subdivide_edgering edges=%he interp_mode=%i cuts=%i smooth=%f " + "profile_shape=%i profile_shape_factor=%f", + BM_ELEM_SELECT, op_props.interp_mode, op_props.cuts, op_props.smooth, + op_props.profile_shape, op_props.profile_shape_factor)) { return OPERATOR_CANCELLED; } @@ -256,6 +266,11 @@ void MESH_OT_subdivide_edgering(wmOperatorType *ot) mesh_operator_edgering_props(ot, 1, 10); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Un-Subdivide Operator + * \{ */ static int edbm_unsubdivide_exec(bContext *C, wmOperator *op) { @@ -311,7 +326,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_type(C), 0, + CTX_data_main(C), CTX_data_scene(C), CTX_data_view_layer(C), 0, ar, CTX_wm_view3d(C)); BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { @@ -337,6 +352,11 @@ void EMBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em) ED_transform_snap_object_context_destroy(snap_context); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Delete Operator + * \{ */ /* Note, these values must match delete_mesh() event values */ enum { @@ -391,7 +411,7 @@ static int edbm_delete_exec(bContext *C, wmOperator *op) EDBM_flag_disable_all(em, BM_ELEM_SELECT); EDBM_update_generic(em, true, true); - + return OPERATOR_FINISHED; } @@ -410,13 +430,13 @@ void MESH_OT_delete(wmOperatorType *ot) ot->name = "Delete"; ot->description = "Delete selected vertices, edges or faces"; ot->idname = "MESH_OT_delete"; - + /* api callbacks */ ot->invoke = WM_menu_invoke; ot->exec = edbm_delete_exec; - + ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -425,6 +445,11 @@ void MESH_OT_delete(wmOperatorType *ot) "Type", "Method used for deleting mesh data"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Delete Loose Operator + * \{ */ static bool bm_face_is_loose(BMFace *f) { @@ -523,6 +548,11 @@ void MESH_OT_delete_loose(wmOperatorType *ot) RNA_def_boolean(ot->srna, "use_faces", false, "Faces", "Remove loose faces"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Collapse Edge Operator + * \{ */ static int edbm_collapse_edge_exec(bContext *C, wmOperator *op) { @@ -552,6 +582,12 @@ void MESH_OT_edge_collapse(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Create Edge/Face Operator + * \{ */ + static bool edbm_add_edge_face__smooth_get(BMesh *bm) { BMEdge *e; @@ -621,8 +657,9 @@ static BMElem *edbm_add_edge_face_exec__tricky_extend_sel(BMesh *bm) (BM_edge_share_face_check(ed_pair[0], ed_pair[1]) == false)) ) { - BMEdge *e_other = BM_edge_exists(BM_edge_other_vert(ed_pair[0], v), - BM_edge_other_vert(ed_pair[1], v)); + BMEdge *e_other = BM_edge_exists( + BM_edge_other_vert(ed_pair[0], v), + BM_edge_other_vert(ed_pair[1], v)); BM_edge_select_set(bm, ed_pair[0], true); BM_edge_select_set(bm, ed_pair[1], true); if (e_other) { @@ -745,13 +782,14 @@ static int edbm_add_edge_face_exec(bContext *C, wmOperator *op) ele_desel = edbm_add_edge_face_exec__tricky_extend_sel(em->bm); #endif - if (!EDBM_op_init(em, &bmop, op, - "contextual_create geom=%hfev mat_nr=%i use_smooth=%b", - BM_ELEM_SELECT, em->mat_nr, use_smooth)) + if (!EDBM_op_init( + em, &bmop, op, + "contextual_create geom=%hfev mat_nr=%i use_smooth=%b", + BM_ELEM_SELECT, em->mat_nr, use_smooth)) { return OPERATOR_CANCELLED; } - + BMO_op_exec(em->bm, &bmop); /* cancel if nothing was done */ @@ -801,16 +839,20 @@ void MESH_OT_edge_face_add(wmOperatorType *ot) ot->name = "Make Edge/Face"; ot->description = "Add an edge or face to selected"; ot->idname = "MESH_OT_edge_face_add"; - + /* api callbacks */ ot->exec = edbm_add_edge_face_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ************************* SEAMS AND EDGES **************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mark Edge (Seam) Operator + * \{ */ static int edbm_mark_seam_exec(bContext *C, wmOperator *op) { @@ -822,7 +864,7 @@ static int edbm_mark_seam_exec(bContext *C, wmOperator *op) BMEdge *eed; BMIter iter; const bool clear = RNA_boolean_get(op->ptr, "clear"); - + /* auto-enable seams drawing */ if (clear == 0) { me->drawflag |= ME_DRAWSEAMS; @@ -832,7 +874,7 @@ static int edbm_mark_seam_exec(bContext *C, wmOperator *op) BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) { if (!BM_elem_flag_test(eed, BM_ELEM_SELECT) || BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) continue; - + BM_elem_flag_disable(eed, BM_ELEM_SEAM); } } @@ -858,11 +900,11 @@ void MESH_OT_mark_seam(wmOperatorType *ot) ot->name = "Mark Seam"; ot->idname = "MESH_OT_mark_seam"; ot->description = "(Un)mark selected edges as a seam"; - + /* api callbacks */ ot->exec = edbm_mark_seam_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -872,6 +914,12 @@ void MESH_OT_mark_seam(wmOperatorType *ot) WM_operatortype_props_advanced_begin(ot); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mark Edge (Sharp) Operator + * \{ */ + static int edbm_mark_sharp_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -914,14 +962,14 @@ void MESH_OT_mark_sharp(wmOperatorType *ot) ot->name = "Mark Sharp"; ot->idname = "MESH_OT_mark_sharp"; ot->description = "(Un)mark selected edges as sharp"; - + /* api callbacks */ ot->exec = edbm_mark_sharp_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + prop = RNA_def_boolean(ot->srna, "clear", false, "Clear", ""); RNA_def_property_flag(prop, PROP_SKIP_SAVE); prop = RNA_def_boolean(ot->srna, "use_verts", false, "Vertices", @@ -965,17 +1013,19 @@ static int edbm_vert_connect_exec(bContext *C, wmOperator *op) } if (is_pair) { - if (!EDBM_op_init(em, &bmop, op, - "connect_vert_pair verts=%eb verts_exclude=%hv faces_exclude=%hf", - verts, verts_len, BM_ELEM_HIDDEN, BM_ELEM_HIDDEN)) + if (!EDBM_op_init( + em, &bmop, op, + "connect_vert_pair verts=%eb verts_exclude=%hv faces_exclude=%hf", + verts, verts_len, BM_ELEM_HIDDEN, BM_ELEM_HIDDEN)) { goto finally; } } else { - if (!EDBM_op_init(em, &bmop, op, - "connect_verts verts=%eb faces_exclude=%hf check_degenerate=%b", - verts, verts_len, BM_ELEM_HIDDEN, check_degenerate)) + if (!EDBM_op_init( + em, &bmop, op, + "connect_verts verts=%eb faces_exclude=%hf check_degenerate=%b", + verts, verts_len, BM_ELEM_HIDDEN, check_degenerate)) { goto finally; } @@ -1012,15 +1062,20 @@ void MESH_OT_vert_connect(wmOperatorType *ot) ot->name = "Vertex Connect"; ot->idname = "MESH_OT_vert_connect"; ot->description = "Connect selected vertices of faces, splitting the face"; - + /* api callbacks */ ot->exec = edbm_vert_connect_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Split Concave Faces Operator + * \{ */ /** * check that endpoints are verts and only have a single selected edge connected. @@ -1071,7 +1126,7 @@ static bool bm_vert_connect_select_history(BMesh *bm) * - Otherwise connect faces. * - If all edges have been created already, closed the loop. */ - if (BLI_listbase_count_ex(&bm->selected, 2) == 2 && (bm->totvertsel > 2)) { + if (BLI_listbase_count_at_most(&bm->selected, 2) == 2 && (bm->totvertsel > 2)) { BMEditSelection *ese; int tot = 0; bool changed = false; @@ -1325,6 +1380,11 @@ void MESH_OT_vert_connect_concave(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Split Non-Planar Faces Operator + * \{ */ static int edbm_vert_connect_nonplaner_exec(bContext *C, wmOperator *op) { @@ -1369,6 +1429,12 @@ void MESH_OT_vert_connect_nonplanar(wmOperatorType *ot) RNA_def_property_float_default(prop, DEG2RADF(5.0f)); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Make Planar Faces Operator + * \{ */ + static int edbm_face_make_planar_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -1406,6 +1472,11 @@ void MESH_OT_face_make_planar(wmOperatorType *ot) RNA_def_int(ot->srna, "repeat", 1, 1, 10000, "Iterations", "", 1, 200); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Split Edge Operator + * \{ */ static int edbm_edge_split_exec(bContext *C, wmOperator *op) { @@ -1420,7 +1491,7 @@ static int edbm_edge_split_exec(bContext *C, wmOperator *op) { return OPERATOR_CANCELLED; } - + if (em->selectmode == SCE_SELECT_FACE) { EDBM_select_flush(em); } @@ -1436,16 +1507,20 @@ void MESH_OT_edge_split(wmOperatorType *ot) ot->name = "Edge Split"; ot->idname = "MESH_OT_edge_split"; ot->description = "Split selected edges so that each neighbor face gets its own copy"; - + /* api callbacks */ ot->exec = edbm_edge_split_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/****************** add duplicate operator ***************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Duplicate Operator + * \{ */ static int edbm_duplicate_exec(bContext *C, wmOperator *op) { @@ -1476,7 +1551,7 @@ static int edbm_duplicate_exec(bContext *C, wmOperator *op) } EDBM_update_generic(em, true, true); - + return OPERATOR_FINISHED; } @@ -1485,7 +1560,7 @@ static int edbm_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *UNU WM_cursor_wait(1); edbm_duplicate_exec(C, op); WM_cursor_wait(0); - + return OPERATOR_FINISHED; } @@ -1495,29 +1570,34 @@ void MESH_OT_duplicate(wmOperatorType *ot) ot->name = "Duplicate"; ot->description = "Duplicate selected vertices, edges or faces"; ot->idname = "MESH_OT_duplicate"; - + /* api callbacks */ ot->invoke = edbm_duplicate_invoke; ot->exec = edbm_duplicate_exec; - + ot->poll = ED_operator_editmesh; - + /* to give to transform */ RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Flip Normals Operator + * \{ */ static int edbm_flip_normals_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); - + if (!EDBM_op_callf( em, op, "reverse_faces faces=%hf flip_multires=%b", BM_ELEM_SELECT, true)) { return OPERATOR_CANCELLED; } - + EDBM_update_generic(em, true, false); return OPERATOR_FINISHED; @@ -1529,15 +1609,21 @@ void MESH_OT_flip_normals(wmOperatorType *ot) ot->name = "Flip Normals"; ot->description = "Flip the direction of selected faces' normals (and of their vertices)"; ot->idname = "MESH_OT_flip_normals"; - + /* api callbacks */ ot->exec = edbm_flip_normals_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Rotate Edge Operator + * \{ */ + /** * Rotate the edges between selected faces, otherwise rotate the selected edges. */ @@ -1571,7 +1657,7 @@ static int edbm_edge_rotate_selected_exec(bContext *C, wmOperator *op) } } } - + /* ok, we don't have two adjacent faces, but we do have two selected ones. * that's an error condition.*/ if (tot == 0) { @@ -1630,12 +1716,17 @@ void MESH_OT_edge_rotate(wmOperatorType *ot) RNA_def_boolean(ot->srna, "use_ccw", false, "Counter Clockwise", ""); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Hide Operator + * \{ */ static int edbm_hide_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); - + EDBM_mesh_hide(em, RNA_boolean_get(op->ptr, "unselected")); EDBM_update_generic(em, true, false); @@ -1649,18 +1740,24 @@ void MESH_OT_hide(wmOperatorType *ot) ot->name = "Hide Selection"; ot->idname = "MESH_OT_hide"; ot->description = "Hide (un)selected vertices, edges or faces"; - + /* api callbacks */ ot->exec = edbm_hide_exec; ot->poll = ED_operator_editmesh; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* props */ RNA_def_boolean(ot->srna, "unselected", false, "Unselected", "Hide unselected rather than selected"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Reveal Operator + * \{ */ + static int edbm_reveal_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -1680,22 +1777,28 @@ void MESH_OT_reveal(wmOperatorType *ot) ot->name = "Reveal Hidden"; ot->idname = "MESH_OT_reveal"; ot->description = "Reveal all hidden vertices, edges and faces"; - + /* api callbacks */ ot->exec = edbm_reveal_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; RNA_def_boolean(ot->srna, "select", true, "Select", ""); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Recalculate Normals Operator + * \{ */ + static int edbm_normals_make_consistent_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); - + /* doflip has to do with bmesh_rationalize_normals, it's an internal * thing */ if (!EDBM_op_callf(em, op, "recalc_face_normals faces=%hf", BM_ELEM_SELECT)) @@ -1716,18 +1819,22 @@ void MESH_OT_normals_make_consistent(wmOperatorType *ot) ot->name = "Make Normals Consistent"; ot->description = "Make face and vertex normals point either outside or inside the mesh"; ot->idname = "MESH_OT_normals_make_consistent"; - + /* api callbacks */ ot->exec = edbm_normals_make_consistent_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + RNA_def_boolean(ot->srna, "inside", false, "Inside", ""); } +/** \} */ +/* -------------------------------------------------------------------- */ +/** \name Smooth Vertex Operator + * \{ */ static int edbm_do_smooth_vertex_exec(bContext *C, wmOperator *op) { @@ -1751,12 +1858,12 @@ static int edbm_do_smooth_vertex_exec(bContext *C, wmOperator *op) } /* if there is a mirror modifier with clipping, flag the verts that - * are within tolerance of the plane(s) of reflection + * are within tolerance of the plane(s) of reflection */ for (md = obedit->modifiers.first; md; md = md->next) { if (md->type == eModifierType_Mirror && (md->mode & eModifierMode_Realtime)) { MirrorModifierData *mmd = (MirrorModifierData *)md; - + if (mmd->flag & MOD_MIR_CLIPPING) { if (mmd->flag & MOD_MIR_AXIS_X) mirrx = true; @@ -1775,10 +1882,11 @@ static int edbm_do_smooth_vertex_exec(bContext *C, wmOperator *op) repeat = 1; for (i = 0; i < repeat; i++) { - if (!EDBM_op_callf(em, op, - "smooth_vert verts=%hv factor=%f mirror_clip_x=%b mirror_clip_y=%b mirror_clip_z=%b " - "clip_dist=%f use_axis_x=%b use_axis_y=%b use_axis_z=%b", - BM_ELEM_SELECT, fac, mirrx, mirry, mirrz, clip_dist, xaxis, yaxis, zaxis)) + if (!EDBM_op_callf( + em, op, + "smooth_vert verts=%hv factor=%f mirror_clip_x=%b mirror_clip_y=%b mirror_clip_z=%b " + "clip_dist=%f use_axis_x=%b use_axis_y=%b use_axis_z=%b", + BM_ELEM_SELECT, fac, mirrx, mirry, mirrz, clip_dist, xaxis, yaxis, zaxis)) { return OPERATOR_CANCELLED; } @@ -1793,19 +1901,20 @@ static int edbm_do_smooth_vertex_exec(bContext *C, wmOperator *op) EDBM_update_generic(em, true, false); return OPERATOR_FINISHED; -} - +} + + void MESH_OT_vertices_smooth(wmOperatorType *ot) { /* identifiers */ ot->name = "Smooth Vertex"; ot->description = "Flatten angles of selected vertices"; ot->idname = "MESH_OT_vertices_smooth"; - + /* api callbacks */ ot->exec = edbm_do_smooth_vertex_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1819,6 +1928,12 @@ void MESH_OT_vertices_smooth(wmOperatorType *ot) RNA_def_boolean(ot->srna, "zaxis", true, "Z-Axis", "Smooth along the Z axis"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Laplacian Vertex Smooth Operator + * \{ */ + static int edbm_do_smooth_laplacian_vertex_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -1832,13 +1947,13 @@ static int edbm_do_smooth_laplacian_vertex_exec(bContext *C, wmOperator *op) BMIter fiter; BMFace *f; - /* Check if select faces are triangles */ + /* Check if select faces are triangles */ BM_ITER_MESH (f, &fiter, em->bm, BM_FACES_OF_MESH) { if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { if (f->len > 4) { BKE_report(op->reports, RPT_WARNING, "Selected faces must be triangles or quads"); return OPERATOR_CANCELLED; - } + } } } @@ -1856,11 +1971,12 @@ static int edbm_do_smooth_laplacian_vertex_exec(bContext *C, wmOperator *op) preserve_volume = RNA_boolean_get(op->ptr, "preserve_volume"); if (!repeat) repeat = 1; - + for (i = 0; i < repeat; i++) { - if (!EDBM_op_callf(em, op, - "smooth_laplacian_vert verts=%hv lambda_factor=%f lambda_border=%f use_x=%b use_y=%b use_z=%b preserve_volume=%b", - BM_ELEM_SELECT, lambda_factor, lambda_border, usex, usey, usez, preserve_volume)) + if (!EDBM_op_callf( + em, op, + "smooth_laplacian_vert verts=%hv lambda_factor=%f lambda_border=%f use_x=%b use_y=%b use_z=%b preserve_volume=%b", + BM_ELEM_SELECT, lambda_factor, lambda_border, usex, usey, usez, preserve_volume)) { return OPERATOR_CANCELLED; } @@ -1883,11 +1999,11 @@ void MESH_OT_vertices_smooth_laplacian(wmOperatorType *ot) ot->name = "Laplacian Smooth Vertex"; ot->description = "Laplacian smooth of selected vertices"; ot->idname = "MESH_OT_vertices_smooth_laplacian"; - + /* api callbacks */ ot->exec = edbm_do_smooth_laplacian_vertex_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1906,7 +2022,11 @@ void MESH_OT_vertices_smooth_laplacian(wmOperatorType *ot) RNA_def_boolean(ot->srna, "preserve_volume", true, "Preserve Volume", "Apply volume preservation after smooth"); } -/********************** Smooth/Solid Operators *************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Set Faces Smooth Shading Operator + * \{ */ static void mesh_set_smooth_faces(BMEditMesh *em, short smooth) { @@ -1914,7 +2034,7 @@ static void mesh_set_smooth_faces(BMEditMesh *em, short smooth) BMFace *efa; if (em == NULL) return; - + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { BM_elem_flag_set(efa, BM_ELEM_SMOOTH, smooth); @@ -1949,6 +2069,12 @@ void MESH_OT_faces_shade_smooth(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Set Faces Flat Shading Operator + * \{ */ + static int edbm_faces_shade_flat_exec(bContext *C, wmOperator *UNUSED(op)) { Object *obedit = CTX_data_edit_object(C); @@ -1976,8 +2102,11 @@ void MESH_OT_faces_shade_flat(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ -/********************** UV/Color Operators *************************/ +/* -------------------------------------------------------------------- */ +/** \name UV/Color Rotate/Reverse Operator + * \{ */ static int edbm_rotate_uvs_exec(bContext *C, wmOperator *op) { @@ -2147,6 +2276,11 @@ void MESH_OT_colors_reverse(wmOperatorType *ot) //RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror colors around"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Merge Vertices Operator + * \{ */ enum { MESH_MERGE_LAST = 1, @@ -2183,7 +2317,7 @@ static bool merge_firstlast(BMEditMesh *em, const bool use_first, const bool use if (!BM_elem_flag_test(mergevert, BM_ELEM_SELECT)) return false; - + if (use_uvmerge) { if (!EDBM_op_callf(em, wmop, "pointmerge_facedata verts=%hv vert_snap=%e", BM_ELEM_SELECT, mergevert)) return false; @@ -2195,8 +2329,9 @@ static bool merge_firstlast(BMEditMesh *em, const bool use_first, const bool use return true; } -static bool merge_target(BMEditMesh *em, Scene *scene, View3D *v3d, Object *ob, - const bool use_cursor, const bool use_uvmerge, wmOperator *wmop) +static bool merge_target( + BMEditMesh *em, Scene *scene, View3D *v3d, Object *ob, + const bool use_cursor, const bool use_uvmerge, wmOperator *wmop) { BMIter iter; BMVert *v; @@ -2217,7 +2352,7 @@ static bool merge_target(BMEditMesh *em, Scene *scene, View3D *v3d, Object *ob, add_v3_v3(cent, v->co); i++; } - + if (!i) return false; @@ -2229,7 +2364,7 @@ static bool merge_target(BMEditMesh *em, Scene *scene, View3D *v3d, Object *ob, if (!vco) return false; - + if (use_uvmerge) { if (!EDBM_op_callf(em, wmop, "average_vert_facedata verts=%hv", BM_ELEM_SELECT)) return false; @@ -2296,14 +2431,14 @@ static const EnumPropertyItem merge_type_items[] = { }; static const EnumPropertyItem *merge_type_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) -{ +{ Object *obedit; EnumPropertyItem *item = NULL; int totitem = 0; - + if (!C) /* needed for docs */ return merge_type_items; - + obedit = CTX_data_edit_object(C); if (obedit && obedit->type == OB_MESH) { BMEditMesh *em = BKE_editmesh_from_object(obedit); @@ -2333,7 +2468,7 @@ static const EnumPropertyItem *merge_type_itemf(bContext *C, PointerRNA *UNUSED( return item; } - + return NULL; } @@ -2361,6 +2496,11 @@ void MESH_OT_merge(wmOperatorType *ot) RNA_def_boolean(ot->srna, "uvs", false, "UVs", "Move UVs according to merge"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Remove Doubles Operator + * \{ */ static int edbm_remove_doubles_exec(bContext *C, wmOperator *op) { @@ -2383,9 +2523,10 @@ static int edbm_remove_doubles_exec(bContext *C, wmOperator *op) if (use_unselected) { - EDBM_op_init(em, &bmop, op, - "automerge verts=%hv dist=%f", - BM_ELEM_SELECT, threshold); + EDBM_op_init( + em, &bmop, op, + "automerge verts=%hv dist=%f", + BM_ELEM_SELECT, threshold); BMO_op_exec(em->bm, &bmop); if (!EDBM_op_finish(em, &bmop, op, true)) { @@ -2393,9 +2534,10 @@ static int edbm_remove_doubles_exec(bContext *C, wmOperator *op) } } else { - EDBM_op_init(em, &bmop, op, - "find_doubles verts=%hv dist=%f", - BM_ELEM_SELECT, threshold); + EDBM_op_init( + em, &bmop, op, + "find_doubles verts=%hv dist=%f", + BM_ELEM_SELECT, threshold); BMO_op_exec(em->bm, &bmop); if (!EDBM_op_callf(em, op, "weld_verts targetmap=%S", &bmop, "targetmap.out")) { @@ -2407,7 +2549,7 @@ static int edbm_remove_doubles_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } } - + count = totvert_orig - em->bm->totvert; BKE_reportf(op->reports, RPT_INFO, "Removed %d vertices", count); @@ -2439,8 +2581,11 @@ void MESH_OT_remove_doubles(wmOperatorType *ot) RNA_def_boolean(ot->srna, "use_unselected", false, "Unselected", "Merge selected to other unselected vertices"); } +/** \} */ -/************************ Shape Operators *************************/ +/* -------------------------------------------------------------------- */ +/** \name Shape Key Propagate Operator + * \{ */ /* BMESH_TODO this should be properly encapsulated in a bmop. but later.*/ static void shape_propagate(BMEditMesh *em, wmOperator *op) @@ -2454,7 +2599,7 @@ static void shape_propagate(BMEditMesh *em, wmOperator *op) BKE_report(op->reports, RPT_ERROR, "Mesh does not have shape keys"); return; } - + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { if (!BM_elem_flag_test(eve, BM_ELEM_SELECT) || BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) continue; @@ -2505,6 +2650,12 @@ void MESH_OT_shape_propagate_to_all(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Blend from Shape Operator + * \{ */ + /* BMESH_TODO this should be properly encapsulated in a bmop. but later.*/ static int edbm_blend_from_shape_exec(bContext *C, wmOperator *op) { @@ -2531,23 +2682,23 @@ static int edbm_blend_from_shape_exec(bContext *C, wmOperator *op) if (key) { kb = BLI_findlink(&key->block, shape); } - + /* perform blending on selected vertices*/ BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { if (!BM_elem_flag_test(eve, BM_ELEM_SELECT) || BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) continue; - + /* get coordinates of shapekey we're blending from */ sco = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, shape); copy_v3_v3(co, sco); - + if (use_add) { /* in add mode, we add relative shape key offset */ if (kb) { const float *rco = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, kb->relative); sub_v3_v3v3(co, co, rco); } - + madd_v3_v3fl(eve->co, co, blend); } else { @@ -2562,7 +2713,7 @@ static int edbm_blend_from_shape_exec(bContext *C, wmOperator *op) } static const EnumPropertyItem *shape_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) -{ +{ Object *obedit = CTX_data_edit_object(C); BMEditMesh *em; EnumPropertyItem *item = NULL; @@ -2635,6 +2786,12 @@ void MESH_OT_blend_from_shape(wmOperatorType *ot) RNA_def_boolean(ot->srna, "add", true, "Add", "Add rather than blend between shapes"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Solidify Mesh Operator + * \{ */ + static int edbm_solidify_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -2689,6 +2846,12 @@ void MESH_OT_solidify(wmOperatorType *ot) RNA_def_property_ui_range(prop, -10.0, 10.0, 0.1, 4); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Knife Subdivide Operator + * \{ */ + /* ******************************************************************** */ /* Knife Subdivide Tool. Subdivides edges intersected by a mouse trail * drawn by user. @@ -2722,8 +2885,9 @@ static const EnumPropertyItem knife_items[] = { /* bm_edge_seg_isect() Determines if and where a mouse trail intersects an BMEdge */ -static float bm_edge_seg_isect(const float sco_a[2], const float sco_b[2], - float (*mouse_path)[2], int len, char mode, int *isected) +static float bm_edge_seg_isect( + const float sco_a[2], const float sco_b[2], + float (*mouse_path)[2], int len, char mode, int *isected) { #define MAXSLOPE 100000 float x11, y11, x12 = 0, y12 = 0, x2max, x2min, y2max; @@ -2732,17 +2896,17 @@ static float bm_edge_seg_isect(const float sco_a[2], const float sco_b[2], float yi, x1min, x1max, y1max, y1min, perc = 0; float threshold = 0.0; int i; - + //threshold = 0.000001; /* tolerance for vertex intersection */ // XXX threshold = scene->toolsettings->select_thresh / 100; - + /* Get screen coords of verts */ x21 = sco_a[0]; y21 = sco_a[1]; - + x22 = sco_b[0]; y22 = sco_b[1]; - + xdiff2 = (x22 - x21); if (xdiff2) { m2 = (y22 - y21) / xdiff2; @@ -2768,7 +2932,7 @@ static float bm_edge_seg_isect(const float sco_a[2], const float sco_b[2], } x12 = mouse_path[i][0]; y12 = mouse_path[i][1]; - + /* test e->v1 */ if ((x11 == x21 && y11 == y21) || (x12 == x21 && y12 == y21)) { perc = 0; @@ -2783,7 +2947,7 @@ static float bm_edge_seg_isect(const float sco_a[2], const float sco_b[2], } } } - + /* now check for edge intersect (may produce vertex intersection as well) */ for (i = 0; i < len; i++) { if (i > 0) { @@ -2796,14 +2960,14 @@ static float bm_edge_seg_isect(const float sco_a[2], const float sco_b[2], } x12 = mouse_path[i][0]; y12 = mouse_path[i][1]; - + /* Perp. Distance from point to line */ if (m2 != MAXSLOPE) dist = (y12 - m2 * x12 - b2); /* /sqrt(m2 * m2 + 1); Only looking for */ /* change in sign. Skip extra math */ else dist = x22 - x12; - + if (i == 0) lastdist = dist; - + /* if dist changes sign, and intersect point in edge's Bound Box */ if ((lastdist * dist) <= 0) { xdiff1 = (x12 - x11); /* Equation of line between last 2 points */ @@ -2819,14 +2983,14 @@ static float bm_edge_seg_isect(const float sco_a[2], const float sco_b[2], x2min = min_ff(x21, x22) - 0.001f; /* due to round off error */ y2max = max_ff(y21, y22) + 0.001f; y2min = min_ff(y21, y22) - 0.001f; - + /* Found an intersect, calc intersect point */ if (m1 == m2) { /* co-incident lines */ /* cut at 50% of overlap area */ x1max = max_ff(x11, x12); x1min = min_ff(x11, x12); xi = (min_ff(x2max, x1max) + max_ff(x2min, x1min)) / 2.0f; - + y1max = max_ff(y11, y12); y1min = min_ff(y11, y12); yi = (min_ff(y2max, y1max) + max_ff(y2min, y1min)) / 2.0f; @@ -2843,7 +3007,7 @@ static float bm_edge_seg_isect(const float sco_a[2], const float sco_b[2], xi = (b1 - b2) / (m2 - m1); yi = (b1 * m2 - m1 * b2) / (m2 - m1); } - + /* Intersect inside bounding box of edge?*/ if ((xi >= x2min) && (xi <= x2max) && (yi <= y2max) && (yi >= y2min)) { /* test for vertex intersect that may be 'close enough'*/ @@ -2866,7 +3030,7 @@ static float bm_edge_seg_isect(const float sco_a[2], const float sco_b[2], if ((m2 <= 1.0f) && (m2 >= -1.0f)) perc = (xi - x21) / (x22 - x21); else perc = (yi - y21) / (y22 - y21); /* lower slope more accurate */ //isect = 32768.0 * (perc + 0.0000153); /* Percentage in 1 / 32768ths */ - + break; } } @@ -2895,11 +3059,11 @@ static int edbm_knife_cut_exec(bContext *C, wmOperator *op) /* allocd vars */ float (*screen_vert_coords)[2], (*sco)[2], (*mouse_path)[2]; - + /* edit-object needed for matrix, and ar->regiondata for projections to work */ if (ELEM(NULL, obedit, ar, ar->regiondata)) return OPERATOR_CANCELLED; - + if (bm->totvertsel < 2) { BKE_report(op->reports, RPT_ERROR, "No edges are selected to operate on"); return OPERATOR_CANCELLED; @@ -2984,7 +3148,7 @@ static int edbm_knife_cut_exec(bContext *C, wmOperator *op) BMO_slot_bool_set(bmop.slots_in, "use_grid_fill", false); BMO_slot_float_set(bmop.slots_in, "radius", 0); - + BMO_op_exec(bm, &bmop); if (!EDBM_op_finish(em, &bmop, op, true)) { return OPERATOR_CANCELLED; @@ -3002,13 +3166,13 @@ void MESH_OT_knife_cut(wmOperatorType *ot) ot->name = "Knife Cut"; ot->description = "Cut selected edges and faces into parts"; ot->idname = "MESH_OT_knife_cut"; - + ot->invoke = WM_gesture_lines_invoke; ot->modal = WM_gesture_lines_modal; ot->exec = edbm_knife_cut_exec; - + ot->poll = EDBM_view3d_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -3018,13 +3182,16 @@ void MESH_OT_knife_cut(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); RNA_def_enum(ot->srna, "type", knife_items, KNIFE_EXACT, "Type", ""); - + /* internal */ RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, BC_NUMCURSORS, "Cursor", "", 0, BC_NUMCURSORS); } +/** \} */ -/* *************** Operator: separate parts *************/ +/* -------------------------------------------------------------------- */ +/** \name Separate Parts Operator + * \{ */ enum { MESH_SEPARATE_SELECTED = 0, @@ -3075,7 +3242,7 @@ static Base *mesh_separate_tagged(Main *bmain, Scene *scene, ViewLayer *view_lay BM_mesh_free(bm_new); ((Mesh *)base_new->object->data)->edit_btmesh = NULL; - + return base_new; } @@ -3304,7 +3471,7 @@ static int edbm_separate_exec(bContext *C, wmOperator *op) ViewLayer *view_layer = CTX_data_view_layer(C); const int type = RNA_enum_get(op->ptr, "type"); int retval = 0; - + if (ED_operator_editmesh(C)) { Base *base = CTX_data_active_base(C); BMEditMesh *em = BKE_editmesh_from_object(base->object); @@ -3374,7 +3541,11 @@ static int edbm_separate_exec(bContext *C, wmOperator *op) } if (retval_iter) { - BM_mesh_bm_to_me(bm_old, me, (&(struct BMeshToMeshParams){0})); + BM_mesh_bm_to_me( + bm_old, me, + (&(struct BMeshToMeshParams){ + .calc_object_remap = true, + })); DEG_id_tag_update(&me->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); @@ -3413,18 +3584,23 @@ void MESH_OT_separate(wmOperatorType *ot) ot->name = "Separate"; ot->description = "Separate selected geometry into a new mesh"; ot->idname = "MESH_OT_separate"; - + /* api callbacks */ ot->invoke = WM_menu_invoke; ot->exec = edbm_separate_exec; ot->poll = ED_operator_scene_editable; /* object and editmode */ - + /* flags */ ot->flag = OPTYPE_UNDO; - + ot->prop = RNA_def_enum(ot->srna, "type", prop_separate_types, MESH_SEPARATE_SELECTED, "Type", ""); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Triangle Fill Operator + * \{ */ static int edbm_fill_exec(bContext *C, wmOperator *op) { @@ -3446,9 +3622,9 @@ static int edbm_fill_exec(bContext *C, wmOperator *op) { return OPERATOR_CANCELLED; } - + BMO_op_exec(em->bm, &bmop); - + if (totface_orig != em->bm->totface) { /* select new geometry */ BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_FACE | BM_EDGE, BM_ELEM_SELECT, true); @@ -3486,9 +3662,11 @@ void MESH_OT_fill(wmOperatorType *ot) RNA_def_boolean(ot->srna, "use_beauty", true, "Beauty", "Use best triangulation division"); } +/** \} */ /* -------------------------------------------------------------------- */ -/* Grid Fill (and helper functions) */ +/** \name Grid Fill Operator + * \{ */ static bool bm_edge_test_fill_grid_cb(BMEdge *e, void *UNUSED(bm_v)) { @@ -3584,7 +3762,7 @@ static void edbm_fill_grid_prepare(BMesh *bm, int offset, int *r_span, bool span * * note: we may have already checked 'edbm_fill_grid_vert_tag_angle()' on each * vert, but advantage of de-duplicating is minimal. */ - struct SortPointerByFloat *ele_sort = MEM_mallocN(sizeof(*ele_sort) * verts_len, __func__); + struct SortPtrByFloat *ele_sort = MEM_mallocN(sizeof(*ele_sort) * verts_len, __func__); LinkData *v_link; for (v_link = verts->first, i = 0; v_link; v_link = v_link->next, i++) { BMVert *v = v_link->data; @@ -3679,10 +3857,11 @@ static int edbm_fill_grid_exec(bContext *C, wmOperator *op) /* end tricky prepare code */ - if (!EDBM_op_init(em, &bmop, op, - "grid_fill edges=%he mat_nr=%i use_smooth=%b use_interp_simple=%b", - use_prepare ? BM_ELEM_TAG : BM_ELEM_SELECT, - em->mat_nr, use_smooth, use_interp_simple)) + if (!EDBM_op_init( + em, &bmop, op, + "grid_fill edges=%he mat_nr=%i use_smooth=%b use_interp_simple=%b", + use_prepare ? BM_ELEM_TAG : BM_ELEM_SELECT, + em->mat_nr, use_smooth, use_interp_simple)) { return OPERATOR_CANCELLED; } @@ -3732,6 +3911,12 @@ void MESH_OT_fill_grid(wmOperatorType *ot) RNA_def_boolean(ot->srna, "use_interp_simple", false, "Simple Blending", ""); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Hole Fill Operator + * \{ */ + static int edbm_fill_holes_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -3771,6 +3956,12 @@ void MESH_OT_fill_holes(wmOperatorType *ot) "Sides", "Number of sides in hole required to fill (zero fills all holes)", 0, 100); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Beauty Fill Operator + * \{ */ + static int edbm_beautify_fill_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -3788,9 +3979,10 @@ static int edbm_beautify_fill_exec(bContext *C, wmOperator *op) BMEdge *e; BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { - BM_elem_flag_set(e, BM_ELEM_TAG, - (BM_elem_flag_test(e, BM_ELEM_SELECT) && - BM_edge_calc_face_angle_ex(e, angle_max) < angle_limit)); + BM_elem_flag_set( + e, BM_ELEM_TAG, + (BM_elem_flag_test(e, BM_ELEM_SELECT) && + BM_edge_calc_face_angle_ex(e, angle_max) < angle_limit)); } @@ -3806,7 +3998,7 @@ static int edbm_beautify_fill_exec(bContext *C, wmOperator *op) } EDBM_update_generic(em, true, true); - + return OPERATOR_FINISHED; } @@ -3832,8 +4024,11 @@ void MESH_OT_beautify_fill(wmOperatorType *ot) RNA_def_property_float_default(prop, DEG2RADF(180.0f)); } +/** \} */ -/********************** Poke Face **********************/ +/* -------------------------------------------------------------------- */ +/** \name Poke Face Operator + * \{ */ static int edbm_poke_face_exec(bContext *C, wmOperator *op) { @@ -3893,7 +4088,11 @@ void MESH_OT_poke(wmOperatorType *ot) "Poke Center", "Poke Face Center Calculation"); } -/********************** Quad/Tri Operators *************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Triangulate Face Operator + * \{ */ static int edbm_quads_convert_to_tris_exec(bContext *C, wmOperator *op) { @@ -3948,6 +4147,12 @@ void MESH_OT_quads_convert_to_tris(wmOperatorType *ot) "Polygon Method", "Method for splitting the polygons into triangles"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Convert to Quads Operator + * \{ */ + static int edbm_tris_convert_to_quads_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -4038,10 +4243,10 @@ void MESH_OT_tris_convert_to_quads(wmOperatorType *ot) join_triangle_props(ot); } +/** \} */ /* -------------------------------------------------------------------- */ - -/** \name Decimate +/** \name Decimate Operator * * \note The function to decimate is intended for use as a modifier, * while its handy allow access as a tool - this does cause access to be a little awkward @@ -4227,9 +4432,9 @@ void MESH_OT_decimate(wmOperatorType *ot) /** \} */ - /* -------------------------------------------------------------------- */ -/* Dissolve */ +/** \name Dissolve Vertices Operator + * \{ */ static void edbm_dissolve_prop__use_verts(wmOperatorType *ot, bool value, int flag) { @@ -4261,9 +4466,10 @@ static int edbm_dissolve_verts_exec(bContext *C, wmOperator *op) const bool use_face_split = RNA_boolean_get(op->ptr, "use_face_split"); const bool use_boundary_tear = RNA_boolean_get(op->ptr, "use_boundary_tear"); - if (!EDBM_op_callf(em, op, - "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b", - BM_ELEM_SELECT, use_face_split, use_boundary_tear)) + if (!EDBM_op_callf( + em, op, + "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b", + BM_ELEM_SELECT, use_face_split, use_boundary_tear)) { return OPERATOR_CANCELLED; } @@ -4291,6 +4497,12 @@ void MESH_OT_dissolve_verts(wmOperatorType *ot) edbm_dissolve_prop__use_boundary_tear(ot); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Dissolve Edges Operator + * \{ */ + static int edbm_dissolve_edges_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -4299,9 +4511,10 @@ static int edbm_dissolve_edges_exec(bContext *C, wmOperator *op) const bool use_verts = RNA_boolean_get(op->ptr, "use_verts"); const bool use_face_split = RNA_boolean_get(op->ptr, "use_face_split"); - if (!EDBM_op_callf(em, op, - "dissolve_edges edges=%he use_verts=%b use_face_split=%b", - BM_ELEM_SELECT, use_verts, use_face_split)) + if (!EDBM_op_callf( + em, op, + "dissolve_edges edges=%he use_verts=%b use_face_split=%b", + BM_ELEM_SELECT, use_verts, use_face_split)) { return OPERATOR_CANCELLED; } @@ -4329,6 +4542,12 @@ void MESH_OT_dissolve_edges(wmOperatorType *ot) edbm_dissolve_prop__use_face_split(ot); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Dissolve Faces Operator + * \{ */ + static int edbm_dissolve_faces_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -4367,6 +4586,11 @@ void MESH_OT_dissolve_faces(wmOperatorType *ot) edbm_dissolve_prop__use_verts(ot, false, 0); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Dissolve (Context Sensitive) Operator + * \{ */ static int edbm_dissolve_mode_exec(bContext *C, wmOperator *op) { @@ -4412,6 +4636,12 @@ void MESH_OT_dissolve_mode(wmOperatorType *ot) edbm_dissolve_prop__use_boundary_tear(ot); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Limited Dissolve Operator + * \{ */ + static int edbm_dissolve_limited_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -4489,6 +4719,12 @@ void MESH_OT_dissolve_limited(wmOperatorType *ot) "Delimit dissolve operation"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Degenerate Dissolve Operator + * \{ */ + static int edbm_dissolve_degenerate_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -4533,6 +4769,11 @@ void MESH_OT_dissolve_degenerate(wmOperatorType *ot) "Minimum distance between elements to merge", 1e-5f, 10.0f); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Delete Edge-Loop Operator + * \{ */ /* internally uses dissolve */ static int edbm_delete_edgeloop_exec(bContext *C, wmOperator *op) @@ -4559,9 +4800,10 @@ static int edbm_delete_edgeloop_exec(bContext *C, wmOperator *op) } } - if (!EDBM_op_callf(em, op, - "dissolve_edges edges=%he use_verts=%b use_face_split=%b", - BM_ELEM_SELECT, true, use_face_split)) + if (!EDBM_op_callf( + em, op, + "dissolve_edges edges=%he use_verts=%b use_face_split=%b", + BM_ELEM_SELECT, true, use_face_split)) { return OPERATOR_CANCELLED; } @@ -4593,6 +4835,12 @@ void MESH_OT_delete_edgeloop(wmOperatorType *ot) "Split off face corners to maintain surrounding geometry"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Split Geometry Operator + * \{ */ + static int edbm_split_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_edit_object(C); @@ -4630,16 +4878,21 @@ void MESH_OT_split(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/****************************************************************************** - * qsort routines. - * Now unified, for vertices/edges/faces. */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sort Geometry Elements Operator + * + * Unified for vertices/edges/faces. + * + * \{ */ enum { SRT_VIEW_ZAXIS = 1, /* Use view Z (deep) axis. */ SRT_VIEW_XAXIS, /* Use view X (left to right) axis. */ SRT_CURSOR_DISTANCE, /* Use distance from element to 3D cursor. */ SRT_MATERIAL, /* Face only: use mat number. */ - SRT_SELECTED, /* Move selected elements in first, without modifying + SRT_SELECTED, /* Move selected elements in first, without modifying * relative order of selected and unselected elements. */ SRT_RANDOMIZE, /* Randomize selected elements. */ SRT_REVERSE, /* Reverse current order of selected elements. */ @@ -4658,10 +4911,11 @@ static int bmelemsort_comp(const void *v1, const void *v2) } /* Reorders vertices/edges/faces using a given methods. Loops are not supported. */ -static void sort_bmelem_flag(Scene *scene, Object *ob, - View3D *v3d, RegionView3D *rv3d, - const int types, const int flag, const int action, - const int reverse, const unsigned int seed) +static void sort_bmelem_flag( + Scene *scene, Object *ob, + View3D *v3d, RegionView3D *rv3d, + const int types, const int flag, const int action, + const int reverse, const unsigned int seed) { BMEditMesh *em = BKE_editmesh_from_object(ob); @@ -5127,8 +5381,9 @@ static int edbm_sort_elements_exec(bContext *C, wmOperator *op) RNA_enum_set(op->ptr, "elements", elem_types); } - sort_bmelem_flag(scene, ob, v3d, rv3d, - elem_types, BM_ELEM_SELECT, action, use_reverse, seed); + sort_bmelem_flag( + scene, ob, v3d, rv3d, + elem_types, BM_ELEM_SELECT, action, use_reverse, seed); return OPERATOR_FINISHED; } @@ -5217,7 +5472,11 @@ void MESH_OT_sort_elements(wmOperatorType *ot) RNA_def_int(ot->srna, "seed", 0, 0, INT_MAX, "Seed", "Seed for random-based operations", 0, 255); } -/****** end of qsort stuff ****/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Noise (Deform Vertices) Operator + * \{ */ static int edbm_noise_exec(bContext *C, wmOperator *op) { @@ -5250,7 +5509,7 @@ static int edbm_noise_exec(bContext *C, wmOperator *op) vec[0] = fac * (b2 - BLI_hnoise(tex->noisesize, eve->co[0] + ofs, eve->co[1], eve->co[2])); vec[1] = fac * (b2 - BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1] + ofs, eve->co[2])); vec[2] = fac * (b2 - BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2] + ofs)); - + add_v3_v3(eve->co, vec); } } @@ -5291,6 +5550,11 @@ void MESH_OT_noise(wmOperatorType *ot) RNA_def_float(ot->srna, "factor", 0.1f, -1e4f, 1e4f, "Factor", "", 0.0f, 1.0f); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Bridge Operator + * \{ */ enum { MESH_BRIDGELOOP_SINGLE = 0, @@ -5377,9 +5641,10 @@ static int edbm_bridge_edge_loops_exec(bContext *C, wmOperator *op) edge_hflag = BM_ELEM_SELECT; } - EDBM_op_init(em, &bmop, op, - "bridge_loops edges=%he use_pairs=%b use_cyclic=%b use_merge=%b merge_factor=%f twist_offset=%i", - edge_hflag, use_pairs, use_cyclic, use_merge, merge_factor, twist_offset); + EDBM_op_init( + em, &bmop, op, + "bridge_loops edges=%he use_pairs=%b use_cyclic=%b use_merge=%b merge_factor=%f twist_offset=%i", + edge_hflag, use_pairs, use_cyclic, use_merge, merge_factor, twist_offset); if (use_faces && totface_del) { int i; @@ -5387,9 +5652,10 @@ static int edbm_bridge_edge_loops_exec(bContext *C, wmOperator *op) for (i = 0; i < totface_del; i++) { BM_elem_flag_enable(totface_del_arr[i], BM_ELEM_TAG); } - BMO_op_callf(em->bm, BMO_FLAG_DEFAULTS, - "delete geom=%hf context=%i", - BM_ELEM_TAG, DEL_FACES_KEEP_BOUNDARY); + BMO_op_callf( + em->bm, BMO_FLAG_DEFAULTS, + "delete geom=%hf context=%i", + BM_ELEM_TAG, DEL_FACES_KEEP_BOUNDARY); } BMO_op_exec(em->bm, &bmop); @@ -5455,11 +5721,11 @@ void MESH_OT_bridge_edge_loops(wmOperatorType *ot) ot->name = "Bridge Edge Loops"; ot->description = "Make faces between two or more edge loops"; ot->idname = "MESH_OT_bridge_edge_loops"; - + /* api callbacks */ ot->exec = edbm_bridge_edge_loops_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -5473,6 +5739,12 @@ void MESH_OT_bridge_edge_loops(wmOperatorType *ot) mesh_operator_edgering_props(ot, 0, 0); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Wire-Frame Operator + * \{ */ + static int edbm_wireframe_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -5487,11 +5759,12 @@ static int edbm_wireframe_exec(bContext *C, wmOperator *op) const float thickness = RNA_float_get(op->ptr, "thickness"); const float offset = RNA_float_get(op->ptr, "offset"); - EDBM_op_init(em, &bmop, op, - "wireframe faces=%hf use_replace=%b use_boundary=%b use_even_offset=%b use_relative_offset=%b " - "use_crease=%b crease_weight=%f thickness=%f offset=%f", - BM_ELEM_SELECT, use_replace, use_boundary, use_even_offset, use_relative_offset, - use_crease, crease_weight, thickness, offset); + EDBM_op_init( + em, &bmop, op, + "wireframe faces=%hf use_replace=%b use_boundary=%b use_even_offset=%b use_relative_offset=%b " + "use_crease=%b crease_weight=%f thickness=%f offset=%f", + BM_ELEM_SELECT, use_replace, use_boundary, use_even_offset, use_relative_offset, + use_crease, crease_weight, thickness, offset); BMO_op_exec(em->bm, &bmop); @@ -5537,6 +5810,12 @@ void MESH_OT_wireframe(wmOperatorType *ot) RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 2); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Offset Edge-Loop Operator + * \{ */ + static int edbm_offset_edgeloop_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -5591,6 +5870,12 @@ void MESH_OT_offset_edge_loops(wmOperatorType *ot) RNA_def_boolean(ot->srna, "use_cap_endpoint", false, "Cap Endpoint", "Extend loop around end-points"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Convex Hull Operator + * \{ */ + #ifdef WITH_BULLET static int edbm_convex_hull_exec(bContext *C, wmOperator *op) { @@ -5598,10 +5883,11 @@ static int edbm_convex_hull_exec(bContext *C, wmOperator *op) BMEditMesh *em = BKE_editmesh_from_object(obedit); BMOperator bmop; - EDBM_op_init(em, &bmop, op, "convex_hull input=%hvef " - "use_existing_faces=%b", - BM_ELEM_SELECT, - RNA_boolean_get(op->ptr, "use_existing_faces")); + EDBM_op_init( + em, &bmop, op, "convex_hull input=%hvef " + "use_existing_faces=%b", + BM_ELEM_SELECT, + RNA_boolean_get(op->ptr, "use_existing_faces")); BMO_op_exec(em->bm, &bmop); /* Hull fails if input is coplanar */ @@ -5614,8 +5900,9 @@ static int edbm_convex_hull_exec(bContext *C, wmOperator *op) /* Delete unused vertices, edges, and faces */ if (RNA_boolean_get(op->ptr, "delete_unused")) { - if (!EDBM_op_callf(em, op, "delete geom=%S context=%i", - &bmop, "geom_unused.out", DEL_ONLYTAGGED)) + if (!EDBM_op_callf( + em, op, "delete geom=%S context=%i", + &bmop, "geom_unused.out", DEL_ONLYTAGGED)) { EDBM_op_finish(em, &bmop, op, true); return OPERATOR_CANCELLED; @@ -5624,8 +5911,9 @@ static int edbm_convex_hull_exec(bContext *C, wmOperator *op) /* Delete hole edges/faces */ if (RNA_boolean_get(op->ptr, "make_holes")) { - if (!EDBM_op_callf(em, op, "delete geom=%S context=%i", - &bmop, "geom_holes.out", DEL_ONLYTAGGED)) + if (!EDBM_op_callf( + em, op, "delete geom=%S context=%i", + &bmop, "geom_holes.out", DEL_ONLYTAGGED)) { EDBM_op_finish(em, &bmop, op, true); return OPERATOR_CANCELLED; @@ -5693,7 +5981,13 @@ void MESH_OT_convex_hull(wmOperatorType *ot) join_triangle_props(ot); } -#endif +#endif /* WITH_BULLET */ + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Symmetrize Operator + * \{ */ static int mesh_symmetrize_exec(bContext *C, wmOperator *op) { @@ -5703,9 +5997,10 @@ static int mesh_symmetrize_exec(bContext *C, wmOperator *op) const float thresh = RNA_float_get(op->ptr, "threshold"); - EDBM_op_init(em, &bmop, op, - "symmetrize input=%hvef direction=%i dist=%f", - BM_ELEM_SELECT, RNA_enum_get(op->ptr, "direction"), thresh); + EDBM_op_init( + em, &bmop, op, + "symmetrize input=%hvef direction=%i dist=%f", + BM_ELEM_SELECT, RNA_enum_get(op->ptr, "direction"), thresh); BMO_op_exec(em->bm, &bmop); EDBM_flag_disable_all(em, BM_ELEM_SELECT); @@ -5736,12 +6031,19 @@ void MESH_OT_symmetrize(struct wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - ot->prop = RNA_def_enum(ot->srna, "direction", rna_enum_symmetrize_direction_items, - BMO_SYMMETRIZE_NEGATIVE_X, - "Direction", "Which sides to copy from and to"); + ot->prop = RNA_def_enum( + ot->srna, "direction", rna_enum_symmetrize_direction_items, + BMO_SYMMETRIZE_NEGATIVE_X, + "Direction", "Which sides to copy from and to"); RNA_def_float(ot->srna, "threshold", 1e-4f, 0.0f, 10.0f, "Threshold", "", 1e-5f, 0.1f); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Snap to Symmetry Operator + * \{ */ + static int mesh_symmetry_snap_exec(bContext *C, wmOperator *op) { const float eps = 0.00001f; @@ -5860,16 +6162,23 @@ void MESH_OT_symmetry_snap(struct wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - ot->prop = RNA_def_enum(ot->srna, "direction", rna_enum_symmetrize_direction_items, - BMO_SYMMETRIZE_NEGATIVE_X, - "Direction", "Which sides to copy from and to"); + ot->prop = RNA_def_enum( + ot->srna, "direction", rna_enum_symmetrize_direction_items, + BMO_SYMMETRIZE_NEGATIVE_X, + "Direction", "Which sides to copy from and to"); RNA_def_float_distance(ot->srna, "threshold", 0.05f, 0.0f, 10.0f, "Threshold", "", 1e-4f, 1.0f); RNA_def_float(ot->srna, "factor", 0.5f, 0.0f, 1.0f, "Factor", "", 0.0f, 1.0f); RNA_def_boolean(ot->srna, "use_center", true, "Center", "Snap mid verts to the axis center"); } +/** \} */ + #ifdef WITH_FREESTYLE +/* -------------------------------------------------------------------- */ +/** \name Mark Edge (FreeStyle) Operator + * \{ */ + static int edbm_mark_freestyle_edge_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -5935,6 +6244,12 @@ void MESH_OT_mark_freestyle_edge(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mark Face (FreeStyle) Operator + * \{ */ + static int edbm_mark_freestyle_face_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -5999,4 +6314,6 @@ void MESH_OT_mark_freestyle_face(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -#endif +/** \} */ + +#endif /* WITH_FREESTYLE */ diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c index 534ca22178e..ab7e13117a0 100644 --- a/source/blender/editors/mesh/editmesh_undo.c +++ b/source/blender/editors/mesh/editmesh_undo.c @@ -29,16 +29,25 @@ #include "DNA_key_types.h" #include "BLI_listbase.h" +#include "BLI_array_utils.h" +#include "BLI_alloca.h" #include "BKE_DerivedMesh.h" #include "BKE_context.h" #include "BKE_key.h" #include "BKE_mesh.h" #include "BKE_editmesh.h" +#include "BKE_undo_system.h" +#include "DEG_depsgraph.h" + +#include "ED_object.h" #include "ED_mesh.h" #include "ED_util.h" +#include "WM_types.h" +#include "WM_api.h" + #define USE_ARRAY_STORE #ifdef USE_ARRAY_STORE @@ -60,6 +69,9 @@ # include "BLI_task.h" #endif +/* -------------------------------------------------------------------- */ +/** \name Undo Conversion + * \{ */ #ifdef USE_ARRAY_STORE @@ -95,6 +107,8 @@ typedef struct UndoMesh { BArrayState *mselect; } store; #endif /* USE_ARRAY_STORE */ + + size_t undo_size; } UndoMesh; @@ -247,7 +261,7 @@ static void um_arraystore_cd_free(BArrayCustomData *bcd) BArrayCustomData *bcd_next = bcd->next; const int stride = CustomData_sizeof(bcd->type); BArrayStore *bs = BLI_array_store_at_size_get(&um_arraystore.bs_stride, stride); - for (int i = 0; i < bcd->states_len; i++) { + for (int i = 0; i < bcd->states_len; i++) { if (bcd->states[i]) { BLI_array_store_state_remove(bs, bcd->states[i]); } @@ -474,28 +488,24 @@ static void um_arraystore_free(UndoMesh *um) /* for callbacks */ /* undo simply makes copies of a bmesh */ -static void *editbtMesh_to_undoMesh(void *emv, void *obdata) +static void *undomesh_from_editmesh(UndoMesh *um, BMEditMesh *em, Key *key) { - + BLI_assert(BLI_array_is_zeroed(um, 1)); #ifdef USE_ARRAY_STORE_THREAD /* changes this waits is low, but must have finished */ if (um_arraystore.task_pool) { BLI_task_pool_work_and_wait(um_arraystore.task_pool); } #endif - - BMEditMesh *em = emv; - Mesh *obme = obdata; - - UndoMesh *um = MEM_callocN(sizeof(UndoMesh), "undo Mesh"); - /* make sure shape keys work */ - um->me.key = obme->key ? BKE_key_copy_nolib(obme->key) : NULL; + um->me.key = key ? BKE_key_copy_nolib(key) : NULL; /* BM_mesh_validate(em->bm); */ /* for troubleshooting */ BM_mesh_bm_to_me( em->bm, &um->me, (&(struct BMeshToMeshParams){ + /* Undo code should not be manipulating 'G.main->object' hooks/vertex-parent. */ + .calc_object_remap = false, .cd_mask_extra = CD_MASK_SHAPE_KEYINDEX, })); @@ -534,13 +544,12 @@ static void *editbtMesh_to_undoMesh(void *emv, void *obdata) return um; } -static void undoMesh_to_editbtMesh(void *um_v, void *em_v, void *obdata) +static void undomesh_to_editmesh(UndoMesh *um, BMEditMesh *em, Mesh *obmesh) { - BMEditMesh *em = em_v, *em_tmp; + BMEditMesh *em_tmp; Object *ob = em->ob; - UndoMesh *um = um_v; BMesh *bm; - Key *key = ((Mesh *) obdata)->key; + Key *key = obmesh->key; #ifdef USE_ARRAY_STORE #ifdef USE_ARRAY_STORE_THREAD @@ -613,9 +622,8 @@ static void undoMesh_to_editbtMesh(void *um_v, void *em_v, void *obdata) #endif } -static void free_undo(void *um_v) +static void undomesh_free_data(UndoMesh *um) { - UndoMesh *um = um_v; Mesh *me = &um->me; #ifdef USE_ARRAY_STORE @@ -642,28 +650,101 @@ static void free_undo(void *um_v) } BKE_mesh_free(me); - MEM_freeN(me); } -static void *getEditMesh(bContext *C) +static Object *editmesh_object_from_context(bContext *C) { Object *obedit = CTX_data_edit_object(C); if (obedit && obedit->type == OB_MESH) { Mesh *me = obedit->data; - return me->edit_btmesh; + if (me->edit_btmesh != NULL) { + return obedit; + } } return NULL; } -/* and this is all the undo system needs to know */ -void undo_push_mesh(bContext *C, const char *name) +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Implements ED Undo System + * \{ */ + +typedef struct MeshUndoStep { + UndoStep step; + /* Use for all ID lookups (can be NULL). */ + struct UndoIDPtrMap *id_map; + + /* note: will split out into list for multi-object-editmode. */ + UndoRefID_Object obedit_ref; + UndoMesh data; +} MeshUndoStep; + +static bool mesh_undosys_poll(bContext *C) { - /* em->ob gets out of date and crashes on mesh undo, - * this is an easy way to ensure its OK - * though we could investigate the matter further. */ - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - em->ob = obedit; + return editmesh_object_from_context(C) != NULL; +} - undo_editmode_push(C, name, getEditMesh, free_undo, undoMesh_to_editbtMesh, editbtMesh_to_undoMesh, NULL); +static bool mesh_undosys_step_encode(struct bContext *C, UndoStep *us_p) +{ + MeshUndoStep *us = (MeshUndoStep *)us_p; + us->obedit_ref.ptr = editmesh_object_from_context(C); + Mesh *me = us->obedit_ref.ptr->data; + undomesh_from_editmesh(&us->data, me->edit_btmesh, me->key); + us->step.data_size = us->data.undo_size; + return true; } + +static void mesh_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir)) +{ + /* TODO(campbell): undo_system: use low-level API to set mode. */ + ED_object_mode_set(C, OB_MODE_EDIT); + BLI_assert(mesh_undosys_poll(C)); + + MeshUndoStep *us = (MeshUndoStep *)us_p; + Object *obedit = us->obedit_ref.ptr; + Mesh *me = obedit->data; + BMEditMesh *em = me->edit_btmesh; + undomesh_to_editmesh(&us->data, em, obedit->data); + DEG_id_tag_update(&obedit->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); +} + +static void mesh_undosys_step_free(UndoStep *us_p) +{ + MeshUndoStep *us = (MeshUndoStep *)us_p; + undomesh_free_data(&us->data); + + if (us->id_map != NULL) { + BKE_undosys_ID_map_destroy(us->id_map); + } +} + +static void mesh_undosys_foreach_ID_ref( + UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data) +{ + MeshUndoStep *us = (MeshUndoStep *)us_p; + foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref)); + if (us->id_map != NULL) { + BKE_undosys_ID_map_foreach_ID_ref(us->id_map, foreach_ID_ref_fn, user_data); + } +} + +/* Export for ED_undo_sys. */ +void ED_mesh_undosys_type(UndoType *ut) +{ + ut->name = "Edit Mesh"; + ut->poll = mesh_undosys_poll; + ut->step_encode = mesh_undosys_step_encode; + ut->step_decode = mesh_undosys_step_decode; + ut->step_free = mesh_undosys_step_free; + + ut->step_foreach_ID_ref = mesh_undosys_foreach_ID_ref; + + ut->mode = BKE_UNDOTYPE_MODE_STORE; + ut->use_context = true; + + ut->step_size = sizeof(MeshUndoStep); +} + +/** \} */ diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index a52f12ec055..3382847c8a4 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -43,8 +43,6 @@ #include "BKE_DerivedMesh.h" #include "BKE_context.h" -#include "BKE_global.h" -#include "BKE_main.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" #include "BKE_report.h" @@ -64,8 +62,14 @@ #include "mesh_intern.h" /* own include */ -/* mesh backup implementation. This would greatly benefit from some sort of binary diffing - * just as the undo stack would. So leaving this as an interface for further work */ +/* -------------------------------------------------------------------- */ +/** \name Redo API + * \{ */ + +/* Mesh backup implementation. + * This would greatly benefit from some sort of binary diffing + * just as the undo stack would. + * So leaving this as an interface for further work */ BMBackup EDBM_redo_state_store(BMEditMesh *em) { @@ -77,8 +81,9 @@ BMBackup EDBM_redo_state_store(BMEditMesh *em) void EDBM_redo_state_restore(BMBackup backup, BMEditMesh *em, int recalctess) { BMesh *tmpbm; - if (!em || !backup.bmcopy) + if (!em || !backup.bmcopy) { return; + } BM_mesh_data_free(em->bm); tmpbm = BM_mesh_copy(backup.bmcopy); @@ -86,8 +91,9 @@ void EDBM_redo_state_restore(BMBackup backup, BMEditMesh *em, int recalctess) MEM_freeN(tmpbm); tmpbm = NULL; - if (recalctess) + if (recalctess) { BKE_editmesh_tessface_calc(em); + } } void EDBM_redo_state_free(BMBackup *backup, BMEditMesh *em, int recalctess) @@ -100,68 +106,21 @@ void EDBM_redo_state_free(BMBackup *backup, BMEditMesh *em, int recalctess) BM_mesh_data_free(backup->bmcopy); } - if (backup->bmcopy) + if (backup->bmcopy) { MEM_freeN(backup->bmcopy); + } backup->bmcopy = NULL; - if (recalctess && em) + if (recalctess && em) { BKE_editmesh_tessface_calc(em); -} - -void EDBM_mesh_normals_update(BMEditMesh *em) -{ - BM_mesh_normals_update(em->bm); -} - -void EDBM_mesh_clear(BMEditMesh *em) -{ - /* clear bmesh */ - BM_mesh_clear(em->bm); - - /* free derived meshes */ - BKE_editmesh_free_derivedmesh(em); - - /* free tessellation data */ - em->tottri = 0; - if (em->looptris) { - MEM_freeN(em->looptris); - em->looptris = NULL; } } -void EDBM_stats_update(BMEditMesh *em) -{ - const char iter_types[3] = {BM_VERTS_OF_MESH, - BM_EDGES_OF_MESH, - BM_FACES_OF_MESH}; - - BMIter iter; - BMElem *ele; - int *tots[3]; - int i; +/** \} */ - tots[0] = &em->bm->totvertsel; - tots[1] = &em->bm->totedgesel; - tots[2] = &em->bm->totfacesel; - - em->bm->totvertsel = em->bm->totedgesel = em->bm->totfacesel = 0; - - for (i = 0; i < 3; i++) { - ele = BM_iter_new(&iter, em->bm, iter_types[i], NULL); - for ( ; ele; ele = BM_iter_step(&iter)) { - if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) { - (*tots[i])++; - } - } - } -} - -DerivedMesh *EDBM_mesh_deform_dm_get(BMEditMesh *em) -{ - return ((em->derivedFinal != NULL) && - (em->derivedFinal->type == DM_TYPE_EDITBMESH) && - (em->derivedFinal->deformedOnly != false)) ? em->derivedFinal : NULL; -} +/* -------------------------------------------------------------------- */ +/** \name BMesh Operator (BMO) API Wrapper + * \{ */ bool EDBM_op_init(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char *fmt, ...) { @@ -175,9 +134,10 @@ bool EDBM_op_init(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char * va_end(list); return false; } - - if (!em->emcopy) + + if (!em->emcopy) { em->emcopy = BKE_editmesh_copy(em); + } em->emcopyusers++; va_end(list); @@ -185,12 +145,11 @@ bool EDBM_op_init(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char * return true; } - /* returns 0 on error, 1 on success. executes and finishes a bmesh operator */ bool EDBM_op_finish(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const bool do_report) { const char *errmsg; - + BMO_op_finish(em->bm, bmop); if (BMO_error_get(em->bm, &errmsg, NULL)) { @@ -245,8 +204,9 @@ bool EDBM_op_callf(BMEditMesh *em, wmOperator *op, const char *fmt, ...) return false; } - if (!em->emcopy) + if (!em->emcopy) { em->emcopy = BKE_editmesh_copy(em); + } em->emcopyusers++; BMO_op_exec(bm, &bmop); @@ -255,9 +215,10 @@ bool EDBM_op_callf(BMEditMesh *em, wmOperator *op, const char *fmt, ...) return EDBM_op_finish(em, &bmop, op, true); } -bool EDBM_op_call_and_selectf(BMEditMesh *em, wmOperator *op, - const char *select_slot_out, const bool select_extend, - const char *fmt, ...) +bool EDBM_op_call_and_selectf( + BMEditMesh *em, wmOperator *op, + const char *select_slot_out, const bool select_extend, + const char *fmt, ...) { BMOpSlot *slot_select_out; BMesh *bm = em->bm; @@ -273,8 +234,9 @@ bool EDBM_op_call_and_selectf(BMEditMesh *em, wmOperator *op, return false; } - if (!em->emcopy) + if (!em->emcopy) { em->emcopy = BKE_editmesh_copy(em); + } em->emcopyusers++; BMO_op_exec(bm, &bmop); @@ -306,8 +268,9 @@ bool EDBM_op_call_silentf(BMEditMesh *em, const char *fmt, ...) return false; } - if (!em->emcopy) + if (!em->emcopy) { em->emcopy = BKE_editmesh_copy(em); + } em->emcopyusers++; BMO_op_exec(bm, &bmop); @@ -316,22 +279,15 @@ bool EDBM_op_call_silentf(BMEditMesh *em, const char *fmt, ...) return EDBM_op_finish(em, &bmop, NULL, false); } -void EDBM_selectmode_to_scene(bContext *C) -{ - Scene *scene = CTX_data_scene(C); - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (!em) - return; +/** \} */ - scene->toolsettings->selectmode = em->selectmode; - - /* Request redraw of header buttons (to show new select mode) */ - WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, scene); -} +/* -------------------------------------------------------------------- */ +/** \name Edit BMesh API + * + * Make/Clear/Free functions. + * \{ */ -void EDBM_mesh_make(ToolSettings *ts, Object *ob, const bool add_key_index) +void EDBM_mesh_make(Object *ob, const int select_mode, const bool add_key_index) { Mesh *me = ob->data; BMesh *bm; @@ -358,7 +314,7 @@ void EDBM_mesh_make(ToolSettings *ts, Object *ob, const bool add_key_index) me->edit_btmesh = BKE_editmesh_create(bm, false); #endif - me->edit_btmesh->selectmode = me->edit_btmesh->bm->selectmode = ts->selectmode; + me->edit_btmesh->selectmode = me->edit_btmesh->bm->selectmode = select_mode; me->edit_btmesh->mat_nr = (ob->actcol > 0) ? ob->actcol - 1 : 0; me->edit_btmesh->ob = ob; @@ -381,7 +337,10 @@ void EDBM_mesh_load(Object *ob) bm->shapenr = 1; } - BM_mesh_bm_to_me(bm, me, (&(struct BMeshToMeshParams){0})); + BM_mesh_bm_to_me( + bm, me, (&(struct BMeshToMeshParams){ + .calc_object_remap = true, + })); #ifdef USE_TESSFACE_DEFAULT BKE_mesh_tessface_calc(me); @@ -410,6 +369,22 @@ void EDBM_mesh_load(Object *ob) #endif } +void EDBM_mesh_clear(BMEditMesh *em) +{ + /* clear bmesh */ + BM_mesh_clear(em->bm); + + /* free derived meshes */ + BKE_editmesh_free_derivedmesh(em); + + /* free tessellation data */ + em->tottri = 0; + if (em->looptris) { + MEM_freeN(em->looptris); + em->looptris = NULL; + } +} + /** * Should only be called on the active editmesh, otherwise call #BKE_editmesh_free */ @@ -424,6 +399,28 @@ void EDBM_mesh_free(BMEditMesh *em) BKE_editmesh_free(em); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Selection Utilities + * \{ */ + +void EDBM_selectmode_to_scene(bContext *C) +{ + Scene *scene = CTX_data_scene(C); + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (!em) { + return; + } + + scene->toolsettings->selectmode = em->selectmode; + + /* Request redraw of header buttons (to show new select mode) */ + WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, scene); +} + void EDBM_selectmode_flush_ex(BMEditMesh *em, const short selectmode) { BM_mesh_select_mode_flush_ex(em->bm, selectmode); @@ -441,7 +438,6 @@ void EDBM_deselect_flush(BMEditMesh *em) BM_mesh_deselect_flush(em->bm); } - void EDBM_select_flush(BMEditMesh *em) { /* function below doesnt use. just do this to keep the values in sync */ @@ -454,9 +450,10 @@ void EDBM_select_more(BMEditMesh *em, const bool use_face_step) BMOperator bmop; const bool use_faces = (em->selectmode == SCE_SELECT_FACE); - BMO_op_initf(em->bm, &bmop, BMO_FLAG_DEFAULTS, - "region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b", - BM_ELEM_SELECT, false, use_faces, use_face_step); + BMO_op_initf( + em->bm, &bmop, BMO_FLAG_DEFAULTS, + "region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b", + BM_ELEM_SELECT, false, use_faces, use_face_step); BMO_op_exec(em->bm, &bmop); /* don't flush selection in edge/vertex mode */ BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, use_faces ? true : false); @@ -470,9 +467,10 @@ void EDBM_select_less(BMEditMesh *em, const bool use_face_step) BMOperator bmop; const bool use_faces = (em->selectmode == SCE_SELECT_FACE); - BMO_op_initf(em->bm, &bmop, BMO_FLAG_DEFAULTS, - "region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b", - BM_ELEM_SELECT, true, use_faces, use_face_step); + BMO_op_initf( + em->bm, &bmop, BMO_FLAG_DEFAULTS, + "region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b", + BM_ELEM_SELECT, true, use_faces, use_face_step); BMO_op_exec(em->bm, &bmop); /* don't flush selection in edge/vertex mode */ BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, use_faces ? true : false); @@ -494,6 +492,12 @@ void EDBM_flag_enable_all(BMEditMesh *em, const char hflag) BM_mesh_elem_hflag_enable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, hflag, true); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name UV Vertex Map API + * \{ */ + /** * Return a new UVVertMap from the editmesh */ @@ -516,7 +520,7 @@ UvVertMap *BM_uv_vert_map_create( BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE); BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE); - + totfaces = bm->totface; totverts = bm->totvert; totuv = 0; @@ -546,7 +550,7 @@ UvVertMap *BM_uv_vert_map_create( BKE_mesh_uv_vert_map_free(vmap); return NULL; } - + BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, a) { if ((use_select == false) || BM_elem_flag_test(efa, BM_ELEM_SELECT)) { float (*tf_uv)[2]; @@ -559,7 +563,7 @@ UvVertMap *BM_uv_vert_map_create( buf->tfindex = i; buf->f = a; buf->separate = 0; - + buf->next = vmap->vert[BM_elem_index_get(l->v)]; vmap->vert[BM_elem_index_get(l->v)] = buf; buf++; @@ -575,7 +579,7 @@ UvVertMap *BM_uv_vert_map_create( } } } - + /* sort individual uvs for each vert */ BM_ITER_MESH_INDEX (ev, &iter, bm, BM_VERTS_OF_MESH, a) { UvMapVert *newvlist = NULL, *vlist = vmap->vert[a]; @@ -589,22 +593,21 @@ UvVertMap *BM_uv_vert_map_create( newvlist = v; efa = BM_face_at_index(bm, v->f); - + l = BM_iter_at_index(bm, BM_LOOPS_OF_FACE, efa, v->tfindex); luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); uv = luv->uv; - + lastv = NULL; iterv = vlist; while (iterv) { next = iterv->next; efa = BM_face_at_index(bm, iterv->f); - l = BM_iter_at_index(bm, BM_LOOPS_OF_FACE, efa, iterv->tfindex); luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); uv2 = luv->uv; - + sub_v2_v2v2(uvdiff, uv2, uv); if (fabsf(uvdiff[0]) < limit[0] && fabsf(uvdiff[1]) < limit[1] && @@ -637,13 +640,11 @@ UvVertMap *BM_uv_vert_map_create( return vmap; } - UvMapVert *BM_uv_vert_map_at_index(UvVertMap *vmap, unsigned int v) { return vmap->vert[v]; } - /* A specialized vert map used by stitch operator */ UvElementMap *BM_uv_element_map_create( BMesh *bm, @@ -901,26 +902,34 @@ void BM_uv_element_map_free(UvElementMap *element_map) UvElement *BM_uv_element_get(UvElementMap *map, BMFace *efa, BMLoop *l) { - UvElement *element; - - element = map->vert[BM_elem_index_get(l->v)]; - - for (; element; element = element->next) - if (element->l->f == efa) + for (UvElement *element = map->vert[BM_elem_index_get(l->v)]; + element; + element = element->next) + { + if (element->l->f == efa) { return element; + } + } return NULL; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Data Layer Checks + * \{ */ + /* last_sel, use em->act_face otherwise get the last selected face in the editselections * at the moment, last_sel is mainly useful for making sure the space image dosnt flicker */ BMFace *EDBM_uv_active_face_get(BMEditMesh *em, const bool sloppy, const bool selected) { BMFace *efa = NULL; - - if (!EDBM_uv_check(em)) + + if (!EDBM_uv_check(em)) { return NULL; - + } + efa = BM_mesh_active_face_get(em->bm, sloppy, selected); if (efa) { @@ -944,6 +953,12 @@ bool EDBM_vert_color_check(BMEditMesh *em) return em && em->bm->totface && CustomData_has_layer(&em->bm->ldata, CD_MLOOPCOL); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mirror Cache API + * \{ */ + static BMVert *cache_mirr_intptr_as_bmvert(intptr_t *index_lookup, int index) { intptr_t eve_i = index_lookup[index]; @@ -978,9 +993,10 @@ static BMVert *cache_mirr_intptr_as_bmvert(intptr_t *index_lookup, int index) * \param maxdist Distance for close point test. * \param r_index Optional array to write into, as an alternative to a customdata layer (length of total verts). */ -void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool use_self, const bool use_select, - /* extra args */ - const bool use_topology, float maxdist, int *r_index) +void EDBM_verts_mirror_cache_begin_ex( + BMEditMesh *em, const int axis, const bool use_self, const bool use_select, + /* extra args */ + const bool use_topology, float maxdist, int *r_index) { Mesh *me = (Mesh *)em->ob->data; BMesh *bm = em->bm; @@ -1004,8 +1020,9 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool em->mirror_cdlayer = CustomData_get_named_layer_index(&bm->vdata, CD_PROP_INT, layer_id); } - cd_vmirr_offset = CustomData_get_n_offset(&bm->vdata, CD_PROP_INT, - em->mirror_cdlayer - CustomData_get_layer_index(&bm->vdata, CD_PROP_INT)); + cd_vmirr_offset = CustomData_get_n_offset( + &bm->vdata, CD_PROP_INT, + em->mirror_cdlayer - CustomData_get_layer_index(&bm->vdata, CD_PROP_INT)); bm->vdata.layers[em->mirror_cdlayer].flag |= CD_FLAG_TEMPORARY; } @@ -1013,7 +1030,7 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool BM_mesh_elem_index_ensure(bm, BM_VERT); if (use_topology) { - ED_mesh_mirrtopo_init(me, NULL, -1, &mesh_topo_store, true); + ED_mesh_mirrtopo_init(me, NULL, &mesh_topo_store, true); } else { tree = BLI_kdtree_new(bm->totvert); @@ -1078,14 +1095,16 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool } } -void EDBM_verts_mirror_cache_begin(BMEditMesh *em, const int axis, - const bool use_self, const bool use_select, - const bool use_topology) +void EDBM_verts_mirror_cache_begin( + BMEditMesh *em, const int axis, + const bool use_self, const bool use_select, + const bool use_topology) { - EDBM_verts_mirror_cache_begin_ex(em, axis, - use_self, use_select, - /* extra args */ - use_topology, BM_SEARCH_MAXDIST_MIRR, NULL); + EDBM_verts_mirror_cache_begin_ex( + em, axis, + use_self, use_select, + /* extra args */ + use_topology, BM_SEARCH_MAXDIST_MIRR, NULL); } BMVert *EDBM_verts_mirror_get(BMEditMesh *em, BMVert *v) @@ -1173,6 +1192,11 @@ void EDBM_verts_mirror_apply(BMEditMesh *em, const int sel_from, const int sel_t } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Hide/Reveal API + * \{ */ /* swap is 0 or 1, if 1 it hides not selected */ void EDBM_mesh_hide(BMEditMesh *em, bool swap) @@ -1207,17 +1231,18 @@ void EDBM_mesh_hide(BMEditMesh *em, bool swap) */ } - void EDBM_mesh_reveal(BMEditMesh *em, bool select) { - const char iter_types[3] = {BM_VERTS_OF_MESH, - BM_EDGES_OF_MESH, - BM_FACES_OF_MESH}; + const char iter_types[3] = { + BM_VERTS_OF_MESH, + BM_EDGES_OF_MESH, + BM_FACES_OF_MESH, + }; const bool sels[3] = { - (em->selectmode & SCE_SELECT_VERTEX) != 0, - (em->selectmode & SCE_SELECT_EDGE) != 0, - (em->selectmode & SCE_SELECT_FACE) != 0, + (em->selectmode & SCE_SELECT_VERTEX) != 0, + (em->selectmode & SCE_SELECT_EDGE) != 0, + (em->selectmode & SCE_SELECT_FACE) != 0, }; int i; @@ -1257,6 +1282,46 @@ void EDBM_mesh_reveal(BMEditMesh *em, bool select) EDBM_mesh_normals_update(em); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Update API + * \{ */ + +void EDBM_mesh_normals_update(BMEditMesh *em) +{ + BM_mesh_normals_update(em->bm); +} + +void EDBM_stats_update(BMEditMesh *em) +{ + const char iter_types[3] = { + BM_VERTS_OF_MESH, + BM_EDGES_OF_MESH, + BM_FACES_OF_MESH, + }; + + BMIter iter; + BMElem *ele; + int *tots[3]; + int i; + + tots[0] = &em->bm->totvertsel; + tots[1] = &em->bm->totedgesel; + tots[2] = &em->bm->totfacesel; + + em->bm->totvertsel = em->bm->totedgesel = em->bm->totfacesel = 0; + + for (i = 0; i < 3; i++) { + ele = BM_iter_new(&iter, em->bm, iter_types[i], NULL); + for ( ; ele; ele = BM_iter_step(&iter)) { + if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) { + (*tots[i])++; + } + } + } +} + /* so many tools call these that we better make it a generic function. */ void EDBM_update_generic(BMEditMesh *em, const bool do_tessface, const bool is_destructive) @@ -1292,15 +1357,41 @@ void EDBM_update_generic(BMEditMesh *em, const bool do_tessface, const bool is_d #endif } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Data Access + * \{ */ + +DerivedMesh *EDBM_mesh_deform_dm_get(BMEditMesh *em) +{ + return ((em->derivedFinal != NULL) && + (em->derivedFinal->type == DM_TYPE_EDITBMESH) && + (em->derivedFinal->deformedOnly != false)) ? em->derivedFinal : NULL; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Operator Helpers + * \{ */ + /* poll call for mesh operators requiring a view3d context */ int EDBM_view3d_poll(bContext *C) { - if (ED_operator_editmesh(C) && ED_operator_view3d_active(C)) + if (ED_operator_editmesh(C) && ED_operator_view3d_active(C)) { return 1; + } return 0; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name BMesh Element API + * \{ */ + BMElem *EDBM_elem_from_selectmode(BMEditMesh *em, BMVert *eve, BMEdge *eed, BMFace *efa) { BMElem *ele = NULL; @@ -1365,22 +1456,19 @@ BMElem *EDBM_elem_from_index_any(BMEditMesh *em, int index) return NULL; } -/* -------------------------------------------------------------------- */ -/* BMBVH functions */ -// XXX -#if 0 //BMESH_TODO: not implemented yet -int BMBVH_VertVisible(BMBVHTree *tree, BMEdge *e, RegionView3D *r3d) -{ +/** \} */ -} -#endif +/* -------------------------------------------------------------------- */ +/** \name BMesh BVH API + * \{ */ static BMFace *edge_ray_cast(struct BMBVHTree *tree, const float co[3], const float dir[3], float *r_hitout, BMEdge *e) { BMFace *f = BKE_bmbvh_ray_cast(tree, co, dir, 0.0f, NULL, r_hitout, NULL); - if (f && BM_edge_in_face(e, f)) + if (f && BM_edge_in_face(e, f)) { return NULL; + } return f; } @@ -1401,8 +1489,10 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree, BMEdge *e, float origin[3], invmat[4][4]; float epsilon = 0.01f; float end[3]; - const float mval_f[2] = {ar->winx / 2.0f, - ar->winy / 2.0f}; + const float mval_f[2] = { + ar->winx / 2.0f, + ar->winy / 2.0f, + }; ED_view3d_win_to_segment(depsgraph, ar, v3d, mval_f, origin, end, false); @@ -1438,12 +1528,17 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree, BMEdge *e, /* do three samplings: left, middle, right */ f = edge_ray_cast(tree, co1, dir1, NULL, e); - if (f && !edge_ray_cast(tree, co2, dir2, NULL, e)) + if (f && !edge_ray_cast(tree, co2, dir2, NULL, e)) { return true; - else if (f && !edge_ray_cast(tree, co3, dir3, NULL, e)) + } + else if (f && !edge_ray_cast(tree, co3, dir3, NULL, e)) { return true; - else if (!f) + } + else if (!f) { return true; + } return false; } + +/** \} */ diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c index 218b97d3ede..69e265f7315 100644 --- a/source/blender/editors/mesh/mesh_data.c +++ b/source/blender/editors/mesh/mesh_data.c @@ -572,7 +572,7 @@ static int drop_named_image_invoke(bContext *C, wmOperator *op, const wmEvent *e obedit = base->object; me = obedit->data; if (me->edit_btmesh == NULL) { - EDBM_mesh_make(scene->toolsettings, obedit, false); + EDBM_mesh_make(obedit, scene->toolsettings->selectmode, false); exitmode = 1; } if (me->edit_btmesh == NULL) @@ -879,9 +879,38 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator CustomData *data = GET_CD_DATA(me, ldata); if (me->edit_btmesh) { + /* Tag edges as sharp according to smooth threshold if needed, to preserve autosmooth shading. */ + if (me->flag & ME_AUTOSMOOTH) { + BM_edges_sharp_from_angle_set(me->edit_btmesh->bm, me->smoothresh); + + me->drawflag |= ME_DRAWSHARP; + } + BM_data_layer_add(me->edit_btmesh->bm, data, CD_CUSTOMLOOPNORMAL); } else { + /* Tag edges as sharp according to smooth threshold if needed, to preserve autosmooth shading. */ + if (me->flag & ME_AUTOSMOOTH) { + float (*polynors)[3] = MEM_mallocN(sizeof(*polynors) * (size_t)me->totpoly, __func__); + + BKE_mesh_calc_normals_poly( + me->mvert, NULL, me->totvert, + me->mloop, me->mpoly, + me->totloop, me->totpoly, + polynors, true); + + BKE_edges_sharp_from_angle_set( + me->mvert, me->totvert, + me->medge, me->totedge, + me->mloop, me->totloop, + me->mpoly, polynors, me->totpoly, + me->smoothresh); + + MEM_freeN(polynors); + + me->drawflag |= ME_DRAWSHARP; + } + CustomData_add_layer(data, CD_CUSTOMLOOPNORMAL, CD_DEFAULT, NULL, me->totloop); } diff --git a/source/blender/editors/mesh/mesh_mirror.c b/source/blender/editors/mesh/mesh_mirror.c new file mode 100644 index 00000000000..22bfd8eedea --- /dev/null +++ b/source/blender/editors/mesh/mesh_mirror.c @@ -0,0 +1,377 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Blender Foundation, Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/mesh/mesh_mirror.c + * \ingroup edmesh + * + * Mirror calculation for edit-mode and object mode. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_bitmap.h" + +#include "DNA_mesh_types.h" +#include "DNA_object_types.h" + +#include "BKE_DerivedMesh.h" +#include "BLI_kdtree.h" +#include "BKE_editmesh.h" + +#include "ED_mesh.h" + +/* -------------------------------------------------------------------- */ +/** \name Mesh Spatial Mirror API + * \{ */ + +#define KD_THRESH 0.00002f + +static struct { void *tree; } MirrKdStore = {NULL}; + +/* mode is 's' start, or 'e' end, or 'u' use */ +/* if end, ob can be NULL */ +int ED_mesh_mirror_spatial_table(Object *ob, BMEditMesh *em, DerivedMesh *dm, const float co[3], char mode) +{ + if (mode == 'u') { /* use table */ + if (MirrKdStore.tree == NULL) + ED_mesh_mirror_spatial_table(ob, em, dm, NULL, 's'); + + if (MirrKdStore.tree) { + KDTreeNearest nearest; + const int i = BLI_kdtree_find_nearest(MirrKdStore.tree, co, &nearest); + + if (i != -1) { + if (nearest.dist < KD_THRESH) { + return i; + } + } + } + return -1; + } + else if (mode == 's') { /* start table */ + Mesh *me = ob->data; + const bool use_em = (!dm && em && me->edit_btmesh == em); + const int totvert = use_em ? em->bm->totvert : dm ? dm->getNumVerts(dm) : me->totvert; + + if (MirrKdStore.tree) /* happens when entering this call without ending it */ + ED_mesh_mirror_spatial_table(ob, em, dm, co, 'e'); + + MirrKdStore.tree = BLI_kdtree_new(totvert); + + if (use_em) { + BMVert *eve; + BMIter iter; + int i; + + /* this needs to be valid for index lookups later (callers need) */ + BM_mesh_elem_table_ensure(em->bm, BM_VERT); + + BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) { + BLI_kdtree_insert(MirrKdStore.tree, i, eve->co); + } + } + else { + MVert *mvert = dm ? dm->getVertArray(dm) : me->mvert; + int i; + + for (i = 0; i < totvert; i++, mvert++) { + BLI_kdtree_insert(MirrKdStore.tree, i, mvert->co); + } + } + + BLI_kdtree_balance(MirrKdStore.tree); + } + else if (mode == 'e') { /* end table */ + if (MirrKdStore.tree) { + BLI_kdtree_free(MirrKdStore.tree); + MirrKdStore.tree = NULL; + } + } + else { + BLI_assert(0); + } + + return 0; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mesh Topology Mirror API + * \{ */ + +typedef unsigned int MirrTopoHash_t; + +typedef struct MirrTopoVert_t { + MirrTopoHash_t hash; + int v_index; +} MirrTopoVert_t; + +static int mirrtopo_hash_sort(const void *l1, const void *l2) +{ + if ((MirrTopoHash_t)(intptr_t)l1 > (MirrTopoHash_t)(intptr_t)l2) return 1; + else if ((MirrTopoHash_t)(intptr_t)l1 < (MirrTopoHash_t)(intptr_t)l2) return -1; + return 0; +} + +static int mirrtopo_vert_sort(const void *v1, const void *v2) +{ + if (((MirrTopoVert_t *)v1)->hash > ((MirrTopoVert_t *)v2)->hash) return 1; + else if (((MirrTopoVert_t *)v1)->hash < ((MirrTopoVert_t *)v2)->hash) return -1; + return 0; +} + +bool ED_mesh_mirrtopo_recalc_check(Mesh *me, DerivedMesh *dm, MirrTopoStore_t *mesh_topo_store) +{ + const bool is_editmode = (me->edit_btmesh != NULL); + int totvert; + int totedge; + + if (dm) { + totvert = dm->getNumVerts(dm); + totedge = dm->getNumEdges(dm); + } + else if (me->edit_btmesh) { + totvert = me->edit_btmesh->bm->totvert; + totedge = me->edit_btmesh->bm->totedge; + } + else { + totvert = me->totvert; + totedge = me->totedge; + } + + if ((mesh_topo_store->index_lookup == NULL) || + (mesh_topo_store->prev_is_editmode != is_editmode) || + (totvert != mesh_topo_store->prev_vert_tot) || + (totedge != mesh_topo_store->prev_edge_tot)) + { + return true; + } + else { + return false; + } + +} + +void ED_mesh_mirrtopo_init( + Mesh *me, DerivedMesh *dm, MirrTopoStore_t *mesh_topo_store, + const bool skip_em_vert_array_init) +{ + const bool is_editmode = (me->edit_btmesh != NULL); + MEdge *medge = NULL, *med; + BMEditMesh *em = dm ? NULL : me->edit_btmesh; + + /* editmode*/ + BMEdge *eed; + BMIter iter; + + int a, last; + int totvert, totedge; + int tot_unique = -1, tot_unique_prev = -1; + int tot_unique_edges = 0, tot_unique_edges_prev; + + MirrTopoHash_t *topo_hash = NULL; + MirrTopoHash_t *topo_hash_prev = NULL; + MirrTopoVert_t *topo_pairs; + MirrTopoHash_t topo_pass = 1; + + intptr_t *index_lookup; /* direct access to mesh_topo_store->index_lookup */ + + /* reallocate if needed */ + ED_mesh_mirrtopo_free(mesh_topo_store); + + mesh_topo_store->prev_is_editmode = is_editmode; + + if (em) { + BM_mesh_elem_index_ensure(em->bm, BM_VERT); + + totvert = em->bm->totvert; + } + else { + totvert = dm ? dm->getNumVerts(dm) : me->totvert; + } + + topo_hash = MEM_callocN(totvert * sizeof(MirrTopoHash_t), "TopoMirr"); + + /* Initialize the vert-edge-user counts used to detect unique topology */ + if (em) { + totedge = me->edit_btmesh->bm->totedge; + + BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { + const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2); + topo_hash[i1]++; + topo_hash[i2]++; + } + } + else { + totedge = dm ? dm->getNumEdges(dm) : me->totedge; + medge = dm ? dm->getEdgeArray(dm) : me->medge; + + for (a = 0, med = medge; a < totedge; a++, med++) { + const unsigned int i1 = med->v1, i2 = med->v2; + topo_hash[i1]++; + topo_hash[i2]++; + } + } + + topo_hash_prev = MEM_dupallocN(topo_hash); + + tot_unique_prev = -1; + tot_unique_edges_prev = -1; + while (1) { + /* use the number of edges per vert to give verts unique topology IDs */ + + tot_unique_edges = 0; + + /* This can make really big numbers, wrapping around here is fine */ + if (em) { + BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { + const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2); + topo_hash[i1] += topo_hash_prev[i2] * topo_pass; + topo_hash[i2] += topo_hash_prev[i1] * topo_pass; + tot_unique_edges += (topo_hash[i1] != topo_hash[i2]); + } + } + else { + for (a = 0, med = medge; a < totedge; a++, med++) { + const unsigned int i1 = med->v1, i2 = med->v2; + topo_hash[i1] += topo_hash_prev[i2] * topo_pass; + topo_hash[i2] += topo_hash_prev[i1] * topo_pass; + tot_unique_edges += (topo_hash[i1] != topo_hash[i2]); + } + } + memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * totvert); + + /* sort so we can count unique values */ + qsort(topo_hash_prev, totvert, sizeof(MirrTopoHash_t), mirrtopo_hash_sort); + + tot_unique = 1; /* account for skiping the first value */ + for (a = 1; a < totvert; a++) { + if (topo_hash_prev[a - 1] != topo_hash_prev[a]) { + tot_unique++; + } + } + + if ((tot_unique <= tot_unique_prev) && (tot_unique_edges <= tot_unique_edges_prev)) { + /* Finish searching for unique values when 1 loop dosnt give a + * higher number of unique values compared to the previous loop */ + break; + } + else { + tot_unique_prev = tot_unique; + tot_unique_edges_prev = tot_unique_edges; + } + /* Copy the hash calculated this iter, so we can use them next time */ + memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * totvert); + + topo_pass++; + } + + /* Hash/Index pairs are needed for sorting to find index pairs */ + topo_pairs = MEM_callocN(sizeof(MirrTopoVert_t) * totvert, "MirrTopoPairs"); + + /* since we are looping through verts, initialize these values here too */ + index_lookup = MEM_mallocN(totvert * sizeof(*index_lookup), "mesh_topo_lookup"); + + if (em) { + if (skip_em_vert_array_init == false) { + BM_mesh_elem_table_ensure(em->bm, BM_VERT); + } + } + + for (a = 0; a < totvert; a++) { + topo_pairs[a].hash = topo_hash[a]; + topo_pairs[a].v_index = a; + + /* initialize lookup */ + index_lookup[a] = -1; + } + + qsort(topo_pairs, totvert, sizeof(MirrTopoVert_t), mirrtopo_vert_sort); + + last = 0; + + /* Get the pairs out of the sorted hashes, note, totvert+1 means we can use the previous 2, + * but you cant ever access the last 'a' index of MirrTopoPairs */ + if (em) { + BMVert **vtable = em->bm->vtable; + for (a = 1; a <= totvert; a++) { + /* printf("I %d %ld %d\n", (a - last), MirrTopoPairs[a].hash, MirrTopoPairs[a].v_indexs); */ + if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) { + const int match_count = a - last; + if (match_count == 2) { + const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index; + index_lookup[j] = (intptr_t)vtable[k]; + index_lookup[k] = (intptr_t)vtable[j]; + } + else if (match_count == 1) { + /* Center vertex. */ + const int j = topo_pairs[a - 1].v_index; + index_lookup[j] = (intptr_t)vtable[j]; + } + last = a; + } + } + } + else { + /* same as above, for mesh */ + for (a = 1; a <= totvert; a++) { + if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) { + const int match_count = a - last; + if (match_count == 2) { + const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index; + index_lookup[j] = k; + index_lookup[k] = j; + } + else if (match_count == 1) { + /* Center vertex. */ + const int j = topo_pairs[a - 1].v_index; + index_lookup[j] = j; + } + last = a; + } + } + } + + MEM_freeN(topo_pairs); + topo_pairs = NULL; + + MEM_freeN(topo_hash); + MEM_freeN(topo_hash_prev); + + mesh_topo_store->index_lookup = index_lookup; + mesh_topo_store->prev_vert_tot = totvert; + mesh_topo_store->prev_edge_tot = totedge; +} + +void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store) +{ + if (mesh_topo_store->index_lookup) { + MEM_freeN(mesh_topo_store->index_lookup); + } + mesh_topo_store->index_lookup = NULL; + mesh_topo_store->prev_vert_tot = -1; + mesh_topo_store->prev_edge_tot = -1; +} + +/** \} */ diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index dd1fbc36d8a..531a26a66a8 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -42,12 +42,11 @@ #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_view3d_types.h" +#include "DNA_workspace_types.h" #include "BLI_math.h" #include "BLI_blenlib.h" - -#include "BLI_kdtree.h" #include "BKE_context.h" #include "BKE_deform.h" #include "BKE_DerivedMesh.h" @@ -57,6 +56,7 @@ #include "BKE_mesh.h" #include "BKE_material.h" #include "BKE_object.h" +#include "BKE_object_deform.h" #include "BKE_report.h" #include "BKE_editmesh.h" #include "BKE_multires.h" @@ -79,7 +79,7 @@ * return 0 if no join is made (error) and 1 if the join is done */ static void join_mesh_single( - bContext *C, Main *bmain, Scene *scene, + const EvaluationContext *eval_ctx, Main *bmain, Scene *scene, Object *ob_dst, Object *ob_src, float imat[4][4], MVert **mvert_pp, MEdge **medge_pp, MLoop **mloop_pp, MPoly **mpoly_pp, CustomData *vdata, CustomData *edata, CustomData *ldata, CustomData *pdata, @@ -88,7 +88,6 @@ static void join_mesh_single( Material **matar, int *matmap, int totcol, int *vertofs, int *edgeofs, int *loopofs, int *polyofs) { - EvaluationContext eval_ctx; int a, b; Mesh *me = ob_src->data; @@ -97,8 +96,6 @@ static void join_mesh_single( MLoop *mloop = *mloop_pp; MPoly *mpoly = *mpoly_pp; - CTX_data_eval_ctx(C, &eval_ctx); - if (me->totvert) { /* merge customdata flag */ ((Mesh *)ob_dst->data)->cd_flag |= me->cd_flag; @@ -116,21 +113,12 @@ static void join_mesh_single( BLI_assert(dvert != NULL); /* Build src to merged mapping of vgroup indices. */ - bDeformGroup *dg_src; - int *vgroup_index_map = alloca(sizeof(*vgroup_index_map) * BLI_listbase_count(&ob_src->defbase)); - bool is_vgroup_remap_needed = false; - - for (dg_src = ob_src->defbase.first, b = 0; dg_src; dg_src = dg_src->next, b++) { - vgroup_index_map[b] = defgroup_name_index(ob_dst, dg_src->name); - is_vgroup_remap_needed = is_vgroup_remap_needed || (vgroup_index_map[b] != b); - } - - if (is_vgroup_remap_needed) { - for (a = 0; a < me->totvert; a++) { - for (b = 0; b < dvert[a].totweight; b++) { - dvert[a].dw[b].def_nr = vgroup_index_map[dvert_src[a].dw[b].def_nr]; - } - } + int *vgroup_index_map; + int vgroup_index_map_len; + vgroup_index_map = BKE_object_defgroup_index_map_create(ob_src, ob_dst, &vgroup_index_map_len); + BKE_object_defgroup_index_map_apply(dvert, me->totvert, vgroup_index_map, vgroup_index_map_len); + if (vgroup_index_map != NULL) { + MEM_freeN(vgroup_index_map); } } @@ -219,7 +207,7 @@ static void join_mesh_single( if (ob_src != ob_dst) { MultiresModifierData *mmd; - multiresModifier_prepare_join(&eval_ctx, scene, ob_src, ob_dst); + multiresModifier_prepare_join(eval_ctx, scene, ob_src, ob_dst); if ((mmd = get_multires_modifier(scene, ob_src, true))) { ED_object_iter_other(bmain, ob_src, true, @@ -293,7 +281,7 @@ int join_mesh_exec(bContext *C, wmOperator *op) bDeformGroup *dg, *odg; CustomData vdata, edata, fdata, ldata, pdata; - if (scene->obedit) { + if (ob->mode & OB_MODE_EDIT) { BKE_report(op->reports, RPT_WARNING, "Cannot join while in edit mode"); return OPERATOR_CANCELLED; } @@ -303,7 +291,10 @@ int join_mesh_exec(bContext *C, wmOperator *op) BKE_report(op->reports, RPT_WARNING, "Active object is not a mesh"); return OPERATOR_CANCELLED; } - + + EvaluationContext eval_ctx; + CTX_data_eval_ctx(C, &eval_ctx); + /* count & check */ CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) { @@ -498,7 +489,7 @@ int join_mesh_exec(bContext *C, wmOperator *op) * active mesh will remain first ones in new result of the merge, in same order for CD layers, etc. See also T50084. */ join_mesh_single( - C, bmain, scene, + &eval_ctx, bmain, scene, ob, ob, imat, &mvert, &medge, &mloop, &mpoly, &vdata, &edata, &ldata, &pdata, @@ -515,7 +506,7 @@ int join_mesh_exec(bContext *C, wmOperator *op) /* only join if this is a mesh */ if (base->object->type == OB_MESH) { join_mesh_single( - C, bmain, scene, + &eval_ctx, bmain, scene, ob, base->object, imat, &mvert, &medge, &mloop, &mpoly, &vdata, &edata, &ldata, &pdata, @@ -567,12 +558,10 @@ int join_mesh_exec(bContext *C, wmOperator *op) if (ma) id_us_min(&ma->id); } - if (ob->mat) MEM_freeN(ob->mat); - if (ob->matbits) MEM_freeN(ob->matbits); - if (me->mat) MEM_freeN(me->mat); - ob->mat = me->mat = NULL; - ob->matbits = NULL; - + MEM_SAFE_FREE(ob->mat); + MEM_SAFE_FREE(ob->matbits); + MEM_SAFE_FREE(me->mat); + if (totcol) { me->mat = matar; ob->mat = MEM_callocN(sizeof(*ob->mat) * totcol, "join obmatar"); @@ -687,84 +676,6 @@ int join_mesh_shapes_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -/* -------------------------------------------------------------------- */ -/* Mesh Mirror (Spatial) */ - -/** \name Mesh Spatial Mirror API - * \{ */ - -#define KD_THRESH 0.00002f - -static struct { void *tree; } MirrKdStore = {NULL}; - -/* mode is 's' start, or 'e' end, or 'u' use */ -/* if end, ob can be NULL */ -int ED_mesh_mirror_spatial_table(Object *ob, BMEditMesh *em, DerivedMesh *dm, const float co[3], char mode) -{ - if (mode == 'u') { /* use table */ - if (MirrKdStore.tree == NULL) - ED_mesh_mirror_spatial_table(ob, em, dm, NULL, 's'); - - if (MirrKdStore.tree) { - KDTreeNearest nearest; - const int i = BLI_kdtree_find_nearest(MirrKdStore.tree, co, &nearest); - - if (i != -1) { - if (nearest.dist < KD_THRESH) { - return i; - } - } - } - return -1; - } - else if (mode == 's') { /* start table */ - Mesh *me = ob->data; - const bool use_em = (!dm && em && me->edit_btmesh == em); - const int totvert = use_em ? em->bm->totvert : dm ? dm->getNumVerts(dm) : me->totvert; - - if (MirrKdStore.tree) /* happens when entering this call without ending it */ - ED_mesh_mirror_spatial_table(ob, em, dm, co, 'e'); - - MirrKdStore.tree = BLI_kdtree_new(totvert); - - if (use_em) { - BMVert *eve; - BMIter iter; - int i; - - /* this needs to be valid for index lookups later (callers need) */ - BM_mesh_elem_table_ensure(em->bm, BM_VERT); - - BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) { - BLI_kdtree_insert(MirrKdStore.tree, i, eve->co); - } - } - else { - MVert *mvert = dm ? dm->getVertArray(dm) : me->mvert; - int i; - - for (i = 0; i < totvert; i++, mvert++) { - BLI_kdtree_insert(MirrKdStore.tree, i, mvert->co); - } - } - - BLI_kdtree_balance(MirrKdStore.tree); - } - else if (mode == 'e') { /* end table */ - if (MirrKdStore.tree) { - BLI_kdtree_free(MirrKdStore.tree); - MirrKdStore.tree = NULL; - } - } - else { - BLI_assert(0); - } - - return 0; -} - -/** \} */ - /* -------------------------------------------------------------------- */ /* Mesh Mirror (Topology) */ @@ -777,15 +688,16 @@ static MirrTopoStore_t mesh_topo_store = {NULL, -1. - 1, -1}; /* mode is 's' start, or 'e' end, or 'u' use */ /* if end, ob can be NULL */ /* note, is supposed return -1 on error, which callers are currently checking for, but is not used so far */ -int ED_mesh_mirror_topo_table(Object *ob, DerivedMesh *dm, char mode) +int ED_mesh_mirror_topo_table( + Object *ob, DerivedMesh *dm, char mode) { if (mode == 'u') { /* use table */ - if (ED_mesh_mirrtopo_recalc_check(ob->data, dm, ob->mode, &mesh_topo_store)) { + if (ED_mesh_mirrtopo_recalc_check(ob->data, dm, &mesh_topo_store)) { ED_mesh_mirror_topo_table(ob, dm, 's'); } } else if (mode == 's') { /* start table */ - ED_mesh_mirrtopo_init(ob->data, dm, ob->mode, &mesh_topo_store, false); + ED_mesh_mirrtopo_init(ob->data, dm, &mesh_topo_store, false); } else if (mode == 'e') { /* end table */ ED_mesh_mirrtopo_free(&mesh_topo_store); @@ -1106,7 +1018,7 @@ bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], unsigned int return false; CTX_data_eval_ctx(C, &eval_ctx); - view3d_set_viewcontext(C, &vc); + ED_view3d_viewcontext_init(C, &vc); if (size) { /* sample rect to increase chances of selecting, so that when clicking @@ -1277,7 +1189,7 @@ bool ED_mesh_pick_vert(bContext *C, Object *ob, const int mval[2], unsigned int if (!me || me->totvert == 0) return false; - view3d_set_viewcontext(C, &vc); + ED_view3d_viewcontext_init(C, &vc); if (use_zbuf) { if (size > 0) { diff --git a/source/blender/editors/metaball/CMakeLists.txt b/source/blender/editors/metaball/CMakeLists.txt index 89ba942ac36..73f80774716 100644 --- a/source/blender/editors/metaball/CMakeLists.txt +++ b/source/blender/editors/metaball/CMakeLists.txt @@ -35,6 +35,7 @@ set(INC_SYS ) set(SRC + editmball_undo.c mball_edit.c mball_ops.c diff --git a/source/blender/editors/metaball/editmball_undo.c b/source/blender/editors/metaball/editmball_undo.c new file mode 100644 index 00000000000..cc461c0c365 --- /dev/null +++ b/source/blender/editors/metaball/editmball_undo.c @@ -0,0 +1,200 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/metaball/editmball_undo.c + * \ingroup edmeta + */ + +#include <math.h> +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" +#include "BLI_listbase.h" +#include "BLI_array_utils.h" + +#include "DNA_defs.h" +#include "DNA_meta_types.h" +#include "DNA_object_types.h" + +#include "BKE_context.h" +#include "BKE_undo_system.h" + +#include "DEG_depsgraph.h" + +#include "ED_object.h" +#include "ED_mball.h" +#include "ED_util.h" + +#include "WM_types.h" +#include "WM_api.h" + +/* -------------------------------------------------------------------- */ +/** \name Undo Conversion + * \{ */ + +typedef struct UndoMBall { + ListBase editelems; + int lastelem_index; + size_t undo_size; +} UndoMBall; + +/* free all MetaElems from ListBase */ +static void freeMetaElemlist(ListBase *lb) +{ + MetaElem *ml; + + if (lb == NULL) { + return; + } + + while ((ml = BLI_pophead(lb))) { + MEM_freeN(ml); + } +} + +static void undomball_to_editmball(UndoMBall *umb, MetaBall *mb) +{ + freeMetaElemlist(mb->editelems); + mb->lastelem = NULL; + + /* copy 'undo' MetaElems to 'edit' MetaElems */ + int index = 0; + for (MetaElem *ml_undo = umb->editelems.first; ml_undo; ml_undo = ml_undo->next, index += 1) { + MetaElem *ml_edit = MEM_dupallocN(ml_undo); + BLI_addtail(mb->editelems, ml_edit); + if (index == umb->lastelem_index) { + mb->lastelem = ml_edit; + } + } +} + +static void *editmball_from_undomball(UndoMBall *umb, MetaBall *mb) +{ + BLI_assert(BLI_array_is_zeroed(umb, 1)); + + /* allocate memory for undo ListBase */ + umb->lastelem_index = -1; + + /* copy contents of current ListBase to the undo ListBase */ + int index = 0; + for (MetaElem *ml_edit = mb->editelems->first; ml_edit; ml_edit = ml_edit->next, index += 1) { + MetaElem *ml_undo = MEM_dupallocN(ml_edit); + BLI_addtail(&umb->editelems, ml_undo); + if (ml_edit == mb->lastelem) { + umb->lastelem_index = index; + } + umb->undo_size += sizeof(MetaElem); + } + + return umb; +} + +/* free undo ListBase of MetaElems */ +static void undomball_free_data(UndoMBall *umb) +{ + freeMetaElemlist(&umb->editelems); +} + +static Object *editmball_object_from_context(bContext *C) +{ + Object *obedit = CTX_data_edit_object(C); + if (obedit && obedit->type == OB_MBALL) { + MetaBall *mb = obedit->data; + if (mb->editelems != NULL) { + return obedit; + } + } + return NULL; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Implements ED Undo System + * \{ */ + +typedef struct MBallUndoStep { + UndoStep step; + /* note: will split out into list for multi-object-editmode. */ + UndoRefID_Object obedit_ref; + UndoMBall data; +} MBallUndoStep; + +static bool mball_undosys_poll(bContext *C) +{ + return editmball_object_from_context(C) != NULL; +} + +static bool mball_undosys_step_encode(struct bContext *C, UndoStep *us_p) +{ + MBallUndoStep *us = (MBallUndoStep *)us_p; + us->obedit_ref.ptr = editmball_object_from_context(C); + MetaBall *mb = us->obedit_ref.ptr->data; + editmball_from_undomball(&us->data, mb); + us->step.data_size = us->data.undo_size; + return true; +} + +static void mball_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir)) +{ + ED_object_mode_set(C, OB_MODE_EDIT); + + MBallUndoStep *us = (MBallUndoStep *)us_p; + Object *obedit = us->obedit_ref.ptr; + MetaBall *mb = obedit->data; + undomball_to_editmball(&us->data, mb); + DEG_id_tag_update(&obedit->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); +} + +static void mball_undosys_step_free(UndoStep *us_p) +{ + MBallUndoStep *us = (MBallUndoStep *)us_p; + undomball_free_data(&us->data); +} + +static void mball_undosys_foreach_ID_ref( + UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data) +{ + MBallUndoStep *us = (MBallUndoStep *)us_p; + foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref)); +} + +/* Export for ED_undo_sys. */ +void ED_mball_undosys_type(UndoType *ut) +{ + ut->name = "Edit MBall"; + ut->poll = mball_undosys_poll; + ut->step_encode = mball_undosys_step_encode; + ut->step_decode = mball_undosys_step_decode; + ut->step_free = mball_undosys_step_free; + + ut->step_foreach_ID_ref = mball_undosys_foreach_ID_ref; + + ut->mode = BKE_UNDOTYPE_MODE_STORE; + ut->use_context = true; + + ut->step_size = sizeof(MBallUndoStep); + +} + +/** \} */ diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c index 935f1a5ea4a..6dd16b52387 100644 --- a/source/blender/editors/metaball/mball_edit.c +++ b/source/blender/editors/metaball/mball_edit.c @@ -29,7 +29,6 @@ * \ingroup edmeta */ - #include <math.h> #include <string.h> @@ -56,7 +55,6 @@ #include "ED_mball.h" #include "ED_screen.h" #include "ED_view3d.h" -#include "ED_util.h" #include "WM_api.h" #include "WM_types.h" @@ -598,7 +596,7 @@ bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool dese rcti rect; CTX_data_eval_ctx(C, &eval_ctx); - view3d_set_viewcontext(C, &vc); + ED_view3d_viewcontext_init(C, &vc); BLI_rcti_init_pt_radius(&rect, mval, 12); @@ -668,94 +666,3 @@ bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool dese } -/* ************* undo for MetaBalls ************* */ - -typedef struct UndoMBall { - ListBase editelems; - int lastelem_index; -} UndoMBall; - -/* free all MetaElems from ListBase */ -static void freeMetaElemlist(ListBase *lb) -{ - MetaElem *ml; - - if (lb == NULL) return; - - while ((ml = BLI_pophead(lb))) { - MEM_freeN(ml); - } -} - - -static void undoMball_to_editMball(void *umb_v, void *mb_v, void *UNUSED(obdata)) -{ - MetaBall *mb = mb_v; - UndoMBall *umb = umb_v; - - freeMetaElemlist(mb->editelems); - mb->lastelem = NULL; - - /* copy 'undo' MetaElems to 'edit' MetaElems */ - int index = 0; - for (MetaElem *ml_undo = umb->editelems.first; ml_undo; ml_undo = ml_undo->next, index += 1) { - MetaElem *ml_edit = MEM_dupallocN(ml_undo); - BLI_addtail(mb->editelems, ml_edit); - if (index == umb->lastelem_index) { - mb->lastelem = ml_edit; - } - } - -} - -static void *editMball_to_undoMball(void *mb_v, void *UNUSED(obdata)) -{ - MetaBall *mb = mb_v; - UndoMBall *umb; - - /* allocate memory for undo ListBase */ - umb = MEM_callocN(sizeof(UndoMBall), __func__); - umb->lastelem_index = -1; - - /* copy contents of current ListBase to the undo ListBase */ - int index = 0; - for (MetaElem *ml_edit = mb->editelems->first; ml_edit; ml_edit = ml_edit->next, index += 1) { - MetaElem *ml_undo = MEM_dupallocN(ml_edit); - BLI_addtail(&umb->editelems, ml_undo); - if (ml_edit == mb->lastelem) { - umb->lastelem_index = index; - } - } - - return umb; -} - -/* free undo ListBase of MetaElems */ -static void free_undoMball(void *umb_v) -{ - UndoMBall *umb = umb_v; - - freeMetaElemlist(&umb->editelems); - MEM_freeN(umb); -} - -static MetaBall *metaball_get_obdata(Object *ob) -{ - if (ob && ob->type == OB_MBALL) { - return ob->data; - } - return NULL; -} - - -static void *get_data(bContext *C) -{ - Object *obedit = CTX_data_edit_object(C); - return metaball_get_obdata(obedit); -} - -/* this is undo system for MetaBalls */ -void undo_push_mball(bContext *C, const char *name) -{ - undo_editmode_push(C, name, get_data, free_undoMball, undoMball_to_editMball, editMball_to_undoMball, NULL); -} diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt index 8050508983b..646b8137b2d 100644 --- a/source/blender/editors/object/CMakeLists.txt +++ b/source/blender/editors/object/CMakeLists.txt @@ -50,8 +50,8 @@ set(SRC object_facemap_ops.c object_group.c object_hook.c - object_lattice.c object_lod.c + object_modes.c object_modifier.c object_ops.c object_random.c diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 89b131fa340..3a12d56d9c2 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -43,8 +43,8 @@ #include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meta_types.h" -#include "DNA_object_fluidsim.h" -#include "DNA_object_force.h" +#include "DNA_object_fluidsim_types.h" +#include "DNA_object_force_types.h" #include "DNA_object_types.h" #include "DNA_lightprobe_types.h" #include "DNA_scene_types.h" @@ -434,7 +434,7 @@ Object *ED_object_add_type( /* for as long scene has editmode... */ if (CTX_data_edit_object(C)) - ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO); /* freedata, and undo */ + ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO); /* freedata, and undo */ /* deselects all, sets scene->basact */ ob = BKE_object_add(bmain, scene, view_layer, type, name); @@ -1194,8 +1194,8 @@ static int object_speaker_add_exec(bContext *C, wmOperator *op) { /* create new data for NLA hierarchy */ AnimData *adt = BKE_animdata_add_id(&ob->id); - NlaTrack *nlt = add_nlatrack(adt, NULL); - NlaStrip *strip = add_nla_soundstrip(scene, ob->data); + NlaTrack *nlt = BKE_nlatrack_add(adt, NULL); + NlaStrip *strip = BKE_nla_add_soundstrip(scene, ob->data); strip->start = CFRA; strip->end += strip->start; @@ -1696,7 +1696,7 @@ static void curvetomesh(EvaluationContext *eval_ctx, Main *bmain, Scene *scene, BKE_mesh_from_nurbs(ob); /* also does users */ if (ob->type == OB_MESH) { - BKE_object_free_modifiers(ob); + BKE_object_free_modifiers(ob, 0); /* Game engine defaults for mesh objects */ ob->body_type = OB_BODY_TYPE_STATIC; @@ -1710,7 +1710,7 @@ static int convert_poll(bContext *C) Base *base_act = CTX_data_active_base(C); Object *obact = base_act ? base_act->object : NULL; - return (!ID_IS_LINKED(scene) && obact && scene->obedit != obact && + return (!ID_IS_LINKED(scene) && obact && (BKE_object_is_in_editmode(obact) == false) && (base_act->flag & BASE_SELECTED) && !ID_IS_LINKED(obact)); } @@ -1756,7 +1756,7 @@ static int convert_exec(bContext *C, wmOperator *op) /* don't forget multiple users! */ { - FOREACH_SCENE_OBJECT(scene, ob) + FOREACH_SCENE_OBJECT_BEGIN(scene, ob) { ob->flag &= ~OB_DONE; @@ -1776,7 +1776,7 @@ static int convert_exec(bContext *C, wmOperator *op) } } } - FOREACH_SCENE_OBJECT_END + FOREACH_SCENE_OBJECT_END; } ListBase selected_editable_bases = CTX_data_collection_get(C, "selected_editable_bases"); @@ -1806,7 +1806,7 @@ static int convert_exec(bContext *C, wmOperator *op) Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true); uint64_t customdata_mask_prev = scene->customdata_mask; scene->customdata_mask |= CD_MASK_MESH; - BKE_scene_graph_update_tagged(bmain->eval_ctx, depsgraph, bmain, scene, view_layer); + BKE_scene_graph_update_tagged(depsgraph, bmain); scene->customdata_mask = customdata_mask_prev; } @@ -1825,7 +1825,7 @@ static int convert_exec(bContext *C, wmOperator *op) /* When 2 objects with linked data are selected, converting both * would keep modifiers on all but the converted object [#26003] */ if (ob->type == OB_MESH) { - BKE_object_free_modifiers(ob); /* after derivedmesh calls! */ + BKE_object_free_modifiers(ob, 0); /* after derivedmesh calls! */ } } } @@ -1850,7 +1850,7 @@ static int convert_exec(bContext *C, wmOperator *op) BKE_mesh_to_curve(&eval_ctx, scene, newob); if (newob->type == OB_CURVE) { - BKE_object_free_modifiers(newob); /* after derivedmesh calls! */ + BKE_object_free_modifiers(newob, 0); /* after derivedmesh calls! */ ED_rigidbody_object_remove(bmain, scene, newob); } } @@ -1883,7 +1883,7 @@ static int convert_exec(bContext *C, wmOperator *op) /* re-tessellation is called by DM_to_mesh */ - BKE_object_free_modifiers(newob); /* after derivedmesh calls! */ + BKE_object_free_modifiers(newob, 0); /* after derivedmesh calls! */ } else if (ob->type == OB_FONT) { ob->flag |= OB_DONE; @@ -2046,7 +2046,7 @@ static int convert_exec(bContext *C, wmOperator *op) if (!keep_original) { if (mballConverted) { - FOREACH_SCENE_OBJECT(scene, ob_mball) + FOREACH_SCENE_OBJECT_BEGIN(scene, ob_mball) { if (ob_mball->type == OB_MBALL) { if (ob_mball->flag & OB_DONE) { @@ -2059,7 +2059,7 @@ static int convert_exec(bContext *C, wmOperator *op) } } } - FOREACH_SCENE_OBJECT_END + FOREACH_SCENE_OBJECT_END; } /* delete object should renew depsgraph */ @@ -2560,10 +2560,9 @@ static int join_poll(bContext *C) static int join_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); - if (scene->obedit) { + if (ob->mode & OB_MODE_EDIT) { BKE_report(op->reports, RPT_ERROR, "This data does not support joining in edit mode"); return OPERATOR_CANCELLED; } @@ -2614,10 +2613,9 @@ static int join_shapes_poll(bContext *C) static int join_shapes_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); - if (scene->obedit) { + if (ob->mode & OB_MODE_EDIT) { BKE_report(op->reports, RPT_ERROR, "This data does not support joining in edit mode"); return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c index 3efb6253f6f..a38b9959dab 100644 --- a/source/blender/editors/object/object_bake.c +++ b/source/blender/editors/object/object_bake.c @@ -576,6 +576,7 @@ typedef struct BakeRender { Render *re; Main *main; Scene *scene; + ViewLayer *view_layer; struct Object *actob; int result, ready; @@ -625,6 +626,7 @@ static void init_bake_internal(BakeRender *bkr, bContext *C) bkr->sa = sc ? BKE_screen_find_big_area(sc, SPACE_IMAGE, 10) : NULL; /* can be NULL */ bkr->main = CTX_data_main(C); bkr->scene = scene; + bkr->view_layer = view_layer; bkr->actob = (scene->r.bake_flag & R_BAKE_TO_ACTIVE) ? OBACT(view_layer) : NULL; bkr->re = RE_NewRender("_Bake View_"); @@ -730,7 +732,7 @@ static void bake_startjob(void *bkv, short *stop, short *do_update, float *progr RE_test_break_cb(bkr->re, NULL, thread_break); G.is_break = false; /* BKE_blender_test_break uses this global */ - RE_Database_Baking(bkr->re, bmain, scene, scene->lay, scene->r.bake_mode, bkr->actob); + RE_Database_Baking(bkr->re, bmain, scene, bkr->view_layer, scene->lay, scene->r.bake_mode, bkr->actob); /* baking itself is threaded, cannot use test_break in threads. we also update optional imagewindow */ bkr->result = RE_bake_shade_all_selected(bkr->re, scene->r.bake_mode, bkr->actob, bkr->do_update, bkr->progress); @@ -838,7 +840,6 @@ static int bake_image_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); int result = OPERATOR_CANCELLED; if (is_multires_bake(scene)) { @@ -858,12 +859,13 @@ static int bake_image_exec(bContext *C, wmOperator *op) RE_test_break_cb(bkr.re, NULL, thread_break); G.is_break = false; /* BKE_blender_test_break uses this global */ - RE_Database_Baking(bkr.re, bmain, scene, scene->lay, scene->r.bake_mode, (scene->r.bake_flag & R_BAKE_TO_ACTIVE) ? OBACT(view_layer) : NULL); + RE_Database_Baking(bkr.re, bmain, scene, bkr.view_layer, scene->lay, scene->r.bake_mode, + (scene->r.bake_flag & R_BAKE_TO_ACTIVE) ? OBACT(bkr.view_layer) : NULL); /* baking itself is threaded, cannot use test_break in threads */ - BLI_init_threads(&threads, do_bake_render, 1); + BLI_threadpool_init(&threads, do_bake_render, 1); bkr.ready = 0; - BLI_insert_thread(&threads, &bkr); + BLI_threadpool_insert(&threads, &bkr); while (bkr.ready == 0) { PIL_sleep_ms(50); @@ -874,7 +876,7 @@ static int bake_image_exec(bContext *C, wmOperator *op) if (!G.background) BKE_blender_test_break(); } - BLI_end_threads(&threads); + BLI_threadpool_end(&threads); if (bkr.result == BAKE_RESULT_NO_OBJECTS) BKE_report(op->reports, RPT_ERROR, "No valid images found to bake to"); diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index 0174a307c16..40a49df1657 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -56,9 +56,11 @@ #include "BKE_report.h" #include "BKE_modifier.h" #include "BKE_mesh.h" +#include "BKE_scene.h" #include "BKE_screen.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" #include "RE_engine.h" #include "RE_pipeline.h" @@ -84,8 +86,8 @@ static void bake_set_props(wmOperator *op, Scene *scene); typedef struct BakeAPIRender { Object *ob; Main *main; - Depsgraph *depsgraph; Scene *scene; + ViewLayer *view_layer; ReportList *reports; ListBase selected_objects; @@ -623,10 +625,9 @@ static size_t initialize_internal_images(BakeImages *bake_images, ReportList *re /* create new mesh with edit mode changes and modifiers applied */ static Mesh *bake_mesh_new_from_object(EvaluationContext *eval_ctx, Main *bmain, Scene *scene, Object *ob) { - if (ob->mode & OB_MODE_EDIT) - ED_object_editmode_load(ob); + ED_object_editmode_load(ob); - Mesh *me = BKE_mesh_new_from_object(eval_ctx, bmain, scene, ob, 1, 2, 0, 0); + Mesh *me = BKE_mesh_new_from_object(eval_ctx, bmain, scene, ob, 1, 0, 0); if (me->flag & ME_AUTOSMOOTH) { BKE_mesh_split_faces(me, true); } @@ -635,7 +636,8 @@ static Mesh *bake_mesh_new_from_object(EvaluationContext *eval_ctx, Main *bmain, } static int bake( - Render *re, Main *bmain, Depsgraph *graph, Scene *scene, Object *ob_low, ListBase *selected_objects, ReportList *reports, + Render *re, Main *bmain, Scene *scene, ViewLayer *view_layer, Object *ob_low, ListBase *selected_objects, + ReportList *reports, const eScenePassType pass_type, const int pass_filter, const int margin, const eBakeSaveMode save_mode, const bool is_clear, const bool is_split_materials, const bool is_automatic_name, const bool is_selected_to_active, const bool is_cage, @@ -643,6 +645,10 @@ static int bake( const char *custom_cage, const char *filepath, const int width, const int height, const char *identifier, ScrArea *sa, const char *uv_layer) { + EvaluationContext *eval_ctx = DEG_evaluation_context_new(DAG_EVAL_RENDER); + Depsgraph *depsgraph = DEG_graph_new(scene, view_layer, DAG_EVAL_RENDER); + DEG_evaluation_context_init_from_view_layer_for_render(eval_ctx, depsgraph, scene, view_layer); + int op_result = OPERATOR_CANCELLED; bool ok = false; @@ -674,7 +680,7 @@ static int bake( size_t num_pixels; int tot_materials; - RE_bake_engine_set_engine_parameters(re, bmain, graph, scene); + RE_bake_engine_set_engine_parameters(re, bmain, scene); if (!RE_bake_has_engine(re)) { BKE_report(reports, RPT_ERROR, "Current render engine does not support baking"); @@ -784,8 +790,12 @@ static int bake( } } + /* Make sure depsgraph is up to date. */ + DEG_graph_build_from_view_layer(depsgraph, bmain, scene, view_layer); + BKE_scene_graph_update_tagged(depsgraph, bmain); + /* get the mesh as it arrives in the renderer */ - me_low = bake_mesh_new_from_object(RE_GetEvalCtx(re), bmain, scene, ob_low); + me_low = bake_mesh_new_from_object(eval_ctx, bmain, scene, ob_low); /* populate the pixel array with the face data */ if ((is_selected_to_active && (ob_cage == NULL) && is_cage) == false) @@ -800,7 +810,7 @@ static int bake( /* prepare cage mesh */ if (ob_cage) { - me_cage = bake_mesh_new_from_object(RE_GetEvalCtx(re), bmain, scene, ob_cage); + me_cage = bake_mesh_new_from_object(eval_ctx, bmain, scene, ob_cage); if ((me_low->totpoly != me_cage->totpoly) || (me_low->totloop != me_cage->totloop)) { BKE_report(reports, RPT_ERROR, "Invalid cage object, the cage mesh must have the same number " @@ -832,7 +842,7 @@ static int bake( ob_low->modifiers = modifiers_tmp; /* get the cage mesh as it arrives in the renderer */ - me_cage = bake_mesh_new_from_object(RE_GetEvalCtx(re), bmain, scene, ob_low); + me_cage = bake_mesh_new_from_object(eval_ctx, bmain, scene, ob_low); RE_bake_pixels_populate(me_cage, pixel_array_low, num_pixels, &bake_images, uv_layer); } @@ -858,7 +868,7 @@ static int bake( tmd->quad_method = MOD_TRIANGULATE_QUAD_FIXED; tmd->ngon_method = MOD_TRIANGULATE_NGON_EARCLIP; - highpoly[i].me = bake_mesh_new_from_object(RE_GetEvalCtx(re), bmain, scene, highpoly[i].ob); + highpoly[i].me = bake_mesh_new_from_object(eval_ctx, bmain, scene, highpoly[i].ob); highpoly[i].ob->restrictflag &= ~OB_RESTRICT_RENDER; /* lowpoly to highpoly transformation matrix */ @@ -961,7 +971,7 @@ cage_cleanup: md->mode &= ~eModifierMode_Render; } - me_nores = bake_mesh_new_from_object(RE_GetEvalCtx(re), bmain, scene, ob_low); + me_nores = bake_mesh_new_from_object(eval_ctx, bmain, scene, ob_low); RE_bake_pixels_populate(me_nores, pixel_array_low, num_pixels, &bake_images, uv_layer); RE_bake_normal_world_to_tangent(pixel_array_low, num_pixels, depth, result, me_nores, normal_swizzle, ob_low->obmat); @@ -1122,7 +1132,7 @@ static void bake_init_api_data(wmOperator *op, bContext *C, BakeAPIRender *bkr) bkr->ob = CTX_data_active_object(C); bkr->main = CTX_data_main(C); - bkr->depsgraph = CTX_data_depsgraph(C); + bkr->view_layer = CTX_data_view_layer(C); bkr->scene = CTX_data_scene(C); bkr->sa = sc ? BKE_screen_find_big_area(sc, SPACE_IMAGE, 10) : NULL; @@ -1206,7 +1216,7 @@ static int bake_exec(bContext *C, wmOperator *op) if (bkr.is_selected_to_active) { result = bake( - bkr.render, bkr.main, bkr.depsgraph, bkr.scene, bkr.ob, &bkr.selected_objects, bkr.reports, + bkr.render, bkr.main, bkr.scene, bkr.view_layer, bkr.ob, &bkr.selected_objects, bkr.reports, bkr.pass_type, bkr.pass_filter, bkr.margin, bkr.save_mode, bkr.is_clear, bkr.is_split_materials, bkr.is_automatic_name, true, bkr.is_cage, bkr.cage_extrusion, bkr.normal_space, bkr.normal_swizzle, @@ -1219,7 +1229,7 @@ static int bake_exec(bContext *C, wmOperator *op) for (link = bkr.selected_objects.first; link; link = link->next) { Object *ob_iter = link->ptr.data; result = bake( - bkr.render, bkr.main, bkr.depsgraph, bkr.scene, ob_iter, NULL, bkr.reports, + bkr.render, bkr.main, bkr.scene, bkr.view_layer, ob_iter, NULL, bkr.reports, bkr.pass_type, bkr.pass_filter, bkr.margin, bkr.save_mode, is_clear, bkr.is_split_materials, bkr.is_automatic_name, false, bkr.is_cage, bkr.cage_extrusion, bkr.normal_space, bkr.normal_swizzle, @@ -1264,7 +1274,7 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa if (bkr->is_selected_to_active) { bkr->result = bake( - bkr->render, bkr->main, bkr->depsgraph, bkr->scene, bkr->ob, &bkr->selected_objects, bkr->reports, + bkr->render, bkr->main, bkr->scene, bkr->view_layer, bkr->ob, &bkr->selected_objects, bkr->reports, bkr->pass_type, bkr->pass_filter, bkr->margin, bkr->save_mode, bkr->is_clear, bkr->is_split_materials, bkr->is_automatic_name, true, bkr->is_cage, bkr->cage_extrusion, bkr->normal_space, bkr->normal_swizzle, @@ -1277,7 +1287,7 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa for (link = bkr->selected_objects.first; link; link = link->next) { Object *ob_iter = link->ptr.data; bkr->result = bake( - bkr->render, bkr->main, bkr->depsgraph, bkr->scene, ob_iter, NULL, bkr->reports, + bkr->render, bkr->main, bkr->scene, bkr->view_layer, ob_iter, NULL, bkr->reports, bkr->pass_type, bkr->pass_filter, bkr->margin, bkr->save_mode, is_clear, bkr->is_split_materials, bkr->is_automatic_name, false, bkr->is_cage, bkr->cage_extrusion, bkr->normal_space, bkr->normal_swizzle, diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index 05a5f652382..1a20a8db5b3 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -684,6 +684,8 @@ static bConstraint *edit_constraint_property_get(wmOperator *op, Object *ob, int static int stretchto_reset_exec(bContext *C, wmOperator *op) { + EvaluationContext eval_ctx; + CTX_data_eval_ctx(C, &eval_ctx); Object *ob = ED_object_active_context(C); bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_STRETCHTO); bStretchToConstraint *data = (con) ? (bStretchToConstraint *)con->data : NULL; @@ -730,6 +732,8 @@ void CONSTRAINT_OT_stretchto_reset(wmOperatorType *ot) static int limitdistance_reset_exec(bContext *C, wmOperator *op) { + EvaluationContext eval_ctx; + CTX_data_eval_ctx(C, &eval_ctx); Object *ob = ED_object_active_context(C); bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_DISTLIMIT); bDistLimitConstraint *data = (con) ? (bDistLimitConstraint *)con->data : NULL; @@ -866,6 +870,8 @@ static void child_get_inverse_matrix(const bContext *C, Scene *scene, Object *ob /* ChildOf Constraint - set inverse callback */ static int childof_set_inverse_exec(bContext *C, wmOperator *op) { + EvaluationContext eval_ctx; + CTX_data_eval_ctx(C, &eval_ctx); Scene *scene = CTX_data_scene(C); Object *ob = ED_object_active_context(C); bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_CHILDOF); @@ -917,6 +923,8 @@ void CONSTRAINT_OT_childof_set_inverse(wmOperatorType *ot) static int childof_clear_inverse_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_active_context(C); + EvaluationContext eval_ctx; + CTX_data_eval_ctx(C, &eval_ctx); bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_CHILDOF); bChildOfConstraint *data = (con) ? (bChildOfConstraint *)con->data : NULL; @@ -964,6 +972,8 @@ void CONSTRAINT_OT_childof_clear_inverse(wmOperatorType *ot) static int followpath_path_animate_exec(bContext *C, wmOperator *op) { + EvaluationContext eval_ctx; + CTX_data_eval_ctx(C, &eval_ctx); Object *ob = ED_object_active_context(C); bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_FOLLOWPATH); bFollowPathConstraint *data = (con) ? (bFollowPathConstraint *)con->data : NULL; @@ -1088,6 +1098,8 @@ void CONSTRAINT_OT_followpath_path_animate(wmOperatorType *ot) static int objectsolver_set_inverse_exec(bContext *C, wmOperator *op) { + EvaluationContext eval_ctx; + CTX_data_eval_ctx(C, &eval_ctx); Scene *scene = CTX_data_scene(C); Object *ob = ED_object_active_context(C); bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_OBJECTSOLVER); @@ -1137,6 +1149,8 @@ void CONSTRAINT_OT_objectsolver_set_inverse(wmOperatorType *ot) static int objectsolver_clear_inverse_exec(bContext *C, wmOperator *op) { + EvaluationContext eval_ctx; + CTX_data_eval_ctx(C, &eval_ctx); Object *ob = ED_object_active_context(C); bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_OBJECTSOLVER); bObjectSolverConstraint *data = (con) ? (bObjectSolverConstraint *)con->data : NULL; @@ -1306,6 +1320,8 @@ void CONSTRAINT_OT_delete(wmOperatorType *ot) static int constraint_move_down_exec(bContext *C, wmOperator *op) { + EvaluationContext eval_ctx; + CTX_data_eval_ctx(C, &eval_ctx); Object *ob = ED_object_active_context(C); bConstraint *con = edit_constraint_property_get(op, ob, 0); @@ -1355,6 +1371,8 @@ void CONSTRAINT_OT_move_down(wmOperatorType *ot) static int constraint_move_up_exec(bContext *C, wmOperator *op) { + EvaluationContext eval_ctx; + CTX_data_eval_ctx(C, &eval_ctx); Object *ob = ED_object_active_context(C); bConstraint *con = edit_constraint_property_get(op, ob, 0); @@ -1575,6 +1593,8 @@ void OBJECT_OT_constraints_copy(wmOperatorType *ot) /* get the Object and/or PoseChannel to use as target */ static bool get_new_constraint_target(bContext *C, int con_type, Object **tar_ob, bPoseChannel **tar_pchan, bool add) { + EvaluationContext eval_ctx; + CTX_data_eval_ctx(C, &eval_ctx); Object *obact = ED_object_active_context(C); bPoseChannel *pchanact = BKE_pose_channel_active(obact); bool only_curve = false, only_mesh = false, only_ob = false; @@ -1653,7 +1673,7 @@ static bool get_new_constraint_target(bContext *C, int con_type, Object **tar_ob /* for armatures in pose mode, look inside the armature for the active bone * so that we set up cross-armature constraints with less effort */ - if ((ob->type == OB_ARMATURE) && (ob->mode & OB_MODE_POSE) && + if ((ob->type == OB_ARMATURE) && (eval_ctx.mode & OB_MODE_POSE) && (!only_curve && !only_mesh)) { /* just use the active bone, and assume that it is visible + usable */ diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 6222dbbf01b..b4fa27c3fd9 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -54,15 +54,17 @@ #include "DNA_property_types.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" -#include "DNA_object_force.h" +#include "DNA_object_force_types.h" #include "DNA_meshdata_types.h" #include "DNA_vfont_types.h" #include "DNA_mesh_types.h" +#include "DNA_lattice_types.h" #include "DNA_workspace_types.h" #include "IMB_imbuf_types.h" #include "BKE_anim.h" +#include "BKE_collection.h" #include "BKE_constraint.h" #include "BKE_context.h" #include "BKE_curve.h" @@ -76,13 +78,16 @@ #include "BKE_mball.h" #include "BKE_mesh.h" #include "BKE_object.h" +#include "BKE_paint.h" #include "BKE_pointcache.h" #include "BKE_property.h" #include "BKE_sca.h" #include "BKE_softbody.h" #include "BKE_modifier.h" +#include "BKE_editlattice.h" #include "BKE_editmesh.h" #include "BKE_report.h" +#include "BKE_object.h" #include "BKE_workspace.h" #include "DEG_depsgraph.h" @@ -96,7 +101,7 @@ #include "ED_lattice.h" #include "ED_object.h" #include "ED_screen.h" -#include "ED_util.h" +#include "ED_undo.h" #include "ED_image.h" #include "RNA_access.h" @@ -106,11 +111,16 @@ /* for menu/popup icons etc etc*/ #include "UI_interface.h" +#include "UI_resources.h" #include "WM_api.h" #include "WM_types.h" #include "object_intern.h" // own include +/* prototypes */ +typedef struct MoveToCollectionData MoveToCollectionData; +static void move_to_collection_menus_items(struct uiLayout *layout, struct MoveToCollectionData *menu); + /* ************* XXX **************** */ static void error(const char *UNUSED(arg)) {} static void waitcursor(int UNUSED(val)) {} @@ -172,6 +182,9 @@ static bool ED_object_editmode_load_ex(Main *bmain, Object *obedit, const bool f if (obedit->type == OB_MESH) { Mesh *me = obedit->data; + if (me->edit_btmesh == NULL) { + return false; + } if (me->edit_btmesh->bm->totvert > MESH_MAX_VERTS) { error("Too many vertices"); @@ -185,15 +198,21 @@ static bool ED_object_editmode_load_ex(Main *bmain, Object *obedit, const bool f MEM_freeN(me->edit_btmesh); me->edit_btmesh = NULL; } - if (obedit->restore_mode & OB_MODE_WEIGHT_PAINT) { + /* will be recalculated as needed. */ + { ED_mesh_mirror_spatial_table(NULL, NULL, NULL, NULL, 'e'); ED_mesh_mirror_topo_table(NULL, NULL, 'e'); } } else if (obedit->type == OB_ARMATURE) { + const bArmature *arm = obedit->data; + if (arm->edbo == NULL) { + return false; + } ED_armature_from_edit(obedit->data); - if (freedata) + if (freedata) { ED_armature_edit_free(obedit->data); + } /* TODO(sergey): Pose channels might have been changed, so need * to inform dependency graph about this. But is it really the * best place to do this? @@ -201,31 +220,50 @@ static bool ED_object_editmode_load_ex(Main *bmain, Object *obedit, const bool f DEG_relations_tag_update(bmain); } else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) { + const Curve *cu = obedit->data; + if (cu->editnurb == NULL) { + return false; + } ED_curve_editnurb_load(obedit); - if (freedata) ED_curve_editnurb_free(obedit); + if (freedata) { + ED_curve_editnurb_free(obedit); + } } else if (obedit->type == OB_FONT) { + const Curve *cu = obedit->data; + if (cu->editfont == NULL) { + return false; + } ED_curve_editfont_load(obedit); - if (freedata) ED_curve_editfont_free(obedit); + if (freedata) { + ED_curve_editfont_free(obedit); + } } else if (obedit->type == OB_LATTICE) { - ED_lattice_editlatt_load(obedit); - if (freedata) ED_lattice_editlatt_free(obedit); + const Lattice *lt = obedit->data; + if (lt->editlatt == NULL) { + return false; + } + BKE_editlattice_load(obedit); + if (freedata) { + BKE_editlattice_free(obedit); + } } else if (obedit->type == OB_MBALL) { + const MetaBall *mb = obedit->data; + if (mb->editelems == NULL) { + return false; + } ED_mball_editmball_load(obedit); - if (freedata) ED_mball_editmball_free(obedit); + if (freedata) { + ED_mball_editmball_free(obedit); + } } else if (obedit->type == OB_GROOM) { ED_groom_editgroom_load(obedit); if (freedata) ED_groom_editgroom_free(obedit); } - /* Tag update so no access to freed data referenced from - * derived cache will happen. - */ - DEG_id_tag_update((ID *)obedit->data, 0); - return true; } @@ -235,18 +273,23 @@ bool ED_object_editmode_load(Object *obedit) return ED_object_editmode_load_ex(G.main, obedit, false); } -void ED_object_editmode_exit(bContext *C, int flag) +/** + * \param C: Can be NULL, only if #EM_DO_UNDO isn't set. + * \param flag: + * - Only in exceptional cases should #EM_DO_UNDO NOT be in the flag. + * - If #EM_FREEDATA isn't in the flag, use ED_object_editmode_load directly. + */ +void ED_object_editmode_exit_ex(bContext *C, Scene *scene, Object *obedit, int flag) { + BLI_assert(C || !(flag & EM_DO_UNDO)); /* Note! only in exceptional cases should 'EM_DO_UNDO' NOT be in the flag */ /* Note! if 'EM_FREEDATA' isn't in the flag, use ED_object_editmode_load directly */ - Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); - Object *obedit = CTX_data_edit_object(C); const bool freedata = (flag & EM_FREEDATA) != 0; if (flag & EM_WAITCURSOR) waitcursor(1); - if (ED_object_editmode_load_ex(CTX_data_main(C), obedit, freedata) == false) { + if (ED_object_editmode_load_ex(G.main, obedit, freedata) == false) { /* in rare cases (background mode) its possible active object * is flagged for editmode, without 'obedit' being set [#35489] */ if (UNLIKELY(view_layer->basact && (view_layer->basact->object->mode & OB_MODE_EDIT))) { @@ -261,9 +304,6 @@ void ED_object_editmode_exit(bContext *C, int flag) ListBase pidlist; PTCacheID *pid; - /* for example; displist make is different in editmode */ - scene->obedit = NULL; // XXX for context - /* flag object caches as outdated */ BKE_ptcache_ids_from_object(&pidlist, obedit, scene, 0); for (pid = pidlist.first; pid; pid = pid->next) { @@ -291,6 +331,12 @@ void ED_object_editmode_exit(bContext *C, int flag) DEG_id_tag_update(&scene->id, 0); } +void ED_object_editmode_exit(bContext *C, int flag) +{ + Scene *scene = CTX_data_scene(C); + Object *obedit = CTX_data_edit_object(C); + ED_object_editmode_exit_ex(C, scene, obedit, flag); +} void ED_object_editmode_enter(bContext *C, int flag) { @@ -328,18 +374,16 @@ void ED_object_editmode_enter(bContext *C, int flag) /* note, when switching scenes the object can have editmode data but * not be scene->obedit: bug 22954, this avoids calling self eternally */ if ((ob->restore_mode & OB_MODE_EDIT) == 0) - ED_object_toggle_modes(C, ob->mode); + ED_object_mode_toggle(C, ob->mode); ob->mode = OB_MODE_EDIT; if (ob->type == OB_MESH) { BMEditMesh *em; ok = 1; - scene->obedit = ob; /* context sees this */ - const bool use_key_index = mesh_needs_keyindex(ob->data); - EDBM_mesh_make(scene->toolsettings, ob, use_key_index); + EDBM_mesh_make(ob, scene->toolsettings->selectmode, use_key_index); em = BKE_editmesh_from_object(ob); if (LIKELY(em)) { @@ -366,7 +410,6 @@ void ED_object_editmode_enter(bContext *C, int flag) return; } ok = 1; - scene->obedit = ob; ED_armature_to_edit(arm); /* to ensure all goes in restposition and without striding */ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); /* XXX: should this be OB_RECALC_DATA? */ @@ -374,35 +417,30 @@ void ED_object_editmode_enter(bContext *C, int flag) WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_EDITMODE_ARMATURE, scene); } else if (ob->type == OB_FONT) { - scene->obedit = ob; /* XXX for context */ ok = 1; ED_curve_editfont_make(ob); WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_EDITMODE_TEXT, scene); } else if (ob->type == OB_MBALL) { - scene->obedit = ob; /* XXX for context */ ok = 1; ED_mball_editmball_make(ob); WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_EDITMODE_MBALL, scene); } else if (ob->type == OB_LATTICE) { - scene->obedit = ob; /* XXX for context */ ok = 1; - ED_lattice_editlatt_make(ob); + BKE_editlattice_make(ob); WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_EDITMODE_LATTICE, scene); } else if (ob->type == OB_SURF || ob->type == OB_CURVE) { ok = 1; - scene->obedit = ob; /* XXX for context */ ED_curve_editnurb_make(ob); WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_EDITMODE_CURVE, scene); } else if (ob->type == OB_GROOM) { - scene->obedit = ob; /* XXX for context */ ok = 1; ED_groom_editgroom_make(ob); @@ -415,7 +453,6 @@ void ED_object_editmode_enter(bContext *C, int flag) DEG_id_tag_update(&scene->id, 0); } else { - scene->obedit = NULL; /* XXX for context */ ob->mode &= ~OB_MODE_EDIT; WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, scene); } @@ -440,7 +477,7 @@ static int editmode_toggle_exec(bContext *C, wmOperator *op) if (!is_mode_set) ED_object_editmode_enter(C, EM_WAITCURSOR); else - ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR); /* had EM_DO_UNDO but op flag calls undo too [#24685] */ + ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR); /* had EM_DO_UNDO but op flag calls undo too [#24685] */ ED_space_image_uv_sculpt_update(CTX_wm_manager(C), scene); @@ -456,8 +493,9 @@ static int editmode_toggle_poll(bContext *C) return 0; /* if hidden but in edit mode, we still display */ - if ((ob->restrictflag & OB_RESTRICT_VIEW) && !(ob->mode & OB_MODE_EDIT)) + if ((ob->restrictflag & OB_RESTRICT_VIEW) && !(ob->mode & OB_MODE_EDIT)) { return 0; + } return OB_TYPE_SUPPORT_EDITMODE(ob->type); } @@ -485,7 +523,7 @@ static int posemode_exec(bContext *C, wmOperator *op) Base *base = CTX_data_active_base(C); Object *ob = base->object; const int mode_flag = OB_MODE_POSE; - const bool is_mode_set = (ob->mode & mode_flag) != 0; + bool is_mode_set = (ob->mode & mode_flag) != 0; if (!is_mode_set) { if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) { @@ -496,13 +534,15 @@ static int posemode_exec(bContext *C, wmOperator *op) if (ob->type == OB_ARMATURE) { if (ob == CTX_data_edit_object(C)) { ED_object_editmode_exit(C, EM_FREEDATA | EM_DO_UNDO); - ED_armature_enter_posemode(C, base); + is_mode_set = false; + } + + if (is_mode_set) { + ED_object_posemode_exit(C, ob); + } + else { + ED_object_posemode_enter(C, ob); } - else if (is_mode_set) - ED_armature_exit_posemode(C, base); - else - ED_armature_enter_posemode(C, base); - return OPERATOR_FINISHED; } @@ -683,7 +723,7 @@ static void copy_attr(Main *bmain, Scene *scene, ViewLayer *view_layer, short ev if (!(ob = OBACT(view_layer))) return; - if (scene->obedit) { // XXX get from context + if (BKE_object_is_in_editmode(ob)) { /* obedit_copymenu(); */ return; } @@ -880,7 +920,7 @@ static void copy_attr(Main *bmain, Scene *scene, ViewLayer *view_layer, short ev } else if (event == 26) { #if 0 // XXX old animation system - copy_nlastrips(&base->object->nlastrips, &ob->nlastrips); + BKE_nlastrip_copy(s(&base->object->nlastrips, &ob->nlastrips); #endif // XXX old animation system } else if (event == 27) { /* autosmooth */ @@ -922,7 +962,7 @@ static void copy_attr(Main *bmain, Scene *scene, ViewLayer *view_layer, short ev DEG_relations_tag_update(bmain); } -static void UNUSED_FUNCTION(copy_attr_menu) (Main *bmain, Scene *scene, ViewLayer *view_layer) +static void UNUSED_FUNCTION(copy_attr_menu) (Main *bmain, Scene *scene, ViewLayer *view_layer, Object *obedit) { Object *ob; short event; @@ -930,7 +970,7 @@ static void UNUSED_FUNCTION(copy_attr_menu) (Main *bmain, Scene *scene, ViewLaye if (!(ob = OBACT(view_layer))) return; - if (scene->obedit) { /* XXX get from context */ + if (obedit) { /* if (ob->type == OB_MESH) */ /* XXX mesh_copy_menu(); */ return; @@ -1011,7 +1051,7 @@ static int forcefield_toggle_exec(bContext *C, wmOperator *UNUSED(op)) ob->pd->forcefield = PFIELD_FORCE; else ob->pd->forcefield = 0; - + ED_object_check_force_modifiers(CTX_data_main(C), CTX_data_scene(C), ob); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); @@ -1346,7 +1386,7 @@ void OBJECT_OT_shade_smooth(wmOperatorType *ot) /* ********************** */ -static void UNUSED_FUNCTION(image_aspect) (Scene *scene, ViewLayer *view_layer) +static void UNUSED_FUNCTION(image_aspect) (Scene *scene, ViewLayer *view_layer, Object *obedit) { /* all selected objects with an image map: scale in image aspect */ Base *base; @@ -1356,7 +1396,7 @@ static void UNUSED_FUNCTION(image_aspect) (Scene *scene, ViewLayer *view_layer) float x, y, space; int a, b, done; - if (scene->obedit) return; // XXX get from context + if (obedit) return; if (ID_IS_LINKED(scene)) return; for (base = FIRSTBASE(view_layer); base; base = base->next) { @@ -1458,97 +1498,6 @@ static const EnumPropertyItem *object_mode_set_itemsf( return item; } -static const char *object_mode_op_string(int mode) -{ - if (mode & OB_MODE_EDIT) - return "OBJECT_OT_editmode_toggle"; - if (mode == OB_MODE_SCULPT) - return "SCULPT_OT_sculptmode_toggle"; - if (mode == OB_MODE_VERTEX_PAINT) - return "PAINT_OT_vertex_paint_toggle"; - if (mode == OB_MODE_WEIGHT_PAINT) - return "PAINT_OT_weight_paint_toggle"; - if (mode == OB_MODE_TEXTURE_PAINT) - return "PAINT_OT_texture_paint_toggle"; - if (mode == OB_MODE_PARTICLE_EDIT) - return "PARTICLE_OT_particle_edit_toggle"; - if (mode == OB_MODE_POSE) - return "OBJECT_OT_posemode_toggle"; - if (mode == OB_MODE_GPENCIL) - return "GPENCIL_OT_editmode_toggle"; - return NULL; -} - -/* checks the mode to be set is compatible with the object - * should be made into a generic function - */ -static bool object_mode_compat_test(Object *ob, eObjectMode mode) -{ - if (ob) { - if (mode == OB_MODE_OBJECT) - return true; - else if (mode == OB_MODE_GPENCIL) - return true; /* XXX: assume this is the case for now... */ - - switch (ob->type) { - case OB_MESH: - if (mode & (OB_MODE_EDIT | OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | - OB_MODE_TEXTURE_PAINT | OB_MODE_PARTICLE_EDIT)) - { - return true; - } - break; - case OB_CURVE: - case OB_SURF: - case OB_FONT: - case OB_MBALL: - case OB_GROOM: - if (mode & (OB_MODE_EDIT)) - return true; - break; - case OB_LATTICE: - if (mode & (OB_MODE_EDIT | OB_MODE_WEIGHT_PAINT)) - return true; - break; - case OB_ARMATURE: - if (mode & (OB_MODE_EDIT | OB_MODE_POSE)) - return true; - break; - } - } - - return false; -} - -/** - * Sets the mode to a compatible state (use before entering the mode). - * - * This is so each mode's exec function can call - */ -bool ED_object_mode_compat_set(bContext *C, Object *ob, int mode, ReportList *reports) -{ - bool ok; - if (!ELEM(ob->mode, mode, OB_MODE_OBJECT)) { - 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(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); - BKE_reportf(reports, RPT_ERROR, "Unable to execute '%s', error changing modes", ot->name); - } - } - else { - ok = true; - } - - return ok; -} - static int object_mode_set_poll(bContext *C) { /* Since Grease Pencil editmode is also handled here, @@ -1588,7 +1537,7 @@ static int object_mode_set_exec(bContext *C, wmOperator *op) } } - if (!ob || !object_mode_compat_test(ob, mode)) + if (!ob || !ED_object_mode_compat_test(ob, mode)) return OPERATOR_PASS_THROUGH; if (ob->mode != mode) { @@ -1599,20 +1548,20 @@ static int object_mode_set_exec(bContext *C, wmOperator *op) /* Exit current mode if it's not the mode we're setting */ if (mode != OB_MODE_OBJECT && (ob->mode != mode || toggle)) { /* Enter new mode */ - ED_object_toggle_modes(C, mode); + ED_object_mode_toggle(C, mode); } if (toggle) { /* Special case for Object mode! */ if (mode == OB_MODE_OBJECT && restore_mode == OB_MODE_OBJECT && ob->restore_mode != OB_MODE_OBJECT) { - ED_object_toggle_modes(C, ob->restore_mode); + ED_object_mode_toggle(C, ob->restore_mode); } else if (ob->mode == mode) { /* For toggling, store old mode so we know what to go back to */ ob->restore_mode = restore_mode; } else if (ob->restore_mode != OB_MODE_OBJECT && ob->restore_mode != mode) { - ED_object_toggle_modes(C, ob->restore_mode); + ED_object_mode_toggle(C, ob->restore_mode); } } @@ -1644,28 +1593,6 @@ void OBJECT_OT_mode_set(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } - -void ED_object_toggle_modes(bContext *C, int mode) -{ - if (mode != OB_MODE_OBJECT) { - const char *opstring = object_mode_op_string(mode); - - if (opstring) { -#ifdef USE_WORKSPACE_MODE - WorkSpace *workspace = CTX_wm_workspace(C); -#endif - WM_operator_name_call(C, opstring, WM_OP_EXEC_REGION_WIN, NULL); - -#ifdef USE_WORKSPACE_MODE - Object *ob = CTX_data_active_object(C); - if (ob) { - BKE_workspace_object_mode_set(workspace, CTX_data_scene(C), ob->mode); - } -#endif - } - } -} - /************************ Game Properties ***********************/ static int game_property_new_exec(bContext *C, wmOperator *op) @@ -2053,8 +1980,6 @@ void OBJECT_OT_game_physics_copy(struct wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* generic utility function */ - bool ED_object_editmode_calc_active_center(Object *obedit, const bool select_only, float r_center[3]) { switch (obedit->type) { @@ -2116,3 +2041,278 @@ bool ED_object_editmode_calc_active_center(Object *obedit, const bool select_onl return false; } + +#define COLLECTION_INVALID_INDEX -1 + +static int move_to_collection_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "collection_index"); + const bool is_add = RNA_boolean_get(op->ptr, "is_add"); + const bool is_new = RNA_boolean_get(op->ptr, "is_new"); + SceneCollection *scene_collection; + + if (!RNA_property_is_set(op->ptr, prop)) { + BKE_report(op->reports, RPT_ERROR, "No collection selected"); + return OPERATOR_CANCELLED; + } + + int collection_index = RNA_property_int_get(op->ptr, prop); + scene_collection = BKE_collection_from_index(CTX_data_scene(C), collection_index); + if (scene_collection == NULL) { + BKE_report(op->reports, RPT_ERROR, "Unexpected error, collection not found"); + return OPERATOR_CANCELLED; + } + + Object *single_object = NULL; + CTX_DATA_BEGIN (C, Object *, ob, selected_objects) + { + if (single_object != NULL) { + single_object = NULL; + break; + } + else { + single_object = ob; + } + } + CTX_DATA_END; + + if (is_new) { + char new_collection_name[MAX_NAME]; + RNA_string_get(op->ptr, "new_collection_name", new_collection_name); + scene_collection = BKE_collection_add(&scene->id, scene_collection, COLLECTION_TYPE_NONE, new_collection_name); + } + + if ((single_object != NULL) && + is_add && + BLI_findptr(&scene_collection->objects, single_object, offsetof(LinkData, data))) + { + BKE_reportf(op->reports, RPT_ERROR, "%s already in %s", single_object->id.name + 2, scene_collection->name); + return OPERATOR_CANCELLED; + } + + CTX_DATA_BEGIN (C, Object *, ob, selected_objects) + { + if (!is_add) { + BKE_collection_object_move(&scene->id, scene_collection, NULL, ob); + } + else { + BKE_collection_object_add(&scene->id, scene_collection, ob); + } + } + CTX_DATA_END; + + BKE_reportf(op->reports, + RPT_INFO, + "%s %s to %s", + (single_object != NULL) ? single_object->id.name + 2 : "Objects", + is_add ? "added" : "moved", + scene_collection->name); + + DEG_relations_tag_update(CTX_data_main(C)); + DEG_id_tag_update(&scene->id, 0); + + WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); + WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene); + + return OPERATOR_FINISHED; +} + +typedef struct MoveToCollectionData { + struct MoveToCollectionData *next, *prev; + int index; + struct SceneCollection *collection; + struct ListBase submenus; + PointerRNA ptr; + struct wmOperatorType *ot; +} MoveToCollectionData; + +static int move_to_collection_menus_create(wmOperator *op, MoveToCollectionData *menu) +{ + int index = menu->index; + for (SceneCollection *scene_collection = menu->collection->scene_collections.first; + scene_collection != NULL; + scene_collection = scene_collection->next) + { + MoveToCollectionData *submenu = MEM_callocN(sizeof(MoveToCollectionData), + "MoveToCollectionData submenu - expected memleak"); + BLI_addtail(&menu->submenus, submenu); + submenu->collection = scene_collection; + submenu->index = ++index; + index = move_to_collection_menus_create(op, submenu); + submenu->ot = op->type; + } + return index; +} + +static void move_to_collection_menus_free_recursive(MoveToCollectionData *menu) +{ + for (MoveToCollectionData *submenu = menu->submenus.first; + submenu != NULL; + submenu = submenu->next) + { + move_to_collection_menus_free_recursive(submenu); + } + BLI_freelistN(&menu->submenus); +} + +static void move_to_collection_menus_free(MoveToCollectionData **menu) +{ + if (*menu == NULL) { + return; + } + + move_to_collection_menus_free_recursive(*menu); + MEM_freeN(*menu); + *menu = NULL; +} + +static void move_to_collection_menu_create(bContext *UNUSED(C), uiLayout *layout, void *menu_v) +{ + MoveToCollectionData *menu = menu_v; + + uiItemIntO(layout, + menu->collection->name, + ICON_NONE, + "OBJECT_OT_move_to_collection", + "collection_index", + menu->index); + uiItemS(layout); + + for (MoveToCollectionData *submenu = menu->submenus.first; + submenu != NULL; + submenu = submenu->next) + { + move_to_collection_menus_items(layout, submenu); + } + + uiItemS(layout); + + WM_operator_properties_create_ptr(&menu->ptr, menu->ot); + RNA_int_set(&menu->ptr, "collection_index", menu->index); + RNA_boolean_set(&menu->ptr, "is_new", true); + + uiItemFullO_ptr(layout, + menu->ot, + "New Collection", + ICON_ZOOMIN, + menu->ptr.data, + /* We use invoke here so we can read ctrl from event. */ + WM_OP_INVOKE_DEFAULT, + 0, + NULL); +} + +static void move_to_collection_menus_items(uiLayout *layout, MoveToCollectionData *menu) +{ + if (BLI_listbase_is_empty(&menu->submenus)) { + uiItemIntO(layout, + menu->collection->name, + ICON_NONE, + "OBJECT_OT_move_to_collection", + "collection_index", + menu->index); + } + else { + uiItemMenuF(layout, + menu->collection->name, + ICON_NONE, + move_to_collection_menu_create, + menu); + } +} + +/* This is allocated statically because we need this available for the menus creation callback. */ +static MoveToCollectionData *master_collection_menu = NULL; + +static int move_to_collection_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + /* Reset the menus data for the current master collection, and free previously allocated data. */ + move_to_collection_menus_free(&master_collection_menu); + + PropertyRNA *prop; + prop = RNA_struct_find_property(op->ptr, "collection_index"); + if (RNA_property_is_set(op->ptr, prop)) { + int collection_index = RNA_property_int_get(op->ptr, prop); + RNA_boolean_set(op->ptr, "is_add", event->ctrl); + + if (RNA_boolean_get(op->ptr, "is_new")) { + prop = RNA_struct_find_property(op->ptr, "new_collection_name"); + if (!RNA_property_is_set(op->ptr, prop)) { + char name[MAX_NAME]; + SceneCollection *scene_collection; + + scene_collection = BKE_collection_from_index(CTX_data_scene(C), collection_index); + BKE_collection_new_name_get(&CTX_data_scene(C)->id, scene_collection, name); + + RNA_property_string_set(op->ptr, prop, name); + return WM_operator_props_dialog_popup(C, op, 10 * UI_UNIT_X, 5 * UI_UNIT_Y); + } + } + return move_to_collection_exec(C, op); + } + + SceneCollection *master_collection = BKE_collection_master(&CTX_data_scene(C)->id); + + /* We need the data to be allocated so it's available during menu drawing. + * Technically we could use wmOperator->customdata. However there is no free callback + * called to an operator that exit with OPERATOR_INTERFACE to launch a menu. + * + * So we are left with a memory that will necessarily leak. It's a small leak though.*/ + if (master_collection_menu == NULL) { + master_collection_menu = MEM_callocN(sizeof(MoveToCollectionData), + "MoveToCollectionData menu - expected eventual memleak"); + } + + master_collection_menu->collection = master_collection; + master_collection_menu->ot = op->type; + move_to_collection_menus_create(op, master_collection_menu); + + uiPopupMenu *pup; + uiLayout *layout; + + /* Build the menus. */ + pup = UI_popup_menu_begin(C, IFACE_("Move to Collection"), ICON_NONE); + layout = UI_popup_menu_layout(pup); + + /* We use invoke here so we can read ctrl from event. */ + uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT); + + move_to_collection_menu_create(C, layout, master_collection_menu); + + UI_popup_menu_end(C, pup); + + return OPERATOR_INTERFACE; +} + +void OBJECT_OT_move_to_collection(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Move to Collection"; + ot->description = "Move to a collection only (Ctrl to add)"; + ot->idname = "OBJECT_OT_move_to_collection"; + + /* api callbacks */ + ot->exec = move_to_collection_exec; + ot->invoke = move_to_collection_invoke; + ot->poll = ED_operator_object_active_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + prop = RNA_def_int(ot->srna, "collection_index", COLLECTION_INVALID_INDEX, COLLECTION_INVALID_INDEX, INT_MAX, + "Collection Index", "Index of the collection to move to", 0, INT_MAX); + RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); + prop = RNA_def_boolean(ot->srna, "is_add", false, "Add", "Keep object in original collections as well"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); + prop = RNA_def_boolean(ot->srna, "is_new", false, "New", "Move objects to a new collection"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); + prop = RNA_def_string(ot->srna, "new_collection_name", NULL, MAX_NAME, "Name", + "Name of the newly added collection"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); +} + +#undef COLLECTION_INVALID_INDEX diff --git a/source/blender/editors/object/object_facemap_ops.c b/source/blender/editors/object/object_facemap_ops.c index 857446ac6b0..a076521b41d 100644 --- a/source/blender/editors/object/object_facemap_ops.c +++ b/source/blender/editors/object/object_facemap_ops.c @@ -35,6 +35,7 @@ #include "DNA_object_types.h" #include "DNA_mesh_types.h" +#include "DNA_workspace_types.h" #include "BKE_context.h" #include "BKE_customdata.h" @@ -173,7 +174,12 @@ static int face_map_supported_edit_mode_poll(bContext *C) { Object *ob = ED_object_context(C); ID *data = (ob) ? ob->data : NULL; - return (ob && !ob->id.lib && ob->type == OB_MESH && data && !data->lib && ob->mode == OB_MODE_EDIT); + if (ob && !ob->id.lib && ob->type == OB_MESH && data && !data->lib) { + if (ob->mode == OB_MODE_EDIT) { + return true; + } + } + return false; } static int face_map_add_exec(bContext *C, wmOperator *UNUSED(op)) diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c index 93546b1bd5d..3ff794772fa 100644 --- a/source/blender/editors/object/object_hook.c +++ b/source/blender/editors/object/object_hook.c @@ -319,7 +319,7 @@ static bool object_hook_index_array(Scene *scene, Object *obedit, BMEditMesh *em; EDBM_mesh_load(obedit); - EDBM_mesh_make(scene->toolsettings, obedit, true); + EDBM_mesh_make(obedit, scene->toolsettings->selectmode, true); DEG_id_tag_update(obedit->data, 0); diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index 5d6d643b9bd..944912ad6b6 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -95,6 +95,8 @@ void OBJECT_OT_game_property_move(struct wmOperatorType *ot); void OBJECT_OT_logic_bricks_copy(struct wmOperatorType *ot); void OBJECT_OT_game_physics_copy(struct wmOperatorType *ot); +void OBJECT_OT_move_to_collection(struct wmOperatorType *ot); + /* object_select.c */ void OBJECT_OT_select_all(struct wmOperatorType *ot); void OBJECT_OT_select_random(struct wmOperatorType *ot); @@ -106,6 +108,7 @@ void OBJECT_OT_select_mirror(struct wmOperatorType *ot); void OBJECT_OT_select_more(struct wmOperatorType *ot); void OBJECT_OT_select_less(struct wmOperatorType *ot); void OBJECT_OT_select_same_group(struct wmOperatorType *ot); +void OBJECT_OT_select_same_collection(struct wmOperatorType *ot); /* object_add.c */ void OBJECT_OT_add(struct wmOperatorType *ot); @@ -139,16 +142,6 @@ void OBJECT_OT_hook_assign(struct wmOperatorType *ot); void OBJECT_OT_hook_reset(struct wmOperatorType *ot); void OBJECT_OT_hook_recenter(struct wmOperatorType *ot); -/* object_lattice.c */ -void LATTICE_OT_select_all(struct wmOperatorType *ot); -void LATTICE_OT_select_more(struct wmOperatorType *ot); -void LATTICE_OT_select_less(struct wmOperatorType *ot); -void LATTICE_OT_select_ungrouped(struct wmOperatorType *ot); -void LATTICE_OT_select_random(struct wmOperatorType *ot); -void LATTICE_OT_select_mirror(struct wmOperatorType *ot); -void LATTICE_OT_make_regular(struct wmOperatorType *ot); -void LATTICE_OT_flip(struct wmOperatorType *ot); - /* object_group.c */ void GROUP_OT_create(struct wmOperatorType *ot); void GROUP_OT_objects_remove_all(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c new file mode 100644 index 00000000000..9e6e6947320 --- /dev/null +++ b/source/blender/editors/object/object_modes.c @@ -0,0 +1,258 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Blender Foundation, 2002-2008 full recode + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/object/object_modes.c + * \ingroup edobj + * + * General utils to handle mode switching, + * actual mode switching logic is per-object type. + */ + +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_workspace_types.h" + +#include "BLI_utildefines.h" + +#include "BKE_context.h" +#include "BKE_object.h" +#include "BKE_paint.h" +#include "BKE_report.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "RNA_access.h" + +#include "DEG_depsgraph.h" + +#include "ED_screen.h" + +#include "ED_object.h" /* own include */ + +/* -------------------------------------------------------------------- */ +/** \name High Level Mode Operations + * + * \{ */ + +static const char *object_mode_op_string(eObjectMode mode) +{ + if (mode & OB_MODE_EDIT) + return "OBJECT_OT_editmode_toggle"; + if (mode == OB_MODE_SCULPT) + return "SCULPT_OT_sculptmode_toggle"; + if (mode == OB_MODE_VERTEX_PAINT) + return "PAINT_OT_vertex_paint_toggle"; + if (mode == OB_MODE_WEIGHT_PAINT) + return "PAINT_OT_weight_paint_toggle"; + if (mode == OB_MODE_TEXTURE_PAINT) + return "PAINT_OT_texture_paint_toggle"; + if (mode == OB_MODE_PARTICLE_EDIT) + return "PARTICLE_OT_particle_edit_toggle"; + if (mode == OB_MODE_POSE) + return "OBJECT_OT_posemode_toggle"; + if (mode == OB_MODE_GPENCIL) + return "GPENCIL_OT_editmode_toggle"; + return NULL; +} + +/** + * Checks the mode to be set is compatible with the object + * should be made into a generic function + */ +bool ED_object_mode_compat_test(const Object *ob, eObjectMode mode) +{ + if (ob) { + if (mode == OB_MODE_OBJECT) + return true; + else if (mode == OB_MODE_GPENCIL) + return true; /* XXX: assume this is the case for now... */ + + switch (ob->type) { + case OB_MESH: + if (mode & (OB_MODE_EDIT | OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | + OB_MODE_TEXTURE_PAINT | OB_MODE_PARTICLE_EDIT)) + { + return true; + } + break; + case OB_CURVE: + case OB_SURF: + case OB_FONT: + case OB_MBALL: + case OB_GROOM: + if (mode & (OB_MODE_EDIT)) + return true; + break; + case OB_LATTICE: + if (mode & (OB_MODE_EDIT | OB_MODE_WEIGHT_PAINT)) + return true; + break; + case OB_ARMATURE: + if (mode & (OB_MODE_EDIT | OB_MODE_POSE)) + return true; + break; + } + } + + return false; +} + +/** + * Sets the mode to a compatible state (use before entering the mode). + * + * This is so each mode's exec function can call + */ +bool ED_object_mode_compat_set(bContext *C, Object *ob, eObjectMode mode, ReportList *reports) +{ + bool ok; + if (!ELEM(ob->mode, mode, OB_MODE_OBJECT)) { + const char *opstring = object_mode_op_string(ob->mode); + + WM_operator_name_call(C, opstring, WM_OP_EXEC_REGION_WIN, NULL); + ok = ELEM(ob->mode, mode, OB_MODE_OBJECT); + if (!ok) { + wmOperatorType *ot = WM_operatortype_find(opstring, false); + BKE_reportf(reports, RPT_ERROR, "Unable to execute '%s', error changing modes", ot->name); + } + } + else { + ok = true; + } + + return ok; +} + +void ED_object_mode_toggle(bContext *C, eObjectMode mode) +{ + if (mode != OB_MODE_OBJECT) { + const char *opstring = object_mode_op_string(mode); + + if (opstring) { + WM_operator_name_call(C, opstring, WM_OP_EXEC_REGION_WIN, NULL); + } + } +} + + +/* Wrapper for operator */ +void ED_object_mode_set(bContext *C, eObjectMode mode) +{ + wmWindowManager *wm = CTX_wm_manager(C); + wm->op_undo_depth++; + /* needed so we don't do undo pushes. */ + ED_object_mode_generic_enter(C, mode); + wm->op_undo_depth--; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Generic Mode Enter/Exit + * + * Supports exiting a mode without it being in the current context. + * This could be done for entering modes too if it's needed. + * + * \{ */ + +bool ED_object_mode_generic_enter( + struct bContext *C, eObjectMode object_mode) +{ + Object *ob = CTX_data_active_object(C); + if (ob->mode == object_mode) { + return true; + } + wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_mode_set", false); + PointerRNA ptr; + WM_operator_properties_create_ptr(&ptr, ot); + RNA_enum_set(&ptr, "mode", object_mode); + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); + WM_operator_properties_free(&ptr); + return (ob->mode == object_mode); +} + +/** + * Use for changing works-paces or changing active object. + * Caller can check #OB_MODE_ALL_MODE_DATA to test if this needs to be run. + */ +static bool ed_object_mode_generic_exit_ex( + const struct EvaluationContext *eval_ctx, + struct Scene *scene, struct Object *ob, + bool only_test) +{ + if (ob->mode & OB_MODE_EDIT) { + if (BKE_object_is_in_editmode(ob)) { + if (only_test) { + return true; + } + ED_object_editmode_exit_ex(NULL, scene, ob, EM_FREEDATA); + } + } + else if (ob->mode & OB_MODE_VERTEX_PAINT) { + if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_VERTEX_PAINT)) { + if (only_test) { + return true; + } + ED_object_vpaintmode_exit_ex(ob); + } + } + else if (ob->mode & OB_MODE_WEIGHT_PAINT) { + if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_WEIGHT_PAINT)) { + if (only_test) { + return true; + } + ED_object_wpaintmode_exit_ex(ob); + } + } + else if (ob->mode & OB_MODE_SCULPT) { + if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_SCULPT)) { + if (only_test) { + return true; + } + ED_object_sculptmode_exit_ex(eval_ctx, scene, ob); + } + } + else { + if (only_test) { + return false; + } + BLI_assert((ob->mode & OB_MODE_ALL_MODE_DATA) == 0); + } + + return false; +} + +void ED_object_mode_generic_exit( + const struct EvaluationContext *eval_ctx, + struct Scene *scene, struct Object *ob) +{ + ed_object_mode_generic_exit_ex(eval_ctx, scene, ob, false); +} + +bool ED_object_mode_generic_has_data( + const struct EvaluationContext *eval_ctx, + struct Object *ob) +{ + return ed_object_mode_generic_exit_ex(eval_ctx, NULL, ob, true); +} + +/** \} */ diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 2099ceaa10b..5458e4c173f 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -40,7 +40,7 @@ #include "DNA_key_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "DNA_object_force.h" +#include "DNA_object_force_types.h" #include "DNA_scene_types.h" #include "BLI_bitmap.h" @@ -524,12 +524,9 @@ int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene * return 1; } -static int modifier_apply_shape(ReportList *reports, const bContext *C, Scene *scene, Object *ob, ModifierData *md) +static int modifier_apply_shape(ReportList *reports, const EvaluationContext *eval_ctx, Scene *scene, Object *ob, ModifierData *md) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - EvaluationContext eval_ctx; - - CTX_data_eval_ctx(C, &eval_ctx); md->scene = scene; @@ -560,7 +557,7 @@ static int modifier_apply_shape(ReportList *reports, const bContext *C, Scene *s return 0; } - dm = mesh_create_derived_for_modifier(&eval_ctx, scene, ob, md, 0); + dm = mesh_create_derived_for_modifier(eval_ctx, scene, ob, md, 0); if (!dm) { BKE_report(reports, RPT_ERROR, "Modifier is disabled or returned error, skipping apply"); return 0; @@ -587,12 +584,9 @@ static int modifier_apply_shape(ReportList *reports, const bContext *C, Scene *s return 1; } -static int modifier_apply_obdata(ReportList *reports, const bContext *C, Scene *scene, Object *ob, ModifierData *md) +static int modifier_apply_obdata(ReportList *reports, const EvaluationContext *eval_ctx, Scene *scene, Object *ob, ModifierData *md) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - EvaluationContext eval_ctx; - - CTX_data_eval_ctx(C, &eval_ctx); md->scene = scene; @@ -616,13 +610,13 @@ static int modifier_apply_obdata(ReportList *reports, const bContext *C, Scene * multires_force_update(ob); if (mmd && mmd->totlvl && mti->type == eModifierTypeType_OnlyDeform) { - if (!multiresModifier_reshapeFromDeformMod(&eval_ctx, scene, mmd, ob, md)) { + if (!multiresModifier_reshapeFromDeformMod(eval_ctx, scene, mmd, ob, md)) { BKE_report(reports, RPT_ERROR, "Multires modifier returned error, skipping apply"); return 0; } } else { - dm = mesh_create_derived_for_modifier(&eval_ctx, scene, ob, md, 1); + dm = mesh_create_derived_for_modifier(eval_ctx, scene, ob, md, 1); if (!dm) { BKE_report(reports, RPT_ERROR, "Modifier returned error, skipping apply"); return 0; @@ -648,7 +642,7 @@ static int modifier_apply_obdata(ReportList *reports, const bContext *C, Scene * BKE_report(reports, RPT_INFO, "Applied modifier only changed CV points, not tessellated/bevel vertices"); vertexCos = BKE_curve_nurbs_vertexCos_get(&cu->nurb, &numVerts); - mti->deformVerts(md, &eval_ctx, ob, NULL, vertexCos, numVerts, 0); + mti->deformVerts(md, eval_ctx, ob, NULL, vertexCos, numVerts, 0); BK_curve_nurbs_vertexCos_apply(&cu->nurb, vertexCos); MEM_freeN(vertexCos); @@ -670,18 +664,20 @@ static int modifier_apply_obdata(ReportList *reports, const bContext *C, Scene * if (psys->part->type != PART_HAIR) continue; - psys_apply_hair_lattice(&eval_ctx, scene, ob, psys); + psys_apply_hair_lattice(eval_ctx, scene, ob, psys); } } return 1; } -int ED_object_modifier_apply(ReportList *reports, const bContext *C, Scene *scene, Object *ob, ModifierData *md, int mode) +int ED_object_modifier_apply( + ReportList *reports, const EvaluationContext *eval_ctx, + Scene *scene, Object *ob, ModifierData *md, int mode) { int prev_mode; - if (scene->obedit) { + if (BKE_object_is_in_editmode(ob)) { BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied in edit mode"); return 0; } @@ -705,13 +701,13 @@ int ED_object_modifier_apply(ReportList *reports, const bContext *C, Scene *scen md->mode |= eModifierMode_Realtime; if (mode == MODIFIER_APPLY_SHAPE) { - if (!modifier_apply_shape(reports, C, scene, ob, md)) { + if (!modifier_apply_shape(reports, eval_ctx, scene, ob, md)) { md->mode = prev_mode; return 0; } } else { - if (!modifier_apply_obdata(reports, C, scene, ob, md)) { + if (!modifier_apply_obdata(reports, eval_ctx, scene, ob, md)) { md->mode = prev_mode; return 0; } @@ -895,11 +891,13 @@ static int modifier_remove_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); /* if cloth/softbody was removed, particle mode could be cleared */ - if (mode_orig & OB_MODE_PARTICLE_EDIT) - if ((ob->mode & OB_MODE_PARTICLE_EDIT) == 0) - if (view_layer->basact && view_layer->basact->object == ob) + if (mode_orig & OB_MODE_PARTICLE_EDIT) { + if ((ob->mode & OB_MODE_PARTICLE_EDIT) == 0) { + if (ob == OBACT(view_layer)) { WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL); - + } + } + } return OPERATOR_FINISHED; } @@ -1013,7 +1011,10 @@ static int modifier_apply_exec(bContext *C, wmOperator *op) ModifierData *md = edit_modifier_property_get(op, ob, 0); int apply_as = RNA_enum_get(op->ptr, "apply_as"); - if (!md || !ED_object_modifier_apply(op->reports, C, scene, ob, md, apply_as)) { + EvaluationContext eval_ctx; + CTX_data_eval_ctx(C, &eval_ctx); + + if (!md || !ED_object_modifier_apply(op->reports, &eval_ctx, scene, ob, md, apply_as)) { return OPERATOR_CANCELLED; } @@ -1240,11 +1241,8 @@ static int multires_reshape_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_active_context(C), *secondob = NULL; Scene *scene = CTX_data_scene(C); - EvaluationContext eval_ctx; MultiresModifierData *mmd = (MultiresModifierData *)edit_modifier_property_get(op, ob, eModifierType_Multires); - CTX_data_eval_ctx(C, &eval_ctx); - if (!mmd) return OPERATOR_CANCELLED; @@ -1267,6 +1265,9 @@ static int multires_reshape_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } + EvaluationContext eval_ctx; + CTX_data_eval_ctx(C, &eval_ctx); + if (!multiresModifier_reshape(&eval_ctx, scene, mmd, ob, secondob)) { BKE_report(op->reports, RPT_ERROR, "Objects do not have the same number of vertices"); return OPERATOR_CANCELLED; @@ -1700,10 +1701,8 @@ static void skin_armature_bone_create(Object *skin_ob, } } -static Object *modifier_skin_armature_create(const bContext *C, Scene *scene, ViewLayer *view_layer, Object *skin_ob) +static Object *modifier_skin_armature_create(const EvaluationContext *eval_ctx, Main *bmain, Scene *scene, Object *skin_ob) { - Main *bmain = CTX_data_main(C); - EvaluationContext eval_ctx; BLI_bitmap *edges_visited; DerivedMesh *deform_dm; MVert *mvert; @@ -1715,9 +1714,7 @@ static Object *modifier_skin_armature_create(const bContext *C, Scene *scene, Vi int *emap_mem; int v; - CTX_data_eval_ctx(C, &eval_ctx); - - deform_dm = mesh_get_derived_deform(&eval_ctx, scene, skin_ob, CD_MASK_BAREMESH); + deform_dm = mesh_get_derived_deform(eval_ctx, scene, skin_ob, CD_MASK_BAREMESH); mvert = deform_dm->getVertArray(deform_dm); /* add vertex weights to original mesh */ @@ -1727,7 +1724,7 @@ static Object *modifier_skin_armature_create(const bContext *C, Scene *scene, Vi NULL, me->totvert); - arm_ob = BKE_object_add(bmain, scene, view_layer, OB_ARMATURE, NULL); + arm_ob = BKE_object_add(bmain, scene, eval_ctx->view_layer, OB_ARMATURE, NULL); BKE_object_transform_copy(arm_ob, skin_ob); arm = arm_ob->data; arm->layer = 1; @@ -1786,7 +1783,6 @@ static int skin_armature_create_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob = CTX_data_active_object(C), *arm_ob; Mesh *me = ob->data; ModifierData *skin_md; @@ -1797,8 +1793,11 @@ static int skin_armature_create_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } + EvaluationContext eval_ctx; + CTX_data_eval_ctx(C, &eval_ctx); + /* create new armature */ - arm_ob = modifier_skin_armature_create(C, scene, view_layer, ob); + arm_ob = modifier_skin_armature_create(&eval_ctx, bmain, scene, ob); /* add a modifier to connect the new armature to the mesh */ arm_md = (ArmatureModifierData *)modifier_new(eModifierType_Armature); diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index 733419d8474..a35a54001e8 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -47,6 +47,8 @@ #include "ED_screen.h" #include "ED_object.h" +#include "DEG_depsgraph.h" + #include "object_intern.h" @@ -92,6 +94,7 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_select_random); WM_operatortype_append(OBJECT_OT_select_all); WM_operatortype_append(OBJECT_OT_select_same_group); + WM_operatortype_append(OBJECT_OT_select_same_collection); WM_operatortype_append(OBJECT_OT_select_by_type); WM_operatortype_append(OBJECT_OT_select_linked); WM_operatortype_append(OBJECT_OT_select_grouped); @@ -218,6 +221,8 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_logic_bricks_copy); WM_operatortype_append(OBJECT_OT_game_physics_copy); + WM_operatortype_append(OBJECT_OT_move_to_collection); + WM_operatortype_append(OBJECT_OT_shape_key_add); WM_operatortype_append(OBJECT_OT_shape_key_remove); WM_operatortype_append(OBJECT_OT_shape_key_clear); @@ -225,15 +230,6 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_shape_key_mirror); WM_operatortype_append(OBJECT_OT_shape_key_move); - WM_operatortype_append(LATTICE_OT_select_all); - WM_operatortype_append(LATTICE_OT_select_more); - WM_operatortype_append(LATTICE_OT_select_less); - WM_operatortype_append(LATTICE_OT_select_ungrouped); - WM_operatortype_append(LATTICE_OT_select_random); - WM_operatortype_append(LATTICE_OT_select_mirror); - WM_operatortype_append(LATTICE_OT_make_regular); - WM_operatortype_append(LATTICE_OT_flip); - WM_operatortype_append(OBJECT_OT_group_add); WM_operatortype_append(OBJECT_OT_group_link); WM_operatortype_append(OBJECT_OT_group_remove); @@ -432,29 +428,7 @@ void ED_keymap_object(wmKeyConfig *keyconf) RNA_int_set(kmi->ptr, "level", i); } - /* ############################################################################ */ - /* ################################ LATTICE ################################### */ - /* ############################################################################ */ - - keymap = WM_keymap_find(keyconf, "Lattice", 0, 0); - keymap->poll = ED_operator_editlattice; - - kmi = WM_keymap_add_item(keymap, "LATTICE_OT_select_all", AKEY, KM_PRESS, 0, 0); - RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE); - kmi = WM_keymap_add_item(keymap, "LATTICE_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0); - RNA_enum_set(kmi->ptr, "action", SEL_INVERT); - WM_keymap_add_item(keymap, "LATTICE_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0); - WM_keymap_add_item(keymap, "LATTICE_OT_select_less", PADMINUS, KM_PRESS, KM_CTRL, 0); - - WM_keymap_add_item(keymap, "OBJECT_OT_vertex_parent_set", PKEY, KM_PRESS, KM_CTRL, 0); - - WM_keymap_add_item(keymap, "LATTICE_OT_flip", FKEY, KM_PRESS, KM_CTRL, 0); - - /* menus */ - WM_keymap_add_menu(keymap, "VIEW3D_MT_hook", HKEY, KM_PRESS, KM_CTRL, 0); - - ED_keymap_proportional_cycle(keyconf, keymap); - ED_keymap_proportional_editmode(keyconf, keymap, false); + WM_keymap_add_item(keymap, "OBJECT_OT_move_to_collection", MKEY, KM_PRESS, 0, 0); } void ED_keymap_proportional_cycle(struct wmKeyConfig *UNUSED(keyconf), struct wmKeyMap *keymap) diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 13cc53c04a7..fee39c8f0fb 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -151,7 +151,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op) BMEditMesh *em; EDBM_mesh_load(obedit); - EDBM_mesh_make(scene->toolsettings, obedit, true); + EDBM_mesh_make(obedit, scene->toolsettings->selectmode, true); DEG_id_tag_update(obedit->data, 0); @@ -401,13 +401,13 @@ static const EnumPropertyItem *proxy_group_object_itemf(bContext *C, PointerRNA return DummyRNA_DEFAULT_items; /* find the object to affect */ - FOREACH_GROUP_OBJECT(ob->dup_group, object) + FOREACH_GROUP_OBJECT_BEGIN(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 + FOREACH_GROUP_OBJECT_END; RNA_enum_item_end(&item, &totitem); *r_free = true; @@ -1629,33 +1629,30 @@ void OBJECT_OT_make_links_data(wmOperatorType *ot) static Object *single_object_users_object(Main *bmain, Scene *scene, Object *ob, const bool copy_groups) { - if (!ID_IS_LINKED(ob) && ob->id.us > 1) { - /* base gets copy of object */ - Object *obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob)); + /* base gets copy of object */ + Object *obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob)); - if (copy_groups) { - if (ob->flag & OB_FROMGROUP) { - obn->flag |= OB_FROMGROUP; - } - } - else { - /* copy already clears */ + if (copy_groups) { + if (ob->flag & OB_FROMGROUP) { + obn->flag |= OB_FROMGROUP; } - /* remap gpencil parenting */ + } + else { + /* copy already clears */ + } + /* remap gpencil parenting */ - if (scene->gpd) { - bGPdata *gpd = scene->gpd; - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - if (gpl->parent == ob) { - gpl->parent = obn; - } + if (scene->gpd) { + bGPdata *gpd = scene->gpd; + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + if (gpl->parent == ob) { + gpl->parent = obn; } } - - id_us_min(&ob->id); - return obn; } - return NULL; + + id_us_min(&ob->id); + return obn; } static void libblock_relink_scene_collection(SceneCollection *sc) @@ -1675,7 +1672,9 @@ static void single_object_users_scene_collection(Main *bmain, Scene *scene, Scen Object *ob = link->data; /* an object may be in more than one collection */ if ((ob->id.newid == NULL) && ((ob->flag & flag) == flag)) { - link->data = single_object_users_object(bmain, scene, link->data, copy_groups); + if (!ID_IS_LINKED(ob) && ob->id.us > 1) { + link->data = single_object_users_object(bmain, scene, link->data, copy_groups); + } } } @@ -1707,19 +1706,19 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in if (copy_groups && group->view_layer->object_bases.first) { bool all_duplicated = true; - FOREACH_GROUP_OBJECT(group, object) + FOREACH_GROUP_OBJECT_BEGIN(group, object) { if (object->id.newid == NULL) { all_duplicated = false; break; } } - FOREACH_GROUP_OBJECT_END + FOREACH_GROUP_OBJECT_END; if (all_duplicated) { groupn = ID_NEW_SET(group, BKE_group_copy(bmain, group)); - FOREACH_GROUP_BASE(groupn, base) + FOREACH_GROUP_BASE_BEGIN(groupn, base) { base->object = (Object *)base->object->id.newid; } @@ -1744,11 +1743,11 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in * button can be functional.*/ void ED_object_single_user(Main *bmain, Scene *scene, Object *ob) { - FOREACH_SCENE_OBJECT(scene, ob_iter) + FOREACH_SCENE_OBJECT_BEGIN(scene, ob_iter) { ob_iter->flag &= ~OB_DONE; } - FOREACH_SCENE_OBJECT_END + FOREACH_SCENE_OBJECT_END; /* tag only the one object */ ob->flag |= OB_DONE; @@ -1788,7 +1787,7 @@ static void single_obdata_users(Main *bmain, Scene *scene, ViewLayer *view_layer ID *id; int a; - FOREACH_OBJECT_FLAG(scene, view_layer, flag, ob) + FOREACH_OBJECT_FLAG_BEGIN(scene, view_layer, flag, ob) { if (!ID_IS_LINKED(ob)) { id = ob->data; @@ -1849,7 +1848,7 @@ static void single_obdata_users(Main *bmain, Scene *scene, ViewLayer *view_layer 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. */ + /* We need to end the FOREACH_OBJECT_FLAG_BEGIN iterator to prevent memory leak. */ BKE_scene_objects_iterator_end(&iter_macro); return; } @@ -1865,7 +1864,7 @@ static void single_obdata_users(Main *bmain, Scene *scene, ViewLayer *view_layer } } } - FOREACH_OBJECT_FLAG_END + FOREACH_OBJECT_FLAG_END; me = bmain->mesh.first; while (me) { @@ -1876,12 +1875,14 @@ static void single_obdata_users(Main *bmain, Scene *scene, ViewLayer *view_layer static void single_object_action_users(Scene *scene, ViewLayer *view_layer, const int flag) { - FOREACH_OBJECT_FLAG(scene, view_layer, flag, ob) + FOREACH_OBJECT_FLAG_BEGIN(scene, view_layer, flag, ob) + { if (!ID_IS_LINKED(ob)) { DEG_id_tag_update(&ob->id, OB_RECALC_DATA); BKE_animdata_copy_id_action(&ob->id, false); } - FOREACH_OBJECT_FLAG_END + } + FOREACH_OBJECT_FLAG_END; } static void single_mat_users(Main *bmain, Scene *scene, ViewLayer *view_layer, const int flag, const bool do_textures) @@ -1890,7 +1891,8 @@ static void single_mat_users(Main *bmain, Scene *scene, ViewLayer *view_layer, c Tex *tex; int a, b; - FOREACH_OBJECT_FLAG(scene, view_layer, flag, ob) + FOREACH_OBJECT_FLAG_BEGIN(scene, view_layer, flag, ob) + { if (!ID_IS_LINKED(ob)) { for (a = 1; a <= ob->totcol; a++) { ma = give_current_material(ob, a); @@ -1920,7 +1922,8 @@ static void single_mat_users(Main *bmain, Scene *scene, ViewLayer *view_layer, c } } } - FOREACH_OBJECT_FLAG_END + } + FOREACH_OBJECT_FLAG_END; } static void do_single_tex_user(Main *bmain, Tex **from) @@ -2045,13 +2048,13 @@ void ED_object_single_users(Main *bmain, Scene *scene, const bool full, const bo { IDP_RelinkProperty(scene->id.properties); - FOREACH_SCENE_OBJECT(scene, ob) + FOREACH_SCENE_OBJECT_BEGIN(scene, ob) { if (!ID_IS_LINKED(ob)) { IDP_RelinkProperty(ob->id.properties); } } - FOREACH_SCENE_OBJECT_END + FOREACH_SCENE_OBJECT_END; if (scene->nodetree) { IDP_RelinkProperty(scene->nodetree->id.properties); @@ -2415,7 +2418,6 @@ static int make_override_static_exec(bContext *C, wmOperator *op) bool success = false; if (!ID_IS_LINKED(obact) && obact->dup_group != NULL && ID_IS_LINKED(obact->dup_group)) { -#if 0 /* Not working yet! */ Base *base = BLI_findlink(&obact->dup_group->view_layer->object_bases, RNA_enum_get(op->ptr, "object")); Object *obgroup = obact; obact = base->object; @@ -2426,9 +2428,9 @@ static int make_override_static_exec(bContext *C, wmOperator *op) /* Then, we tag our 'main' object and its detected dependencies to be also overridden. */ obact->id.tag |= LIB_TAG_DOIT; - FOREACH_GROUP_OBJECT(obgroup->dup_group, ob) + FOREACH_GROUP_OBJECT_BEGIN(obgroup->dup_group, ob) { - make_override_tag_object(obact, ob); + make_override_static_tag_object(obact, ob); } FOREACH_GROUP_OBJECT_END; @@ -2439,7 +2441,7 @@ static int make_override_static_exec(bContext *C, wmOperator *op) ViewLayer *view_layer = CTX_data_view_layer(C); Object *new_obact = (Object *)obact->id.newid; if (new_obact != NULL && (base = BKE_view_layer_base_find(view_layer, new_obact)) == NULL) { - BKE_collection_object_add_from(scene, obact, new_obact); + BKE_collection_object_add_from(scene, obgroup, new_obact); base = BKE_view_layer_base_find(view_layer, new_obact); BKE_view_layer_base_select(view_layer, base); } @@ -2457,9 +2459,6 @@ static int make_override_static_exec(bContext *C, wmOperator *op) /* Cleanup. */ BKE_main_id_clear_newpoins(bmain); BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, false); -#else - UNUSED_VARS(op); -#endif } /* Else, poll func ensures us that ID_IS_LINKED(obact) is true. */ else if (obact->type == OB_ARMATURE) { @@ -2516,8 +2515,8 @@ void OBJECT_OT_make_override_static(wmOperatorType *ot) /* properties */ PropertyRNA *prop; - prop = RNA_def_enum(ot->srna, "object", DummyRNA_DEFAULT_items, 0, "Proxy Object", - "Name of lib-linked/grouped object to make a proxy for"); + prop = RNA_def_enum(ot->srna, "object", DummyRNA_DEFAULT_items, 0, "Override Object", + "Name of lib-linked/group object to make an override from"); RNA_def_enum_funcs(prop, proxy_group_object_itemf); RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); ot->prop = prop; diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c index b20fe9a004c..cd1300dd52e 100644 --- a/source/blender/editors/object/object_select.c +++ b/source/blender/editors/object/object_select.c @@ -56,7 +56,9 @@ #include "BKE_layer.h" #include "BKE_main.h" #include "BKE_material.h" +#include "BKE_object.h" #include "BKE_particle.h" +#include "BKE_paint.h" #include "BKE_property.h" #include "BKE_report.h" #include "BKE_scene.h" @@ -64,6 +66,8 @@ #include "BKE_library.h" #include "BKE_deform.h" +#include "DEG_depsgraph.h" + #include "WM_api.h" #include "WM_types.h" @@ -122,9 +126,6 @@ void ED_object_base_activate(bContext *C, Base *base) view_layer->basact = base; if (base) { -#ifdef USE_WORKSPACE_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); } else { @@ -498,7 +499,7 @@ enum { OBJECT_GRPSEL_PARENT = 2, OBJECT_GRPSEL_SIBLINGS = 3, OBJECT_GRPSEL_TYPE = 4, - /*OBJECT_GRPSEL_LAYER = 5,*/ + OBJECT_GRPSEL_COLLECTION = 5, OBJECT_GRPSEL_GROUP = 6, OBJECT_GRPSEL_HOOK = 7, OBJECT_GRPSEL_PASS = 8, @@ -514,6 +515,7 @@ static const EnumPropertyItem prop_select_grouped_types[] = { {OBJECT_GRPSEL_PARENT, "PARENT", 0, "Parent", ""}, {OBJECT_GRPSEL_SIBLINGS, "SIBLINGS", 0, "Siblings", "Shared Parent"}, {OBJECT_GRPSEL_TYPE, "TYPE", 0, "Type", "Shared object type"}, + {OBJECT_GRPSEL_COLLECTION, "COLLECTION", 0, "Collection", "Shared collection"}, {OBJECT_GRPSEL_GROUP, "GROUP", 0, "Group", "Shared group"}, {OBJECT_GRPSEL_HOOK, "HOOK", 0, "Hook", ""}, {OBJECT_GRPSEL_PASS, "PASS", 0, "Pass", "Render pass Index"}, @@ -687,6 +689,60 @@ static bool select_grouped_type(bContext *C, Object *ob) return changed; } +#define COLLECTION_MENU_MAX 24 +static bool select_grouped_collection(bContext *C, Object *ob) /* Select objects in the same collection as the active */ +{ + typedef struct EnumeratedCollection { + struct SceneCollection *collection; + int index; + } EnumeratedCollection; + + bool changed = false; + SceneCollection *collection; + EnumeratedCollection ob_collections[COLLECTION_MENU_MAX]; + int collection_count = 0, i; + uiPopupMenu *pup; + uiLayout *layout; + + i = 0; + FOREACH_SCENE_COLLECTION_BEGIN(CTX_data_scene(C), scene_collection) + { + if (BKE_collection_object_exists(scene_collection, ob)) { + ob_collections[collection_count].index = i; + ob_collections[collection_count].collection = scene_collection; + if (++collection_count >= COLLECTION_MENU_MAX) { + break; + } + } + i++; + } + FOREACH_SCENE_COLLECTION_END; + + if (!collection_count) { + return 0; + } + else if (collection_count == 1) { + collection = ob_collections[0].collection; + return BKE_collection_objects_select(CTX_data_view_layer(C), collection); + } + + /* build the menu. */ + pup = UI_popup_menu_begin(C, IFACE_("Select Collection"), ICON_NONE); + layout = UI_popup_menu_layout(pup); + + for (i = 0; i < collection_count; i++) { + uiItemIntO(layout, + ob_collections[i].collection->name, + ICON_NONE, + "OBJECT_OT_select_same_collection", + "collection_index", + ob_collections[i].index); + } + + UI_popup_menu_end(C, pup); + return changed; /* The operator already handle this! */ +} + static bool select_grouped_index_object(bContext *C, Object *ob) { bool changed = false; @@ -836,6 +892,9 @@ static int object_select_grouped_exec(bContext *C, wmOperator *op) case OBJECT_GRPSEL_TYPE: changed |= select_grouped_type(C, ob); break; + case OBJECT_GRPSEL_COLLECTION: + changed |= select_grouped_collection(C, ob); + break; case OBJECT_GRPSEL_GROUP: changed |= select_grouped_group(C, ob); break; @@ -1009,6 +1068,49 @@ void OBJECT_OT_select_same_group(wmOperatorType *ot) RNA_def_string(ot->srna, "group", NULL, MAX_ID_NAME, "Group", "Name of the group to select"); } +/**************************** Select In The Same Collection ****************************/ + +static int object_select_same_collection_exec(bContext *C, wmOperator *op) +{ + SceneCollection *collection; + + /* passthrough if no objects are visible */ + if (CTX_DATA_COUNT(C, visible_bases) == 0) return OPERATOR_PASS_THROUGH; + + int collection_index = RNA_int_get(op->ptr, "collection_index"); + collection = BKE_collection_from_index(CTX_data_scene(C), collection_index); + + if (!collection) { + return OPERATOR_PASS_THROUGH; + } + + if (BKE_collection_objects_select(CTX_data_view_layer(C), collection)) { + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C)); + } + + return OPERATOR_FINISHED; +} + +void OBJECT_OT_select_same_collection(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Select Same Collection"; + ot->description = "Select object in the same collection"; + ot->idname = "OBJECT_OT_select_same_collection"; + + /* api callbacks */ + ot->exec = object_select_same_collection_exec; + ot->poll = objects_selectable_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + prop = RNA_def_int(ot->srna, "collection_index", -1, -1, INT_MAX, + "Collection Index", "Index of the collection to select", 0, INT_MAX); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); +} /**************************** Select Mirror ****************************/ static int object_select_mirror_exec(bContext *C, wmOperator *op) { diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index 100b9018d00..bb23f871a25 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -982,7 +982,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) /* Function to recenter armatures in editarmature.c * Bone + object locations are handled there. */ - ED_armature_origin_set(scene, ob, cursor, centermode, around); + ED_armature_origin_set(ob, cursor, centermode, around); tot_change++; arm->id.tag |= LIB_TAG_DOIT; @@ -1285,7 +1285,7 @@ static void object_transform_axis_target_cancel(bContext *C, wmOperator *op) static int object_transform_axis_target_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ViewContext vc; - view3d_set_viewcontext(C, &vc); + ED_view3d_viewcontext_init(C, &vc); if (!object_is_target_compat(vc.obact)) { /* Falls back to texture space transform. */ @@ -1342,9 +1342,9 @@ static int object_transform_axis_target_invoke(bContext *C, wmOperator *op, cons CTX_DATA_END; xfd->object_data = object_data; - xfd->object_data_len = BLI_array_count(object_data); + xfd->object_data_len = BLI_array_len(object_data); - if (xfd->object_data_len != BLI_array_count(object_data)) { + if (xfd->object_data_len != BLI_array_len(object_data)) { xfd->object_data = MEM_reallocN(xfd->object_data, xfd->object_data_len * sizeof(*xfd->object_data)); } } diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index bf2da284591..7026e8671ad 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -43,6 +43,7 @@ #include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_workspace_types.h" #include "BLI_alloca.h" #include "BLI_array.h" @@ -255,9 +256,10 @@ bool ED_vgroup_parray_alloc(ID *id, MDeformVert ***dvert_arr, int *dvert_tot, co * * \note \a dvert_array has mirrored weights filled in, incase cleanup operations are needed on both. */ -void ED_vgroup_parray_mirror_sync(Object *ob, - MDeformVert **dvert_array, const int dvert_tot, - const bool *vgroup_validmap, const int vgroup_tot) +void ED_vgroup_parray_mirror_sync( + Object *ob, + MDeformVert **dvert_array, const int dvert_tot, + const bool *vgroup_validmap, const int vgroup_tot) { BMEditMesh *em = BKE_editmesh_from_object(ob); MDeformVert **dvert_array_all = NULL; @@ -300,8 +302,9 @@ void ED_vgroup_parray_mirror_sync(Object *ob, * * similar to #ED_vgroup_parray_mirror_sync but only fill in mirror points. */ -void ED_vgroup_parray_mirror_assign(Object *ob, - MDeformVert **dvert_array, const int dvert_tot) +void ED_vgroup_parray_mirror_assign( + Object *ob, + MDeformVert **dvert_array, const int dvert_tot) { BMEditMesh *em = BKE_editmesh_from_object(ob); MDeformVert **dvert_array_all = NULL; @@ -332,9 +335,10 @@ void ED_vgroup_parray_mirror_assign(Object *ob, MEM_freeN(dvert_array_all); } -void ED_vgroup_parray_remove_zero(MDeformVert **dvert_array, const int dvert_tot, - const bool *vgroup_validmap, const int vgroup_tot, - const float epsilon, const bool keep_single) +void ED_vgroup_parray_remove_zero( + MDeformVert **dvert_array, const int dvert_tot, + const bool *vgroup_validmap, const int vgroup_tot, + const float epsilon, const bool keep_single) { MDeformVert *dv; int i; @@ -484,9 +488,10 @@ void ED_vgroup_parray_from_weight_array( /* TODO, cache flip data to speedup calls within a loop. */ -static void mesh_defvert_mirror_update_internal(Object *ob, - MDeformVert *dvert_dst, MDeformVert *dvert_src, - const int def_nr) +static void mesh_defvert_mirror_update_internal( + Object *ob, + MDeformVert *dvert_dst, MDeformVert *dvert_src, + const int def_nr) { if (def_nr == -1) { /* all vgroups, add groups where neded */ @@ -504,8 +509,9 @@ static void mesh_defvert_mirror_update_internal(Object *ob, } } -static void ED_mesh_defvert_mirror_update_em(Object *ob, BMVert *eve, int def_nr, int vidx, - const int cd_dvert_offset) +static void ED_mesh_defvert_mirror_update_em( + Object *ob, BMVert *eve, int def_nr, int vidx, + const int cd_dvert_offset) { Mesh *me = ob->data; BMEditMesh *em = me->edit_btmesh; @@ -713,26 +719,30 @@ const EnumPropertyItem *ED_object_vgroup_selection_itemf_helper( return item; } -static const EnumPropertyItem *rna_vertex_group_with_single_itemf(bContext *C, PointerRNA *ptr, - PropertyRNA *prop, bool *r_free) +static const EnumPropertyItem *rna_vertex_group_with_single_itemf( + bContext *C, PointerRNA *ptr, + PropertyRNA *prop, bool *r_free) { return ED_object_vgroup_selection_itemf_helper(C, ptr, prop, r_free, WT_VGROUP_MASK_ALL); } -static const EnumPropertyItem *rna_vertex_group_select_itemf(bContext *C, PointerRNA *ptr, - PropertyRNA *prop, bool *r_free) +static const EnumPropertyItem *rna_vertex_group_select_itemf( + bContext *C, PointerRNA *ptr, + PropertyRNA *prop, bool *r_free) { - return ED_object_vgroup_selection_itemf_helper(C, ptr, prop, r_free, WT_VGROUP_MASK_ALL & ~(1 << WT_VGROUP_ACTIVE)); + return ED_object_vgroup_selection_itemf_helper( + C, ptr, prop, r_free, WT_VGROUP_MASK_ALL & ~(1 << WT_VGROUP_ACTIVE)); } static void vgroup_operator_subset_select_props(wmOperatorType *ot, bool use_active) { PropertyRNA *prop; - prop = RNA_def_enum(ot->srna, - "group_select_mode", DummyRNA_NULL_items, - use_active ? WT_VGROUP_ACTIVE : WT_VGROUP_ALL, "Subset", - "Define which subset of Groups shall be used"); + prop = RNA_def_enum( + ot->srna, + "group_select_mode", DummyRNA_NULL_items, + use_active ? WT_VGROUP_ACTIVE : WT_VGROUP_ALL, "Subset", + "Define which subset of Groups shall be used"); if (use_active) { RNA_def_enum_funcs(prop, rna_vertex_group_with_single_itemf); @@ -749,9 +759,10 @@ static void vgroup_operator_subset_select_props(wmOperatorType *ot, bool use_act /* for Mesh in Object mode */ /* allows editmode for Lattice */ -static void ED_vgroup_nr_vert_add(Object *ob, - const int def_nr, const int vertnum, - const float weight, const int assignmode) +static void ED_vgroup_nr_vert_add( + Object *ob, + const int def_nr, const int vertnum, + const float weight, const int assignmode) { /* add the vert to the deform group with the * specified number @@ -1179,7 +1190,7 @@ static int *getSurroundingVerts(Mesh *me, int vert, int *count) } /* Append a and b verts to array, if not yet present. */ - k = BLI_array_count(verts); + k = BLI_array_len(verts); /* XXX Maybe a == b is enough? */ while (k-- && !(a == b && a == -1)) { if (verts[k] == a) @@ -1201,7 +1212,7 @@ static int *getSurroundingVerts(Mesh *me, int vert, int *count) } /* Do not free the array! */ - *count = BLI_array_count(verts); + *count = BLI_array_len(verts); return verts; } @@ -1222,9 +1233,10 @@ static void getSingleCoordinate(MVert *points, int count, float coord[3]) * compute the amount of vertical distance relative to the plane and store it in dists, * then get the horizontal and vertical change and store them in changes */ -static void getVerticalAndHorizontalChange(const float norm[3], float d, const float coord[3], - const float start[3], float distToStart, - float *end, float (*changes)[2], float *dists, int index) +static void getVerticalAndHorizontalChange( + const float norm[3], float d, const float coord[3], + const float start[3], float distToStart, + float *end, float (*changes)[2], float *dists, int index) { /* A = Q - ((Q - P).N)N * D = (a * x0 + b * y0 +c * z0 + d) */ @@ -1275,8 +1287,9 @@ static DerivedMesh *dm_deform_recalc(EvaluationContext *eval_ctx, Scene *scene, * norm and d are the plane's properties for the equation: ax + by + cz + d = 0 * coord is a point on the plane */ -static void moveCloserToDistanceFromPlane(EvaluationContext *eval_ctx, Scene *scene, Object *ob, Mesh *me, int index, float norm[3], - float coord[3], float d, float distToBe, float strength, float cp) +static void moveCloserToDistanceFromPlane( + EvaluationContext *eval_ctx, Scene *scene, Object *ob, Mesh *me, int index, float norm[3], + float coord[3], float d, float distToBe, float strength, float cp) { DerivedMesh *dm; MDeformWeight *dw; @@ -1499,9 +1512,10 @@ static void vgroup_fix(const bContext *C, Scene *scene, Object *ob, float distTo } } -static void vgroup_levels_subset(Object *ob, const bool *vgroup_validmap, const int vgroup_tot, - const int UNUSED(subset_count), - const float offset, const float gain) +static void vgroup_levels_subset( + Object *ob, const bool *vgroup_validmap, const int vgroup_tot, + const int UNUSED(subset_count), + const float offset, const float gain) { MDeformWeight *dw; MDeformVert *dv, **dvert_array = NULL; @@ -1536,8 +1550,9 @@ static void vgroup_levels_subset(Object *ob, const bool *vgroup_validmap, const } if (use_mirror && use_vert_sel) { - ED_vgroup_parray_mirror_sync(ob, dvert_array, dvert_tot, - vgroup_validmap, vgroup_tot); + ED_vgroup_parray_mirror_sync( + ob, dvert_array, dvert_tot, + vgroup_validmap, vgroup_tot); } MEM_freeN(dvert_array); @@ -1594,12 +1609,14 @@ static bool vgroup_normalize_all( /* in case its not selected */ if ((dv = dvert_array[i])) { if (lock_flags) { - defvert_normalize_lock_map(dv, vgroup_validmap, vgroup_tot, - lock_flags, defbase_tot); + defvert_normalize_lock_map( + dv, vgroup_validmap, vgroup_tot, + lock_flags, defbase_tot); } else if (lock_active) { - defvert_normalize_lock_single(dv, vgroup_validmap, vgroup_tot, - def_nr); + defvert_normalize_lock_single( + dv, vgroup_validmap, vgroup_tot, + def_nr); } else { defvert_normalize_subset(dv, vgroup_validmap, vgroup_tot); @@ -1666,9 +1683,10 @@ static void vgroup_lock_all(Object *ob, int action) } } -static void vgroup_invert_subset(Object *ob, - const bool *vgroup_validmap, const int vgroup_tot, - const int UNUSED(subset_count), const bool auto_assign, const bool auto_remove) +static void vgroup_invert_subset( + Object *ob, + const bool *vgroup_validmap, const int vgroup_tot, + const int UNUSED(subset_count), const bool auto_assign, const bool auto_remove) { MDeformWeight *dw; MDeformVert *dv, **dvert_array = NULL; @@ -1707,14 +1725,16 @@ static void vgroup_invert_subset(Object *ob, } if (use_mirror && use_vert_sel) { - ED_vgroup_parray_mirror_sync(ob, dvert_array, dvert_tot, - vgroup_validmap, vgroup_tot); + ED_vgroup_parray_mirror_sync( + ob, dvert_array, dvert_tot, + vgroup_validmap, vgroup_tot); } if (auto_remove) { - ED_vgroup_parray_remove_zero(dvert_array, dvert_tot, - vgroup_validmap, vgroup_tot, - 0.0f, false); + ED_vgroup_parray_remove_zero( + dvert_array, dvert_tot, + vgroup_validmap, vgroup_tot, + 0.0f, false); } MEM_freeN(dvert_array); @@ -1934,8 +1954,9 @@ static void vgroup_smooth_subset( /* not so efficient to get 'dvert_array' again just so unselected verts are NULL'd */ if (use_mirror) { ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, true); - ED_vgroup_parray_mirror_sync(ob, dvert_array, dvert_tot, - vgroup_validmap, vgroup_tot); + ED_vgroup_parray_mirror_sync( + ob, dvert_array, dvert_tot, + vgroup_validmap, vgroup_tot); if (dvert_array) MEM_freeN(dvert_array); } @@ -1959,11 +1980,12 @@ static int inv_cmp_mdef_vert_weights(const void *a1, const void *a2) /* Used for limiting the number of influencing bones per vertex when exporting * skinned meshes. if all_deform_weights is True, limit all deform modifiers * to max_weights regardless of type, otherwise, only limit the number of influencing bones per vertex*/ -static int vgroup_limit_total_subset(Object *ob, - const bool *vgroup_validmap, - const int vgroup_tot, - const int subset_count, - const int max_weights) +static int vgroup_limit_total_subset( + Object *ob, + const bool *vgroup_validmap, + const int vgroup_tot, + const int subset_count, + const int max_weights) { MDeformVert *dv, **dvert_array = NULL; int i, dvert_tot = 0; @@ -2030,8 +2052,9 @@ static int vgroup_limit_total_subset(Object *ob, } -static void vgroup_clean_subset(Object *ob, const bool *vgroup_validmap, const int vgroup_tot, const int UNUSED(subset_count), - const float epsilon, const bool keep_single) +static void vgroup_clean_subset( + Object *ob, const bool *vgroup_validmap, const int vgroup_tot, const int UNUSED(subset_count), + const float epsilon, const bool keep_single) { MDeformVert **dvert_array = NULL; int dvert_tot = 0; @@ -2048,16 +2071,18 @@ static void vgroup_clean_subset(Object *ob, const bool *vgroup_validmap, const i ED_vgroup_parray_mirror_assign(ob, dvert_array, dvert_tot); } - ED_vgroup_parray_remove_zero(dvert_array, dvert_tot, - vgroup_validmap, vgroup_tot, - epsilon, keep_single); + ED_vgroup_parray_remove_zero( + dvert_array, dvert_tot, + vgroup_validmap, vgroup_tot, + epsilon, keep_single); MEM_freeN(dvert_array); } } -static void vgroup_quantize_subset(Object *ob, const bool *vgroup_validmap, const int vgroup_tot, const int UNUSED(subset_count), - const int steps) +static void vgroup_quantize_subset( + Object *ob, const bool *vgroup_validmap, const int vgroup_tot, const int UNUSED(subset_count), + const int steps) { MDeformVert **dvert_array = NULL; int dvert_tot = 0; @@ -2095,11 +2120,12 @@ static void vgroup_quantize_subset(Object *ob, const bool *vgroup_validmap, cons } } -static void dvert_mirror_op(MDeformVert *dvert, MDeformVert *dvert_mirr, - const char sel, const char sel_mirr, - const int *flip_map, const int flip_map_len, - const bool mirror_weights, const bool flip_vgroups, const bool all_vgroups, - const int act_vgroup) +static void dvert_mirror_op( + MDeformVert *dvert, MDeformVert *dvert_mirr, + const char sel, const char sel_mirr, + const int *flip_map, const int flip_map_len, + const bool mirror_weights, const bool flip_vgroups, const bool all_vgroups, + const int act_vgroup) { BLI_assert(sel || sel_mirr); @@ -2158,10 +2184,11 @@ static void dvert_mirror_op(MDeformVert *dvert, MDeformVert *dvert_mirr, /* TODO, vgroup locking */ /* TODO, face masking */ -void ED_vgroup_mirror(Object *ob, - const bool mirror_weights, const bool flip_vgroups, - const bool all_vgroups, const bool use_topology, - int *r_totmirr, int *r_totfail) +void ED_vgroup_mirror( + Object *ob, + const bool mirror_weights, const bool flip_vgroups, + const bool all_vgroups, const bool use_topology, + int *r_totmirr, int *r_totfail) { #define VGROUP_MIRR_OP \ @@ -3282,12 +3309,13 @@ static int vertex_group_mirror_exec(bContext *C, wmOperator *op) Object *ob = ED_object_context(C); int totmirr = 0, totfail = 0; - ED_vgroup_mirror(ob, - RNA_boolean_get(op->ptr, "mirror_weights"), - RNA_boolean_get(op->ptr, "flip_group_names"), - RNA_boolean_get(op->ptr, "all_groups"), - RNA_boolean_get(op->ptr, "use_topology"), - &totmirr, &totfail); + ED_vgroup_mirror( + ob, + RNA_boolean_get(op->ptr, "mirror_weights"), + RNA_boolean_get(op->ptr, "flip_group_names"), + RNA_boolean_get(op->ptr, "all_groups"), + RNA_boolean_get(op->ptr, "use_topology"), + &totmirr, &totfail); ED_mesh_report_mirror(op, totmirr, totfail); @@ -3327,7 +3355,7 @@ static int vertex_group_copy_to_linked_exec(bContext *C, wmOperator *UNUSED(op)) Object *ob_active = ED_object_context(C); int retval = OPERATOR_CANCELLED; - FOREACH_SCENE_OBJECT(scene, ob_iter) + FOREACH_SCENE_OBJECT_BEGIN(scene, ob_iter) { if (ob_iter->type == ob_active->type) { if (ob_iter != ob_active && ob_iter->data == ob_active->data) { @@ -3343,7 +3371,7 @@ static int vertex_group_copy_to_linked_exec(bContext *C, wmOperator *UNUSED(op)) } } } - FOREACH_SCENE_OBJECT_END + FOREACH_SCENE_OBJECT_END; return retval; } diff --git a/source/blender/editors/physics/CMakeLists.txt b/source/blender/editors/physics/CMakeLists.txt index 3cecdccd758..3705ff9d41a 100644 --- a/source/blender/editors/physics/CMakeLists.txt +++ b/source/blender/editors/physics/CMakeLists.txt @@ -41,6 +41,7 @@ set(SRC dynamicpaint_ops.c particle_boids.c particle_edit.c + particle_edit_undo.c particle_object.c physics_fluid.c physics_ops.c @@ -49,6 +50,7 @@ set(SRC rigidbody_object.c rigidbody_world.c + particle_edit_utildefines.h physics_intern.h ) diff --git a/source/blender/editors/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c index e068b898345..5d928d69da2 100644 --- a/source/blender/editors/physics/dynamicpaint_ops.c +++ b/source/blender/editors/physics/dynamicpaint_ops.c @@ -288,7 +288,6 @@ typedef struct DynamicPaintBakeJob { struct Main *bmain; Scene *scene; - ViewLayer *view_layer; Depsgraph *depsgraph; Object *ob; @@ -365,9 +364,9 @@ static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job) frame = surface->start_frame; orig_frame = scene->r.cfra; scene->r.cfra = (int)frame; - ED_update_for_newframe(job->bmain, scene, job->view_layer, job->depsgraph); + ED_update_for_newframe(job->bmain, job->depsgraph); - /* Init surface */ + /* Init surface */ if (!dynamicPaint_createUVSurface(scene, surface, job->progress, job->do_update)) { job->success = 0; return; @@ -391,7 +390,7 @@ static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job) /* calculate a frame */ scene->r.cfra = (int)frame; - ED_update_for_newframe(job->bmain, scene, job->view_layer, job->depsgraph); + ED_update_for_newframe(job->bmain, job->depsgraph); if (!dynamicPaint_calculateFrame(surface, job->eval_ctx, scene, cObject, frame)) { job->success = 0; return; @@ -460,7 +459,6 @@ static int dynamicpaint_bake_exec(struct bContext *C, struct wmOperator *op) DynamicPaintCanvasSettings *canvas; Object *ob = ED_object_context(C); Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); EvaluationContext *eval_ctx = MEM_mallocN(sizeof(*eval_ctx), "EvaluationContext"); CTX_data_eval_ctx(C, eval_ctx); @@ -491,7 +489,6 @@ static int dynamicpaint_bake_exec(struct bContext *C, struct wmOperator *op) DynamicPaintBakeJob *job = MEM_mallocN(sizeof(DynamicPaintBakeJob), "DynamicPaintBakeJob"); job->bmain = CTX_data_main(C); job->scene = scene; - job->view_layer = view_layer; job->depsgraph = CTX_data_depsgraph(C); job->ob = ob; job->canvas = canvas; @@ -508,7 +505,7 @@ static int dynamicpaint_bake_exec(struct bContext *C, struct wmOperator *op) WM_set_locked_interface(CTX_wm_manager(C), true); - /* Bake Dynamic Paint */ + /* Bake Dynamic Paint */ WM_jobs_start(CTX_wm_manager(C), wm_job); return OPERATOR_FINISHED; diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index 89dd46681cb..51abb5b2eaa 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -29,7 +29,6 @@ * \ingroup edphys */ - #include <stdlib.h> #include <math.h> #include <string.h> @@ -45,7 +44,7 @@ #include "DNA_space_types.h" #include "BLI_math.h" -#include "BLI_lasso.h" +#include "BLI_lasso_2d.h" #include "BLI_listbase.h" #include "BLI_string.h" #include "BLI_kdtree.h" @@ -71,6 +70,7 @@ #include "ED_physics.h" #include "ED_mesh.h" #include "ED_particle.h" +#include "ED_screen.h" #include "ED_view3d.h" #include "GPU_immediate.h" @@ -86,54 +86,31 @@ #include "physics_intern.h" -void PE_create_particle_edit( - const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, Object *ob, - PointCache *cache, ParticleSystem *psys); -void PTCacheUndo_clear(PTCacheEdit *edit); -void recalc_lengths(PTCacheEdit *edit); -void recalc_emitter_field(Object *ob, ParticleSystem *psys); -void update_world_cos(Object *ob, PTCacheEdit *edit); - -#define KEY_K PTCacheEditKey *key; int k -#define POINT_P PTCacheEditPoint *point; int p -#define LOOP_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) -#define LOOP_VISIBLE_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (!(point->flag & PEP_HIDE)) -#define LOOP_SELECTED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point_is_selected(point)) -#define LOOP_UNSELECTED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (!point_is_selected(point)) -#define LOOP_EDITED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point->flag & PEP_EDIT_RECALC) -#define LOOP_TAGGED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point->flag & PEP_TAG) -#define LOOP_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) -#define LOOP_VISIBLE_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if (!(key->flag & PEK_HIDE)) -#define LOOP_SELECTED_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if ((key->flag & PEK_SELECT) && !(key->flag & PEK_HIDE)) -#define LOOP_TAGGED_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if (key->flag & PEK_TAG) - -#define KEY_WCO ((key->flag & PEK_USE_WCO) ? key->world_co : key->co) +#include "particle_edit_utildefines.h" /**************************** utilities *******************************/ int PE_poll(bContext *C) { Scene *scene= CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob= CTX_data_active_object(C); - if (!scene || !view_layer || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT)) + if (!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT)) { return 0; - - return (PE_get_current(scene, view_layer, ob) != NULL); + } + return (PE_get_current(scene, ob) != NULL); } int PE_hair_poll(bContext *C) { Scene *scene= CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob= CTX_data_active_object(C); PTCacheEdit *edit; - if (!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT)) + if (!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT)) { return 0; - - edit= PE_get_current(scene, view_layer, ob); + } + edit= PE_get_current(scene, ob); return (edit && edit->psys); } @@ -154,8 +131,6 @@ void PE_free_ptcache_edit(PTCacheEdit *edit) if (edit==0) return; - PTCacheUndo_clear(edit); - if (edit->points) { LOOP_POINTS { if (point->keys) @@ -219,7 +194,7 @@ static float pe_brush_size_get(const Scene *UNUSED(scene), ParticleBrushData *br * note: this function runs on poll, therefor it can runs many times a second * keep it fast! */ static PTCacheEdit *pe_get_current( - const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, Object *ob, int create) + const EvaluationContext *eval_ctx, Scene *scene, Object *ob, int create) { ParticleEditSettings *pset= PE_settings(scene); PTCacheEdit *edit = NULL; @@ -230,7 +205,6 @@ static PTCacheEdit *pe_get_current( return NULL; pset->scene = scene; - pset->view_layer = view_layer; pset->object = ob; BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0); @@ -259,18 +233,18 @@ static PTCacheEdit *pe_get_current( if (psys->part && psys->part->type == PART_HAIR) { if (psys->flag & PSYS_HAIR_DYNAMICS && psys->pointcache->flag & PTCACHE_BAKED) { if (create && !psys->pointcache->edit) - PE_create_particle_edit(eval_ctx, scene, view_layer, ob, pid->cache, NULL); + PE_create_particle_edit(eval_ctx, scene, ob, pid->cache, NULL); edit = pid->cache->edit; } else { if (create && !psys->edit && psys->flag & PSYS_HAIR_DONE) - PE_create_particle_edit(eval_ctx, scene, view_layer, ob, NULL, psys); + PE_create_particle_edit(eval_ctx, scene, ob, NULL, psys); edit = psys->edit; } } else { if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) - PE_create_particle_edit(eval_ctx, scene, view_layer, ob, pid->cache, psys); + PE_create_particle_edit(eval_ctx, scene, ob, pid->cache, psys); edit = pid->cache->edit; } @@ -281,7 +255,7 @@ static PTCacheEdit *pe_get_current( if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) { pset->flag |= PE_FADE_TIME; // NICE TO HAVE but doesn't work: pset->brushtype = PE_BRUSH_COMB; - PE_create_particle_edit(eval_ctx, scene, view_layer, ob, pid->cache, NULL); + PE_create_particle_edit(eval_ctx, scene, ob, pid->cache, NULL); } edit = pid->cache->edit; break; @@ -290,7 +264,7 @@ static PTCacheEdit *pe_get_current( if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) { pset->flag |= PE_FADE_TIME; // NICE TO HAVE but doesn't work: pset->brushtype = PE_BRUSH_COMB; - PE_create_particle_edit(eval_ctx, scene, view_layer, ob, pid->cache, NULL); + PE_create_particle_edit(eval_ctx, scene, ob, pid->cache, NULL); } edit = pid->cache->edit; break; @@ -305,14 +279,14 @@ static PTCacheEdit *pe_get_current( return edit; } -PTCacheEdit *PE_get_current(Scene *scene, ViewLayer *view_layer, Object *ob) +PTCacheEdit *PE_get_current(Scene *scene, Object *ob) { - return pe_get_current(NULL, scene, view_layer, ob, 0); + return pe_get_current(NULL, scene, ob, 0); } PTCacheEdit *PE_create_current(const EvaluationContext *eval_ctx, Scene *scene, Object *ob) { - return pe_get_current(eval_ctx, scene, NULL, ob, 1); + return pe_get_current(eval_ctx, scene, ob, 1); } void PE_current_changed(const EvaluationContext *eval_ctx, Scene *scene, Object *ob) @@ -369,6 +343,7 @@ typedef struct PEData { DerivedMesh *dm; PTCacheEdit *edit; BVHTreeFromMesh shape_bvh; + EvaluationContext eval_ctx; const int *mval; rcti *rect; @@ -401,24 +376,22 @@ static void PE_set_data(bContext *C, PEData *data) data->scene = CTX_data_scene(C); data->view_layer = CTX_data_view_layer(C); data->ob = CTX_data_active_object(C); - data->edit = PE_get_current(data->scene, data->view_layer, data->ob); + CTX_data_eval_ctx(C, &data->eval_ctx); + data->edit = PE_get_current(data->scene, data->ob); } static void PE_set_view3d_data(bContext *C, PEData *data) { PE_set_data(C, data); - view3d_set_viewcontext(C, &data->vc); + ED_view3d_viewcontext_init(C, &data->vc); if (V3D_IS_ZBUF(data->vc.v3d)) { if (data->vc.v3d->flag & V3D_INVALID_BACKBUF) { - EvaluationContext eval_ctx; - CTX_data_eval_ctx(C, &eval_ctx); - /* needed or else the draw matrix can be incorrect */ view3d_operator_needs_opengl(C); - ED_view3d_backbuf_validate(&eval_ctx, &data->vc); + ED_view3d_backbuf_validate(&data->eval_ctx, &data->vc); /* we may need to force an update here by setting the rv3d as dirty * for now it seems ok, but take care!: * rv3d->depths->dirty = 1; */ @@ -1163,15 +1136,12 @@ void recalc_emitter_field(Object *ob, ParticleSystem *psys) BLI_kdtree_balance(edit->emitter_field); } -static void PE_update_selection(const bContext *C, Scene *scene, ViewLayer *view_layer, Object *ob, int useflag) +static void PE_update_selection(const EvaluationContext *eval_ctx, Scene *scene, Object *ob, int useflag) { - PTCacheEdit *edit = PE_get_current(scene, view_layer, ob); + PTCacheEdit *edit = PE_get_current(scene, ob); HairKey *hkey; - EvaluationContext eval_ctx; POINT_P; KEY_K; - CTX_data_eval_ctx(C, &eval_ctx); - /* flag all particles to be updated if not using flag */ if (!useflag) LOOP_POINTS @@ -1187,7 +1157,7 @@ static void PE_update_selection(const bContext *C, Scene *scene, ViewLayer *view } } - psys_cache_edit_paths(&eval_ctx, scene, ob, edit, CFRA, G.is_rendering); + psys_cache_edit_paths(eval_ctx, scene, ob, edit, CFRA, G.is_rendering); /* disable update flag */ @@ -1273,12 +1243,12 @@ static void update_velocities(PTCacheEdit *edit) } } -void PE_update_object(const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, Object *ob, int useflag) +void PE_update_object(const EvaluationContext *eval_ctx, Scene *scene, Object *ob, int useflag) { /* use this to do partial particle updates, not usable when adding or * removing, then a full redo is necessary and calling this may crash */ ParticleEditSettings *pset= PE_settings(scene); - PTCacheEdit *edit = PE_get_current(scene, view_layer, ob); + PTCacheEdit *edit = PE_get_current(scene, ob); POINT_P; if (!edit) @@ -1312,6 +1282,8 @@ void PE_update_object(const EvaluationContext *eval_ctx, Scene *scene, ViewLayer if (edit->psys) edit->psys->flag &= ~PSYS_HAIR_UPDATED; + + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); } /************************************************/ @@ -1413,9 +1385,10 @@ static void select_action_apply(PTCacheEditPoint *point, PTCacheEditKey *key, in static int pe_select_all_exec(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); + EvaluationContext eval_ctx; + CTX_data_eval_ctx(C, &eval_ctx); Object *ob= CTX_data_active_object(C); - PTCacheEdit *edit= PE_get_current(scene, view_layer, ob); + PTCacheEdit *edit= PE_get_current(scene, ob); POINT_P; KEY_K; int action = RNA_enum_get(op->ptr, "action"); @@ -1438,7 +1411,7 @@ static int pe_select_all_exec(bContext *C, wmOperator *op) } } - PE_update_selection(C, scene, view_layer, ob, 1); + PE_update_selection(&eval_ctx, scene, ob, 1); WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob); return OPERATOR_FINISHED; @@ -1467,9 +1440,8 @@ int PE_mouse_particles(bContext *C, const int mval[2], bool extend, bool deselec { PEData data; Scene *scene= CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob= CTX_data_active_object(C); - PTCacheEdit *edit= PE_get_current(scene, view_layer, ob); + PTCacheEdit *edit= PE_get_current(scene, ob); POINT_P; KEY_K; if (!PE_start_edit(edit)) @@ -1496,7 +1468,7 @@ int PE_mouse_particles(bContext *C, const int mval[2], bool extend, bool deselec else for_mouse_hit_keys(&data, toggle_key_select, 1); - PE_update_selection(C, scene, view_layer, ob, 1); + PE_update_selection(&data.eval_ctx, scene, ob, 1); WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob); return OPERATOR_FINISHED; @@ -1537,7 +1509,7 @@ static int select_roots_exec(bContext *C, wmOperator *op) data.select_action = action; foreach_point(&data, select_root); - PE_update_selection(C, data.scene, data.view_layer, data.ob, 1); + PE_update_selection(&data.eval_ctx, data.scene, data.ob, 1); WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob); return OPERATOR_FINISHED; @@ -1602,7 +1574,7 @@ static int select_tips_exec(bContext *C, wmOperator *op) data.select_action = action; foreach_point(&data, select_tip); - PE_update_selection(C, data.scene, data.view_layer, data.ob, 1); + PE_update_selection(&data.eval_ctx, data.scene, data.ob, 1); WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob); return OPERATOR_FINISHED; @@ -1641,7 +1613,6 @@ static int select_random_exec(bContext *C, wmOperator *op) PEData data; int type; Scene *scene; - ViewLayer *view_layer; Object *ob; /* used by LOOP_VISIBLE_POINTS, LOOP_VISIBLE_KEYS and LOOP_KEYS */ @@ -1661,9 +1632,8 @@ static int select_random_exec(bContext *C, wmOperator *op) PE_set_data(C, &data); data.select_action = SEL_SELECT; scene = CTX_data_scene(C); - view_layer = CTX_data_view_layer(C); ob = CTX_data_active_object(C); - edit = PE_get_current(scene, view_layer, ob); + edit = PE_get_current(scene, ob); rng = BLI_rng_new_srandom(seed); @@ -1688,7 +1658,7 @@ static int select_random_exec(bContext *C, wmOperator *op) BLI_rng_free(rng); - PE_update_selection(C, data.scene, data.view_layer, data.ob, 1); + PE_update_selection(&data.eval_ctx, data.scene, data.ob, 1); WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob); return OPERATOR_FINISHED; @@ -1732,7 +1702,7 @@ static int select_linked_exec(bContext *C, wmOperator *op) data.select= !RNA_boolean_get(op->ptr, "deselect"); for_mouse_hit_keys(&data, select_keys, 1); /* nearest only */ - PE_update_selection(C, data.scene, data.view_layer, data.ob, 1); + PE_update_selection(&data.eval_ctx, data.scene, data.ob, 1); WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob); return OPERATOR_FINISHED; @@ -1780,9 +1750,8 @@ void PE_deselect_all_visible(PTCacheEdit *edit) int PE_border_select(bContext *C, rcti *rect, bool select, bool extend) { Scene *scene= CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob= CTX_data_active_object(C); - PTCacheEdit *edit= PE_get_current(scene, view_layer, ob); + PTCacheEdit *edit= PE_get_current(scene, ob); PEData data; if (!PE_start_edit(edit)) @@ -1797,7 +1766,7 @@ int PE_border_select(bContext *C, rcti *rect, bool select, bool extend) for_mouse_hit_keys(&data, select_key, 0); - PE_update_selection(C, scene, view_layer, ob, 1); + PE_update_selection(&data.eval_ctx, scene, ob, 1); WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob); return OPERATOR_FINISHED; @@ -1808,9 +1777,8 @@ int PE_border_select(bContext *C, rcti *rect, bool select, bool extend) int PE_circle_select(bContext *C, int selecting, const int mval[2], float rad) { Scene *scene= CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob= CTX_data_active_object(C); - PTCacheEdit *edit= PE_get_current(scene, view_layer, ob); + PTCacheEdit *edit= PE_get_current(scene, ob); PEData data; if (!PE_start_edit(edit)) @@ -1823,7 +1791,7 @@ int PE_circle_select(bContext *C, int selecting, const int mval[2], float rad) for_mouse_hit_keys(&data, select_key, 0); - PE_update_selection(C, scene, view_layer, ob, 1); + PE_update_selection(&data.eval_ctx, scene, ob, 1); WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob); return OPERATOR_FINISHED; @@ -1834,11 +1802,10 @@ int PE_circle_select(bContext *C, int selecting, const int mval[2], float rad) int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, bool extend, bool select) { Scene *scene= CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob= CTX_data_active_object(C); ARegion *ar= CTX_wm_region(C); ParticleEditSettings *pset= PE_settings(scene); - PTCacheEdit *edit = PE_get_current(scene, view_layer, ob); + PTCacheEdit *edit = PE_get_current(scene, ob); ParticleSystem *psys = edit->psys; ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); POINT_P; KEY_K; @@ -1912,7 +1879,7 @@ int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, bool } } - PE_update_selection(C, scene, view_layer, ob, 1); + PE_update_selection(&data.eval_ctx, scene, ob, 1); WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob); return OPERATOR_FINISHED; @@ -1924,10 +1891,13 @@ static int hide_exec(bContext *C, wmOperator *op) { Object *ob= CTX_data_active_object(C); Scene *scene= CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - PTCacheEdit *edit= PE_get_current(scene, view_layer, ob); + EvaluationContext eval_ctx; + CTX_data_eval_ctx(C, &eval_ctx); + + PTCacheEdit *edit= PE_get_current(scene, ob); POINT_P; KEY_K; - + + if (RNA_enum_get(op->ptr, "unselected")) { LOOP_UNSELECTED_POINTS { point->flag |= PEP_HIDE; @@ -1947,7 +1917,7 @@ static int hide_exec(bContext *C, wmOperator *op) } } - PE_update_selection(C, scene, view_layer, ob, 1); + PE_update_selection(&eval_ctx, scene, ob, 1); WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob); return OPERATOR_FINISHED; @@ -1977,8 +1947,9 @@ static int reveal_exec(bContext *C, wmOperator *op) { Object *ob= CTX_data_active_object(C); Scene *scene= CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - PTCacheEdit *edit= PE_get_current(scene, view_layer, ob); + EvaluationContext eval_ctx; + CTX_data_eval_ctx(C, &eval_ctx); + PTCacheEdit *edit= PE_get_current(scene, ob); const bool select = RNA_boolean_get(op->ptr, "select"); POINT_P; KEY_K; @@ -1993,7 +1964,7 @@ static int reveal_exec(bContext *C, wmOperator *op) } } - PE_update_selection(C, scene, view_layer, ob, 1); + PE_update_selection(&eval_ctx, scene, ob, 1); WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob); return OPERATOR_FINISHED; @@ -2055,7 +2026,7 @@ static int select_less_exec(bContext *C, wmOperator *UNUSED(op)) PE_set_data(C, &data); foreach_point(&data, select_less_keys); - PE_update_selection(C, data.scene, data.view_layer, data.ob, 1); + PE_update_selection(&data.eval_ctx, data.scene, data.ob, 1); WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob); return OPERATOR_FINISHED; @@ -2117,7 +2088,7 @@ static int select_more_exec(bContext *C, wmOperator *UNUSED(op)) PE_set_data(C, &data); foreach_point(&data, select_more_keys); - PE_update_selection(C, data.scene, data.view_layer, data.ob, 1); + PE_update_selection(&data.eval_ctx, data.scene, data.ob, 1); WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob); return OPERATOR_FINISHED; @@ -2220,7 +2191,7 @@ static int rekey_exec(bContext *C, wmOperator *op) foreach_selected_point(&data, rekey_particle); recalc_lengths(data.edit); - PE_update_object(&eval_ctx, data.scene, data.view_layer, data.ob, 1); + PE_update_object(&eval_ctx, data.scene, data.ob, 1); WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, data.ob); return OPERATOR_FINISHED; @@ -2245,9 +2216,9 @@ void PARTICLE_OT_rekey(wmOperatorType *ot) RNA_def_int(ot->srna, "keys_number", 2, 2, INT_MAX, "Number of Keys", "", 2, 100); } -static void rekey_particle_to_time(const bContext *C, Scene *scene, ViewLayer *view_layer, Object *ob, int pa_index, float path_time) +static void rekey_particle_to_time(const bContext *C, Scene *scene, Object *ob, int pa_index, float path_time) { - PTCacheEdit *edit= PE_get_current(scene, view_layer, ob); + PTCacheEdit *edit= PE_get_current(scene, ob); ParticleSystem *psys; ParticleSimulationData sim = {0}; ParticleData *pa; @@ -2561,7 +2532,7 @@ static int subdivide_exec(bContext *C, wmOperator *UNUSED(op)) foreach_point(&data, subdivide_particle); recalc_lengths(data.edit); - PE_update_object(&eval_ctx, data.scene, data.view_layer, data.ob, 1); + PE_update_object(&eval_ctx, data.scene, data.ob, 1); WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, data.ob); return OPERATOR_FINISHED; @@ -2587,9 +2558,8 @@ void PARTICLE_OT_subdivide(wmOperatorType *ot) static int remove_doubles_exec(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob= CTX_data_active_object(C); - PTCacheEdit *edit= PE_get_current(scene, view_layer, ob); + PTCacheEdit *edit= PE_get_current(scene, ob); ParticleSystem *psys = edit->psys; ParticleSystemModifierData *psmd; KDTree *tree; @@ -2680,10 +2650,9 @@ void PARTICLE_OT_remove_doubles(wmOperatorType *ot) static int weight_set_exec(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); ParticleEditSettings *pset= PE_settings(scene); Object *ob= CTX_data_active_object(C); - PTCacheEdit *edit= PE_get_current(scene, view_layer, ob); + PTCacheEdit *edit= PE_get_current(scene, ob); ParticleSystem *psys = edit->psys; POINT_P; KEY_K; @@ -2840,11 +2809,12 @@ void PARTICLE_OT_delete(wmOperatorType *ot) /*************************** mirror operator **************************/ -static void PE_mirror_x(Scene *scene, ViewLayer *view_layer, Object *ob, int tagged) +static void PE_mirror_x( + Scene *scene, Object *ob, int tagged) { Mesh *me= (Mesh *)(ob->data); ParticleSystemModifierData *psmd; - PTCacheEdit *edit = PE_get_current(scene, view_layer, ob); + PTCacheEdit *edit = PE_get_current(scene, ob); ParticleSystem *psys = edit->psys; ParticleData *pa, *newpa, *new_pars; PTCacheEditPoint *newpoint, *new_points; @@ -2991,11 +2961,10 @@ static void PE_mirror_x(Scene *scene, ViewLayer *view_layer, Object *ob, int tag static int mirror_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene= CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob= CTX_data_active_object(C); - PTCacheEdit *edit= PE_get_current(scene, view_layer, ob); + PTCacheEdit *edit= PE_get_current(scene, ob); - PE_mirror_x(scene, view_layer, ob, 0); + PE_mirror_x(scene, ob, 0); update_world_cos(ob, edit); WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob); @@ -3132,7 +3101,7 @@ static void brush_cut(PEData *data, int pa_index) edit->points[pa_index].flag |= PEP_TAG; } else { - rekey_particle_to_time(data->context, data->scene, data->view_layer, ob, pa_index, cut_time); + rekey_particle_to_time(data->context, data->scene, ob, pa_index, cut_time); edit->points[pa_index].flag |= PEP_EDIT_RECALC; } } @@ -3787,7 +3756,7 @@ static int brush_edit_init(bContext *C, wmOperator *op) ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob= CTX_data_active_object(C); ParticleEditSettings *pset= PE_settings(scene); - PTCacheEdit *edit= PE_get_current(scene, view_layer, ob); + PTCacheEdit *edit= PE_get_current(scene, ob); ARegion *ar= CTX_wm_region(C); BrushEdit *bedit; float min[3], max[3]; @@ -3821,7 +3790,6 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) { BrushEdit *bedit= op->customdata; Scene *scene= bedit->scene; - ViewLayer *view_layer = bedit->view_layer; Object *ob= bedit->ob; PTCacheEdit *edit= bedit->edit; ParticleEditSettings *pset= PE_settings(scene); @@ -3865,6 +3833,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) (sqrtf(dx * dx + dy * dy) > pset->brush[PE_BRUSH_ADD].step) : (dx != 0 || dy != 0)) || bedit->first) { PEData data= bedit->data; + data.context = C; // TODO(mai): why isnt this set in bedit->data? view3d_operator_needs_opengl(C); selected= (short)count_selected_keys(scene, edit); @@ -4015,14 +3984,14 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) if (ELEM(pset->brushtype, PE_BRUSH_ADD, PE_BRUSH_CUT) && (added || removed)) { if (pset->brushtype == PE_BRUSH_ADD && pe_x_mirror(ob)) - PE_mirror_x(scene, view_layer, ob, 1); + PE_mirror_x(scene, ob, 1); update_world_cos(ob, edit); psys_free_path_cache(NULL, edit); DEG_id_tag_update(&ob->id, OB_RECALC_DATA); } else { - PE_update_object(&eval_ctx, scene, view_layer, ob, 1); + PE_update_object(&eval_ctx, scene, ob, 1); } } @@ -4238,7 +4207,7 @@ static void shape_cut(PEData *data, int pa_index) edit->points[pa_index].flag |= PEP_TAG; } else { - rekey_particle_to_time(data->context, data->scene, data->view_layer, ob, pa_index, cut_time); + rekey_particle_to_time(data->context, data->scene, ob, pa_index, cut_time); edit->points[pa_index].flag |= PEP_EDIT_RECALC; } } @@ -4247,10 +4216,9 @@ static void shape_cut(PEData *data, int pa_index) static int shape_cut_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob = CTX_data_active_object(C); ParticleEditSettings *pset = PE_settings(scene); - PTCacheEdit *edit = PE_get_current(scene, view_layer, ob); + PTCacheEdit *edit = PE_get_current(scene, ob); Object *shapeob = pset->shape_object; int selected = count_selected_keys(scene, edit); int lock_root = pset->flag & PE_LOCK_FIRST; @@ -4258,9 +4226,6 @@ static int shape_cut_exec(bContext *C, wmOperator *UNUSED(op)) if (!PE_start_edit(edit)) return OPERATOR_CANCELLED; - EvaluationContext eval_ctx; - CTX_data_eval_ctx(C, &eval_ctx); - /* disable locking temporatily for disconnected hair */ if (edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR) pset->flag &= ~PE_LOCK_FIRST; @@ -4289,7 +4254,7 @@ static int shape_cut_exec(bContext *C, wmOperator *UNUSED(op)) DEG_id_tag_update(&ob->id, OB_RECALC_DATA); } else { - PE_update_object(&eval_ctx, scene, view_layer, ob, 1); + PE_update_object(&data.eval_ctx, scene, ob, 1); } if (edit->psys) { @@ -4323,299 +4288,12 @@ void PARTICLE_OT_shape_cut(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; } -/*********************** undo ***************************/ - -static void free_PTCacheUndo(PTCacheUndo *undo) -{ - PTCacheEditPoint *point; - int i; - - for (i=0, point=undo->points; i<undo->totpoint; i++, point++) { - if (undo->particles && (undo->particles + i)->hair) - MEM_freeN((undo->particles + i)->hair); - if (point->keys) - MEM_freeN(point->keys); - } - if (undo->points) - MEM_freeN(undo->points); - - if (undo->particles) - MEM_freeN(undo->particles); - - BKE_ptcache_free_mem(&undo->mem_cache); -} - -static void make_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo) -{ - PTCacheEditPoint *point; - int i; - - undo->totpoint= edit->totpoint; - - if (edit->psys) { - ParticleData *pa; - - pa= undo->particles= MEM_dupallocN(edit->psys->particles); - - for (i=0; i<edit->totpoint; i++, pa++) - pa->hair= MEM_dupallocN(pa->hair); - - undo->psys_flag = edit->psys->flag; - } - else { - PTCacheMem *pm; - - BLI_duplicatelist(&undo->mem_cache, &edit->pid.cache->mem_cache); - pm = undo->mem_cache.first; - - for (; pm; pm=pm->next) { - for (i=0; i<BPHYS_TOT_DATA; i++) - pm->data[i] = MEM_dupallocN(pm->data[i]); - } - } - - point= undo->points = MEM_dupallocN(edit->points); - undo->totpoint = edit->totpoint; - - for (i=0; i<edit->totpoint; i++, point++) { - point->keys= MEM_dupallocN(point->keys); - /* no need to update edit key->co & key->time pointers here */ - } -} - -static void get_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo) -{ - ParticleSystem *psys = edit->psys; - ParticleData *pa; - HairKey *hkey; - POINT_P; KEY_K; - - LOOP_POINTS { - if (psys && psys->particles[p].hair) - MEM_freeN(psys->particles[p].hair); - - if (point->keys) - MEM_freeN(point->keys); - } - if (psys && psys->particles) - MEM_freeN(psys->particles); - if (edit->points) - MEM_freeN(edit->points); - if (edit->mirror_cache) { - MEM_freeN(edit->mirror_cache); - edit->mirror_cache= NULL; - } - - edit->points= MEM_dupallocN(undo->points); - edit->totpoint = undo->totpoint; - - LOOP_POINTS { - point->keys= MEM_dupallocN(point->keys); - } - - if (psys) { - psys->particles= MEM_dupallocN(undo->particles); - - psys->totpart= undo->totpoint; - - LOOP_POINTS { - pa = psys->particles + p; - hkey= pa->hair = MEM_dupallocN(pa->hair); - - LOOP_KEYS { - key->co= hkey->co; - key->time= &hkey->time; - hkey++; - } - } - - psys->flag = undo->psys_flag; - } - else { - PTCacheMem *pm; - int i; - - BKE_ptcache_free_mem(&edit->pid.cache->mem_cache); - - BLI_duplicatelist(&edit->pid.cache->mem_cache, &undo->mem_cache); - - pm = edit->pid.cache->mem_cache.first; - - for (; pm; pm=pm->next) { - for (i=0; i<BPHYS_TOT_DATA; i++) - pm->data[i] = MEM_dupallocN(pm->data[i]); - - BKE_ptcache_mem_pointers_init(pm); - - LOOP_POINTS { - LOOP_KEYS { - if ((int)key->ftime == (int)pm->frame) { - key->co = pm->cur[BPHYS_DATA_LOCATION]; - key->vel = pm->cur[BPHYS_DATA_VELOCITY]; - key->rot = pm->cur[BPHYS_DATA_ROTATION]; - key->time = &key->ftime; - } - } - BKE_ptcache_mem_pointers_incr(pm); - } - } - } -} - -void PE_undo_push(Scene *scene, ViewLayer *view_layer, const char *str) -{ - PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer)); - PTCacheUndo *undo; - int nr; - - if (!edit) return; - - /* remove all undos after (also when curundo==NULL) */ - while (edit->undo.last != edit->curundo) { - undo= edit->undo.last; - BLI_remlink(&edit->undo, undo); - free_PTCacheUndo(undo); - MEM_freeN(undo); - } - - /* make new */ - edit->curundo= undo= MEM_callocN(sizeof(PTCacheUndo), "particle undo file"); - BLI_strncpy(undo->name, str, sizeof(undo->name)); - BLI_addtail(&edit->undo, undo); - - /* and limit amount to the maximum */ - nr= 0; - undo= edit->undo.last; - while (undo) { - nr++; - if (nr==U.undosteps) break; - undo= undo->prev; - } - if (undo) { - while (edit->undo.first != undo) { - PTCacheUndo *first= edit->undo.first; - BLI_remlink(&edit->undo, first); - free_PTCacheUndo(first); - MEM_freeN(first); - } - } - - /* copy */ - make_PTCacheUndo(edit, edit->curundo); -} - -void PE_undo_step(Scene *scene, ViewLayer *view_layer, int step) -{ - PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer)); - - if (!edit) return; - - if (step==0) { - get_PTCacheUndo(edit, edit->curundo); - } - else if (step==1) { - - if (edit->curundo==NULL || edit->curundo->prev==NULL) { - /* pass */ - } - else { - if (G.debug & G_DEBUG) printf("undo %s\n", edit->curundo->name); - edit->curundo= edit->curundo->prev; - get_PTCacheUndo(edit, edit->curundo); - } - } - else { - /* curundo has to remain current situation! */ - - if (edit->curundo==NULL || edit->curundo->next==NULL) { - /* pass */ - } - else { - get_PTCacheUndo(edit, edit->curundo->next); - edit->curundo= edit->curundo->next; - if (G.debug & G_DEBUG) printf("redo %s\n", edit->curundo->name); - } - } - - DEG_id_tag_update(&OBACT(view_layer)->id, OB_RECALC_DATA); -} - -bool PE_undo_is_valid(Scene *scene, ViewLayer *view_layer) -{ - PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer)); - - if (edit) { - return (edit->undo.last != edit->undo.first); - } - return 0; -} - -void PTCacheUndo_clear(PTCacheEdit *edit) -{ - PTCacheUndo *undo; - - if (edit==NULL) return; - - undo= edit->undo.first; - while (undo) { - free_PTCacheUndo(undo); - undo= undo->next; - } - BLI_freelistN(&edit->undo); - edit->curundo= NULL; -} - -void PE_undo(Scene *scene, ViewLayer *view_layer) -{ - PE_undo_step(scene, view_layer, 1); -} - -void PE_redo(Scene *scene, ViewLayer *view_layer) -{ - PE_undo_step(scene, view_layer, -1); -} - -void PE_undo_number(Scene *scene, ViewLayer *view_layer, int nr) -{ - PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer)); - PTCacheUndo *undo; - int a=0; - - for (undo= edit->undo.first; undo; undo= undo->next, a++) { - if (a==nr) break; - } - edit->curundo= undo; - PE_undo_step(scene, view_layer, 0); -} - - -/* get name of undo item, return null if no item with this index */ -/* if active pointer, set it to 1 if true */ -const char *PE_undo_get_name(Scene *scene, ViewLayer *view_layer, int nr, bool *r_active) -{ - PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer)); - PTCacheUndo *undo; - - if (r_active) *r_active = false; - - if (edit) { - undo= BLI_findlink(&edit->undo, nr); - if (undo) { - if (r_active && (undo == edit->curundo)) { - *r_active = true; - } - return undo->name; - } - } - return NULL; -} - /************************ utilities ******************************/ int PE_minmax(Scene *scene, ViewLayer *view_layer, float min[3], float max[3]) { Object *ob= OBACT(view_layer); - PTCacheEdit *edit= PE_get_current(scene, view_layer, ob); + PTCacheEdit *edit= PE_get_current(scene, ob); ParticleSystem *psys; ParticleSystemModifierData *psmd = NULL; POINT_P; KEY_K; @@ -4653,7 +4331,7 @@ int PE_minmax(Scene *scene, ViewLayer *view_layer, float min[3], float max[3]) /* initialize needed data for bake edit */ void PE_create_particle_edit( - const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, Object *ob, PointCache *cache, ParticleSystem *psys) + const EvaluationContext *eval_ctx, Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys) { PTCacheEdit *edit; ParticleSystemModifierData *psmd = (psys) ? psys_get_modifier(ob, psys) : NULL; @@ -4754,10 +4432,8 @@ void PE_create_particle_edit( recalc_lengths(edit); if (psys && !cache) recalc_emitter_field(ob, psys); - PE_update_object(eval_ctx, scene, view_layer, ob, 1); - PTCacheUndo_clear(edit); - PE_undo_push(scene, view_layer, "Original"); + PE_update_object(eval_ctx, scene, ob, 1); } } @@ -4784,9 +4460,6 @@ static int particle_edit_toggle_exec(bContext *C, wmOperator *op) const int mode_flag = OB_MODE_PARTICLE_EDIT; const bool is_mode_set = (ob->mode & mode_flag) != 0; - BKE_report(op->reports, RPT_INFO, "Particles are changing, editing is not possible"); - return OPERATOR_CANCELLED; - if (!is_mode_set) { if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) { return OPERATOR_CANCELLED; @@ -4815,6 +4488,8 @@ static int particle_edit_toggle_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_OBJECT, NULL); } + // ED_workspace_object_mode_sync_from_object(wm, workspace, ob); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); return OPERATOR_FINISHED; @@ -4967,8 +4642,10 @@ static int unify_length_exec(bContext *C, wmOperator *UNUSED(op)) { Object *ob = CTX_data_active_object(C); Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - PTCacheEdit *edit = PE_get_current(scene, view_layer, ob); + EvaluationContext eval_ctx; + CTX_data_eval_ctx(C, &eval_ctx); + + PTCacheEdit *edit = PE_get_current(scene, ob); float average_length = calculate_average_length(edit); if (average_length == 0.0f) { @@ -4976,10 +4653,8 @@ static int unify_length_exec(bContext *C, wmOperator *UNUSED(op)) } scale_points_to_length(edit, average_length); - EvaluationContext eval_ctx; - CTX_data_eval_ctx(C, &eval_ctx); - PE_update_object(&eval_ctx, scene, view_layer, ob, 1); + PE_update_object(&eval_ctx, scene, ob, 1); if (edit->psys) { WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob); } diff --git a/source/blender/editors/physics/particle_edit_undo.c b/source/blender/editors/physics/particle_edit_undo.c new file mode 100644 index 00000000000..5199b1c54fa --- /dev/null +++ b/source/blender/editors/physics/particle_edit_undo.c @@ -0,0 +1,301 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2007 by Janne Karhu. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/physics/particle_edit_undo.c + * \ingroup edphys + */ + +#include <stdlib.h> +#include <math.h> +#include <string.h> +#include <assert.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_scene_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_windowmanager_types.h" + +#include "BLI_listbase.h" +#include "BLI_string.h" +#include "BLI_utildefines.h" + +#include "BKE_particle.h" +#include "BKE_pointcache.h" +#include "BKE_context.h" +#include "BKE_undo_system.h" + +#include "DEG_depsgraph.h" + +#include "ED_object.h" +#include "ED_particle.h" +#include "ED_physics.h" + +#include "particle_edit_utildefines.h" + +#include "physics_intern.h" + +/* -------------------------------------------------------------------- */ +/** \name Undo Conversion + * \{ */ + +static void undoptcache_from_editcache(PTCacheUndo *undo, PTCacheEdit *edit) +{ + PTCacheEditPoint *point; + int i; + + size_t mem_used_prev = MEM_get_memory_in_use(); + + undo->totpoint= edit->totpoint; + + if (edit->psys) { + ParticleData *pa; + + pa= undo->particles= MEM_dupallocN(edit->psys->particles); + + for (i=0; i<edit->totpoint; i++, pa++) { + pa->hair= MEM_dupallocN(pa->hair); + } + + undo->psys_flag = edit->psys->flag; + } + else { + PTCacheMem *pm; + + BLI_duplicatelist(&undo->mem_cache, &edit->pid.cache->mem_cache); + pm = undo->mem_cache.first; + + for (; pm; pm=pm->next) { + for (i=0; i<BPHYS_TOT_DATA; i++) { + pm->data[i] = MEM_dupallocN(pm->data[i]); + } + } + } + + point= undo->points = MEM_dupallocN(edit->points); + undo->totpoint = edit->totpoint; + + for (i=0; i<edit->totpoint; i++, point++) { + point->keys= MEM_dupallocN(point->keys); + /* no need to update edit key->co & key->time pointers here */ + } + + size_t mem_used_curr = MEM_get_memory_in_use(); + + undo->undo_size = mem_used_prev < mem_used_curr ? mem_used_curr - mem_used_prev : sizeof(PTCacheUndo); +} + +static void undoptcache_to_editcache(PTCacheUndo *undo, PTCacheEdit *edit) +{ + ParticleSystem *psys = edit->psys; + ParticleData *pa; + HairKey *hkey; + POINT_P; KEY_K; + + LOOP_POINTS { + if (psys && psys->particles[p].hair) { + MEM_freeN(psys->particles[p].hair); + } + + if (point->keys) { + MEM_freeN(point->keys); + } + } + if (psys && psys->particles) { + MEM_freeN(psys->particles); + } + if (edit->points) { + MEM_freeN(edit->points); + } + if (edit->mirror_cache) { + MEM_freeN(edit->mirror_cache); + edit->mirror_cache= NULL; + } + + edit->points= MEM_dupallocN(undo->points); + edit->totpoint = undo->totpoint; + + LOOP_POINTS { + point->keys= MEM_dupallocN(point->keys); + } + + if (psys) { + psys->particles= MEM_dupallocN(undo->particles); + + psys->totpart= undo->totpoint; + + LOOP_POINTS { + pa = psys->particles + p; + hkey= pa->hair = MEM_dupallocN(pa->hair); + + LOOP_KEYS { + key->co= hkey->co; + key->time= &hkey->time; + hkey++; + } + } + + psys->flag = undo->psys_flag; + } + else { + PTCacheMem *pm; + int i; + + BKE_ptcache_free_mem(&edit->pid.cache->mem_cache); + + BLI_duplicatelist(&edit->pid.cache->mem_cache, &undo->mem_cache); + + pm = edit->pid.cache->mem_cache.first; + + for (; pm; pm=pm->next) { + for (i = 0; i < BPHYS_TOT_DATA; i++) { + pm->data[i] = MEM_dupallocN(pm->data[i]); + } + BKE_ptcache_mem_pointers_init(pm); + + LOOP_POINTS { + LOOP_KEYS { + if ((int)key->ftime == (int)pm->frame) { + key->co = pm->cur[BPHYS_DATA_LOCATION]; + key->vel = pm->cur[BPHYS_DATA_VELOCITY]; + key->rot = pm->cur[BPHYS_DATA_ROTATION]; + key->time = &key->ftime; + } + } + BKE_ptcache_mem_pointers_incr(pm); + } + } + } +} + +static void undoptcache_free_data(PTCacheUndo *undo) +{ + PTCacheEditPoint *point; + int i; + + for (i = 0, point=undo->points; i < undo->totpoint; i++, point++) { + if (undo->particles && (undo->particles + i)->hair) { + MEM_freeN((undo->particles + i)->hair); + } + if (point->keys) { + MEM_freeN(point->keys); + } + } + if (undo->points) { + MEM_freeN(undo->points); + } + if (undo->particles) { + MEM_freeN(undo->particles); + } + BKE_ptcache_free_mem(&undo->mem_cache); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Implements ED Undo System + * \{ */ + +typedef struct ParticleUndoStep { + UndoStep step; + UndoRefID_Scene scene_ref; + UndoRefID_Object object_ref; + PTCacheUndo data; +} ParticleUndoStep; + +static bool particle_undosys_poll(struct bContext *C) +{ + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob = OBACT(view_layer); + PTCacheEdit *edit = PE_get_current(scene, ob); + + return (edit != NULL); +} + +static bool particle_undosys_step_encode(struct bContext *C, UndoStep *us_p) +{ + ParticleUndoStep *us = (ParticleUndoStep *)us_p; + ViewLayer *view_layer = CTX_data_view_layer(C); + us->scene_ref.ptr = CTX_data_scene(C); + us->object_ref.ptr = OBACT(view_layer); + PTCacheEdit *edit = PE_get_current(us->scene_ref.ptr, us->object_ref.ptr); + undoptcache_from_editcache(&us->data, edit); + return true; +} + +static void particle_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir)) +{ + /* TODO(campbell): undo_system: use low-level API to set mode. */ + ED_object_mode_set(C, OB_MODE_PARTICLE_EDIT); + BLI_assert(particle_undosys_poll(C)); + + ParticleUndoStep *us = (ParticleUndoStep *)us_p; + Scene *scene = us->scene_ref.ptr; + Object *ob = us->object_ref.ptr; + PTCacheEdit *edit = PE_get_current(scene, ob); + if (edit) { + undoptcache_to_editcache(&us->data, edit); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + } + else { + BLI_assert(0); + } +} + +static void particle_undosys_step_free(UndoStep *us_p) +{ + ParticleUndoStep *us = (ParticleUndoStep *)us_p; + undoptcache_free_data(&us->data); +} + +static void particle_undosys_foreach_ID_ref( + UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data) +{ + ParticleUndoStep *us = (ParticleUndoStep *)us_p; + foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->scene_ref)); + foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->object_ref)); +} + +/* Export for ED_undo_sys. */ +void ED_particle_undosys_type(UndoType *ut) +{ + ut->name = "Edit Particle"; + ut->poll = particle_undosys_poll; + ut->step_encode = particle_undosys_step_encode; + ut->step_decode = particle_undosys_step_decode; + ut->step_free = particle_undosys_step_free; + + ut->step_foreach_ID_ref = particle_undosys_foreach_ID_ref; + + ut->mode = BKE_UNDOTYPE_MODE_STORE; + ut->use_context = true; + + ut->step_size = sizeof(ParticleUndoStep); +} + +/** \} */ diff --git a/source/blender/editors/physics/particle_edit_utildefines.h b/source/blender/editors/physics/particle_edit_utildefines.h new file mode 100644 index 00000000000..7608b885459 --- /dev/null +++ b/source/blender/editors/physics/particle_edit_utildefines.h @@ -0,0 +1,50 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2007 by Janne Karhu. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/physics/particle_edit_utildefines.h + * \ingroup edphys + */ + +#ifndef __PARTICLE_EDIT_UTILDEFNIES_H__ +#define __PARTICLE_EDIT_UTILDEFNIES_H__ + +#define KEY_K PTCacheEditKey *key; int k +#define POINT_P PTCacheEditPoint *point; int p +#define LOOP_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) +#define LOOP_VISIBLE_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (!(point->flag & PEP_HIDE)) +#define LOOP_SELECTED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point_is_selected(point)) +#define LOOP_UNSELECTED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (!point_is_selected(point)) +#define LOOP_EDITED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point->flag & PEP_EDIT_RECALC) +#define LOOP_TAGGED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point->flag & PEP_TAG) +#define LOOP_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) +#define LOOP_VISIBLE_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if (!(key->flag & PEK_HIDE)) +#define LOOP_SELECTED_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if ((key->flag & PEK_SELECT) && !(key->flag & PEK_HIDE)) +#define LOOP_TAGGED_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if (key->flag & PEK_TAG) + +#define KEY_WCO ((key->flag & PEK_USE_WCO) ? key->world_co : key->co) + +#endif /* __PARTICLE_EDIT_UTILDEFNIES_H__ */ diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c index 1536c15525f..1fae5b70aff 100644 --- a/source/blender/editors/physics/particle_object.c +++ b/source/blender/editors/physics/particle_object.c @@ -69,32 +69,9 @@ #include "UI_resources.h" -#include "physics_intern.h" +#include "particle_edit_utildefines.h" -extern void PE_create_particle_edit(const bContext *C, Scene *scene, ViewLayer *view_layer, Object *ob, PointCache *cache, ParticleSystem *psys); -extern void PTCacheUndo_clear(PTCacheEdit *edit); -extern void recalc_lengths(PTCacheEdit *edit); -extern void recalc_emitter_field(Object *ob, ParticleSystem *psys); -extern void update_world_cos(Object *ob, PTCacheEdit *edit); - -#define KEY_K PTCacheEditKey *key; int k -#define POINT_P PTCacheEditPoint *point; int p -#define LOOP_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) -#if 0 -#define LOOP_VISIBLE_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (!(point->flag & PEP_HIDE)) -#define LOOP_SELECTED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point_is_selected(point)) -#define LOOP_UNSELECTED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (!point_is_selected(point)) -#define LOOP_EDITED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point->flag & PEP_EDIT_RECALC) -#define LOOP_TAGGED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point->flag & PEP_TAG) -#endif -#define LOOP_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) -#if 0 -#define LOOP_VISIBLE_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if (!(key->flag & PEK_HIDE)) -#define LOOP_SELECTED_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if ((key->flag & PEK_SELECT) && !(key->flag & PEK_HIDE)) -#define LOOP_TAGGED_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if (key->flag & PEK_TAG) - -#define KEY_WCO (key->flag & PEK_USE_WCO ? key->world_co : key->co) -#endif +#include "physics_intern.h" static float I[4][4] = {{1.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 0.0f, 1.0f}}; @@ -569,7 +546,7 @@ void PARTICLE_OT_dupliob_move_down(wmOperatorType *ot) /************************ connect/disconnect hair operators *********************/ static void disconnect_hair( - const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, + const EvaluationContext *eval_ctx, Scene *scene, Object *ob, ParticleSystem *psys) { ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); @@ -616,13 +593,12 @@ static void disconnect_hair( if (ELEM(pset->brushtype, PE_BRUSH_ADD, PE_BRUSH_PUFF)) pset->brushtype = PE_BRUSH_NONE; - PE_update_object(eval_ctx, scene, view_layer, ob, 0); + PE_update_object(eval_ctx, scene, ob, 0); } static int disconnect_hair_exec(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob= ED_object_context(C); ParticleSystem *psys= NULL; const bool all = RNA_boolean_get(op->ptr, "all"); @@ -635,12 +611,12 @@ static int disconnect_hair_exec(bContext *C, wmOperator *op) if (all) { for (psys=ob->particlesystem.first; psys; psys=psys->next) { - disconnect_hair(&eval_ctx, scene, view_layer, ob, psys); + disconnect_hair(&eval_ctx, scene, ob, psys); } } else { psys = psys_get_current(ob); - disconnect_hair(&eval_ctx, scene, view_layer, ob, psys); + disconnect_hair(&eval_ctx, scene, ob, psys); } DEG_id_tag_update(&ob->id, OB_RECALC_DATA); @@ -667,7 +643,7 @@ void PARTICLE_OT_disconnect_hair(wmOperatorType *ot) * from/to_mat : additional transform for from/to particles (e.g. for using object space copying) */ static bool remap_hair_emitter( - const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, Object *ob, ParticleSystem *psys, + const EvaluationContext *eval_ctx, Scene *scene, Object *ob, ParticleSystem *psys, Object *target_ob, ParticleSystem *target_psys, PTCacheEdit *target_edit, float from_mat[4][4], float to_mat[4][4], bool from_global, bool to_global) { @@ -853,13 +829,13 @@ static bool remap_hair_emitter( psys_free_path_cache(target_psys, target_edit); - PE_update_object(eval_ctx, scene, view_layer, target_ob, 0); + PE_update_object(eval_ctx, scene, target_ob, 0); return true; } static bool connect_hair( - const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, + const EvaluationContext *eval_ctx, Scene *scene, Object *ob, ParticleSystem *psys) { bool ok; @@ -868,7 +844,7 @@ static bool connect_hair( return false; ok = remap_hair_emitter( - eval_ctx, scene, view_layer, ob, psys, ob, psys, psys->edit, + eval_ctx, scene, ob, psys, ob, psys, psys->edit, ob->obmat, ob->obmat, psys->flag & PSYS_GLOBAL_HAIR, false); psys->flag &= ~PSYS_GLOBAL_HAIR; @@ -879,7 +855,6 @@ static int connect_hair_exec(bContext *C, wmOperator *op) { EvaluationContext eval_ctx; Scene *scene= CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob= ED_object_context(C); ParticleSystem *psys= NULL; const bool all = RNA_boolean_get(op->ptr, "all"); @@ -892,12 +867,12 @@ static int connect_hair_exec(bContext *C, wmOperator *op) if (all) { for (psys=ob->particlesystem.first; psys; psys=psys->next) { - any_connected |= connect_hair(&eval_ctx, scene, view_layer, ob, psys); + any_connected |= connect_hair(&eval_ctx, scene, ob, psys); } } else { psys = psys_get_current(ob); - any_connected |= connect_hair(&eval_ctx, scene, view_layer, ob, psys); + any_connected |= connect_hair(&eval_ctx, scene, ob, psys); } if (!any_connected) { @@ -934,7 +909,7 @@ typedef enum eCopyParticlesSpace { } eCopyParticlesSpace; static void copy_particle_edit( - const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, + const EvaluationContext *eval_ctx, Scene *scene, Object *ob, ParticleSystem *psys, ParticleSystem *psys_from) { PTCacheEdit *edit_from = psys_from->edit, *edit; @@ -954,10 +929,7 @@ static void copy_particle_edit( edit->emitter_field = NULL; edit->emitter_cosnos = NULL; - - BLI_listbase_clear(&edit->undo); - edit->curundo = NULL; - + edit->points = MEM_dupallocN(edit_from->points); pa = psys->particles; LOOP_POINTS { @@ -985,10 +957,7 @@ static void copy_particle_edit( recalc_lengths(edit); recalc_emitter_field(ob, psys); - PE_update_object(eval_ctx, scene, view_layer, ob, true); - - PTCacheUndo_clear(edit); - PE_undo_push(scene, view_layer, "Original"); + PE_update_object(eval_ctx, scene, ob, true); } static void remove_particle_systems_from_object(Object *ob_to) @@ -1018,7 +987,6 @@ static void remove_particle_systems_from_object(Object *ob_to) /* single_psys_from is optional, if NULL all psys of ob_from are copied */ static bool copy_particle_systems_to_object(const bContext *C, Scene *scene, - ViewLayer *view_layer, Object *ob_from, ParticleSystem *single_psys_from, Object *ob_to, @@ -1103,7 +1071,7 @@ static bool copy_particle_systems_to_object(const bContext *C, DM_ensure_tessface(psmd->dm_final); if (psys_from->edit) { - copy_particle_edit(&eval_ctx, scene, view_layer, ob_to, psys, psys_from); + copy_particle_edit(&eval_ctx, scene, ob_to, psys, psys_from); } if (duplicate_settings) { @@ -1139,7 +1107,7 @@ static bool copy_particle_systems_to_object(const bContext *C, } if (ob_from != ob_to) { remap_hair_emitter( - &eval_ctx, scene, view_layer, ob_from, psys_from, ob_to, psys, psys->edit, + &eval_ctx, scene, ob_from, psys_from, ob_to, psys, psys->edit, from_mat, to_mat, psys_from->flag & PSYS_GLOBAL_HAIR, psys->flag & PSYS_GLOBAL_HAIR); } @@ -1174,7 +1142,6 @@ static int copy_particle_systems_exec(bContext *C, wmOperator *op) const bool remove_target_particles = RNA_boolean_get(op->ptr, "remove_target_particles"); const bool use_active = RNA_boolean_get(op->ptr, "use_active"); Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob_from = ED_object_active_context(C); ParticleSystem *psys_from = use_active ? CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data : NULL; @@ -1189,7 +1156,7 @@ static int copy_particle_systems_exec(bContext *C, wmOperator *op) remove_particle_systems_from_object(ob_to); changed = true; } - if (copy_particle_systems_to_object(C, scene, view_layer, ob_from, psys_from, ob_to, space, false)) + if (copy_particle_systems_to_object(C, scene, ob_from, psys_from, ob_to, space, false)) changed = true; else fail++; @@ -1250,7 +1217,7 @@ static int duplicate_particle_systems_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); Object *ob = ED_object_active_context(C); ParticleSystem *psys = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data; - copy_particle_systems_to_object(C, scene, CTX_data_view_layer(C), ob, psys, ob, + copy_particle_systems_to_object(C, scene, ob, psys, ob, PAR_COPY_SPACE_OBJECT, duplicate_settings); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c index 12e01228e1e..c0b2ae8ded4 100644 --- a/source/blender/editors/physics/physics_fluid.c +++ b/source/blender/editors/physics/physics_fluid.c @@ -39,7 +39,7 @@ /* types */ #include "DNA_action_types.h" #include "DNA_object_types.h" -#include "DNA_object_fluidsim.h" +#include "DNA_object_fluidsim_types.h" #include "BLI_blenlib.h" #include "BLI_math.h" @@ -48,8 +48,6 @@ #include "BKE_context.h" #include "BKE_customdata.h" #include "BKE_fluidsim.h" -#include "BKE_global.h" -#include "BKE_main.h" #include "BKE_modifier.h" #include "BKE_object.h" #include "BKE_report.h" @@ -69,6 +67,8 @@ /* enable/disable overall compilation */ #ifdef WITH_MOD_FLUID +#include "BKE_global.h" + #include "WM_api.h" #include "DNA_scene_types.h" @@ -409,7 +409,7 @@ static void fluid_init_all_channels(bContext *C, Object *UNUSED(fsDomain), Fluid /* Modifying the global scene isn't nice, but we can do it in * this part of the process before a threaded job is created */ scene->r.cfra = (int)eval_time; - ED_update_for_newframe(CTX_data_main(C), scene, view_layer, depsgraph); + ED_update_for_newframe(CTX_data_main(C), depsgraph); /* now scene data should be current according to animation system, so we fill the channels */ @@ -959,7 +959,7 @@ static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, shor /* reset to original current frame */ scene->r.cfra = origFrame; - ED_update_for_newframe(CTX_data_main(C), scene, view_layer, depsgraph); + ED_update_for_newframe(CTX_data_main(C), depsgraph); /* ******** init domain object's matrix ******** */ copy_m4_m4(domainMat, fsDomain->obmat); diff --git a/source/blender/editors/physics/physics_intern.h b/source/blender/editors/physics/physics_intern.h index 6b6df15e987..246bf79360f 100644 --- a/source/blender/editors/physics/physics_intern.h +++ b/source/blender/editors/physics/physics_intern.h @@ -33,6 +33,13 @@ #ifndef __PHYSICS_INTERN_H__ #define __PHYSICS_INTERN_H__ +struct EvaluationContext; +struct Object; +struct PTCacheEdit; +struct ParticleSystem; +struct PointCache; +struct Scene; +struct ViewLayer; struct wmOperatorType; /* particle_edit.c */ @@ -63,6 +70,13 @@ void PARTICLE_OT_edited_clear(struct wmOperatorType *ot); void PARTICLE_OT_unify_length(struct wmOperatorType *ot); +void PE_create_particle_edit( + const struct EvaluationContext *eval_ctx, struct Scene *scene, + struct Object *ob, struct PointCache *cache, struct ParticleSystem *psys); +void recalc_lengths(struct PTCacheEdit *edit); +void recalc_emitter_field(struct Object *ob, struct ParticleSystem *psys); +void update_world_cos(struct Object *ob, struct PTCacheEdit *edit); + /* particle_object.c */ void OBJECT_OT_particle_system_add(struct wmOperatorType *ot); void OBJECT_OT_particle_system_remove(struct wmOperatorType *ot); diff --git a/source/blender/editors/physics/physics_pointcache.c b/source/blender/editors/physics/physics_pointcache.c index a859f664dc8..fdafd6c28ed 100644 --- a/source/blender/editors/physics/physics_pointcache.c +++ b/source/blender/editors/physics/physics_pointcache.c @@ -177,18 +177,7 @@ static PTCacheBaker *ptcache_baker_create(bContext *C, wmOperator *op, bool all) PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache); Object *ob = ptr.id.data; PointCache *cache = ptr.data; - - ListBase pidlist; - BKE_ptcache_ids_from_object(&pidlist, ob, baker->scene, MAX_DUPLI_RECUR); - - for (PTCacheID *pid = pidlist.first; pid; pid = pid->next) { - if (pid->cache == cache) { - baker->pid = *pid; - break; - } - } - - BLI_freelistN(&pidlist); + baker->pid = BKE_ptcache_id_find(ob, baker->scene, cache); } return baker; @@ -260,7 +249,7 @@ static int ptcache_free_bake_all_exec(bContext *C, wmOperator *UNUSED(op)) PTCacheID *pid; ListBase pidlist; - FOREACH_SCENE_OBJECT(scene, ob) + FOREACH_SCENE_OBJECT_BEGIN(scene, ob) { BKE_ptcache_ids_from_object(&pidlist, ob, scene, MAX_DUPLI_RECUR); @@ -272,7 +261,7 @@ static int ptcache_free_bake_all_exec(bContext *C, wmOperator *UNUSED(op)) WM_event_add_notifier(C, NC_OBJECT|ND_POINTCACHE, ob); } - FOREACH_SCENE_OBJECT_END + FOREACH_SCENE_OBJECT_END; WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene); @@ -391,22 +380,14 @@ static int ptcache_add_new_exec(bContext *C, wmOperator *UNUSED(op)) PointerRNA ptr= CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache); Object *ob= ptr.id.data; PointCache *cache= ptr.data; - PTCacheID *pid; - ListBase pidlist; + PTCacheID pid = BKE_ptcache_id_find(ob, scene, cache); - BKE_ptcache_ids_from_object(&pidlist, ob, scene, MAX_DUPLI_RECUR); - - for (pid=pidlist.first; pid; pid=pid->next) { - if (pid->cache == cache) { - PointCache *cache_new = BKE_ptcache_add(pid->ptcaches); - cache_new->step = pid->default_step; - *(pid->cache_ptr) = cache_new; - break; - } + if (pid.cache) { + PointCache *cache_new = BKE_ptcache_add(pid.ptcaches); + cache_new->step = pid.default_step; + *(pid.cache_ptr) = cache_new; } - BLI_freelistN(&pidlist); - WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene); WM_event_add_notifier(C, NC_OBJECT|ND_POINTCACHE, ob); @@ -418,26 +399,15 @@ static int ptcache_remove_exec(bContext *C, wmOperator *UNUSED(op)) Scene *scene= CTX_data_scene(C); Object *ob= ptr.id.data; PointCache *cache= ptr.data; - PTCacheID *pid; - ListBase pidlist; - - BKE_ptcache_ids_from_object(&pidlist, ob, scene, MAX_DUPLI_RECUR); - - for (pid=pidlist.first; pid; pid=pid->next) { - if (pid->cache == cache) { - if (pid->ptcaches->first == pid->ptcaches->last) - continue; /* don't delete last cache */ - - BLI_remlink(pid->ptcaches, pid->cache); - BKE_ptcache_free(pid->cache); - *(pid->cache_ptr) = pid->ptcaches->first; + PTCacheID pid = BKE_ptcache_id_find(ob, scene, cache); - break; - } + /* don't delete last cache */ + if (pid.cache && pid.ptcaches->first != pid.ptcaches->last) { + BLI_remlink(pid.ptcaches, pid.cache); + BKE_ptcache_free(pid.cache); + *(pid.cache_ptr) = pid.ptcaches->first; } - BLI_freelistN(&pidlist); - WM_event_add_notifier(C, NC_OBJECT|ND_POINTCACHE, ob); return OPERATOR_FINISHED; diff --git a/source/blender/editors/physics/rigidbody_constraint.c b/source/blender/editors/physics/rigidbody_constraint.c index f77e164ba16..3bcc047bf5b 100644 --- a/source/blender/editors/physics/rigidbody_constraint.c +++ b/source/blender/editors/physics/rigidbody_constraint.c @@ -38,7 +38,6 @@ #include "DNA_scene_types.h" #include "BKE_context.h" -#include "BKE_global.h" #include "BKE_group.h" #include "BKE_main.h" #include "BKE_report.h" diff --git a/source/blender/editors/physics/rigidbody_object.c b/source/blender/editors/physics/rigidbody_object.c index 3b667520550..3553ffa5033 100644 --- a/source/blender/editors/physics/rigidbody_object.c +++ b/source/blender/editors/physics/rigidbody_object.c @@ -43,7 +43,6 @@ #include "BLT_translation.h" #include "BKE_context.h" -#include "BKE_global.h" #include "BKE_group.h" #include "BKE_main.h" #include "BKE_report.h" diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index 80bdeaa8069..51a75e36044 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -65,6 +65,7 @@ #include "BKE_sequencer.h" #include "BKE_screen.h" #include "BKE_scene.h" +#include "BKE_undo_system.h" #include "BKE_workspace.h" #include "DEG_depsgraph.h" @@ -76,6 +77,7 @@ #include "ED_render.h" #include "ED_screen.h" #include "ED_util.h" +#include "ED_undo.h" #include "ED_view3d.h" #include "RE_pipeline.h" @@ -92,6 +94,7 @@ #include "RNA_access.h" #include "RNA_define.h" +#include "BLO_undofile.h" #include "render_intern.h" @@ -295,8 +298,8 @@ static void screen_render_view_layer_set(wmOperator *op, Main *mainp, Scene **sc static int screen_render_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); + RenderEngineType *re_type = RE_engines_find(scene->view_render.engine_id); ViewLayer *view_layer = NULL; - Depsgraph *depsgraph = CTX_data_depsgraph(C); Render *re; Image *ima; View3D *v3d = CTX_wm_view3d(C); @@ -306,6 +309,11 @@ static int screen_render_exec(bContext *C, wmOperator *op) const bool is_write_still = RNA_boolean_get(op->ptr, "write_still"); struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL; + /* Cannot do render if there is not this function. */ + if (re_type->render_to_image == NULL) { + return OPERATOR_CANCELLED; + } + /* custom scene and single layer re-render */ screen_render_view_layer_set(op, mainp, &scene, &view_layer); @@ -315,7 +323,6 @@ static int screen_render_exec(bContext *C, wmOperator *op) } re = RE_NewSceneRender(scene); - RE_SetDepsgraph(re, CTX_data_depsgraph(C)); lay_override = (v3d && v3d->lay != scene->lay) ? v3d->lay : 0; G.is_break = false; @@ -333,17 +340,17 @@ static int screen_render_exec(bContext *C, wmOperator *op) RE_SetReports(re, op->reports); - BLI_begin_threaded_malloc(); + BLI_threaded_malloc_begin(); if (is_animation) RE_BlenderAnim(re, mainp, scene, camera_override, lay_override, scene->r.sfra, scene->r.efra, scene->r.frame_step); else RE_BlenderFrame(re, mainp, scene, view_layer, camera_override, lay_override, scene->r.cfra, is_write_still); - BLI_end_threaded_malloc(); + BLI_threaded_malloc_end(); RE_SetReports(re, NULL); // no redraw needed, we leave state as we entered it - ED_update_for_newframe(mainp, scene, view_layer, depsgraph); + ED_update_for_newframe(mainp, CTX_data_depsgraph(C)); WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, scene); @@ -532,10 +539,8 @@ static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr, int layer = BLI_findstringindex(&main_rr->layers, (char *)rr->renlay->name, offsetof(RenderLayer, name)); - if (layer != rj->last_layer) { - sima->iuser.layer = layer; - rj->last_layer = layer; - } + sima->iuser.layer = layer; + rj->last_layer = layer; } iuser->pass = sima->iuser.pass; @@ -633,7 +638,21 @@ static void render_image_restore_layer(RenderJob *rj) if (sa == rj->sa) { if (sa->spacetype == SPACE_IMAGE) { SpaceImage *sima = sa->spacedata.first; - sima->iuser.layer = rj->orig_layer; + + if (RE_HasSingleLayer(rj->re)) { + /* For single layer renders keep the active layer + * visible, or show the compositing result. */ + RenderResult *rr = RE_AcquireResultRead(rj->re); + if (RE_HasCombinedLayer(rr)) { + sima->iuser.layer = 0; + } + RE_ReleaseResult(rj->re); + } + else { + /* For multiple layer render, set back the layer + * that was set at the start of rendering. */ + sima->iuser.layer = rj->orig_layer; + } } return; } @@ -657,7 +676,7 @@ static void render_endjob(void *rjv) if (rj->anim && !(rj->scene->r.scemode & R_NO_FRAME_UPDATE)) { /* possible this fails of loading new file while rendering */ if (G.main->wm.first) { - ED_update_for_newframe(G.main, rj->scene, rj->view_layer, rj->depsgraph); + ED_update_for_newframe(G.main, rj->depsgraph); } } @@ -844,6 +863,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even Main *mainp; ViewLayer *view_layer = NULL; Scene *scene = CTX_data_scene(C); + RenderEngineType *re_type = RE_engines_find(scene->view_render.engine_id); Render *re; wmJob *wm_job; RenderJob *rj; @@ -856,7 +876,12 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL; const char *name; ScrArea *sa; - + + /* Cannot do render if there is not this function. */ + if (re_type->render_to_image == NULL) { + return OPERATOR_CANCELLED; + } + /* only one render job at a time */ if (WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_RENDER)) return OPERATOR_CANCELLED; @@ -879,7 +904,8 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even /* get main */ if (G.debug_value == 101) { /* thread-safety experiment, copy main from the undo buffer */ - mainp = BKE_undo_get_main(&scene); + struct MemFile *memfile = ED_undosys_stack_memfile_get_active(CTX_wm_manager(C)->undo_stack); + mainp = BLO_memfile_main_get(memfile, CTX_data_main(C), &scene); } else mainp = CTX_data_main(C); @@ -996,7 +1022,6 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even RE_current_scene_update_cb(re, rj, current_scene_update); RE_stats_draw_cb(re, rj, image_renderinfo_cb); RE_progress_cb(re, rj, render_progress_update); - RE_SetDepsgraph(re, CTX_data_depsgraph(C)); rj->re = re; G.is_break = false; @@ -1067,6 +1092,7 @@ typedef struct RenderPreview { wmJob *job; Scene *scene; + EvaluationContext *eval_ctx; Depsgraph *depsgraph; ScrArea *sa; ARegion *ar; @@ -1315,7 +1341,7 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda WM_job_main_thread_lock_release(rp->job); /* do preprocessing like building raytree, shadows, volumes, SSS */ - RE_Database_Preprocess(re); + RE_Database_Preprocess(rp->eval_ctx, re); /* conversion not completed, need to do it again */ if (!rstats->convertdone) { @@ -1381,6 +1407,7 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda static void render_view3d_free(void *customdata) { RenderPreview *rp = customdata; + DEG_evaluation_context_free(rp->eval_ctx); MEM_freeN(rp); } @@ -1423,8 +1450,10 @@ static bool render_view3d_flag_changed(RenderEngine *engine, const bContext *C) job_update_flag |= PR_UPDATE_DATABASE; /* load editmesh */ - if (scene->obedit) - ED_object_editmode_load(scene->obedit); + Object *obedit = CTX_data_edit_object(C); + if (obedit) { + ED_object_editmode_load(obedit); + } } engine->update_flag = 0; @@ -1494,6 +1523,8 @@ static void render_view3d_do(RenderEngine *engine, const bContext *C) /* customdata for preview thread */ rp->scene = scene; rp->depsgraph = depsgraph; + rp->eval_ctx = DEG_evaluation_context_new(DAG_EVAL_PREVIEW); + CTX_data_eval_ctx(C, rp->eval_ctx); rp->engine = engine; rp->sa = CTX_wm_area(C); rp->ar = CTX_wm_region(C); diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index 6e969067985..be2b184626d 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -57,6 +57,8 @@ #include "DEG_depsgraph.h" +#include "DRW_engine.h" + #include "WM_api.h" #include "WM_types.h" @@ -72,7 +74,6 @@ #include "RNA_access.h" #include "RNA_define.h" -#include "GPU_compositing.h" #include "GPU_framebuffer.h" #include "GPU_glew.h" #include "GPU_matrix.h" @@ -120,7 +121,6 @@ typedef struct OGLRender { GPUOffScreen *ofs; int ofs_samples; bool ofs_full_samples; - GPUFX *fx; int sizex, sizey; int write_still; @@ -323,6 +323,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R unsigned char *gp_rect; unsigned char *render_rect = (unsigned char *)RE_RenderViewGetById(rr, oglrender->view_id)->rect32; + DRW_opengl_context_enable(); GPU_offscreen_bind(oglrender->ofs, true); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); @@ -342,6 +343,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R blend_color_mix_byte(&render_rect[i], &render_rect[i], &gp_rect[i]); } GPU_offscreen_unbind(oglrender->ofs, true); + DRW_opengl_context_disable(); MEM_freeN(gp_rect); } @@ -351,6 +353,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R char err_out[256] = "unknown"; ImBuf *ibuf_view; const int alpha_mode = (draw_sky) ? R_ADDSKY : R_ALPHAPREMUL; + struct RenderEngineType *engine_type = CTX_data_engine_type(C); unsigned int draw_flags = V3D_OFSDRAW_NONE; draw_flags |= (oglrender->ofs_full_samples) ? V3D_OFSDRAW_USE_FULL_SAMPLE : 0; @@ -359,9 +362,10 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R draw_flags |= (draw_bgpic) ? V3D_OFSDRAW_USE_BACKGROUND : 0; ibuf_view = ED_view3d_draw_offscreen_imbuf( - &eval_ctx, scene, view_layer, v3d, ar, sizex, sizey, + &eval_ctx, scene, view_layer, engine_type, + v3d, ar, sizex, sizey, IB_rectfloat, draw_flags, alpha_mode, oglrender->ofs_samples, viewname, - oglrender->fx, oglrender->ofs, err_out); + oglrender->ofs, err_out); /* for stamp only */ if (rv3d->persp == RV3D_CAMOB && v3d->camera) { @@ -371,10 +375,11 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R else { draw_flags |= (V3D_OFSDRAW_USE_GPENCIL | V3D_OFSDRAW_USE_BACKGROUND); ibuf_view = ED_view3d_draw_offscreen_imbuf_simple( - &eval_ctx, scene, view_layer, scene->camera, oglrender->sizex, oglrender->sizey, + &eval_ctx, scene, view_layer, engine_type, + scene->camera, oglrender->sizex, oglrender->sizey, IB_rectfloat, draw_flags, OB_SOLID, alpha_mode, oglrender->ofs_samples, viewname, - oglrender->fx, oglrender->ofs, err_out); + oglrender->ofs, err_out); camera = scene->camera; } @@ -541,7 +546,6 @@ static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender) for (view_id = 0; view_id < oglrender->views_len; view_id++) { context.view_id = view_id; context.gpu_offscreen = oglrender->ofs; - context.gpu_fx = oglrender->fx; context.gpu_full_samples = oglrender->ofs_full_samples; oglrender->seq_data.ibufs_arr[view_id] = BKE_sequencer_give_ibuf(&context, CFRA, chanshown); @@ -652,7 +656,9 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) sizey = (scene->r.size * scene->r.ysch) / 100; /* corrects render size with actual size, not every card supports non-power-of-two dimensions */ - ofs = GPU_offscreen_create(sizex, sizey, full_samples ? 0 : samples, true, err_out); + DRW_opengl_context_enable(); /* Offscreen creation needs to be done in DRW context. */ + ofs = GPU_offscreen_create(sizex, sizey, full_samples ? 0 : samples, true, true, err_out); + DRW_opengl_context_disable(); if (!ofs) { BKE_reportf(op->reports, RPT_ERROR, "Failed to create OpenGL off-screen buffer, %s", err_out); @@ -700,19 +706,6 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) /* apply immediately in case we're rendering from a script, * running notifiers again will overwrite */ oglrender->scene->customdata_mask |= oglrender->scene->customdata_mask_modal; - - if (oglrender->v3d->fx_settings.fx_flag & (GPU_FX_FLAG_DOF | GPU_FX_FLAG_SSAO)) { - oglrender->fx = GPU_fx_compositor_create(); - } - } - else if (is_sequencer) { - /* NOTE: We allow animation of DoF setting for flexibility in edits, so - * we can't check in advance whether we need FX compositor or not. - * We just always allocated it and make sure it doesn't add extra - * overhead rather than memory allocation here if it's not really - * needed. - */ - oglrender->fx = GPU_fx_compositor_create(); } /* create render */ @@ -827,9 +820,8 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender) if (oglrender->timer) { /* exec will not have a timer */ Depsgraph *depsgraph = oglrender->depsgraph; - ViewLayer *view_layer = oglrender->view_layer; scene->r.cfra = oglrender->cfrao; - BKE_scene_graph_update_for_newframe(bmain->eval_ctx, depsgraph, bmain, scene, view_layer); + BKE_scene_graph_update_for_newframe(depsgraph, bmain); WM_event_remove_timer(oglrender->wm, oglrender->win, oglrender->timer); } @@ -838,10 +830,9 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender) WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, oglrender->scene); - if (oglrender->fx) - GPU_fx_compositor_destroy(oglrender->fx); - + DRW_opengl_context_enable(); GPU_offscreen_free(oglrender->ofs); + DRW_opengl_context_disable(); if (oglrender->is_sequencer) { MEM_freeN(oglrender->seq_data.ibufs_arr); @@ -1029,7 +1020,6 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op) Main *bmain = CTX_data_main(C); OGLRender *oglrender = op->customdata; Scene *scene = oglrender->scene; - ViewLayer *view_layer = oglrender->view_layer; Depsgraph *depsgraph = oglrender->depsgraph; char name[FILE_MAX]; bool ok = false; @@ -1041,7 +1031,7 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op) if (CFRA < oglrender->nfra) CFRA++; while (CFRA < oglrender->nfra) { - BKE_scene_graph_update_for_newframe(bmain->eval_ctx, depsgraph, bmain, scene, view_layer); + BKE_scene_graph_update_for_newframe(depsgraph, bmain); CFRA++; } @@ -1063,7 +1053,7 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op) WM_cursor_time(oglrender->win, scene->r.cfra); - BKE_scene_graph_update_for_newframe(bmain->eval_ctx, depsgraph, bmain, scene, view_layer); + BKE_scene_graph_update_for_newframe(depsgraph, bmain); if (view_context) { if (oglrender->rv3d->persp == RV3D_CAMOB && oglrender->v3d->camera && oglrender->v3d->scenelock) { diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index 2e3091268a9..4297d4fa316 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -455,9 +455,18 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty } else { /* use current scene world to light sphere */ - if (mat->pr_type == MA_SPHERE_A) { + if (mat->pr_type == MA_SPHERE_A && sp->pr_method == PR_BUTS_RENDER) { + /* Use current scene world to light sphere. */ sce->world = preview_get_localized_world(sp, scene->world); } + else if (sce->world) { + /* Use a default world color. Using the current + * scene world can be slow if it has big textures. */ + sce->world->use_nodes = false; + sce->world->horr = 0.5f; + sce->world->horg = 0.5f; + sce->world->horb = 0.5f; + } } if (sp->pr_method == PR_ICON_RENDER) { @@ -466,10 +475,6 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty } else { set_preview_layer(view_layer, MA_SPHERE_A); - - /* same as above, use current scene world to light sphere */ - if (BKE_scene_use_new_shading_nodes(scene)) - sce->world = preview_get_localized_world(sp, scene->world); } } else { @@ -569,6 +574,14 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty } else { set_preview_layer(view_layer, MA_LAMP); + + if (sce->world) { + /* Only use lighting from the lamp. */ + sce->world->use_nodes = false; + sce->world->horr = 0.0f; + sce->world->horg = 0.0f; + sce->world->horb = 0.0f; + } } for (Base *base = view_layer->object_bases.first; base; base = base->next) { @@ -607,7 +620,7 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty /* TODO(sergey): Use proper flag for tagging here. */ DEG_graph_id_tag_update(pr_main, depsgraph, &sce->id, 0); DEG_relations_tag_update(pr_main); - BKE_scene_graph_update_tagged(pr_main->eval_ctx, depsgraph, pr_main, sce, view_layer); + BKE_scene_graph_update_tagged(depsgraph, pr_main); return sce; } @@ -1363,7 +1376,7 @@ void ED_preview_shader_job(const bContext *C, void *owner, ID *id, ID *parent, M sp->bmain = CTX_data_main(C); sp->view_render = view_render; - /* hardcoded preview .blend for cycles/internal, this should be solved + /* hardcoded preview .blend for Eevee + cycles/internal, this should be solved * once with custom preview .blend path for external engines */ if ((method != PR_NODE_RENDER) && id_type != ID_TE && use_new_shading) { sp->pr_main = G_pr_main_cycles; diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c index eebe69b7a19..d29985041c6 100644 --- a/source/blender/editors/render/render_update.c +++ b/source/blender/editors/render/render_update.c @@ -202,7 +202,7 @@ void ED_render_engine_changed(Main *bmain) update_ctx.bmain = bmain; for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { update_ctx.scene = scene; - BLI_LISTBASE_FOREACH(ViewLayer *, view_layer, &scene->view_layers) { + LISTBASE_FOREACH(ViewLayer *, view_layer, &scene->view_layers) { /* TDODO(sergey): Iterate over depsgraphs instead? */ update_ctx.depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true); update_ctx.view_layer = view_layer; @@ -542,8 +542,6 @@ void ED_render_id_flush_update(const DEGEditorUpdateContext *update_ctx, ID *id) 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: @@ -570,42 +568,6 @@ void ED_render_id_flush_update(const DEGEditorUpdateContext *update_ctx, 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 812f9a736bf..d16d60ba7b9 100644 --- a/source/blender/editors/scene/scene_edit.c +++ b/source/blender/editors/scene/scene_edit.c @@ -42,6 +42,7 @@ #include "BLT_translation.h" +#include "DNA_object_types.h" #include "DNA_workspace_types.h" #include "ED_object.h" @@ -113,32 +114,42 @@ bool ED_scene_delete(bContext *C, Main *bmain, wmWindow *win, Scene *scene) return true; } -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) +void ED_scene_change_update( + Main *bmain, bContext *C, + wmWindow *win, const bScreen *screen, Scene *UNUSED(scene_old), Scene *scene_new) { 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); - + Object *obact_new = OBACT(layer_new); + UNUSED_VARS(obact_new); + +#if 0 + /* mode syncing */ + EvaluationContext eval_ctx_old; + CTX_data_eval_ctx(C, &eval_ctx_old); + eObjectMode object_mode_old = workspace->object_mode; + ViewLayer *layer_old = BKE_view_layer_from_workspace_get(scene_old, workspace); + Object *obact_old = OBACT(layer_old); + UNUSED_VARS(obact_old, object_mode_old); +#endif + + win->scene = scene_new; CTX_data_scene_set(C, scene_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); - ED_screen_update_after_scene_change(active_screen, scene_new, layer_new); + ED_screen_update_after_scene_change(screen, scene_new, layer_new); ED_render_engine_changed(bmain); - ED_update_for_newframe(bmain, scene_new, layer_new, depsgraph); + ED_update_for_newframe(bmain, depsgraph); /* complete redraw */ WM_event_add_notifier(C, NC_WINDOW, NULL); @@ -186,13 +197,15 @@ bool ED_scene_view_layer_delete( return false; } + /* We need to unset nodetrees before removing the layer, otherwise its index will be -1. */ + view_layer_remove_unset_nodetrees(bmain, scene, layer); + BLI_remlink(&scene->view_layers, layer); BLI_assert(BLI_listbase_is_empty(&scene->view_layers) == false); scene->active_view_layer = 0; 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/CMakeLists.txt b/source/blender/editors/screen/CMakeLists.txt index 02584a4611b..29b9971eabb 100644 --- a/source/blender/editors/screen/CMakeLists.txt +++ b/source/blender/editors/screen/CMakeLists.txt @@ -26,6 +26,7 @@ set(INC ../../blenloader ../../blentranslation ../../bmesh + ../../depsgraph ../../gpu ../../imbuf ../../makesdna diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 274dbcc73cb..105fff38f62 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -41,10 +41,10 @@ #include "BLI_utildefines.h" #include "BLI_linklist_stack.h" - #include "BKE_context.h" #include "BKE_global.h" #include "BKE_screen.h" +#include "BKE_workspace.h" #include "RNA_access.h" #include "RNA_types.h" @@ -52,7 +52,6 @@ #include "WM_api.h" #include "WM_types.h" #include "WM_message.h" -#include "wm_subwindow.h" #include "ED_screen.h" #include "ED_screen_types.h" @@ -67,6 +66,7 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" +#include "IMB_metadata.h" #include "UI_interface.h" #include "UI_interface_icons.h" @@ -91,7 +91,7 @@ static void region_draw_emboss(const ARegion *ar, const rcti *scirct) /* set transp line */ glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); Gwn_VertFormat *format = immVertexFormat(); unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); @@ -103,9 +103,11 @@ static void region_draw_emboss(const ARegion *ar, const rcti *scirct) /* right */ immAttrib4ub(color, 0, 0, 0, 30); immVertex2f(pos, rect.xmax, rect.ymax); + immAttrib4ub(color, 0, 0, 0, 30); immVertex2f(pos, rect.xmax, rect.ymin); /* bottom */ + immAttrib4ub(color, 0, 0, 0, 30); immVertex2f(pos, rect.xmin, rect.ymin); /* left */ @@ -113,6 +115,7 @@ static void region_draw_emboss(const ARegion *ar, const rcti *scirct) immVertex2f(pos, rect.xmin, rect.ymax); /* top */ + immAttrib4ub(color, 255, 255, 255, 30); immVertex2f(pos, rect.xmax, rect.ymax); immEnd(); @@ -265,26 +268,32 @@ static void area_draw_azone(short x1, short y1, short x2, short y2) immAttrib4ub(col, 255, 255, 255, 180); immVertex2f(pos, x1, y2); + immAttrib4ub(col, 255, 255, 255, 180); immVertex2f(pos, x2, y1); immAttrib4ub(col, 255, 255, 255, 130); immVertex2f(pos, x1, y2 - dy); + immAttrib4ub(col, 255, 255, 255, 130); immVertex2f(pos, x2 - dx, y1); immAttrib4ub(col, 255, 255, 255, 80); immVertex2f(pos, x1, y2 - 2 * dy); + immAttrib4ub(col, 255, 255, 255, 80); immVertex2f(pos, x2 - 2 * dx, y1); immAttrib4ub(col, 0, 0, 0, 210); immVertex2f(pos, x1, y2 + 1); + immAttrib4ub(col, 0, 0, 0, 210); immVertex2f(pos, x2 + 1, y1); immAttrib4ub(col, 0, 0, 0, 180); immVertex2f(pos, x1, y2 - dy + 1); + immAttrib4ub(col, 0, 0, 0, 180); immVertex2f(pos, x2 - dx + 1, y1); immAttrib4ub(col, 0, 0, 0, 150); immVertex2f(pos, x1, y2 - 2 * dy + 1); + immAttrib4ub(col, 0, 0, 0, 150); immVertex2f(pos, x2 - 2 * dx + 1, y1); immEnd(); @@ -450,7 +459,7 @@ static void region_draw_azones(ScrArea *sa, ARegion *ar) glLineWidth(1.0f); glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); gpuPushMatrix(); gpuTranslate2f(-ar->winrct.xmin, -ar->winrct.ymin); @@ -495,23 +504,6 @@ static void region_draw_azones(ScrArea *sa, ARegion *ar) glDisable(GL_BLEND); } -/* only exported for WM */ -/* makes region ready for drawing, sets pixelspace */ -void ED_region_set(const bContext *C, ARegion *ar) -{ - wmWindow *win = CTX_wm_window(C); - ScrArea *sa = CTX_wm_area(C); - - ar->drawrct = ar->winrct; - - /* note; this sets state, so we can use wmOrtho and friends */ - wmSubWindowScissorSet(win, ar->swinid, &ar->drawrct, true); - - UI_SetTheme(sa ? sa->spacetype : 0, ar->type ? ar->type->regionid : 0); - - 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) @@ -546,27 +538,15 @@ void ED_region_do_draw(bContext *C, ARegion *ar) wmWindow *win = CTX_wm_window(C); ScrArea *sa = CTX_wm_area(C); ARegionType *at = ar->type; - bool scissor_pad; /* see BKE_spacedata_draw_locks() */ if (at->do_lock) return; - /* if no partial draw rect set, full rect */ - if (ar->drawrct.xmin == ar->drawrct.xmax) { - ar->drawrct = ar->winrct; - scissor_pad = true; - } - else { - /* extra clip for safety */ - BLI_rcti_isect(&ar->winrct, &ar->drawrct, &ar->drawrct); - scissor_pad = false; - } - ar->do_draw |= RGN_DRAWING; - /* note; this sets state, so we can use wmOrtho and friends */ - wmSubWindowScissorSet(win, ar->swinid, &ar->drawrct, scissor_pad); + /* Set viewport, scissor, ortho and ar->drawrct. */ + wmPartialViewport(&ar->drawrct, &ar->winrct, &ar->drawrct); wmOrtho2_region_pixelspace(ar); @@ -1453,24 +1433,14 @@ static void area_calc_totrct(ScrArea *sa, int sizex, int sizey) /* used for area initialize below */ -static void region_subwindow(wmWindow *win, ARegion *ar, bool activate) +static void region_subwindow(ARegion *ar) { bool hidden = (ar->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL)) != 0; if ((ar->alignment & RGN_SPLIT_PREV) && ar->prev) hidden = hidden || (ar->prev->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL)); - if (hidden) { - if (ar->swinid) - wm_subwindow_close(win, ar->swinid); - ar->swinid = 0; - } - else if (ar->swinid == 0) { - ar->swinid = wm_subwindow_open(win, &ar->winrct, activate); - } - else { - wm_subwindow_position(win, ar->swinid, &ar->winrct, activate); - } + ar->visible = !hidden; } static void ed_default_handlers(wmWindowManager *wm, ScrArea *sa, ListBase *handlers, int flag) @@ -1577,9 +1547,9 @@ void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *sa) /* region windows, default and own handlers */ for (ar = sa->regionbase.first; ar; ar = ar->next) { - region_subwindow(win, ar, false); + region_subwindow(ar); - if (ar->swinid) { + if (ar->visible) { /* default region handlers */ ed_default_handlers(wm, sa, &ar->handlers, ar->type->keymapflag); /* own handlers */ @@ -1606,22 +1576,16 @@ static void region_update_rect(ARegion *ar) /** * Call to move a popup window (keep OpenGL context free!) */ -void ED_region_update_rect(bContext *C, ARegion *ar) +void ED_region_update_rect(bContext *UNUSED(C), ARegion *ar) { - wmWindow *win = CTX_wm_window(C); - - wm_subwindow_rect_set(win, ar->swinid, &ar->winrct); - region_update_rect(ar); } /* externally called for floating regions like menus */ -void ED_region_init(bContext *C, ARegion *ar) +void ED_region_init(bContext *UNUSED(C), ARegion *ar) { -// ARegionType *at = ar->type; - /* refresh can be called before window opened */ - region_subwindow(CTX_wm_window(C), ar, false); + region_subwindow(ar); region_update_rect(ar); } @@ -1870,6 +1834,7 @@ int ED_area_header_switchbutton(const bContext *C, uiBlock *block, int yco) void ED_region_panels(const bContext *C, ARegion *ar, const char *context, int contextnr, const bool vertical) { + const WorkSpace *workspace = CTX_wm_workspace(C); ScrArea *sa = CTX_wm_area(C); uiStyle *style = UI_style_get_dpi(); uiBlock *block; @@ -1920,6 +1885,11 @@ void ED_region_panels(const bContext *C, ARegion *ar, const char *context, int c continue; } + /* If we're tagged, only use compatible. */ + if (pt->owner_id[0] && BKE_workspace_owner_id_check(workspace, pt->owner_id) == false) { + continue; + } + /* draw panel */ if (pt->draw && (!pt->poll || pt->poll(C, pt))) { BLI_SMALLSTACK_PUSH(pt_stack, pt); @@ -2045,15 +2015,29 @@ void ED_region_panels(const bContext *C, ARegion *ar, const char *context, int c /* before setting the view */ if (vertical) { /* we always keep the scroll offset - so the total view gets increased with the scrolled away part */ - if (v2d->cur.ymax < - 0.001f) - y = min_ii(y, v2d->cur.ymin); - + if (v2d->cur.ymax < -FLT_EPSILON) { + /* Clamp to lower view boundary */ + if (v2d->tot.ymin < -v2d->winy) { + y = min_ii(y, 0); + } + else { + y = min_ii(y, v2d->cur.ymin); + } + } + y = -y; } else { /* don't jump back when panels close or hide */ - if (!is_context_new) - x = max_ii(x, v2d->cur.xmax); + if (!is_context_new) { + if (v2d->tot.xmax > v2d->winx) { + x = max_ii(x, 0); + } + else { + x = max_ii(x, v2d->cur.xmax); + } + } + y = -y; } @@ -2227,7 +2211,7 @@ void ED_region_info_draw_multiline(ARegion *ar, const char *text_array[], float BLI_rcti_size_x(&rect) + 1, BLI_rcti_size_y(&rect) + 1); glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); Gwn_VertFormat *format = immVertexFormat(); unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); @@ -2280,7 +2264,7 @@ static const char *meta_data_list[] = BLI_INLINE bool metadata_is_valid(ImBuf *ibuf, char *r_str, short index, int offset) { - return (IMB_metadata_get_field(ibuf, meta_data_list[index], r_str + offset, MAX_METADATA_STR - offset) && r_str[0]); + return (IMB_metadata_get_field(ibuf->metadata, meta_data_list[index], r_str + offset, MAX_METADATA_STR - offset) && r_str[0]); } static void metadata_draw_imbuf(ImBuf *ibuf, const rctf *rect, int fontid, const bool is_top) @@ -2543,28 +2527,34 @@ void ED_region_grid_draw(ARegion *ar, float zoomx, float zoomy) float theme_color[3]; UI_GetThemeColorShade3fv(TH_BACK, (int)(20.0f * (1.0f - blendfac)), theme_color); - immAttrib3fv(color, theme_color); fac = 0.0f; /* the fine resolution level */ for (int i = 0; i < count_fine; i++) { + immAttrib3fv(color, theme_color); immVertex2f(pos, x1, y1 * (1.0f - fac) + y2 * fac); + immAttrib3fv(color, theme_color); immVertex2f(pos, x2, y1 * (1.0f - fac) + y2 * fac); + immAttrib3fv(color, theme_color); immVertex2f(pos, x1 * (1.0f - fac) + x2 * fac, y1); + immAttrib3fv(color, theme_color); immVertex2f(pos, x1 * (1.0f - fac) + x2 * fac, y2); fac += gridstep; } if (count_large > 0) { UI_GetThemeColor3fv(TH_BACK, theme_color); - immAttrib3fv(color, theme_color); fac = 0.0f; /* the large resolution level */ for (int i = 0; i < count_large; i++) { + immAttrib3fv(color, theme_color); immVertex2f(pos, x1, y1 * (1.0f - fac) + y2 * fac); + immAttrib3fv(color, theme_color); immVertex2f(pos, x2, y1 * (1.0f - fac) + y2 * fac); + immAttrib3fv(color, theme_color); immVertex2f(pos, x1 * (1.0f - fac) + x2 * fac, y1); + immAttrib3fv(color, theme_color); immVertex2f(pos, x1 * (1.0f - fac) + x2 * fac, y2); fac += 4.0f * gridstep; } diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c index 7ce16efdb97..cd875c73eda 100644 --- a/source/blender/editors/screen/glutil.c +++ b/source/blender/editors/screen/glutil.c @@ -198,6 +198,7 @@ void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state, glGetIntegerv(GL_UNPACK_ROW_LENGTH, &unpack_row_length); glPixelStorei(GL_UNPACK_ROW_LENGTH, img_w); + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texid); /* don't want nasty border artifacts */ @@ -354,142 +355,6 @@ void immDrawPixelsTex_clipping(IMMDrawPixelsTexState *state, clip_min_x, clip_min_y, clip_max_x, clip_max_y, xzoom, yzoom, color); } -/* 2D Drawing Assistance */ - -void glaDefine2DArea(rcti *screen_rect) -{ - const int sc_w = BLI_rcti_size_x(screen_rect) + 1; - const int sc_h = BLI_rcti_size_y(screen_rect) + 1; - - glViewport(screen_rect->xmin, screen_rect->ymin, sc_w, sc_h); - glScissor(screen_rect->xmin, screen_rect->ymin, sc_w, sc_h); - - /* The GLA_PIXEL_OFS magic number is to shift the matrix so that - * both raster and vertex integer coordinates fall at pixel - * centers properly. For a longer discussion see the OpenGL - * Programming Guide, Appendix H, Correctness Tips. - */ - - gpuOrtho2D(GLA_PIXEL_OFS, sc_w + GLA_PIXEL_OFS, GLA_PIXEL_OFS, sc_h + GLA_PIXEL_OFS); - gpuLoadIdentity(); -} - -/* TODO(merwin): put the following 2D code to use, or build new 2D code inspired & informd by it */ - -#if 0 /* UNUSED */ - -struct gla2DDrawInfo { - int orig_vp[4], orig_sc[4]; - float orig_projmat[16], orig_viewmat[16]; - - rcti screen_rect; - rctf world_rect; - - float wo_to_sc[2]; -}; - -void gla2DGetMap(gla2DDrawInfo *di, rctf *rect) -{ - *rect = di->world_rect; -} - -void gla2DSetMap(gla2DDrawInfo *di, rctf *rect) -{ - int sc_w, sc_h; - float wo_w, wo_h; - - di->world_rect = *rect; - - sc_w = BLI_rcti_size_x(&di->screen_rect); - sc_h = BLI_rcti_size_y(&di->screen_rect); - wo_w = BLI_rcti_size_x(&di->world_rect); - wo_h = BLI_rcti_size_y(&di->world_rect); - - di->wo_to_sc[0] = sc_w / wo_w; - di->wo_to_sc[1] = sc_h / wo_h; -} - -/** Save the current OpenGL state and initialize OpenGL for 2D - * rendering. glaEnd2DDraw should be called on the returned structure - * to free it and to return OpenGL to its previous state. The - * scissor rectangle is set to match the viewport. - * - * See glaDefine2DArea for an explanation of why this function uses integers. - * - * \param screen_rect The screen rectangle to be used for 2D drawing. - * \param world_rect The world rectangle that the 2D area represented - * by \a screen_rect is supposed to represent. If NULL it is assumed the - * world has a 1 to 1 mapping to the screen. - */ -gla2DDrawInfo *glaBegin2DDraw(rcti *screen_rect, rctf *world_rect) -{ - gla2DDrawInfo *di = MEM_mallocN(sizeof(*di), "gla2DDrawInfo"); - int sc_w, sc_h; - float wo_w, wo_h; - - glGetIntegerv(GL_VIEWPORT, (GLint *)di->orig_vp); - glGetIntegerv(GL_SCISSOR_BOX, (GLint *)di->orig_sc); - gpuGetProjectionMatrix(di->orig_projmat); - gpuGetModelViewMatrix(di->orig_viewmat); - - di->screen_rect = *screen_rect; - if (world_rect) { - di->world_rect = *world_rect; - } - else { - di->world_rect.xmin = di->screen_rect.xmin; - di->world_rect.ymin = di->screen_rect.ymin; - di->world_rect.xmax = di->screen_rect.xmax; - di->world_rect.ymax = di->screen_rect.ymax; - } - - sc_w = BLI_rcti_size_x(&di->screen_rect); - sc_h = BLI_rcti_size_y(&di->screen_rect); - wo_w = BLI_rcti_size_x(&di->world_rect); - wo_h = BLI_rcti_size_y(&di->world_rect); - - di->wo_to_sc[0] = sc_w / wo_w; - di->wo_to_sc[1] = sc_h / wo_h; - - glaDefine2DArea(&di->screen_rect); - - return di; -} - -/** - * Translate the (\a wo_x, \a wo_y) point from world coordinates into screen space. - */ -void gla2DDrawTranslatePt(gla2DDrawInfo *di, float wo_x, float wo_y, int *r_sc_x, int *r_sc_y) -{ - *r_sc_x = (wo_x - di->world_rect.xmin) * di->wo_to_sc[0]; - *r_sc_y = (wo_y - di->world_rect.ymin) * di->wo_to_sc[1]; -} - -/** - * Translate the \a world point from world coordinates into screen space. - */ -void gla2DDrawTranslatePtv(gla2DDrawInfo *di, float world[2], int r_screen[2]) -{ - screen_r[0] = (world[0] - di->world_rect.xmin) * di->wo_to_sc[0]; - screen_r[1] = (world[1] - di->world_rect.ymin) * di->wo_to_sc[1]; -} - -/** - * Restores the previous OpenGL state and frees the auxiliary gla data. - */ -void glaEnd2DDraw(gla2DDrawInfo *di) -{ - glViewport(di->orig_vp[0], di->orig_vp[1], di->orig_vp[2], di->orig_vp[3]); - glScissor(di->orig_vp[0], di->orig_vp[1], di->orig_vp[2], di->orig_vp[3]); - gpuLoadProjectionMatrix(di->orig_projmat); - gpuLoadMatrix(di->orig_viewmat); - - MEM_freeN(di); -} - -#endif /* UNUSED */ - - /* *************** glPolygonOffset hack ************* */ /** diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c index 4c62253bef6..98a6670d10f 100644 --- a/source/blender/editors/screen/screen_context.c +++ b/source/blender/editors/screen/screen_context.c @@ -53,6 +53,8 @@ #include "BKE_sequencer.h" #include "BKE_workspace.h" +#include "DEG_depsgraph.h" + #include "RNA_access.h" #include "ED_armature.h" @@ -90,8 +92,8 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult Scene *scene = WM_window_get_active_scene(win); 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 && view_layer->basact) ? view_layer->basact->object : NULL; + Object *obedit = view_layer ? OBEDIT_FROM_VIEW_LAYER(view_layer) : NULL; if (CTX_data_dir(member)) { CTX_data_dir_set(result, screen_context_dir); @@ -102,11 +104,11 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult return 1; } else if (CTX_data_equals(member, "visible_objects")) { - FOREACH_VISIBLE_OBJECT(view_layer, ob) + FOREACH_VISIBLE_OBJECT_BEGIN(view_layer, ob) { CTX_data_id_list_add(result, &ob->id); } - FOREACH_VISIBLE_BASE_END + FOREACH_VISIBLE_BASE_END; CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); return 1; } @@ -120,43 +122,43 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult return 1; } else if (CTX_data_equals(member, "selected_objects")) { - FOREACH_SELECTED_OBJECT(view_layer, ob) + FOREACH_SELECTED_OBJECT_BEGIN(view_layer, ob) { CTX_data_id_list_add(result, &ob->id); } - FOREACH_SELECTED_OBJECT_END + FOREACH_SELECTED_OBJECT_END; CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); return 1; } else if (CTX_data_equals(member, "selected_editable_objects")) { - FOREACH_SELECTED_OBJECT(view_layer, ob) + FOREACH_SELECTED_OBJECT_BEGIN(view_layer, ob) { if (0 == BKE_object_is_libdata(ob)) { CTX_data_id_list_add(result, &ob->id); } } - FOREACH_SELECTED_OBJECT_END + FOREACH_SELECTED_OBJECT_END; CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); return 1; } else if (CTX_data_equals(member, "editable_objects")) { /* Visible + Editable, but not necessarily selected */ - FOREACH_VISIBLE_OBJECT(view_layer, ob) + FOREACH_VISIBLE_OBJECT_BEGIN(view_layer, ob) { if (0 == BKE_object_is_libdata(ob)) { CTX_data_id_list_add(result, &ob->id); } } - FOREACH_VISIBLE_OBJECT_END + FOREACH_VISIBLE_OBJECT_END; CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); return 1; } else if ( CTX_data_equals(member, "visible_bases")) { - FOREACH_VISIBLE_BASE(view_layer, base) + FOREACH_VISIBLE_BASE_BEGIN(view_layer, base) { CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); } - FOREACH_VISIBLE_BASE_END + FOREACH_VISIBLE_BASE_END; CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); return 1; } diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c index 2e4e9127ed6..3ffb125cdde 100644 --- a/source/blender/editors/screen/screen_draw.c +++ b/source/blender/editors/screen/screen_draw.c @@ -213,7 +213,7 @@ static void draw_join_shape(ScrArea *sa, char dir, unsigned int pos) */ static void scrarea_draw_shape_dark(ScrArea *sa, char dir, unsigned int pos) { - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); immUniformColor4ub(0, 0, 0, 50); draw_join_shape(sa, dir, pos); @@ -298,7 +298,7 @@ void ED_screen_draw_edges(wmWindow *win) ScrArea *sa; - wmSubWindowSet(win, screen->mainwin); + wmWindowViewport(win); unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); @@ -485,6 +485,7 @@ static void screen_preview_draw(const bScreen *screen, int size_x, int size_y) wmOrtho2(0.0f, size_x, 0.0f, size_y); /* center */ gpuPushMatrix(); + gpuLoadIdentity(); gpuTranslate2f(size_x * (1.0f - asp[0]) * 0.5f, size_y * (1.0f - asp[1]) * 0.5f); screen_preview_scale_get(screen, size_x, size_y, asp, scale); @@ -499,11 +500,11 @@ static void screen_preview_draw(const bScreen *screen, int size_x, int size_y) void ED_screen_preview_render(const bScreen *screen, int size_x, int size_y, unsigned int *r_rect) { char err_out[256] = "unknown"; - GPUOffScreen *offscreen = GPU_offscreen_create(size_x, size_y, 0, false, err_out); + GPUOffScreen *offscreen = GPU_offscreen_create(size_x, size_y, 0, true, false, err_out); GPU_offscreen_bind(offscreen, true); glClearColor(0.0, 0.0, 0.0, 0.0); - glClear(GL_COLOR_BUFFER_BIT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); screen_preview_draw(screen, size_x, size_y); diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 0b78590d4d8..e65fd2701b4 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -33,6 +33,7 @@ #include "MEM_guardedalloc.h" +#include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_workspace_types.h" #include "DNA_userdef_types.h" @@ -68,8 +69,7 @@ #include "WM_message.h" -/* XXX actually should be not here... solve later */ -#include "wm_subwindow.h" +#include "DEG_depsgraph_query.h" #include "screen_intern.h" /* own module include */ @@ -848,14 +848,14 @@ static void screen_test_scale(bScreen *sc, int winsize_x, int winsize_y) /* ****************** EXPORTED API TO OTHER MODULES *************************** */ -/* screen sets cursor based on swinid */ -static void region_cursor_set(wmWindow *win, int swinid, int swin_changed) +/* screen sets cursor based on active region */ +static void region_cursor_set(wmWindow *win, bool swin_changed) { bScreen *screen = WM_window_get_active_screen(win); for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) { - if (ar->swinid == swinid) { + if (ar == screen->active_region) { if (swin_changed || (ar->type && ar->type->event_cursor)) { if (ar->manipulator_map != NULL) { if (WM_manipulatormap_cursor_set(ar->manipulator_map, win)) { @@ -890,7 +890,7 @@ void ED_screen_do_listen(bContext *C, wmNotifier *note) break; case NC_SCENE: if (note->data == ND_MODE) - region_cursor_set(win, note->swinid, true); + region_cursor_set(win, true); break; } } @@ -918,12 +918,6 @@ void ED_screen_refresh(wmWindowManager *wm, wmWindow *win) const int winsize_x = WM_window_pixels_x(win); const int winsize_y = WM_window_pixels_y(win); ScrArea *sa; - rcti winrct; - - winrct.xmin = 0; - winrct.xmax = winsize_x - 1; - winrct.ymin = 0; - winrct.ymax = winsize_y - 1; /* header size depends on DPI, let's verify */ WM_window_set_dpi(win); @@ -931,13 +925,6 @@ void ED_screen_refresh(wmWindowManager *wm, wmWindow *win) screen_test_scale(screen, winsize_x, winsize_y); - if (screen->mainwin == 0) { - screen->mainwin = wm_subwindow_open(win, &winrct, false); - } - else { - wm_subwindow_position(win, screen->mainwin, &winrct, false); - } - for (sa = screen->areabase.first; sa; sa = sa->next) { /* set spacetype and region callbacks, calls init() */ /* sets subwindows for regions, adds handlers */ @@ -989,10 +976,7 @@ void ED_region_exit(bContext *C, ARegion *ar) WM_event_remove_handlers(C, &ar->handlers); WM_event_modal_handler_region_replace(win, ar, NULL); - if (ar->swinid) { - wm_subwindow_close(win, ar->swinid); - ar->swinid = 0; - } + ar->visible = 0; if (ar->headerstr) { MEM_freeN(ar->headerstr); @@ -1044,10 +1028,7 @@ void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen) screen->animtimer = NULL; screen->scrubbing = false; - if (screen->mainwin) - wm_subwindow_close(window, screen->mainwin); - screen->mainwin = 0; - screen->subwinactive = 0; + screen->active_region = NULL; for (ar = screen->regionbase.first; ar; ar = ar->next) ED_region_exit(C, ar); @@ -1112,7 +1093,7 @@ static void screen_cursor_set(wmWindow *win, const wmEvent *event) /* called in wm_event_system.c. sets state vars in screen, cursors */ /* event type is mouse move */ -void ED_screen_set_subwinactive(bContext *C, const wmEvent *event) +void ED_screen_set_active_region(bContext *C, const wmEvent *event) { wmWindow *win = CTX_wm_window(C); bScreen *scr = WM_window_get_active_screen(win); @@ -1120,7 +1101,7 @@ void ED_screen_set_subwinactive(bContext *C, const wmEvent *event) if (scr) { ScrArea *sa; ARegion *ar; - int oldswin = scr->subwinactive; + ARegion *old_ar = scr->active_region; for (sa = scr->areabase.first; sa; sa = sa->next) { if (event->x > sa->totrct.xmin && event->x < sa->totrct.xmax) @@ -1132,22 +1113,22 @@ void ED_screen_set_subwinactive(bContext *C, const wmEvent *event) /* make overlap active when mouse over */ for (ar = sa->regionbase.first; ar; ar = ar->next) { if (BLI_rcti_isect_pt_v(&ar->winrct, &event->x)) { - scr->subwinactive = ar->swinid; + scr->active_region = ar; break; } } } else - scr->subwinactive = scr->mainwin; + scr->active_region = NULL; /* check for redraw headers */ - if (oldswin != scr->subwinactive) { + if (old_ar != scr->active_region) { for (sa = scr->areabase.first; sa; sa = sa->next) { bool do_draw = false; for (ar = sa->regionbase.first; ar; ar = ar->next) - if (ar->swinid == oldswin || ar->swinid == scr->subwinactive) + if (ar == old_ar || ar == scr->active_region) do_draw = true; if (do_draw) { @@ -1159,13 +1140,13 @@ void ED_screen_set_subwinactive(bContext *C, const wmEvent *event) } /* cursors, for time being set always on edges, otherwise aregion doesnt switch */ - if (scr->subwinactive == scr->mainwin) { + if (scr->active_region == NULL) { screen_cursor_set(win, event); } else { /* notifier invokes freeing the buttons... causing a bit too much redraws */ - if (oldswin != scr->subwinactive) { - region_cursor_set(win, scr->subwinactive, true); + if (old_ar != scr->active_region) { + region_cursor_set(win, true); /* this used to be a notifier, but needs to be done immediate * because it can undo setting the right button as active due @@ -1173,7 +1154,7 @@ void ED_screen_set_subwinactive(bContext *C, const wmEvent *event) UI_screen_free_active_but(C, scr); } else - region_cursor_set(win, scr->subwinactive, false); + region_cursor_set(win, false); } } } @@ -1192,7 +1173,7 @@ int ED_screen_area_active(const bContext *C) return 1; for (ar = sa->regionbase.first; ar; ar = ar->next) - if (ar->swinid == sc->subwinactive) + if (ar == sc->active_region) return 1; } return 0; @@ -1260,7 +1241,7 @@ bScreen *screen_change_prepare(bScreen *screen_old, bScreen *screen_new, Main *b return NULL; } -void screen_changed_update(bContext *C, wmWindow *win, bScreen *sc) +void screen_change_update(bContext *C, wmWindow *win, bScreen *sc) { Scene *scene = WM_window_get_active_scene(win); WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook); @@ -1297,7 +1278,7 @@ bool ED_screen_change(bContext *C, bScreen *sc) if (screen_new) { WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook); WM_window_set_active_screen(win, workspace, sc); - screen_changed_update(C, win, screen_new); + screen_change_update(C, win, screen_new); return true; } @@ -1729,8 +1710,10 @@ void ED_screen_animation_timer_update(bScreen *screen, int redraws, int refresh) } /* results in fully updated anim system */ -void ED_update_for_newframe(Main *bmain, Scene *scene, ViewLayer *view_layer, struct Depsgraph *depsgraph) +void ED_update_for_newframe(Main *bmain, Depsgraph *depsgraph) { + Scene *scene = DEG_get_input_scene(depsgraph); + #ifdef DURIAN_CAMERA_SWITCH void *camera = BKE_scene_camera_switch_find(scene); if (camera && scene->camera != camera) { @@ -1746,7 +1729,7 @@ void ED_update_for_newframe(Main *bmain, Scene *scene, ViewLayer *view_layer, st ED_clip_update_frame(bmain, scene->r.cfra); /* this function applies the changes too */ - BKE_scene_graph_update_for_newframe(bmain->eval_ctx, depsgraph, bmain, scene, view_layer); + BKE_scene_graph_update_for_newframe(depsgraph, bmain); /* composite */ if (scene->use_nodes && scene->nodetree) @@ -1850,10 +1833,14 @@ bool ED_screen_stereo3d_required(const bScreen *screen, const Scene *scene) * Find the scene displayed in \a screen. * \note Assumes \a screen to be visible/active! */ -Scene *ED_screen_scene_find(const bScreen *screen, const wmWindowManager *wm) + +Scene *ED_screen_scene_find_with_window(const bScreen *screen, const wmWindowManager *wm, struct wmWindow **r_window) { for (wmWindow *win = wm->windows.first; win; win = win->next) { if (WM_window_get_active_screen(win) == screen) { + if (r_window) { + *r_window = win; + } return WM_window_get_active_scene(win); } } @@ -1861,3 +1848,20 @@ Scene *ED_screen_scene_find(const bScreen *screen, const wmWindowManager *wm) BLI_assert(0); return NULL; } + + +Scene *ED_screen_scene_find(const bScreen *screen, const wmWindowManager *wm) +{ + return ED_screen_scene_find_with_window(screen, wm, NULL); +} + + +wmWindow *ED_screen_window_find(const bScreen *screen, const wmWindowManager *wm) +{ + for (wmWindow *win = wm->windows.first; win; win = win->next) { + if (WM_window_get_active_screen(win) == screen) { + return win; + } + } + return NULL; +} diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h index df92ab86ef2..6d0a9f1e7d0 100644 --- a/source/blender/editors/screen/screen_intern.h +++ b/source/blender/editors/screen/screen_intern.h @@ -50,7 +50,7 @@ void region_toggle_hidden(struct bContext *C, ARegion *ar, const bool do_ bScreen *screen_add(const char *name, const int winsize_x, const int winsize_y); void screen_data_copy(bScreen *to, bScreen *from); void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new); -void screen_changed_update(struct bContext *C, wmWindow *win, bScreen *sc); +void screen_change_update(struct bContext *C, wmWindow *win, bScreen *sc); bScreen *screen_change_prepare(bScreen *screen_old, bScreen *screen_new, struct Main *bmain, struct bContext *C, wmWindow *win); ScrEdge *screen_findedge(bScreen *sc, ScrVert *v1, ScrVert *v2); ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge); diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 030c24b0061..898010858b9 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -69,6 +69,8 @@ #include "WM_api.h" #include "WM_types.h" +#include "DEG_depsgraph.h" + #include "ED_armature.h" #include "ED_clip.h" #include "ED_image.h" @@ -78,6 +80,7 @@ #include "ED_screen_types.h" #include "ED_sequencer.h" #include "ED_util.h" +#include "ED_undo.h" #include "ED_view3d.h" #include "RNA_access.h" @@ -137,7 +140,7 @@ int ED_operator_screen_mainwinactive(bContext *C) if (CTX_wm_window(C) == NULL) return 0; screen = CTX_wm_screen(C); if (screen == NULL) return 0; - if (screen->subwinactive != screen->mainwin) return 0; + if (screen->active_region != NULL) return 0; return 1; } @@ -556,7 +559,7 @@ int ED_operator_mask(bContext *C) { SpaceImage *sima = sa->spacedata.first; ViewLayer *view_layer = CTX_data_view_layer(C); - return ED_space_image_check_show_maskedit(view_layer, sima); + return ED_space_image_check_show_maskedit(sima, view_layer); } } } @@ -887,23 +890,23 @@ static void SCREEN_OT_actionzone(wmOperatorType *ot) /** \name Swap Area Operator * \{ */ -/* operator state vars used: - * sa1 start area - * sa2 area to swap with - * +/* operator state vars used: + * sa1 start area + * sa2 area to swap with + * * functions: - * + * * init() set custom data for operator, based on actionzone event custom data - * - * cancel() cancel the operator - * - * exit() cleanup, send notifier - * + * + * cancel() cancel the operator + * + * exit() cleanup, send notifier + * * callbacks: - * + * * invoke() gets called on shift+lmb drag in actionzone * call init(), add handler - * + * * modal() accept modal events while doing it */ @@ -1444,35 +1447,35 @@ static void SCREEN_OT_area_move(wmOperatorType *ot) /** \name Split Area Operator * \{ */ -/* - * operator state vars: +/* + * operator state vars: * fac spit point * dir direction 'v' or 'h' - * + * * operator customdata: * area pointer to (active) area - * x, y last used mouse pos + * x, y last used mouse pos * (more, see below) - * + * * functions: - * + * * init() set default property values, find area based on context - * - * apply() split area based on state vars - * - * exit() cleanup, send notifier - * + * + * apply() split area based on state vars + * + * exit() cleanup, send notifier + * * cancel() remove duplicated area - * + * * callbacks: - * + * * exec() execute without any user interaction, based on state vars * call init(), apply(), exit() - * + * * invoke() gets called on mouse click in action-widget * call init(), add modal handler * call apply() with initial motion - * + * * modal() accept modal events while doing it * call move-areas code with delta motion * call exit() or cancel() and remove handler @@ -3570,7 +3573,6 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv if (screen->animtimer && screen->animtimer == event->customdata) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); struct Depsgraph *depsgraph = CTX_data_depsgraph(C); wmTimer *wt = screen->animtimer; ScreenAnimData *sad = wt->customdata; @@ -3682,7 +3684,7 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv } /* since we follow drawflags, we can't send notifier but tag regions ourselves */ - ED_update_for_newframe(bmain, scene, view_layer, depsgraph); + ED_update_for_newframe(bmain, depsgraph); for (window = wm->windows.first; window; window = window->next) { const bScreen *win_screen = WM_window_get_active_screen(window); diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c index 00dc1003121..ace3f17542e 100644 --- a/source/blender/editors/screen/workspace_edit.c +++ b/source/blender/editors/screen/workspace_edit.c @@ -36,6 +36,7 @@ #include "BKE_context.h" #include "BKE_idcode.h" #include "BKE_main.h" +#include "BKE_layer.h" #include "BKE_library.h" #include "BKE_report.h" #include "BKE_scene.h" @@ -55,6 +56,9 @@ #include "MEM_guardedalloc.h" #include "RNA_access.h" +#include "RNA_define.h" + +#include "DEG_depsgraph.h" #include "UI_interface.h" #include "UI_resources.h" @@ -79,14 +83,9 @@ WorkSpace *ED_workspace_add( 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, scene, OB_MODE_OBJECT); -#endif - return workspace; } -#ifdef USE_WORKSPACE_MODE /** * Changes the object mode (if needed) to the one set in \a workspace_new. * Object mode is still stored on object level. In future it should all be workspace level instead. @@ -95,16 +94,17 @@ static void workspace_change_update_mode( const WorkSpace *workspace_old, const WorkSpace *workspace_new, bContext *C, Object *ob_act, ReportList *reports) { - 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); + UNUSED_VARS(workspace_old, workspace_new, C, ob_act, reports); +#if 0 + eObjectMode mode_old = workspace_old->object_mode; + eObjectMode mode_new = workspace_new->object_mode; if (mode_old != mode_new) { ED_object_mode_compat_set(C, ob_act, mode_new, reports); - ED_object_toggle_modes(C, mode_new); + ED_object_mode_toggle(C, mode_new); } -} #endif +} static void workspace_change_update_view_layer( WorkSpace *workspace_new, const WorkSpace *workspace_old, @@ -121,11 +121,7 @@ static void workspace_change_update( { /* needs to be done before changing mode! (to ensure right context) */ 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 - UNUSED_VARS(C, wm); -#endif } static bool workspace_change_find_new_layout_cb(const WorkSpaceLayout *layout, void *UNUSED(arg)) @@ -198,8 +194,9 @@ bool ED_workspace_change( WM_window_set_active_layout(win, workspace_new, layout_new); WM_window_set_active_workspace(win, workspace_new); - /* update screen *after* changing workspace - which also causes the actual screen change */ - screen_changed_update(C, win, screen_new); + /* update screen *after* changing workspace - which also causes the + * actual screen change and updates context (including CTX_wm_workspace) */ + screen_change_update(C, win, screen_new); workspace_change_update(workspace_new, workspace_old, C, wm); BLI_assert(BKE_workspace_view_layer_get(workspace_new, CTX_data_scene(C)) != NULL); @@ -231,9 +228,6 @@ WorkSpace *ED_workspace_duplicate( 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, scene, BKE_workspace_object_mode_get(workspace_old, scene)); -#endif BLI_duplicatelist(transform_orientations_new, transform_orientations_old); workspace_new->tool = workspace_old->tool; @@ -345,6 +339,66 @@ static void WORKSPACE_OT_workspace_delete(wmOperatorType *ot) ot->exec = workspace_delete_exec; } +static int workspace_append(bContext *C, const char *directory, const char *idname) +{ + wmOperatorType *ot = WM_operatortype_find("WM_OT_append", false); + PointerRNA opptr; + int retval; + + WM_operator_properties_create_ptr(&opptr, ot); + RNA_string_set(&opptr, "directory", directory); + RNA_string_set(&opptr, "filename", idname); + RNA_boolean_set(&opptr, "autoselect", false); + + retval = WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &opptr); + + WM_operator_properties_free(&opptr); + + return retval; +} + +static int workspace_append_activate_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + char idname[MAX_ID_NAME - 2], directory[FILE_MAX]; + + if (!RNA_struct_property_is_set(op->ptr, "idname") || + !RNA_struct_property_is_set(op->ptr, "directory")) + { + return OPERATOR_CANCELLED; + } + RNA_string_get(op->ptr, "idname", idname); + RNA_string_get(op->ptr, "directory", directory); + + if (workspace_append(C, directory, idname) != OPERATOR_CANCELLED) { + WorkSpace *appended_workspace = BLI_findstring(&bmain->workspaces, idname, offsetof(ID, name) + 2); + + BLI_assert(appended_workspace != NULL); + /* Changing workspace changes context. Do delayed! */ + WM_event_add_notifier(C, NC_SCREEN | ND_WORKSPACE_SET, appended_workspace); + + return OPERATOR_FINISHED; + } + + return OPERATOR_CANCELLED; +} + +static void WORKSPACE_OT_append_activate(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Append and Activate Workspace"; + ot->description = "Append a workspace and make it the active one in the current window"; + ot->idname = "WORKSPACE_OT_append_activate"; + + /* api callbacks */ + ot->exec = workspace_append_activate_exec; + + RNA_def_string(ot->srna, "idname", NULL, MAX_ID_NAME - 2, "Identifier", + "Name of the workspace to append and activate"); + RNA_def_string(ot->srna, "directory", NULL, FILE_MAX, "Directory", + "Path to the library"); +} + static void workspace_config_file_path_from_folder_id( const Main *bmain, int folder_id, char *r_path) { @@ -390,13 +444,12 @@ static void workspace_append_button( BLI_path_join( lib_path, sizeof(lib_path), from_main->name, BKE_idcode_to_name(GS(id->name)), NULL); - BLI_assert(STREQ(ot_append->idname, "WM_OT_append")); + BLI_assert(STREQ(ot_append->idname, "WORKSPACE_OT_append_activate")); uiItemFullO_ptr( layout, ot_append, workspace->id.name + 2, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &opptr); + RNA_string_set(&opptr, "idname", id->name + 2); RNA_string_set(&opptr, "directory", lib_path); - RNA_string_set(&opptr, "filename", id->name + 2); - RNA_boolean_set(&opptr, "autoselect", false); } ATTR_NONNULL(1, 2) @@ -406,7 +459,7 @@ static void workspace_config_file_append_buttons( WorkspaceConfigFileData *workspace_config = workspace_config_file_read(bmain, reports); if (workspace_config) { - wmOperatorType *ot_append = WM_operatortype_find("WM_OT_append", true); + wmOperatorType *ot_append = WM_operatortype_find("WORKSPACE_OT_append_activate", true); for (WorkSpace *workspace = workspace_config->workspaces.first; workspace; workspace = workspace->id.next) { workspace_append_button(layout, ot_append, workspace, workspace_config->main); @@ -449,6 +502,7 @@ void ED_operatortypes_workspace(void) WM_operatortype_append(WORKSPACE_OT_workspace_duplicate); WM_operatortype_append(WORKSPACE_OT_workspace_delete); WM_operatortype_append(WORKSPACE_OT_workspace_add_menu); + WM_operatortype_append(WORKSPACE_OT_append_activate); } /** \} Workspace Operators */ diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index b3e125baae3..80c58e5b91d 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -43,14 +43,15 @@ set(INC_SYS set(SRC paint_cursor.c paint_curve.c + paint_curve_undo.c paint_hide.c paint_image.c paint_image_2d.c paint_image_proj.c + paint_image_undo.c paint_mask.c paint_ops.c paint_stroke.c - paint_undo.c paint_utils.c paint_vertex.c paint_vertex_color_ops.c diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index 3a43c7a6585..6229b91a518 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -338,6 +338,7 @@ static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool prima size = target->old_size; } + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, target->overlay_texture); if (refresh) { @@ -464,6 +465,7 @@ static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom) size = cursor_snap.size; } + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, cursor_snap.overlay_texture); if (refresh) { @@ -767,7 +769,7 @@ static void paint_draw_cursor_overlay(UnifiedPaintSettings *ups, Brush *brush, /* draw textured quad */ /* draw textured quad */ - immUniform1i("image", GL_TEXTURE0); + immUniform1i("image", 0); immBegin(GWN_PRIM_TRI_FAN, 4); immAttrib2f(texCoord, 0.0f, 0.0f); @@ -1033,7 +1035,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) /* can't use stroke vc here because this will be called during * mouse over too, not just during a stroke */ ViewContext vc; - view3d_set_viewcontext(C, &vc); + ED_view3d_viewcontext_init(C, &vc); if (vc.rv3d && (vc.rv3d->rflag & RV3D_NAVIGATING)) { return; diff --git a/source/blender/editors/sculpt_paint/paint_curve.c b/source/blender/editors/sculpt_paint/paint_curve.c index 337f7a1ef2b..049d8ff8c0b 100644 --- a/source/blender/editors/sculpt_paint/paint_curve.c +++ b/source/blender/editors/sculpt_paint/paint_curve.c @@ -34,14 +34,15 @@ #include "DNA_view3d_types.h" #include "BLI_math_vector.h" -#include "BLI_string.h" #include "BKE_context.h" #include "BKE_main.h" #include "BKE_paint.h" -#include "ED_paint.h" +#include "DEG_depsgraph.h" + #include "ED_view3d.h" +#include "ED_paint.h" #include "WM_api.h" #include "WM_types.h" @@ -56,7 +57,6 @@ #define PAINT_CURVE_SELECT_THRESHOLD 40.0f #define PAINT_CURVE_POINT_SELECT(pcp, i) (*(&pcp->bez.f1 + i) = SELECT) - int paint_curve_poll(bContext *C) { Object *ob = CTX_data_active_object(C); @@ -81,91 +81,6 @@ int paint_curve_poll(bContext *C) return false; } -/* Paint Curve Undo*/ - -typedef struct UndoCurve { - struct UndoImageTile *next, *prev; - - PaintCurvePoint *points; /* points of curve */ - int tot_points; - int active_point; - - char idname[MAX_ID_NAME]; /* name instead of pointer*/ -} UndoCurve; - -static void paintcurve_undo_restore(bContext *C, ListBase *lb) -{ - Paint *p = BKE_paint_get_active_from_context(C); - UndoCurve *uc; - PaintCurve *pc = NULL; - - if (p->brush) { - pc = p->brush->paint_curve; - } - - if (!pc) - return; - - uc = (UndoCurve *)lb->first; - - if (STREQLEN(uc->idname, pc->id.name, BLI_strnlen(uc->idname, sizeof(uc->idname)))) { - SWAP(PaintCurvePoint *, pc->points, uc->points); - SWAP(int, pc->tot_points, uc->tot_points); - SWAP(int, pc->add_index, uc->active_point); - } -} - -static void paintcurve_undo_delete(ListBase *lb) -{ - UndoCurve *uc; - uc = (UndoCurve *)lb->first; - - if (uc->points) - MEM_freeN(uc->points); - uc->points = NULL; -} - - -static void paintcurve_undo_begin(bContext *C, wmOperator *op, PaintCurve *pc) -{ - ePaintMode mode = BKE_paintmode_get_active_from_context(C); - ListBase *lb = NULL; - int undo_stack_id; - UndoCurve *uc; - - switch (mode) { - case ePaintTexture2D: - case ePaintTextureProjective: - undo_stack_id = UNDO_PAINT_IMAGE; - break; - - case ePaintSculpt: - undo_stack_id = UNDO_PAINT_MESH; - break; - - default: - /* do nothing, undo is handled by global */ - return; - } - - - ED_undo_paint_push_begin(undo_stack_id, op->type->name, - paintcurve_undo_restore, paintcurve_undo_delete, NULL); - lb = undo_paint_push_get_list(undo_stack_id); - - uc = MEM_callocN(sizeof(*uc), "Undo_curve"); - - lb->first = uc; - - BLI_strncpy(uc->idname, pc->id.name, sizeof(uc->idname)); - uc->tot_points = pc->tot_points; - uc->active_point = pc->add_index; - uc->points = MEM_dupallocN(pc->points); - - undo_paint_push_count_alloc(undo_stack_id, sizeof(*uc) + sizeof(*pc->points) * pc->tot_points); - - ED_undo_paint_push_end(undo_stack_id); -} #define SEL_F1 (1 << 0) #define SEL_F2 (1 << 1) #define SEL_F3 (1 << 2) @@ -291,7 +206,7 @@ static void paintcurve_point_add(bContext *C, wmOperator *op, const int loc[2]) br->paint_curve = pc = BKE_paint_curve_add(bmain, "PaintCurve"); } - paintcurve_undo_begin(C, op, pc); + ED_paintcurve_undo_push_begin(op->type->name); pcp = MEM_mallocN((pc->tot_points + 1) * sizeof(PaintCurvePoint), "PaintCurvePoint"); add_index = pc->add_index; @@ -329,6 +244,8 @@ static void paintcurve_point_add(bContext *C, wmOperator *op, const int loc[2]) pcp[add_index].bez.h1 = HD_ALIGN; } + ED_paintcurve_undo_push_end(); + WM_paint_cursor_tag_redraw(window, ar); } @@ -390,7 +307,7 @@ static int paintcurve_delete_point_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - paintcurve_undo_begin(C, op, pc); + ED_paintcurve_undo_push_begin(op->type->name); #define DELETE_TAG 2 @@ -430,6 +347,8 @@ static int paintcurve_delete_point_exec(bContext *C, wmOperator *op) #undef DELETE_TAG + ED_paintcurve_undo_push_end(); + WM_paint_cursor_tag_redraw(window, ar); return OPERATOR_FINISHED; @@ -467,7 +386,7 @@ static bool paintcurve_point_select(bContext *C, wmOperator *op, const int loc[2 if (!pc) return false; - paintcurve_undo_begin(C, op, pc); + ED_paintcurve_undo_push_begin(op->type->name); if (toggle) { PaintCurvePoint *pcp; @@ -532,10 +451,14 @@ static bool paintcurve_point_select(bContext *C, wmOperator *op, const int loc[2 } } - if (!pcp) + if (!pcp) { + ED_paintcurve_undo_push_end(); return false; + } } + ED_paintcurve_undo_push_end(); + WM_paint_cursor_tag_redraw(window, ar); return true; @@ -650,9 +573,6 @@ static int paintcurve_slide_invoke(bContext *C, wmOperator *op, const wmEvent *e psd->align = align; op->customdata = psd; - if (do_select) - paintcurve_undo_begin(C, op, pc); - /* first, clear all selection from points */ for (i = 0; i < pc->tot_points; i++) pc->points[i].bez.f1 = pc->points[i].bez.f3 = pc->points[i].bez.f2 = 0; @@ -675,6 +595,8 @@ static int paintcurve_slide_modal(bContext *C, wmOperator *op, const wmEvent *ev if (event->type == psd->event && event->val == KM_RELEASE) { MEM_freeN(psd); + ED_paintcurve_undo_push_begin(op->type->name); + ED_paintcurve_undo_push_end(); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/sculpt_paint/paint_curve_undo.c b/source/blender/editors/sculpt_paint/paint_curve_undo.c new file mode 100644 index 00000000000..77f06180df6 --- /dev/null +++ b/source/blender/editors/sculpt_paint/paint_curve_undo.c @@ -0,0 +1,168 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/sculpt_paint/paint_curve_undo.c + * \ingroup edsculpt + */ + +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_brush_types.h" +#include "DNA_space_types.h" + +#include "BLI_string.h" +#include "BLI_array_utils.h" + +#include "BKE_context.h" +#include "BKE_paint.h" +#include "BKE_undo_system.h" + +#include "ED_paint.h" +#include "ED_undo.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "paint_intern.h" + +/* -------------------------------------------------------------------- */ +/** \name Undo Conversion + * \{ */ + +typedef struct UndoCurve { + PaintCurvePoint *points; /* points of curve */ + int tot_points; + int add_index; +} UndoCurve; + +static void undocurve_from_paintcurve(UndoCurve *uc, const PaintCurve *pc) +{ + BLI_assert(BLI_array_is_zeroed(uc, 1)); + uc->points = MEM_dupallocN(pc->points); + uc->tot_points = pc->tot_points; + uc->add_index = pc->add_index; +} + +static void undocurve_to_paintcurve(const UndoCurve *uc, PaintCurve *pc) +{ + MEM_SAFE_FREE(pc->points); + pc->points = MEM_dupallocN(uc->points); + pc->tot_points = uc->tot_points; + pc->add_index = uc->add_index; +} + +static void undocurve_free_data(UndoCurve *uc) +{ + MEM_SAFE_FREE(uc->points); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Implements ED Undo System + * \{ */ + +typedef struct PaintCurveUndoStep { + UndoStep step; + PaintCurve *pc; + UndoCurve data; +} PaintCurveUndoStep; + +static bool paintcurve_undosys_poll(bContext *C) +{ + Paint *p = BKE_paint_get_active_from_context(C); + return (p->brush && p->brush->paint_curve); +} + +static void paintcurve_undosys_step_encode_init(struct bContext *C, UndoStep *us_p) +{ + /* XXX, use to set the undo type only. */ + UNUSED_VARS(C, us_p); +} + +static bool paintcurve_undosys_step_encode(struct bContext *C, UndoStep *us_p) +{ + Paint *p = BKE_paint_get_active_from_context(C); + PaintCurve *pc = p ? (p->brush ? p->brush->paint_curve : NULL) : NULL; + if (pc == NULL) { + return false; + } + + PaintCurveUndoStep *us = (PaintCurveUndoStep *)us_p; + BLI_assert(us->step.data_size == 0); + + us->pc = pc; + undocurve_from_paintcurve(&us->data, pc); + + return true; +} + +static void paintcurve_undosys_step_decode(struct bContext *UNUSED(C), UndoStep *us_p, int UNUSED(dir)) +{ + PaintCurveUndoStep *us = (PaintCurveUndoStep *)us_p; + undocurve_to_paintcurve(&us->data, us->pc); +} + +static void paintcurve_undosys_step_free(UndoStep *us_p) +{ + PaintCurveUndoStep *us = (PaintCurveUndoStep *)us_p; + undocurve_free_data(&us->data); +} + +/* Export for ED_undo_sys. */ +void ED_paintcurve_undosys_type(UndoType *ut) +{ + ut->name = "Paint Curve"; + /* don't poll for now */ + ut->poll = paintcurve_undosys_poll; + ut->step_encode_init = paintcurve_undosys_step_encode_init; + ut->step_encode = paintcurve_undosys_step_encode; + ut->step_decode = paintcurve_undosys_step_decode; + ut->step_free = paintcurve_undosys_step_free; + + ut->mode = BKE_UNDOTYPE_MODE_STORE; + ut->use_context = false; + + ut->step_size = sizeof(PaintCurveUndoStep); +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ +/** \name Utilities + * \{ */ + +void ED_paintcurve_undo_push_begin(const char *name) +{ + UndoStack *ustack = ED_undo_stack_get(); + bContext *C = NULL; /* special case, we never read from this. */ + BKE_undosys_step_push_init_with_type(ustack, C, name, BKE_UNDOSYS_TYPE_PAINTCURVE); +} + +void ED_paintcurve_undo_push_end(void) +{ + UndoStack *ustack = ED_undo_stack_get(); + BKE_undosys_step_push(ustack, NULL, NULL); +} + +/** \} */ diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c index 8377b22756e..4d3c8fe4d5c 100644 --- a/source/blender/editors/sculpt_paint/paint_hide.c +++ b/source/blender/editors/sculpt_paint/paint_hide.c @@ -325,7 +325,7 @@ static void clip_planes_from_rect(bContext *C, BoundBox bb; view3d_operator_needs_opengl(C); - view3d_set_viewcontext(C, &vc); + ED_view3d_viewcontext_init(C, &vc); ED_view3d_clipping_calc(&bb, clip_planes, vc.ar, vc.obact, rect); negate_m4(clip_planes); } @@ -418,7 +418,7 @@ static int hide_show_exec(bContext *C, wmOperator *op) MEM_freeN(nodes); /* end undo */ - sculpt_undo_push_end(C); + sculpt_undo_push_end(); /* ensure that edges and faces get hidden as well (not used by * sculpt but it looks wrong when entering editmode otherwise) */ diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index aebd0c10e9c..ae26de8b269 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -39,7 +39,6 @@ #include "BLI_math.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" -#include "BLI_threads.h" #include "BLT_translation.h" @@ -54,11 +53,12 @@ #include "BKE_context.h" #include "BKE_DerivedMesh.h" #include "BKE_brush.h" -#include "BKE_image.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_node.h" #include "BKE_paint.h" +#include "BKE_undo_system.h" + #include "DEG_depsgraph.h" @@ -87,43 +87,10 @@ #include "paint_intern.h" -typedef struct UndoImageTile { - struct UndoImageTile *next, *prev; - - char idname[MAX_ID_NAME]; /* name instead of pointer*/ - char ibufname[IMB_FILENAME_SIZE]; - - union { - float *fp; - unsigned int *uint; - void *pt; - } rect; - - unsigned short *mask; - - int x, y; - - Image *ima; - short source, use_float; - char gen_type; - bool valid; -} UndoImageTile; - /* this is a static resource for non-globality, * Maybe it should be exposed as part of the * paint operation, but for now just give a public interface */ static ImagePaintPartialRedraw imapaintpartial = {0, 0, 0, 0, 0}; -static SpinLock undolock; - -void image_undo_init_locks(void) -{ - BLI_spin_init(&undolock); -} - -void image_undo_end_locks(void) -{ - BLI_spin_end(&undolock); -} ImagePaintPartialRedraw *get_imapaintpartial(void) { @@ -135,296 +102,6 @@ void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr) imapaintpartial = *ippr; } -/* UNDO */ -typedef enum { - COPY = 0, - RESTORE = 1, - RESTORE_COPY = 2 -} CopyMode; - -static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, CopyMode mode) -{ - if (mode == COPY) { - /* copy or swap contents of tile->rect and region in ibuf->rect */ - IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x * IMAPAINT_TILE_SIZE, - tile->y * IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE); - - if (ibuf->rect_float) { - SWAP(float *, tmpibuf->rect_float, tile->rect.fp); - } - else { - SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint); - } - } - else { - if (mode == RESTORE_COPY) { - IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x * IMAPAINT_TILE_SIZE, - tile->y * IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE); - } - /* swap to the tmpbuf for easy copying */ - if (ibuf->rect_float) { - SWAP(float *, tmpibuf->rect_float, tile->rect.fp); - } - else { - SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint); - } - - IMB_rectcpy(ibuf, tmpibuf, tile->x * IMAPAINT_TILE_SIZE, - tile->y * IMAPAINT_TILE_SIZE, 0, 0, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE); - - if (mode == RESTORE) { - if (ibuf->rect_float) { - SWAP(float *, tmpibuf->rect_float, tile->rect.fp); - } - else { - SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint); - } - } - } -} - -void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask, bool validate) -{ - ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE); - UndoImageTile *tile; - short use_float = ibuf->rect_float ? 1 : 0; - - for (tile = lb->first; tile; tile = tile->next) { - if (tile->x == x_tile && tile->y == y_tile && ima->gen_type == tile->gen_type && ima->source == tile->source) { - if (tile->use_float == use_float) { - if (STREQ(tile->idname, ima->id.name) && STREQ(tile->ibufname, ibuf->name)) { - if (mask) { - /* allocate mask if requested */ - if (!tile->mask) { - tile->mask = MEM_callocN(sizeof(unsigned short) * IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE, - "UndoImageTile.mask"); - } - - *mask = tile->mask; - } - if (validate) - tile->valid = true; - - return tile->rect.pt; - } - } - } - } - - return NULL; -} - -void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile, unsigned short **mask, bool **valid, bool proj, bool find_prev) -{ - ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE); - UndoImageTile *tile; - int allocsize; - short use_float = ibuf->rect_float ? 1 : 0; - void *data; - - /* check if tile is already pushed */ - - /* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */ - if (find_prev) { - data = image_undo_find_tile(ima, ibuf, x_tile, y_tile, mask, true); - if (data) - return data; - } - - if (*tmpibuf == NULL) - *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect); - - tile = MEM_callocN(sizeof(UndoImageTile), "UndoImageTile"); - BLI_strncpy(tile->idname, ima->id.name, sizeof(tile->idname)); - tile->x = x_tile; - tile->y = y_tile; - - /* add mask explicitly here */ - if (mask) - *mask = tile->mask = MEM_callocN(sizeof(unsigned short) * IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE, - "UndoImageTile.mask"); - - allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4; - allocsize *= (ibuf->rect_float) ? sizeof(float) : sizeof(char); - tile->rect.pt = MEM_mapallocN(allocsize, "UndeImageTile.rect"); - - BLI_strncpy(tile->ibufname, ibuf->name, sizeof(tile->ibufname)); - - tile->gen_type = ima->gen_type; - tile->source = ima->source; - tile->use_float = use_float; - tile->valid = true; - tile->ima = ima; - - if (valid) - *valid = &tile->valid; - - undo_copy_tile(tile, *tmpibuf, ibuf, COPY); - - if (proj) - BLI_spin_lock(&undolock); - - undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, allocsize); - BLI_addtail(lb, tile); - - if (proj) - BLI_spin_unlock(&undolock); - - return tile->rect.pt; -} - -void image_undo_remove_masks(void) -{ - ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE); - UndoImageTile *tile; - - for (tile = lb->first; tile; tile = tile->next) { - if (tile->mask) { - MEM_freeN(tile->mask); - tile->mask = NULL; - } - } -} - -static void image_undo_restore_runtime(ListBase *lb) -{ - ImBuf *ibuf, *tmpibuf; - UndoImageTile *tile; - - tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, - IB_rectfloat | IB_rect); - - for (tile = lb->first; tile; tile = tile->next) { - Image *ima = tile->ima; - ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); - - undo_copy_tile(tile, tmpibuf, ibuf, RESTORE); - - GPU_free_image(ima); /* force OpenGL reload (maybe partial update will operate better?) */ - if (ibuf->rect_float) - ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */ - if (ibuf->mipmap[0]) - ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */ - ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; - - BKE_image_release_ibuf(ima, ibuf, NULL); - } - - IMB_freeImBuf(tmpibuf); -} - -void ED_image_undo_restore(bContext *C, ListBase *lb) -{ - Main *bmain = CTX_data_main(C); - Image *ima = NULL; - ImBuf *ibuf, *tmpibuf; - UndoImageTile *tile; - - tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, - IB_rectfloat | IB_rect); - - for (tile = lb->first; tile; tile = tile->next) { - short use_float; - - /* find image based on name, pointer becomes invalid with global undo */ - if (ima && STREQ(tile->idname, ima->id.name)) { - /* ima is valid */ - } - else { - ima = BLI_findstring(&bmain->image, tile->idname, offsetof(ID, name)); - } - - ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); - - if (ima && ibuf && !STREQ(tile->ibufname, ibuf->name)) { - /* current ImBuf filename was changed, probably current frame - * was changed when painting on image sequence, rather than storing - * full image user (which isn't so obvious, btw) try to find ImBuf with - * matched file name in list of already loaded images */ - - BKE_image_release_ibuf(ima, ibuf, NULL); - - ibuf = BKE_image_get_ibuf_with_name(ima, tile->ibufname); - } - - if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) { - BKE_image_release_ibuf(ima, ibuf, NULL); - continue; - } - - if (ima->gen_type != tile->gen_type || ima->source != tile->source) { - BKE_image_release_ibuf(ima, ibuf, NULL); - continue; - } - - use_float = ibuf->rect_float ? 1 : 0; - - if (use_float != tile->use_float) { - BKE_image_release_ibuf(ima, ibuf, NULL); - continue; - } - - undo_copy_tile(tile, tmpibuf, ibuf, RESTORE_COPY); - - GPU_free_image(ima); /* force OpenGL reload */ - if (ibuf->rect_float) - ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */ - if (ibuf->mipmap[0]) - ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */ - ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; - - DEG_id_tag_update(&ima->id, 0); - - BKE_image_release_ibuf(ima, ibuf, NULL); - } - - IMB_freeImBuf(tmpibuf); -} - -void ED_image_undo_free(ListBase *lb) -{ - UndoImageTile *tile; - - for (tile = lb->first; tile; tile = tile->next) - MEM_freeN(tile->rect.pt); -} - -static void image_undo_end(void) -{ - ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE); - UndoImageTile *tile; - int deallocsize = 0; - int allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4; - - /* first dispose of invalid tiles (may happen due to drag dot for instance) */ - for (tile = lb->first; tile;) { - if (!tile->valid) { - UndoImageTile *tmp_tile = tile->next; - deallocsize += allocsize * ((tile->use_float) ? sizeof(float) : sizeof(char)); - MEM_freeN(tile->rect.pt); - BLI_freelinkN(lb, tile); - tile = tmp_tile; - } - else { - tile = tile->next; - } - } - - /* don't forget to remove the size of deallocated tiles */ - undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, -deallocsize); - - ED_undo_paint_push_end(UNDO_PAINT_IMAGE); -} - -static void image_undo_invalidate(void) -{ - UndoImageTile *tile; - ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE); - - for (tile = lb->first; tile; tile = tile->next) - tile->valid = false; -} - /* Imagepaint Partial Redraw & Dirty Region */ void ED_imapaint_clear_partial_redraw(void) @@ -454,7 +131,7 @@ void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int if (w == 0 || h == 0) return; - + if (!imapaintpartial.enabled) { imapaintpartial.x1 = x; imapaintpartial.y1 = y; @@ -471,12 +148,14 @@ void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int imapaint_region_tiles(ibuf, x, y, w, h, &tilex, &tiley, &tilew, &tileh); + ListBase *undo_tiles = ED_image_undo_get_tiles(); + for (ty = tiley; ty <= tileh; ty++) for (tx = tilex; tx <= tilew; tx++) - image_undo_push_tile(ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false, find_old); + image_undo_push_tile(undo_tiles, ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false, find_old); ibuf->userflags |= IB_BITMAPDIRTY; - + if (tmpibuf) IMB_freeImBuf(tmpibuf); } @@ -656,8 +335,9 @@ bool paint_use_opacity_masking(Brush *brush) false : true; } -void paint_brush_color_get(struct Scene *scene, struct Brush *br, bool color_correction, bool invert, float distance, - float pressure, float color[3], struct ColorManagedDisplay *display) +void paint_brush_color_get( + struct Scene *scene, struct Brush *br, bool color_correction, bool invert, float distance, + float pressure, float color[3], struct ColorManagedDisplay *display) { if (invert) copy_v3_v3(color, BKE_brush_secondary_color_get(scene, br)); @@ -758,7 +438,7 @@ static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const flo PaintOperation *pop = MEM_callocN(sizeof(PaintOperation), "PaintOperation"); /* caller frees */ Brush *brush = BKE_paint_brush(&settings->imapaint.paint); int mode = RNA_enum_get(op->ptr, "mode"); - view3d_set_viewcontext(C, &pop->vc); + ED_view3d_viewcontext_init(C, &pop->vc); copy_v2_v2(pop->prevmouse, mouse); copy_v2_v2(pop->startmouse, mouse); @@ -792,20 +472,11 @@ static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const flo } settings->imapaint.flag |= IMAGEPAINT_DRAWING; - ED_undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name, - ED_image_undo_restore, ED_image_undo_free, NULL); + ED_image_undo_push_begin(op->type->name); return pop; } -/* restore painting image to previous state. Used for anchored and drag-dot style brushes*/ -static void paint_stroke_restore(void) -{ - ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE); - image_undo_restore_runtime(lb); - image_undo_invalidate(); -} - static void paint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr) { PaintOperation *pop = paint_stroke_mode_data(stroke); @@ -842,7 +513,8 @@ static void paint_stroke_update_step(bContext *C, struct PaintStroke *stroke, Po BKE_brush_alpha_set(scene, brush, max_ff(0.0f, startalpha * alphafac)); if ((brush->flag & BRUSH_DRAG_DOT) || (brush->flag & BRUSH_ANCHORED)) { - paint_stroke_restore(); + UndoStack *ustack = CTX_wm_manager(C)->undo_stack; + ED_image_undo_restore(ustack->step_init); } if (pop->mode == PAINT_MODE_3D_PROJECT) { @@ -919,7 +591,7 @@ static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke) WM_paint_cursor_end(CTX_wm_manager(C), pop->cursor); } - image_undo_end(); + ED_image_undo_push_end(); /* duplicate warning, see texpaint_init */ #if 0 @@ -1426,8 +1098,10 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op) if (sl->spacetype == SPACE_IMAGE) { SpaceImage *sima = (SpaceImage *)sl; - if (!sima->pin) - ED_space_image_set(sima, scene, scene->obedit, ima); + if (!sima->pin) { + Object *obedit = CTX_data_edit_object(C); + ED_space_image_set(sima, scene, obedit, ima); + } } } } @@ -1445,6 +1119,8 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op) toggle_paint_cursor(C, 1); } + // ED_workspace_object_mode_sync_from_object(wm, workspace, ob); + GPU_drawobject_free(ob->derivedFinal); WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene); @@ -1471,8 +1147,8 @@ static int brush_colors_flip_exec(bContext *C, wmOperator *UNUSED(op)) { UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings; - Brush *br; Object *ob = CTX_data_active_object(C); + Brush *br; if (!(ob && (ob->mode & OB_MODE_VERTEX_PAINT))) { br = image_paint_brush(C); } @@ -1529,15 +1205,17 @@ void PAINT_OT_brush_colors_flip(wmOperatorType *ot) void ED_imapaint_bucket_fill(struct bContext *C, float color[3], wmOperator *op) { + wmWindowManager *wm = CTX_wm_manager(C); SpaceImage *sima = CTX_wm_space_image(C); Image *ima = sima->image; - ED_undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name, - ED_image_undo_restore, ED_image_undo_free, NULL); + BKE_undosys_step_push_init_with_type(wm->undo_stack, C, op->type->name, BKE_UNDOSYS_TYPE_IMAGE); + + ED_image_undo_push_begin(op->type->name); paint_2d_bucket_fill(C, color, NULL, NULL, NULL); - ED_undo_paint_push_end(UNDO_PAINT_IMAGE); + BKE_undosys_step_push(wm->undo_stack, C, op->type->name); DEG_id_tag_update(&ima->id, 0); } diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c index 2ce7c51b6b4..83a5a0d0b1b 100644 --- a/source/blender/editors/sculpt_paint/paint_image_2d.c +++ b/source/blender/editors/sculpt_paint/paint_image_2d.c @@ -1036,6 +1036,8 @@ static void paint_2d_do_making_brush(ImagePaintState *s, ImBuf tmpbuf; IMB_initImBuf(&tmpbuf, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, 0); + ListBase *undo_tiles = ED_image_undo_get_tiles(); + for (int ty = tiley; ty <= tileh; ty++) { for (int tx = tilex; tx <= tilew; tx++) { /* retrieve original pixels + mask from undo buffer */ @@ -1044,9 +1046,9 @@ static void paint_2d_do_making_brush(ImagePaintState *s, int origy = region->desty - ty * IMAPAINT_TILE_SIZE; if (s->canvas->rect_float) - tmpbuf.rect_float = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask, false); + tmpbuf.rect_float = image_undo_find_tile(undo_tiles, s->image, s->canvas, tx, ty, &mask, false); else - tmpbuf.rect = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask, false); + tmpbuf.rect = image_undo_find_tile(undo_tiles, s->image, s->canvas, tx, ty, &mask, false); IMB_rectblend(s->canvas, &tmpbuf, frombuf, mask, curveb, texmaskb, mask_max, diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 4a14e985827..c81a59b045f 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -1501,15 +1501,16 @@ static int project_paint_undo_subtiles(const TileInfo *tinf, int tx, int ty) if (generate_tile) { + ListBase *undo_tiles = ED_image_undo_get_tiles(); volatile void *undorect; if (tinf->masked) { undorect = image_undo_push_tile( - pjIma->ima, pjIma->ibuf, tinf->tmpibuf, + undo_tiles, pjIma->ima, pjIma->ibuf, tinf->tmpibuf, tx, ty, &pjIma->maskRect[tile_index], &pjIma->valid[tile_index], true, false); } else { undorect = image_undo_push_tile( - pjIma->ima, pjIma->ibuf, tinf->tmpibuf, + undo_tiles, pjIma->ima, pjIma->ibuf, tinf->tmpibuf, tx, ty, NULL, &pjIma->valid[tile_index], true, false); } @@ -2694,7 +2695,7 @@ static void project_paint_face_init( int face_seam_flag; if (threaded) - BLI_lock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */ + BLI_thread_lock(LOCK_CUSTOM1); /* Other threads could be modifying these vars */ face_seam_flag = ps->faceSeamFlags[tri_index]; @@ -2711,7 +2712,7 @@ static void project_paint_face_init( if ((face_seam_flag & (PROJ_FACE_SEAM1 | PROJ_FACE_SEAM2 | PROJ_FACE_SEAM3)) == 0) { if (threaded) - BLI_unlock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */ + BLI_thread_unlock(LOCK_CUSTOM1); /* Other threads could be modifying these vars */ } else { @@ -2737,7 +2738,7 @@ static void project_paint_face_init( /* ps->faceSeamUVs cant be modified when threading, now this is done we can unlock */ if (threaded) - BLI_unlock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */ + BLI_thread_unlock(LOCK_CUSTOM1); /* Other threads could be modifying these vars */ vCoSS[0] = ps->screenCoords[lt_vtri[0]]; vCoSS[1] = ps->screenCoords[lt_vtri[1]]; @@ -4138,7 +4139,7 @@ static bool project_bucket_iter_next( const int diameter = 2 * ps->brush_size; if (ps->thread_tot > 1) - BLI_lock_thread(LOCK_CUSTOM1); + BLI_thread_lock(LOCK_CUSTOM1); //printf("%d %d\n", ps->context_bucket_x, ps->context_bucket_y); @@ -4155,7 +4156,7 @@ static bool project_bucket_iter_next( ps->context_bucket_x++; if (ps->thread_tot > 1) - BLI_unlock_thread(LOCK_CUSTOM1); + BLI_thread_unlock(LOCK_CUSTOM1); return 1; } @@ -4164,7 +4165,7 @@ static bool project_bucket_iter_next( } if (ps->thread_tot > 1) - BLI_unlock_thread(LOCK_CUSTOM1); + BLI_thread_unlock(LOCK_CUSTOM1); return 0; } @@ -4883,7 +4884,7 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po } if (ps->thread_tot > 1) - BLI_init_threads(&threads, do_projectpaint_thread, ps->thread_tot); + BLI_threadpool_init(&threads, do_projectpaint_thread, ps->thread_tot); pool = BKE_image_pool_new(); @@ -4913,11 +4914,11 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po handles[a].pool = pool; if (ps->thread_tot > 1) - BLI_insert_thread(&threads, &handles[a]); + BLI_threadpool_insert(&threads, &handles[a]); } if (ps->thread_tot > 1) /* wait for everything to be done */ - BLI_end_threads(&threads); + BLI_threadpool_end(&threads); else do_projectpaint_thread(&handles[0]); @@ -5396,8 +5397,7 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op) scene->toolsettings->imapaint.flag |= IMAGEPAINT_DRAWING; - ED_undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name, - ED_image_undo_restore, ED_image_undo_free, NULL); + ED_image_undo_push_begin(op->type->name); /* allocate and initialize spatial data structures */ project_paint_begin(C, &ps, false, 0); @@ -5459,6 +5459,7 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); + struct RenderEngineType *engine_type = CTX_data_engine_type(C); EvaluationContext eval_ctx; ToolSettings *settings = scene->toolsettings; int w = settings->imapaint.screen_grab_size[0]; @@ -5476,9 +5477,10 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op) if (h > maxsize) h = maxsize; ibuf = ED_view3d_draw_offscreen_imbuf( - &eval_ctx, scene, view_layer, CTX_wm_view3d(C), CTX_wm_region(C), + &eval_ctx, scene, view_layer, engine_type, + CTX_wm_view3d(C), CTX_wm_region(C), w, h, IB_rect, V3D_OFSDRAW_NONE, R_ALPHAPREMUL, 0, NULL, - NULL, NULL, err_out); + NULL, err_out); if (!ibuf) { /* Mostly happens when OpenGL offscreen buffer was failed to create, */ /* but could be other reasons. Should be handled in the future. nazgul */ @@ -5943,9 +5945,9 @@ static int add_simple_uvs_poll(bContext *C) { Object *ob = CTX_data_active_object(C); - if (!ob || ob->type != OB_MESH || ob->mode != OB_MODE_TEXTURE_PAINT) + if (!ob || ob->type != OB_MESH || ob->mode != OB_MODE_TEXTURE_PAINT) { return false; - + } return true; } diff --git a/source/blender/editors/sculpt_paint/paint_image_undo.c b/source/blender/editors/sculpt_paint/paint_image_undo.c new file mode 100644 index 00000000000..ade775d14e6 --- /dev/null +++ b/source/blender/editors/sculpt_paint/paint_image_undo.c @@ -0,0 +1,535 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/sculpt_paint/paint_image_undo.c + * \ingroup edsculpt + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" +#include "BLI_threads.h" + +#include "DNA_image_types.h" +#include "DNA_windowmanager_types.h" +#include "DNA_object_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_workspace_types.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "BKE_context.h" +#include "BKE_image.h" +#include "BKE_main.h" +#include "BKE_undo_system.h" + +#include "DEG_depsgraph.h" + +#include "ED_paint.h" +#include "ED_undo.h" + +#include "GPU_draw.h" + +#include "paint_intern.h" + +/* -------------------------------------------------------------------- */ +/** \name Undo Conversion + * \{ */ + +typedef struct UndoImageTile { + struct UndoImageTile *next, *prev; + + char ibufname[IMB_FILENAME_SIZE]; + + union { + float *fp; + unsigned int *uint; + void *pt; + } rect; + + unsigned short *mask; + + int x, y; + + Image *ima; + short source, use_float; + char gen_type; + bool valid; + + size_t undo_size; +} UndoImageTile; + +/* this is a static resource for non-globality, + * Maybe it should be exposed as part of the + * paint operation, but for now just give a public interface */ +static SpinLock undolock; + +void image_undo_init_locks(void) +{ + BLI_spin_init(&undolock); +} + +void image_undo_end_locks(void) +{ + BLI_spin_end(&undolock); +} + +/* UNDO */ +typedef enum { + COPY = 0, + RESTORE = 1, + RESTORE_COPY = 2 +} CopyMode; + +static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, CopyMode mode) +{ + if (mode == COPY) { + /* copy or swap contents of tile->rect and region in ibuf->rect */ + IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x * IMAPAINT_TILE_SIZE, + tile->y * IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE); + + if (ibuf->rect_float) { + SWAP(float *, tmpibuf->rect_float, tile->rect.fp); + } + else { + SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint); + } + } + else { + if (mode == RESTORE_COPY) { + IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x * IMAPAINT_TILE_SIZE, + tile->y * IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE); + } + /* swap to the tmpbuf for easy copying */ + if (ibuf->rect_float) { + SWAP(float *, tmpibuf->rect_float, tile->rect.fp); + } + else { + SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint); + } + + IMB_rectcpy(ibuf, tmpibuf, tile->x * IMAPAINT_TILE_SIZE, + tile->y * IMAPAINT_TILE_SIZE, 0, 0, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE); + + if (mode == RESTORE) { + if (ibuf->rect_float) { + SWAP(float *, tmpibuf->rect_float, tile->rect.fp); + } + else { + SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint); + } + } + } +} + +void *image_undo_find_tile( + ListBase *undo_tiles, + Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask, bool validate) +{ + UndoImageTile *tile; + short use_float = ibuf->rect_float ? 1 : 0; + + for (tile = undo_tiles->first; tile; tile = tile->next) { + if (tile->x == x_tile && tile->y == y_tile && ima->gen_type == tile->gen_type && ima->source == tile->source) { + if (tile->use_float == use_float) { + if (STREQ(tile->ibufname, ibuf->name)) { + if (mask) { + /* allocate mask if requested */ + if (!tile->mask) { + tile->mask = MEM_callocN(sizeof(unsigned short) * IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE, + "UndoImageTile.mask"); + } + + *mask = tile->mask; + } + if (validate) { + tile->valid = true; + } + return tile->rect.pt; + } + } + } + } + + return NULL; +} + +void *image_undo_push_tile( + ListBase *undo_tiles, + Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile, + unsigned short **mask, bool **valid, bool proj, bool find_prev) +{ + UndoImageTile *tile; + int allocsize; + short use_float = ibuf->rect_float ? 1 : 0; + void *data; + + /* check if tile is already pushed */ + + /* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */ + if (find_prev) { + data = image_undo_find_tile(undo_tiles, ima, ibuf, x_tile, y_tile, mask, true); + if (data) { + return data; + } + } + + if (*tmpibuf == NULL) { + *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect); + } + + tile = MEM_callocN(sizeof(UndoImageTile), "UndoImageTile"); + tile->x = x_tile; + tile->y = y_tile; + + /* add mask explicitly here */ + if (mask) { + *mask = tile->mask = MEM_callocN(sizeof(unsigned short) * IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE, + "UndoImageTile.mask"); + } + allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4; + allocsize *= (ibuf->rect_float) ? sizeof(float) : sizeof(char); + tile->rect.pt = MEM_mapallocN(allocsize, "UndeImageTile.rect"); + + BLI_strncpy(tile->ibufname, ibuf->name, sizeof(tile->ibufname)); + + tile->gen_type = ima->gen_type; + tile->source = ima->source; + tile->use_float = use_float; + tile->valid = true; + tile->ima = ima; + + if (valid) { + *valid = &tile->valid; + } + undo_copy_tile(tile, *tmpibuf, ibuf, COPY); + + if (proj) { + BLI_spin_lock(&undolock); + } + BLI_addtail(undo_tiles, tile); + + if (proj) { + BLI_spin_unlock(&undolock); + } + return tile->rect.pt; +} + +void image_undo_remove_masks(void) +{ + ListBase *undo_tiles = ED_image_undo_get_tiles(); + UndoImageTile *tile; + + for (tile = undo_tiles->first; tile; tile = tile->next) { + if (tile->mask) { + MEM_freeN(tile->mask); + tile->mask = NULL; + } + } +} + +static void image_undo_restore_runtime(ListBase *lb) +{ + ImBuf *ibuf, *tmpibuf; + UndoImageTile *tile; + + tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, + IB_rectfloat | IB_rect); + + for (tile = lb->first; tile; tile = tile->next) { + Image *ima = tile->ima; + ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); + + undo_copy_tile(tile, tmpibuf, ibuf, RESTORE); + + GPU_free_image(ima); /* force OpenGL reload (maybe partial update will operate better?) */ + if (ibuf->rect_float) { + ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */ + } + if (ibuf->mipmap[0]) { + ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */ + } + ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; + + BKE_image_release_ibuf(ima, ibuf, NULL); + } + + IMB_freeImBuf(tmpibuf); +} + +static void image_undo_restore_list(ListBase *lb, struct UndoIDPtrMap *id_map) +{ + ImBuf *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect); + + /* Store last found image. */ + ID *image_prev[2] = {NULL}; + + for (UndoImageTile *tile = lb->first; tile; tile = tile->next) { + short use_float; + + Image *ima = (Image *)BKE_undosys_ID_map_lookup_with_prev(id_map, &tile->ima->id, image_prev); + + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); + + if (ima && ibuf && !STREQ(tile->ibufname, ibuf->name)) { + /* current ImBuf filename was changed, probably current frame + * was changed when painting on image sequence, rather than storing + * full image user (which isn't so obvious, btw) try to find ImBuf with + * matched file name in list of already loaded images */ + + BKE_image_release_ibuf(ima, ibuf, NULL); + + ibuf = BKE_image_get_ibuf_with_name(ima, tile->ibufname); + } + + if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) { + BKE_image_release_ibuf(ima, ibuf, NULL); + continue; + } + + if (ima->gen_type != tile->gen_type || ima->source != tile->source) { + BKE_image_release_ibuf(ima, ibuf, NULL); + continue; + } + + use_float = ibuf->rect_float ? 1 : 0; + + if (use_float != tile->use_float) { + BKE_image_release_ibuf(ima, ibuf, NULL); + continue; + } + + undo_copy_tile(tile, tmpibuf, ibuf, RESTORE_COPY); + + GPU_free_image(ima); /* force OpenGL reload */ + if (ibuf->rect_float) { + ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */ + } + if (ibuf->mipmap[0]) { + ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */ + } + ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; + + DEG_id_tag_update(&ima->id, 0); + + BKE_image_release_ibuf(ima, ibuf, NULL); + } + + IMB_freeImBuf(tmpibuf); +} + +static void image_undo_free_list(ListBase *lb) +{ + UndoImageTile *tile; + + for (tile = lb->first; tile; tile = tile->next) { + MEM_freeN(tile->rect.pt); + } +} + +void ED_image_undo_push_begin(const char *name) +{ + UndoStack *ustack = ED_undo_stack_get(); + bContext *C = NULL; /* special case, we never read from this. */ + BKE_undosys_step_push_init_with_type(ustack, C, name, BKE_UNDOSYS_TYPE_IMAGE); +} + +void ED_image_undo_push_end(void) +{ + UndoStack *ustack = ED_undo_stack_get(); + BKE_undosys_step_push(ustack, NULL, NULL); +} + +static void image_undo_invalidate(void) +{ + UndoImageTile *tile; + ListBase *lb = ED_image_undo_get_tiles(); + + for (tile = lb->first; tile; tile = tile->next) { + tile->valid = false; + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Implements ED Undo System + * \{ */ + +typedef struct ImageUndoStep { + UndoStep step; + ListBase tiles; + + /* Use for all ID lookups (can be NULL). */ + struct UndoIDPtrMap *id_map; +} ImageUndoStep; + +static void image_undosys_step_encode_store_ids(ImageUndoStep *us) +{ + us->id_map = BKE_undosys_ID_map_create(); + + ID *image_prev = NULL; + for (UndoImageTile *tile = us->tiles.first; tile; tile = tile->next) { + BKE_undosys_ID_map_add_with_prev(us->id_map, &tile->ima->id, &image_prev); + } +} + +/* Restore at runtime. */ +#if 0 +static void paint_undosys_step_decode_restore_ids(ImageUndoStep *us) +{ + ID *image_prev[2] = {NULL}; + for (UndoImageTile *tile = us->tiles.first; tile; tile = tile->next) { + tile->ima = (Image *)BKE_undosys_ID_map_lookup_with_prev(us->id_map, &tile->ima->id, image_prev); + } +} +#endif + +static bool image_undosys_poll(bContext *C) +{ + Object *obact = CTX_data_active_object(C); + + ScrArea *sa = CTX_wm_area(C); + if (sa && (sa->spacetype == SPACE_IMAGE)) { + SpaceImage *sima = (SpaceImage *)sa->spacedata.first; + if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) { + return true; + } + } + else if (sa && (sa->spacetype == SPACE_VIEW3D)) { + if (obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) { + return true; + } + } + return false; +} + +static void image_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep *us_p) +{ + ImageUndoStep *us = (ImageUndoStep *)us_p; + /* dummy, memory is cleared anyway. */ + BLI_listbase_clear(&us->tiles); +} + +static bool image_undosys_step_encode(struct bContext *UNUSED(C), UndoStep *us_p) +{ + /* dummy, encoding is done along the way by adding tiles + * to the current 'ImageUndoStep' added by encode_init. */ + ImageUndoStep *us = (ImageUndoStep *)us_p; + + BLI_assert(us->step.data_size == 0); + + int allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4; + + + /* first dispose of invalid tiles (may happen due to drag dot for instance) */ + for (UndoImageTile *tile = us->tiles.first; tile;) { + if (!tile->valid) { + UndoImageTile *tmp_tile = tile->next; + MEM_freeN(tile->rect.pt); + BLI_freelinkN(&us->tiles, tile); + tile = tmp_tile; + } + else { + us->step.data_size += allocsize * ((tile->use_float) ? sizeof(float) : sizeof(char)); + tile = tile->next; + } + } + + image_undosys_step_encode_store_ids(us); + + return true; +} + +static void image_undosys_step_decode(struct bContext *UNUSED(C), UndoStep *us_p, int UNUSED(dir)) +{ + ImageUndoStep *us = (ImageUndoStep *)us_p; +#if 0 + paint_undosys_step_decode_restore_ids(us); +#endif + image_undo_restore_list(&us->tiles, us->id_map); +} + +static void image_undosys_step_free(UndoStep *us_p) +{ + ImageUndoStep *us = (ImageUndoStep *)us_p; + image_undo_free_list(&us->tiles); + BKE_undosys_ID_map_destroy(us->id_map); +} + +static void image_undosys_foreach_ID_ref( + UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data) +{ + ImageUndoStep *us = (ImageUndoStep *)us_p; + if (us->id_map != NULL) { + BKE_undosys_ID_map_foreach_ID_ref(us->id_map, foreach_ID_ref_fn, user_data); + } +} + +/* Export for ED_undo_sys. */ +void ED_image_undosys_type(UndoType *ut) +{ + ut->name = "Image"; + ut->poll = image_undosys_poll; + ut->step_encode_init = image_undosys_step_encode_init; + ut->step_encode = image_undosys_step_encode; + ut->step_decode = image_undosys_step_decode; + ut->step_free = image_undosys_step_free; + + ut->step_foreach_ID_ref = image_undosys_foreach_ID_ref; + + ut->mode = BKE_UNDOTYPE_MODE_ACCUMULATE; + ut->use_context = true; + + ut->step_size = sizeof(ImageUndoStep); +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ +/** \name Utilities + * \{ */ + +ListBase *ED_image_undosys_step_get_tiles(UndoStep *us_p) +{ + ImageUndoStep *us = (ImageUndoStep *)us_p; + return &us->tiles; +} + +ListBase *ED_image_undo_get_tiles(void) +{ + UndoStack *ustack = ED_undo_stack_get(); + UndoStep *us = BKE_undosys_stack_init_or_active_with_type(ustack, BKE_UNDOSYS_TYPE_IMAGE); + return ED_image_undosys_step_get_tiles(us); +} + +/* restore painting image to previous state. Used for anchored and drag-dot style brushes*/ +void ED_image_undo_restore(UndoStep *us) +{ + ListBase *lb = ED_image_undosys_step_get_tiles(us); + image_undo_restore_runtime(lb); + image_undo_invalidate(); +} + +/** \} */ diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index 28d9dfe13b0..e22b996c6e5 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -43,6 +43,7 @@ struct MTex; struct Object; struct PaintStroke; struct Paint; +struct PaintCurve; struct PointerRNA; struct rcti; struct Scene; @@ -54,6 +55,7 @@ struct wmOperator; struct wmOperatorType; struct wmWindowManager; struct DMCoNo; +struct UndoStep; enum ePaintMode; /* paint_stroke.c */ @@ -176,12 +178,6 @@ typedef struct ImagePaintPartialRedraw { #define IMAPAINT_TILE_NUMBER(size) (((size) + IMAPAINT_TILE_SIZE - 1) >> IMAPAINT_TILE_BITS) int image_texture_paint_poll(struct bContext *C); -void *image_undo_find_tile(struct Image *ima, struct ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask, bool validate); -void *image_undo_push_tile(struct Image *ima, struct ImBuf *ibuf, struct ImBuf **tmpibuf, int x_tile, int y_tile, unsigned short **, bool **valid, bool proj, bool find_prev); -void image_undo_remove_masks(void); -void image_undo_init_locks(void); -void image_undo_end_locks(void); - void imapaint_image_update(struct SpaceImage *sima, struct Image *image, struct ImBuf *ibuf, short texpaint); struct ImagePaintPartialRedraw *get_imapaintpartial(void); void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr); @@ -190,15 +186,25 @@ int get_imapaint_zoom(struct bContext *C, float *zoomx, float *zoomy); void *paint_2d_new_stroke(struct bContext *, struct wmOperator *, int mode); void paint_2d_redraw(const struct bContext *C, void *ps, bool final); void paint_2d_stroke_done(void *ps); -void paint_2d_stroke(void *ps, const float prev_mval[2], const float mval[2], const bool eraser, float pressure, float distance, float size); -void paint_2d_bucket_fill(const struct bContext *C, const float color[3], struct Brush *br, const float mouse_init[2], void *ps); -void paint_2d_gradient_fill(const struct bContext *C, struct Brush *br, const float mouse_init[2], const float mouse_final[2], void *ps); -void *paint_proj_new_stroke(struct bContext *C, struct Object *ob, const float mouse[2], int mode); -void paint_proj_stroke(const struct bContext *C, void *ps, const float prevmval_i[2], const float mval_i[2], const bool eraser, float pressure, float distance, float size); +void paint_2d_stroke( + void *ps, const float prev_mval[2], const float mval[2], + const bool eraser, float pressure, float distance, float size); +void paint_2d_bucket_fill( + const struct bContext *C, const float color[3], struct Brush *br, const float mouse_init[2], void *ps); +void paint_2d_gradient_fill( + const struct bContext *C, struct Brush *br, const float mouse_init[2], const float mouse_final[2], void *ps); +void *paint_proj_new_stroke( + struct bContext *C, struct Object *ob, const float mouse[2], int mode); +void paint_proj_stroke( + const struct bContext *C, void *ps, const float prevmval_i[2], const float mval_i[2], + const bool eraser, float pressure, float distance, float size); void paint_proj_redraw(const struct bContext *C, void *pps, bool final); void paint_proj_stroke_done(void *ps); -void paint_brush_color_get(struct Scene *scene, struct Brush *br, bool color_correction, bool invert, float distance, float pressure, float color[3], struct ColorManagedDisplay *display); +void paint_brush_color_get( + struct Scene *scene, struct Brush *br, + bool color_correction, bool invert, float distance, float pressure, float color[3], + struct ColorManagedDisplay *display); bool paint_use_opacity_masking(struct Brush *brush); void paint_brush_init_tex(struct Brush *brush); void paint_brush_exit_tex(struct Brush *brush); @@ -214,7 +220,23 @@ void PAINT_OT_delete_texture_paint_slot(struct wmOperatorType *ot); void PAINT_OT_image_paint(struct wmOperatorType *ot); void PAINT_OT_add_simple_uvs(struct wmOperatorType *ot); -/* uv sculpting */ +/* paint_image_undo.c */ +void *image_undo_find_tile( + ListBase *undo_tiles, + struct Image *ima, struct ImBuf *ibuf, int x_tile, int y_tile, + unsigned short **mask, bool validate); +void *image_undo_push_tile( + ListBase *undo_tiles, + struct Image *ima, struct ImBuf *ibuf, struct ImBuf **tmpibuf, int x_tile, int y_tile, + unsigned short **, bool **valid, bool proj, bool find_prev); +void image_undo_remove_masks(void); +void image_undo_init_locks(void); +void image_undo_end_locks(void); + +struct ListBase *ED_image_undosys_step_get_tiles(struct UndoStep *us_p); +struct ListBase *ED_image_undo_get_tiles(void); + +/* sculpt_uv.c */ int uv_sculpt_poll(struct bContext *C); int uv_sculpt_keymap_poll(struct bContext *C); @@ -287,10 +309,6 @@ typedef enum { void set_brush_rc_props(struct PointerRNA *ptr, const char *paint, const char *prop, const char *secondary_prop, RCFlags flags); -/* paint_undo.c */ -struct ListBase *undo_paint_push_get_list(int type); -void undo_paint_push_count_alloc(int type, int size); - /* paint_hide.c */ typedef enum { @@ -327,6 +345,9 @@ void PAINTCURVE_OT_slide(struct wmOperatorType *ot); void PAINTCURVE_OT_draw(struct wmOperatorType *ot); void PAINTCURVE_OT_cursor(struct wmOperatorType *ot); +/* paint_curve_undo.c */ +void ED_paintcurve_undo_push(struct bContext *C, struct wmOperator *op, struct PaintCurve *pc); + /* image painting blur kernel */ typedef struct { float *wdata; /* actual kernel */ diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index ff261a808da..162c067166c 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -39,7 +39,7 @@ #include "BLI_math_matrix.h" #include "BLI_math_geom.h" #include "BLI_utildefines.h" -#include "BLI_lasso.h" +#include "BLI_lasso_2d.h" #include "BLI_task.h" #include "BKE_pbvh.h" @@ -171,7 +171,7 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op) if (multires) multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED); - sculpt_undo_push_end(C); + sculpt_undo_push_end(); if (nodes) MEM_freeN(nodes); @@ -327,7 +327,7 @@ int ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *r if (multires) multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED); - sculpt_undo_push_end(C); + sculpt_undo_push_end(); ED_region_tag_redraw(ar); @@ -449,7 +449,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) /* Calculations of individual vertices are done in 2D screen space to diminish the amount of * calculations done. Bounding box PBVH collision is not computed against enclosing rectangle * of lasso */ - view3d_set_viewcontext(C, &vc); + ED_view3d_viewcontext_init(C, &vc); /* lasso data calculations */ data.vc = &vc; @@ -514,7 +514,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) if (multires) multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED); - sculpt_undo_push_end(C); + sculpt_undo_push_end(); ED_region_tag_redraw(vc.ar); MEM_freeN((void *)mcords); diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index 3982c9a3c30..861015375cb 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -698,7 +698,7 @@ PaintStroke *paint_stroke_new(bContext *C, Brush *br = stroke->brush = BKE_paint_brush(p); float zoomx, zoomy; - view3d_set_viewcontext(C, &stroke->vc); + ED_view3d_viewcontext_init(C, &stroke->vc); stroke->get_location = get_location; stroke->test_start = test_start; diff --git a/source/blender/editors/sculpt_paint/paint_undo.c b/source/blender/editors/sculpt_paint/paint_undo.c deleted file mode 100644 index 27d3f6648a2..00000000000 --- a/source/blender/editors/sculpt_paint/paint_undo.c +++ /dev/null @@ -1,410 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/sculpt_paint/paint_undo.c - * \ingroup edsculpt - * \brief Undo system for painting and sculpting. - */ - -#include <stdlib.h> -#include <string.h> - -#include "MEM_guardedalloc.h" - -#include "BLI_listbase.h" -#include "BLI_utildefines.h" -#include "BLI_string.h" - -#include "DNA_userdef_types.h" - -#include "BKE_blender_undo.h" -#include "BKE_context.h" -#include "BKE_global.h" - -#include "ED_paint.h" - -#include "paint_intern.h" - -typedef struct UndoElem { - struct UndoElem *next, *prev; - char name[BKE_UNDO_STR_MAX]; - uintptr_t undosize; - - ListBase elems; - - UndoRestoreCb restore; - UndoFreeCb free; - UndoCleanupCb cleanup; -} UndoElem; - -typedef struct UndoStack { - int type; - ListBase elems; - UndoElem *current; -} UndoStack; - -static UndoStack ImageUndoStack = {UNDO_PAINT_IMAGE, {NULL, NULL}, NULL}; -static UndoStack MeshUndoStack = {UNDO_PAINT_MESH, {NULL, NULL}, NULL}; - -/* Generic */ - -static void undo_restore(bContext *C, UndoStack *UNUSED(stack), UndoElem *uel) -{ - if (uel && uel->restore) - uel->restore(C, &uel->elems); -} - -static void undo_elem_free(UndoStack *UNUSED(stack), UndoElem *uel) -{ - if (uel && uel->free) { - uel->free(&uel->elems); - BLI_freelistN(&uel->elems); - } -} - -static void undo_stack_push_begin(UndoStack *stack, const char *name, UndoRestoreCb restore, UndoFreeCb free, UndoCleanupCb cleanup) -{ - UndoElem *uel; - int nr; - - /* Undo push is split up in begin and end, the reason is that as painting - * happens more tiles/nodes are added to the list, and at the very end we - * know how much memory the undo used to remove old undo elements */ - - /* remove all undos after (also when stack->current==NULL) */ - while (stack->elems.last != stack->current) { - uel = stack->elems.last; - undo_elem_free(stack, uel); - BLI_freelinkN(&stack->elems, uel); - } - - /* make new */ - stack->current = uel = MEM_callocN(sizeof(UndoElem), "undo file"); - uel->restore = restore; - uel->free = free; - uel->cleanup = cleanup; - BLI_addtail(&stack->elems, uel); - - /* name can be a dynamic string */ - BLI_strncpy(uel->name, name, sizeof(uel->name)); - - /* limit amount to the maximum amount*/ - nr = 0; - uel = stack->elems.last; - while (uel) { - nr++; - if (nr == U.undosteps) break; - uel = uel->prev; - } - if (uel) { - while (stack->elems.first != uel) { - UndoElem *first = stack->elems.first; - undo_elem_free(stack, first); - BLI_freelinkN(&stack->elems, first); - } - } -} - -static void undo_stack_push_end(UndoStack *stack) -{ - UndoElem *uel; - uintptr_t totmem, maxmem; - int totundo = 0; - - /* first limit to undo steps */ - uel = stack->elems.last; - - while (uel) { - totundo++; - if (totundo > U.undosteps) break; - uel = uel->prev; - } - - if (uel) { - UndoElem *first; - - /* in case the undo steps are zero, the current pointer will be invalid */ - if (uel == stack->current) - stack->current = NULL; - - do { - first = stack->elems.first; - undo_elem_free(stack, first); - BLI_freelinkN(&stack->elems, first); - } while (first != uel); - } - - if (U.undomemory != 0) { - /* limit to maximum memory (afterwards, we can't know in advance) */ - totmem = 0; - maxmem = ((uintptr_t)U.undomemory) * 1024 * 1024; - - uel = stack->elems.last; - while (uel) { - totmem += uel->undosize; - if (totmem > maxmem) break; - uel = uel->prev; - } - - if (uel) { - while (stack->elems.first != uel) { - UndoElem *first = stack->elems.first; - undo_elem_free(stack, first); - BLI_freelinkN(&stack->elems, first); - } - } - } -} - -static void undo_stack_cleanup(UndoStack *stack, bContext *C) -{ - UndoElem *uel = stack->elems.first; - bool stack_reset = false; - - while (uel) { - if (uel->cleanup && uel->cleanup(C, &uel->elems)) { - UndoElem *uel_tmp = uel->next; - if (stack->current == uel) { - stack->current = NULL; - stack_reset = true; - } - undo_elem_free(stack, uel); - BLI_freelinkN(&stack->elems, uel); - uel = uel_tmp; - } - else - uel = uel->next; - } - if (stack_reset) { - stack->current = stack->elems.last; - } - -} - -static int undo_stack_step(bContext *C, UndoStack *stack, int step, const char *name) -{ - UndoElem *undo; - - /* first cleanup any old undo steps that may belong to invalid data */ - undo_stack_cleanup(stack, C); - - if (step == 1) { - if (stack->current == NULL) { - /* pass */ - } - else { - if (!name || STREQ(stack->current->name, name)) { - if (G.debug & G_DEBUG_WM) { - printf("%s: undo '%s'\n", __func__, stack->current->name); - } - undo_restore(C, stack, stack->current); - stack->current = stack->current->prev; - return 1; - } - } - } - else if (step == -1) { - if ((stack->current != NULL && stack->current->next == NULL) || BLI_listbase_is_empty(&stack->elems)) { - /* pass */ - } - else { - if (!name || STREQ(stack->current->name, name)) { - undo = (stack->current && stack->current->next) ? stack->current->next : stack->elems.first; - undo_restore(C, stack, undo); - stack->current = undo; - if (G.debug & G_DEBUG_WM) { - printf("%s: redo %s\n", __func__, undo->name); - } - return 1; - } - } - } - - return 0; -} - -static void undo_stack_free(UndoStack *stack) -{ - UndoElem *uel; - - for (uel = stack->elems.first; uel; uel = uel->next) - undo_elem_free(stack, uel); - - BLI_freelistN(&stack->elems); - stack->current = NULL; -} - -/* Exported Functions */ - -void ED_undo_paint_push_begin(int type, const char *name, UndoRestoreCb restore, UndoFreeCb free, UndoCleanupCb cleanup) -{ - if (type == UNDO_PAINT_IMAGE) - undo_stack_push_begin(&ImageUndoStack, name, restore, free, cleanup); - else if (type == UNDO_PAINT_MESH) - undo_stack_push_begin(&MeshUndoStack, name, restore, free, cleanup); -} - -ListBase *undo_paint_push_get_list(int type) -{ - if (type == UNDO_PAINT_IMAGE) { - if (ImageUndoStack.current) { - return &ImageUndoStack.current->elems; - } - } - else if (type == UNDO_PAINT_MESH) { - if (MeshUndoStack.current) { - return &MeshUndoStack.current->elems; - } - } - - return NULL; -} - -void undo_paint_push_count_alloc(int type, int size) -{ - if (type == UNDO_PAINT_IMAGE) - ImageUndoStack.current->undosize += size; - else if (type == UNDO_PAINT_MESH) - MeshUndoStack.current->undosize += size; -} - -void ED_undo_paint_push_end(int type) -{ - if (type == UNDO_PAINT_IMAGE) - undo_stack_push_end(&ImageUndoStack); - else if (type == UNDO_PAINT_MESH) - undo_stack_push_end(&MeshUndoStack); -} - -int ED_undo_paint_step(bContext *C, int type, int step, const char *name) -{ - if (type == UNDO_PAINT_IMAGE) - return undo_stack_step(C, &ImageUndoStack, step, name); - else if (type == UNDO_PAINT_MESH) - return undo_stack_step(C, &MeshUndoStack, step, name); - - return 0; -} - -static void undo_step_num(bContext *C, UndoStack *stack, int step) -{ - UndoElem *uel; - int a = 0; - int curnum = BLI_findindex(&stack->elems, stack->current); - - for (uel = stack->elems.first; uel; uel = uel->next, a++) { - if (a == step) break; - } - - if (curnum > a) { - while (a++ != curnum) - undo_stack_step(C, stack, 1, NULL); - } - else if (curnum < a) { - while (a-- != curnum) - undo_stack_step(C, stack, -1, NULL); - } -} - -void ED_undo_paint_step_num(bContext *C, int type, int step) -{ - if (type == UNDO_PAINT_IMAGE) - undo_step_num(C, &ImageUndoStack, step); - else if (type == UNDO_PAINT_MESH) - undo_step_num(C, &MeshUndoStack, step); -} - -static char *undo_stack_get_name(UndoStack *stack, int nr, bool *r_active) -{ - UndoElem *uel; - - if (r_active) *r_active = false; - - uel = BLI_findlink(&stack->elems, nr); - if (uel) { - if (r_active && (uel == stack->current)) { - *r_active = true; - } - return uel->name; - } - - return NULL; -} - -const char *ED_undo_paint_get_name(bContext *C, int type, int nr, bool *r_active) -{ - - if (type == UNDO_PAINT_IMAGE) { - undo_stack_cleanup(&ImageUndoStack, C); - return undo_stack_get_name(&ImageUndoStack, nr, r_active); - } - else if (type == UNDO_PAINT_MESH) { - undo_stack_cleanup(&MeshUndoStack, C); - return undo_stack_get_name(&MeshUndoStack, nr, r_active); - } - return NULL; -} - -bool ED_undo_paint_empty(int type) -{ - UndoStack *stack; - - if (type == UNDO_PAINT_IMAGE) - stack = &ImageUndoStack; - else if (type == UNDO_PAINT_MESH) - stack = &MeshUndoStack; - else - return true; - - if (stack->current == NULL) { - return true; - } - - return false; -} - -bool ED_undo_paint_is_valid(int type, const char *name) -{ - UndoStack *stack; - - if (type == UNDO_PAINT_IMAGE) - stack = &ImageUndoStack; - else if (type == UNDO_PAINT_MESH) - stack = &MeshUndoStack; - else - return 0; - - if (stack->current == NULL) { - /* pass */ - } - else { - if (name && STREQ(stack->current->name, name)) - return 1; - else - return stack->elems.first != stack->elems.last; - } - return 0; -} - -void ED_undo_paint_free(void) -{ - undo_stack_free(&ImageUndoStack); - undo_stack_free(&MeshUndoStack); -} diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c index 1ec1e052d43..0f22973c45d 100644 --- a/source/blender/editors/sculpt_paint/paint_utils.c +++ b/source/blender/editors/sculpt_paint/paint_utils.c @@ -468,7 +468,7 @@ void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_pr unsigned int totpoly = me->totpoly; if (dm->getLoopDataArray(dm, CD_MLOOPUV)) { - view3d_set_viewcontext(C, &vc); + ED_view3d_viewcontext_init(C, &vc); view3d_operator_needs_opengl(C); diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 0c1df71b1aa..12fe55fb956 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -55,6 +55,8 @@ #include "BKE_brush.h" #include "BKE_context.h" #include "BKE_deform.h" +#include "BKE_global.h" +#include "BKE_main.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" #include "BKE_object_deform.h" @@ -940,6 +942,9 @@ static void do_weight_paint_vertex( /* Toggle operator for turning vertex paint mode on or off (copied from sculpt.c) */ static void vertex_paint_init_session(const EvaluationContext *eval_ctx, Scene *scene, Object *ob) { + /* Create persistent sculpt mode data */ + BKE_sculpt_toolsettings_data_ensure(scene); + if (ob->sculpt == NULL) { ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session"); BKE_sculpt_update_mesh_elements(eval_ctx, scene, scene->toolsettings->sculpt, ob, 0, false); @@ -1024,78 +1029,193 @@ static void vertex_paint_init_session_data(const ToolSettings *ts, Object *ob) } -/* *************** set wpaint operator ****************** */ +/* -------------------------------------------------------------------- */ +/** \name Enter Vertex/Weight Paint Mode + * \{ */ -/** - * \note Keep in sync with #vpaint_mode_toggle_exec - */ -static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op) +static void ed_vwpaintmode_enter_generic( + const EvaluationContext *eval_ctx, wmWindowManager *wm, Scene *scene, + Object *ob, const eObjectMode mode_flag) { - Object *ob = CTX_data_active_object(C); - const int mode_flag = OB_MODE_WEIGHT_PAINT; - const bool is_mode_set = (ob->mode & mode_flag) != 0; - Scene *scene = CTX_data_scene(C); - VPaint *wp = scene->toolsettings->wpaint; - Mesh *me; + ob->mode |= mode_flag; + Mesh *me = BKE_mesh_from_object(ob); - if (!is_mode_set) { - if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) { - return OPERATOR_CANCELLED; - } - } + if (mode_flag == OB_MODE_VERTEX_PAINT) { + const ePaintMode paint_mode = ePaintVertex; + ED_mesh_color_ensure(me, NULL); - me = BKE_mesh_from_object(ob); + if (scene->toolsettings->vpaint == NULL) { + scene->toolsettings->vpaint = new_vpaint(); + } - if (ob->mode & mode_flag) { - ob->mode &= ~mode_flag; + Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode); + paint_cursor_start_explicit(paint, wm, vertex_paint_poll); + BKE_paint_init(scene, paint_mode, PAINT_CURSOR_VERTEX_PAINT); + } + else if (mode_flag == OB_MODE_WEIGHT_PAINT) { + const ePaintMode paint_mode = ePaintWeight; - if (me->editflag & ME_EDIT_PAINT_VERT_SEL) { - BKE_mesh_flush_select_from_verts(me); - } - else if (me->editflag & ME_EDIT_PAINT_FACE_SEL) { - BKE_mesh_flush_select_from_polys(me); + if (scene->toolsettings->wpaint == NULL) { + scene->toolsettings->wpaint = new_vpaint(); } + Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode); + paint_cursor_start_explicit(paint, wm, weight_paint_poll); + BKE_paint_init(scene, paint_mode, PAINT_CURSOR_WEIGHT_PAINT); + /* weight paint specific */ - ED_mesh_mirror_spatial_table(NULL, NULL, NULL, NULL, 'e'); - ED_mesh_mirror_topo_table(NULL, NULL, 'e'); + ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 's'); + ED_vgroup_sync_from_pose(ob); + } + else { + BLI_assert(0); + } - /* If the cache is not released by a cancel or a done, free it now. */ + /* Create vertex/weight paint mode session data */ + if (ob->sculpt) { if (ob->sculpt->cache) { sculpt_cache_free(ob->sculpt->cache); ob->sculpt->cache = NULL; } - BKE_sculptsession_free(ob); + } - paint_cursor_delete_textures(); + vertex_paint_init_session(eval_ctx, scene, ob); +} + +void ED_object_vpaintmode_enter_ex( + const EvaluationContext *eval_ctx, wmWindowManager *wm, + Scene *scene, Object *ob) +{ + ed_vwpaintmode_enter_generic( + eval_ctx, wm, scene, ob, OB_MODE_VERTEX_PAINT); +} +void ED_object_vpaintmode_enter(struct bContext *C) +{ + EvaluationContext eval_ctx; + CTX_data_eval_ctx(C, &eval_ctx); + wmWindowManager *wm = CTX_wm_manager(C); + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + ED_object_vpaintmode_enter_ex(&eval_ctx, wm, scene, ob); +} + +void ED_object_wpaintmode_enter_ex( + const EvaluationContext *eval_ctx, wmWindowManager *wm, + Scene *scene, Object *ob) +{ + ed_vwpaintmode_enter_generic( + eval_ctx, wm, scene, ob, OB_MODE_WEIGHT_PAINT); +} +void ED_object_wpaintmode_enter(struct bContext *C) +{ + EvaluationContext eval_ctx; + CTX_data_eval_ctx(C, &eval_ctx); + wmWindowManager *wm = CTX_wm_manager(C); + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + ED_object_wpaintmode_enter_ex(&eval_ctx, wm, scene, ob); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Exit Vertex/Weight Paint Mode + * \{ */ + +static void ed_vwpaintmode_exit_generic( + Object *ob, const eObjectMode mode_flag) +{ + Mesh *me = BKE_mesh_from_object(ob); + ob->mode &= ~mode_flag; + + if (mode_flag == OB_MODE_VERTEX_PAINT) { + if (me->editflag & ME_EDIT_PAINT_FACE_SEL) { + BKE_mesh_flush_select_from_polys(me); + } + else if (me->editflag & ME_EDIT_PAINT_VERT_SEL) { + BKE_mesh_flush_select_from_verts(me); + } + } + else if (mode_flag == OB_MODE_WEIGHT_PAINT) { + if (me->editflag & ME_EDIT_PAINT_VERT_SEL) { + BKE_mesh_flush_select_from_verts(me); + } + else if (me->editflag & ME_EDIT_PAINT_FACE_SEL) { + BKE_mesh_flush_select_from_polys(me); + } } else { - EvaluationContext eval_ctx; + BLI_assert(0); + } - CTX_data_eval_ctx(C, &eval_ctx); + /* If the cache is not released by a cancel or a done, free it now. */ + if (ob->sculpt && ob->sculpt->cache) { + sculpt_cache_free(ob->sculpt->cache); + ob->sculpt->cache = NULL; + } - ob->mode |= mode_flag; + BKE_sculptsession_free(ob); - if (wp == NULL) - wp = scene->toolsettings->wpaint = new_vpaint(); + paint_cursor_delete_textures(); - paint_cursor_start(C, weight_paint_poll); + if (mode_flag == OB_MODE_WEIGHT_PAINT) { + ED_mesh_mirror_spatial_table(NULL, NULL, NULL, NULL, 'e'); + ED_mesh_mirror_topo_table(NULL, NULL, 'e'); + } +} - BKE_paint_init(scene, ePaintWeight, PAINT_CURSOR_WEIGHT_PAINT); +void ED_object_vpaintmode_exit_ex(Object *ob) +{ + ed_vwpaintmode_exit_generic(ob, OB_MODE_VERTEX_PAINT); +} +void ED_object_vpaintmode_exit(struct bContext *C) +{ + Object *ob = CTX_data_active_object(C); + ED_object_vpaintmode_exit_ex(ob); +} - /* weight paint specific */ - ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 's'); - ED_vgroup_sync_from_pose(ob); +void ED_object_wpaintmode_exit_ex(Object *ob) +{ + ed_vwpaintmode_exit_generic(ob, OB_MODE_WEIGHT_PAINT); +} +void ED_object_wpaintmode_exit(struct bContext *C) +{ + Object *ob = CTX_data_active_object(C); + ED_object_wpaintmode_exit_ex(ob); +} - /* Create vertex/weight paint mode session data */ - if (ob->sculpt) { - BKE_sculptsession_free(ob); +/** \} */ + +/* *************** set wpaint operator ****************** */ + +/** + * \note Keep in sync with #vpaint_mode_toggle_exec + */ +static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op) +{ + Object *ob = CTX_data_active_object(C); + const int mode_flag = OB_MODE_WEIGHT_PAINT; + const bool is_mode_set = (ob->mode & mode_flag) != 0; + Scene *scene = CTX_data_scene(C); + + if (!is_mode_set) { + if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) { + return OPERATOR_CANCELLED; } - vertex_paint_init_session(&eval_ctx, scene, ob); } - BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_ALL); + Mesh *me = BKE_mesh_from_object(ob); + + if (is_mode_set) { + ED_object_wpaintmode_exit_ex(ob); + } + else { + EvaluationContext eval_ctx; + CTX_data_eval_ctx(C, &eval_ctx); + wmWindowManager *wm = CTX_wm_manager(C); + ED_object_wpaintmode_enter_ex(&eval_ctx, wm, scene, ob); + } /* Weightpaint works by overriding colors in mesh, * so need to make sure we recalc on enter and @@ -1285,14 +1405,11 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo bool *defbase_sel; SculptSession *ss = ob->sculpt; VPaint *vp = CTX_data_tool_settings(C)->wpaint; - EvaluationContext eval_ctx; if (ED_wpaint_ensure_data(C, op->reports, WPAINT_ENSURE_MIRROR, &vgroup_index) == false) { return false; } - CTX_data_eval_ctx(C, &eval_ctx); - { /* check if we are attempting to paint onto a locked vertex group, * and other options disallow it from doing anything useful */ @@ -1339,7 +1456,7 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo /* make mode data storage */ wpd = MEM_callocN(sizeof(struct WPaintData), "WPaintData"); paint_stroke_set_mode_data(stroke, wpd); - view3d_set_viewcontext(C, &wpd->vc); + ED_view3d_viewcontext_init(C, &wpd->vc); view_angle_limits_init(&wpd->normal_angle_precalc, vp->paint.brush->falloff_angle, (vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0); @@ -1390,6 +1507,9 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo wpd->precomputed_weight = MEM_mallocN(sizeof(float) * me->totvert, __func__); } + EvaluationContext eval_ctx; + CTX_data_eval_ctx(C, &eval_ctx); + /* If not previously created, create vertex/weight paint mode session data */ vertex_paint_init_session(&eval_ctx, scene, ob); vwpaint_update_cache_invariants(C, vp, ss, op, mouse); @@ -1832,7 +1952,8 @@ static void wpaint_paint_leaves( /* threaded loop over nodes */ SculptThreadedTaskData data = { - .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, .vp = vp, .wpd = wpd, .wpi = wpi, .me = me, .C = C, + .C = C, .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, + .vp = vp, .wpd = wpd, .wpi = wpi, .me = me, }; /* Use this so average can modify its weight without touching the brush. */ @@ -2212,8 +2333,6 @@ static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op) const int mode_flag = OB_MODE_VERTEX_PAINT; const bool is_mode_set = (ob->mode & mode_flag) != 0; Scene *scene = CTX_data_scene(C); - VPaint *vp = scene->toolsettings->vpaint; - Mesh *me; if (!is_mode_set) { if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) { @@ -2221,54 +2340,17 @@ static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op) } } - me = BKE_mesh_from_object(ob); + Mesh *me = BKE_mesh_from_object(ob); /* toggle: end vpaint */ if (is_mode_set) { - ob->mode &= ~mode_flag; - - if (me->editflag & ME_EDIT_PAINT_FACE_SEL) { - BKE_mesh_flush_select_from_polys(me); - } - else if (me->editflag & ME_EDIT_PAINT_VERT_SEL) { - BKE_mesh_flush_select_from_verts(me); - } - - /* If the cache is not released by a cancel or a done, free it now. */ - if (ob->sculpt->cache) { - sculpt_cache_free(ob->sculpt->cache); - ob->sculpt->cache = NULL; - } - - BKE_sculptsession_free(ob); - - paint_cursor_delete_textures(); + ED_object_vpaintmode_exit_ex(ob); } else { EvaluationContext eval_ctx; - CTX_data_eval_ctx(C, &eval_ctx); - - ob->mode |= mode_flag; - - ED_mesh_color_ensure(me, NULL); - - if (vp == NULL) - vp = scene->toolsettings->vpaint = new_vpaint(); - - paint_cursor_start(C, vertex_paint_poll); - - BKE_paint_init(scene, ePaintVertex, PAINT_CURSOR_VERTEX_PAINT); - - /* Create vertex/weight paint mode session data */ - if (ob->sculpt) { - if (ob->sculpt->cache) { - sculpt_cache_free(ob->sculpt->cache); - ob->sculpt->cache = NULL; - } - BKE_sculptsession_free(ob); - } - vertex_paint_init_session(&eval_ctx, scene, ob); + wmWindowManager *wm = CTX_wm_manager(C); + ED_object_vpaintmode_enter_ex(&eval_ctx, wm, scene, ob); } BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_ALL); @@ -2376,7 +2458,7 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f /* make mode data storage */ vpd = MEM_callocN(sizeof(*vpd), "VPaintData"); paint_stroke_set_mode_data(stroke, vpd); - view3d_set_viewcontext(C, &vpd->vc); + ED_view3d_viewcontext_init(C, &vpd->vc); view_angle_limits_init(&vpd->normal_angle_precalc, vp->paint.brush->falloff_angle, (vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0); @@ -2871,8 +2953,8 @@ static void vpaint_paint_leaves( const Brush *brush = ob->sculpt->cache->brush; SculptThreadedTaskData data = { - .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, .vp = vp, .vpd = vpd, - .lcol = (uint *)me->mloopcol, .me = me, .C = C, + .C = C, .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, .vp = vp, .vpd = vpd, + .lcol = (uint *)me->mloopcol, .me = me, }; ParallelRangeSettings settings; BLI_parallel_range_settings_defaults(&settings); diff --git a/source/blender/editors/sculpt_paint/paint_vertex_proj.c b/source/blender/editors/sculpt_paint/paint_vertex_proj.c index 999c9dc7880..336f851d4c1 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_proj.c +++ b/source/blender/editors/sculpt_paint/paint_vertex_proj.c @@ -78,8 +78,9 @@ struct VertProjUpdate { /* -------------------------------------------------------------------- */ /* Internal Init */ -static void vpaint_proj_dm_map_cosnos_init__map_cb(void *userData, int index, const float co[3], - const float no_f[3], const short no_s[3]) +static void vpaint_proj_dm_map_cosnos_init__map_cb( + void *userData, int index, const float co[3], + const float no_f[3], const short no_s[3]) { struct VertProjHandle *vp_handle = userData; DMCoNo *co_no = &vp_handle->vcosnos[index]; @@ -131,8 +132,9 @@ static void vpaint_proj_dm_map_cosnos_init( /* Same as init but take mouse location into account */ -static void vpaint_proj_dm_map_cosnos_update__map_cb(void *userData, int index, const float co[3], - const float no_f[3], const short no_s[3]) +static void vpaint_proj_dm_map_cosnos_update__map_cb( + void *userData, int index, const float co[3], + const float no_f[3], const short no_s[3]) { struct VertProjUpdate *vp_update = userData; struct VertProjHandle *vp_handle = vp_update->vp_handle; @@ -144,9 +146,10 @@ static void vpaint_proj_dm_map_cosnos_update__map_cb(void *userData, int index, /* first find distance to this vertex */ float co_ss[2]; /* screenspace */ - if (ED_view3d_project_float_object(vp_update->ar, - co, co_ss, - V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) + if (ED_view3d_project_float_object( + vp_update->ar, + co, co_ss, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) { const float dist_sq = len_squared_v2v2(vp_update->mval_fl, co_ss); if (dist_sq > vp_handle->dists_sq[index]) { diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c index 1348847167c..3892b776440 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c +++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c @@ -182,7 +182,7 @@ static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *even Mesh *me; bool changed = false; - view3d_set_viewcontext(C, &vc); + ED_view3d_viewcontext_init(C, &vc); me = BKE_mesh_from_object(vc.obact); if (me && me->dvert && vc.v3d && vc.rv3d && (vc.obact->actdef != 0)) { @@ -297,7 +297,7 @@ static const EnumPropertyItem *weight_paint_sample_enum_itemf( ViewContext vc; Mesh *me; - view3d_set_viewcontext(C, &vc); + ED_view3d_viewcontext_init(C, &vc); me = BKE_mesh_from_object(vc.obact); if (me && me->dvert && vc.v3d && vc.rv3d && vc.obact->defbase.first) { @@ -366,7 +366,7 @@ static int weight_sample_group_exec(bContext *C, wmOperator *op) { int type = RNA_enum_get(op->ptr, "group"); ViewContext vc; - view3d_set_viewcontext(C, &vc); + ED_view3d_viewcontext_init(C, &vc); BLI_assert(type + 1 >= 0); vc.obact->actdef = type + 1; diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c index 4d70d82d5c6..51cd759b260 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c +++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c @@ -43,6 +43,7 @@ #include "BKE_modifier.h" #include "BKE_object_deform.h" #include "BKE_report.h" +#include "BKE_object.h" #include "WM_api.h" #include "WM_types.h" @@ -58,7 +59,6 @@ bool ED_wpaint_ensure_data( bContext *C, struct ReportList *reports, enum eWPaintFlag flag, struct WPaintVGroupIndex *vgroup_index) { - Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); Mesh *me = BKE_mesh_from_object(ob); @@ -67,7 +67,7 @@ bool ED_wpaint_ensure_data( vgroup_index->mirror = -1; } - if (scene->obedit) { + if (BKE_object_is_in_editmode(ob)) { return false; } @@ -308,4 +308,4 @@ float ED_wpaint_blend_tool( } } -/** \} */
\ No newline at end of file +/** \} */ diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index c9d550aa4bd..4a9d2597415 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -37,7 +37,7 @@ #include "BLI_math.h" #include "BLI_blenlib.h" -#include "BLI_dial.h" +#include "BLI_dial_2d.h" #include "BLI_task.h" #include "BLI_utildefines.h" #include "BLI_ghash.h" @@ -60,6 +60,7 @@ #include "BKE_image.h" #include "BKE_key.h" #include "BKE_library.h" +#include "BKE_main.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" #include "BKE_modifier.h" @@ -1562,7 +1563,7 @@ static float neighbor_average_mask(SculptSession *ss, unsigned vert) static void bmesh_neighbor_average(float avg[3], BMVert *v) { /* logic for 3 or more is identical */ - const int vfcount = BM_vert_face_count_ex(v, 3); + const int vfcount = BM_vert_face_count_at_most(v, 3); /* Don't modify corner vertices */ if (vfcount > 1) { @@ -1577,7 +1578,7 @@ static void bmesh_neighbor_average(float avg[3], BMVert *v) for (i = 0; i < ARRAY_SIZE(adj_v); i++) { const BMVert *v_other = adj_v[i]; - if (vfcount != 2 || BM_vert_face_count_ex(v_other, 2) <= 2) { + if (vfcount != 2 || BM_vert_face_count_at_most(v_other, 2) <= 2) { add_v3_v3(avg, v_other->co); total++; } @@ -4595,19 +4596,17 @@ static bool sculpt_any_smooth_mode(const Brush *brush, (brush->mask_tool == BRUSH_MASK_SMOOTH))); } -static void sculpt_stroke_modifiers_check(const bContext *C, Object *ob) +static void sculpt_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *brush) { SculptSession *ss = ob->sculpt; if (ss->kb || ss->modifiers_active) { EvaluationContext eval_ctx; - Sculpt *sd = CTX_data_tool_settings(C)->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - CTX_data_eval_ctx(C, &eval_ctx); - - BKE_sculpt_update_mesh_elements(&eval_ctx, CTX_data_scene(C), sd, ob, - sculpt_any_smooth_mode(brush, ss->cache, 0), false); + Scene *scene = CTX_data_scene(C); + Sculpt *sd = scene->toolsettings->sculpt; + bool need_pmap = sculpt_any_smooth_mode(brush, ss->cache, 0); + BKE_sculpt_update_mesh_elements(&eval_ctx, scene, sd, ob, need_pmap, false); } } @@ -4728,7 +4727,7 @@ bool sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2]) bool original; ViewContext vc; - view3d_set_viewcontext(C, &vc); + ED_view3d_viewcontext_init(C, &vc); ob = vc.obact; @@ -4736,7 +4735,9 @@ bool sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2]) cache = ss->cache; original = (cache) ? cache->original : 0; - sculpt_stroke_modifiers_check(C, ob); + const Brush *brush = BKE_paint_brush(BKE_paint_get_active_from_context(C)); + + sculpt_stroke_modifiers_check(C, ob, brush); depth = sculpt_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, original); @@ -4762,7 +4763,6 @@ bool sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2]) } if (hit == false) { - const Brush *brush = BKE_paint_brush(BKE_paint_get_active_from_context(C)); if (ELEM(brush->falloff_shape, PAINT_FALLOFF_SHAPE_TUBE)) { SculptFindNearestToRayData srd = { .original = original, @@ -4953,7 +4953,7 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *UNUSED(st SculptSession *ss = ob->sculpt; const Brush *brush = BKE_paint_brush(&sd->paint); - sculpt_stroke_modifiers_check(C, ob); + sculpt_stroke_modifiers_check(C, ob, brush); sculpt_update_cache_variants(C, sd, ob, itemptr); sculpt_restore_mesh(sd, ob); @@ -5028,7 +5028,7 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str BLI_assert(brush == ss->cache->brush); /* const, so we shouldn't change. */ ups->draw_inverted = false; - sculpt_stroke_modifiers_check(C, ob); + sculpt_stroke_modifiers_check(C, ob, brush); /* Alt-Smooth */ if (ss->cache->alt_smooth) { @@ -5047,7 +5047,7 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str sculpt_cache_free(ss->cache); ss->cache = NULL; - sculpt_undo_push_end(C); + sculpt_undo_push_end(); BKE_pbvh_update(ss->pbvh, PBVH_UpdateOriginalBB, NULL); @@ -5255,24 +5255,21 @@ void sculpt_dyntopo_node_layers_add(SculptSession *ss) } -void sculpt_update_after_dynamic_topology_toggle(bContext *C) +void sculpt_update_after_dynamic_topology_toggle( + const EvaluationContext *eval_ctx, + Scene *scene, Object *ob) { - Scene *scene = CTX_data_scene(C); - Object *ob = CTX_data_active_object(C); - EvaluationContext eval_ctx; Sculpt *sd = scene->toolsettings->sculpt; - CTX_data_eval_ctx(C, &eval_ctx); - /* Create the PBVH */ - BKE_sculpt_update_mesh_elements(&eval_ctx, scene, sd, ob, false, false); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + BKE_sculpt_update_mesh_elements(eval_ctx, scene, sd, ob, false, false); + WM_main_add_notifier(NC_OBJECT | ND_DRAW, ob); } -void sculpt_dynamic_topology_enable(bContext *C) +void sculpt_dynamic_topology_enable_ex( + const EvaluationContext *eval_ctx, + Scene *scene, Object *ob) { - Scene *scene = CTX_data_scene(C); - Object *ob = CTX_data_active_object(C); SculptSession *ss = ob->sculpt; Mesh *me = ob->data; const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me); @@ -5308,17 +5305,17 @@ void sculpt_dynamic_topology_enable(bContext *C) ss->bm_log = BM_log_create(ss->bm); /* Refresh */ - sculpt_update_after_dynamic_topology_toggle(C); + sculpt_update_after_dynamic_topology_toggle(eval_ctx, scene, ob); } /* Free the sculpt BMesh and BMLog * * If 'unode' is given, the BMesh's data is copied out to the unode * before the BMesh is deleted so that it can be restored from */ -void sculpt_dynamic_topology_disable(bContext *C, - SculptUndoNode *unode) +void sculpt_dynamic_topology_disable_ex( + const EvaluationContext *eval_ctx, + Scene *scene, Object *ob, SculptUndoNode *unode) { - Object *ob = CTX_data_active_object(C); SculptSession *ss = ob->sculpt; Mesh *me = ob->data; @@ -5367,28 +5364,59 @@ void sculpt_dynamic_topology_disable(bContext *C, } /* Refresh */ - sculpt_update_after_dynamic_topology_toggle(C); + sculpt_update_after_dynamic_topology_toggle(eval_ctx, scene, ob); } +void sculpt_dynamic_topology_disable(bContext *C, SculptUndoNode *unode) +{ + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + EvaluationContext eval_ctx; + CTX_data_eval_ctx(C, &eval_ctx); + sculpt_dynamic_topology_disable_ex(&eval_ctx, scene, ob, unode); +} + +static void sculpt_dynamic_topology_disable_with_undo( + const EvaluationContext *eval_ctx, Scene *scene, Object *ob) +{ + SculptSession *ss = ob->sculpt; + if (ss->bm) { + sculpt_undo_push_begin("Dynamic topology disable"); + sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_END); + sculpt_dynamic_topology_disable_ex(eval_ctx, scene, ob, NULL); + sculpt_undo_push_end(); + } +} + +static void sculpt_dynamic_topology_enable_with_undo( + const EvaluationContext *eval_ctx, + Scene *scene, Object *ob) +{ + SculptSession *ss = ob->sculpt; + if (ss->bm == NULL) { + sculpt_undo_push_begin("Dynamic topology enable"); + sculpt_dynamic_topology_enable_ex(eval_ctx, scene, ob); + sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN); + sculpt_undo_push_end(); + } +} static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(op)) { + Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); SculptSession *ss = ob->sculpt; + EvaluationContext eval_ctx; + CTX_data_eval_ctx(C, &eval_ctx); WM_cursor_wait(1); if (ss->bm) { - sculpt_undo_push_begin("Dynamic topology disable"); - sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_END); - sculpt_dynamic_topology_disable(C, NULL); + sculpt_dynamic_topology_disable_with_undo(&eval_ctx, scene, ob); } else { - sculpt_undo_push_begin("Dynamic topology enable"); - sculpt_dynamic_topology_enable(C); - sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN); + sculpt_dynamic_topology_enable_with_undo(&eval_ctx, scene, ob); } - sculpt_undo_push_end(C); WM_cursor_wait(0); @@ -5431,13 +5459,11 @@ static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, enum eDynTopoW return OPERATOR_INTERFACE; } -static enum eDynTopoWarnFlag sculpt_dynamic_topology_check(bContext *C) +static enum eDynTopoWarnFlag sculpt_dynamic_topology_check(Scene *scene, Object *ob) { - Object *ob = CTX_data_active_object(C); Mesh *me = ob->data; SculptSession *ss = ob->sculpt; - Scene *scene = CTX_data_scene(C); enum eDynTopoWarnFlag flag = 0; BLI_assert(ss->bm == NULL); @@ -5482,7 +5508,8 @@ static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, co SculptSession *ss = ob->sculpt; if (!ss->bm) { - enum eDynTopoWarnFlag flag = sculpt_dynamic_topology_check(C); + Scene *scene = CTX_data_scene(C); + enum eDynTopoWarnFlag flag = sculpt_dynamic_topology_check(scene, ob); if (flag) { /* The mesh has customdata that will be lost, let the user confirm this is OK */ @@ -5576,7 +5603,7 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op)) /* Finish undo */ BM_log_all_added(ss->bm, ss->bm_log); - sculpt_undo_push_end(C); + sculpt_undo_push_end(); /* Redraw */ sculpt_pbvh_clear(ob); @@ -5599,177 +5626,215 @@ static void SCULPT_OT_symmetrize(wmOperatorType *ot) /**** Toggle operator for turning sculpt mode on or off ****/ -static void sculpt_init_session(const bContext *C, Scene *scene, Object *ob) +static void sculpt_init_session(const EvaluationContext *eval_ctx, Scene *scene, Object *ob) { - EvaluationContext eval_ctx; - - CTX_data_eval_ctx(C, &eval_ctx); + /* Create persistent sculpt mode data */ + BKE_sculpt_toolsettings_data_ensure(scene); ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session"); - - BKE_sculpt_update_mesh_elements(&eval_ctx, scene, scene->toolsettings->sculpt, ob, 0, false); + ob->sculpt->mode_type = OB_MODE_SCULPT; + BKE_sculpt_update_mesh_elements(eval_ctx, scene, scene->toolsettings->sculpt, ob, 0, false); } +static int ed_object_sculptmode_flush_recalc_flag(Scene *scene, Object *ob, MultiresModifierData *mmd) +{ + int flush_recalc = 0; + /* multires in sculpt mode could have different from object mode subdivision level */ + flush_recalc |= mmd && mmd->sculptlvl != mmd->lvl; + /* if object has got active modifiers, it's dm could be different in sculpt mode */ + flush_recalc |= sculpt_has_active_modifiers(scene, ob); + return flush_recalc; +} -static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op) +void ED_object_sculptmode_enter_ex( + const EvaluationContext *eval_ctx, + Scene *scene, Object *ob, + ReportList *reports) { - Scene *scene = CTX_data_scene(C); - ToolSettings *ts = CTX_data_tool_settings(C); - Object *ob = CTX_data_active_object(C); const int mode_flag = OB_MODE_SCULPT; - const bool is_mode_set = (ob->mode & mode_flag) != 0; - Mesh *me; + Mesh *me = BKE_mesh_from_object(ob); + + /* Enter sculptmode */ + ob->mode |= mode_flag; + MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob); - int flush_recalc = 0; - if (!is_mode_set) { - if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) { - return OPERATOR_CANCELLED; - } + const int flush_recalc = ed_object_sculptmode_flush_recalc_flag(scene, ob, mmd); + + if (flush_recalc) + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + + /* Create sculpt mode session data */ + if (ob->sculpt) { + BKE_sculptsession_free(ob); } - me = BKE_mesh_from_object(ob); + sculpt_init_session(eval_ctx, scene, ob); - /* multires in sculpt mode could have different from object mode subdivision level */ - flush_recalc |= mmd && mmd->sculptlvl != mmd->lvl; - /* if object has got active modifiers, it's dm could be different in sculpt mode */ - flush_recalc |= sculpt_has_active_modifiers(scene, ob); + /* Mask layer is required */ + if (mmd) { + /* XXX, we could attempt to support adding mask data mid-sculpt mode (with multi-res) + * but this ends up being quite tricky (and slow) */ + BKE_sculpt_mask_layers_ensure(ob, mmd); + } - if (is_mode_set) { - if (mmd) - multires_force_update(ob); + if (!(fabsf(ob->size[0] - ob->size[1]) < 1e-4f && fabsf(ob->size[1] - ob->size[2]) < 1e-4f)) { + BKE_report(reports, RPT_WARNING, + "Object has non-uniform scale, sculpting may be unpredictable"); + } + else if (is_negative_m4(ob->obmat)) { + BKE_report(reports, RPT_WARNING, + "Object has negative scale, sculpting may be unpredictable"); + } - /* Always for now, so leaving sculpt mode always ensures scene is in - * a consistent state. - */ - if (true || flush_recalc || (ob->sculpt && ob->sculpt->bm)) { - DEG_id_tag_update(&ob->id, OB_RECALC_DATA); - } + Paint *paint = BKE_paint_get_active_from_paintmode(scene, ePaintSculpt); + BKE_paint_init(scene, ePaintSculpt, PAINT_CURSOR_SCULPT); - if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) { - /* Dynamic topology must be disabled before exiting sculpt - * mode to ensure the undo stack stays in a consistent - * state */ - sculpt_dynamic_topology_toggle_exec(C, NULL); + paint_cursor_start_explicit(paint, G.main->wm.first, sculpt_poll_view3d); - /* store so we know to re-enable when entering sculpt mode */ - me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY; + /* Check dynamic-topology flag; re-enter dynamic-topology mode when changing modes, + * As long as no data was added that is not supported. */ + if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) { + const char *message_unsupported = NULL; + if (me->totloop != me->totpoly * 3) { + message_unsupported = TIP_("non-triangle face"); + } + else if (mmd != NULL) { + message_unsupported = TIP_("multi-res modifier"); + } + else { + enum eDynTopoWarnFlag flag = sculpt_dynamic_topology_check(scene, ob); + if (flag == 0) { + /* pass */ + } + else if (flag & DYNTOPO_WARN_VDATA) { + message_unsupported = TIP_("vertex data"); + } + else if (flag & DYNTOPO_WARN_EDATA) { + message_unsupported = TIP_("edge data"); + } + else if (flag & DYNTOPO_WARN_LDATA) { + message_unsupported = TIP_("face data"); + } + else if (flag & DYNTOPO_WARN_MODIFIER) { + message_unsupported = TIP_("constructive modifier"); + } + else { + BLI_assert(0); + } } - /* Leave sculptmode */ - ob->mode &= ~mode_flag; + if (message_unsupported == NULL) { + /* undo push is needed to prevent memory leak */ + sculpt_undo_push_begin("Dynamic topology enable"); + sculpt_dynamic_topology_enable_ex(eval_ctx, scene, ob); + sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN); + } + else { + BKE_reportf(reports, RPT_WARNING, + "Dynamic Topology found: %s, disabled", + message_unsupported); + me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY; + } + } - BKE_sculptsession_free(ob); + // ED_workspace_object_mode_sync_from_object(G.main->wm.first, workspace, ob); - paint_cursor_delete_textures(); + /* VBO no longer valid */ + if (ob->derivedFinal) { + GPU_drawobject_free(ob->derivedFinal); } - else { - /* Enter sculptmode */ - ob->mode |= mode_flag; +} - if (flush_recalc) - DEG_id_tag_update(&ob->id, OB_RECALC_DATA); +void ED_object_sculptmode_enter(struct bContext *C, ReportList *reports) +{ + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + EvaluationContext eval_ctx; + CTX_data_eval_ctx(C, &eval_ctx); + ED_object_sculptmode_enter_ex(&eval_ctx, scene, ob, reports); +} - /* Create persistent sculpt mode data */ - if (!ts->sculpt) { - ts->sculpt = MEM_callocN(sizeof(Sculpt), "sculpt mode data"); +void ED_object_sculptmode_exit_ex( + const EvaluationContext *eval_ctx, + Scene *scene, Object *ob) +{ + const int mode_flag = OB_MODE_SCULPT; + Mesh *me = BKE_mesh_from_object(ob); - /* Turn on X plane mirror symmetry by default */ - ts->sculpt->paint.symmetry_flags |= PAINT_SYMM_X; - ts->sculpt->paint.flags |= PAINT_SHOW_BRUSH; + MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob); + if (mmd) { + multires_force_update(ob); + } - /* Make sure at least dyntopo subdivision is enabled */ - ts->sculpt->flags |= SCULPT_DYNTOPO_SUBDIVIDE | SCULPT_DYNTOPO_COLLAPSE; - } + /* Not needed for now. */ +#if 0 + const int flush_recalc = ed_object_sculptmode_flush_recalc_flag(scene, ob, mmd); +#endif - if (!ts->sculpt->detail_size) - ts->sculpt->detail_size = 12; - if (!ts->sculpt->detail_percent) - ts->sculpt->detail_percent = 25; - if (ts->sculpt->constant_detail == 0.0f) - ts->sculpt->constant_detail = 3.0f; + /* Always for now, so leaving sculpt mode always ensures scene is in + * a consistent state. + */ + if (true || /* flush_recalc || */ (ob->sculpt && ob->sculpt->bm)) { + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + } - /* Set sane default tiling offsets */ - if (!ts->sculpt->paint.tile_offset[0]) ts->sculpt->paint.tile_offset[0] = 1.0f; - if (!ts->sculpt->paint.tile_offset[1]) ts->sculpt->paint.tile_offset[1] = 1.0f; - if (!ts->sculpt->paint.tile_offset[2]) ts->sculpt->paint.tile_offset[2] = 1.0f; + if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) { + /* Dynamic topology must be disabled before exiting sculpt + * mode to ensure the undo stack stays in a consistent + * state */ + sculpt_dynamic_topology_disable_with_undo(eval_ctx, scene, ob); + /* store so we know to re-enable when entering sculpt mode */ + me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY; + } - /* Create sculpt mode session data */ - if (ob->sculpt) - BKE_sculptsession_free(ob); + /* Leave sculptmode */ + ob->mode &= ~mode_flag; - sculpt_init_session(C, scene, ob); + // ED_workspace_object_mode_sync_from_object(G.main->wm.first, workspace, ob); - /* Mask layer is required */ - if (mmd) { - /* XXX, we could attempt to support adding mask data mid-sculpt mode (with multi-res) - * but this ends up being quite tricky (and slow) */ - BKE_sculpt_mask_layers_ensure(ob, mmd); - } + BKE_sculptsession_free(ob); - if (!(fabsf(ob->size[0] - ob->size[1]) < 1e-4f && fabsf(ob->size[1] - ob->size[2]) < 1e-4f)) { - BKE_report(op->reports, RPT_WARNING, - "Object has non-uniform scale, sculpting may be unpredictable"); - } - else if (is_negative_m4(ob->obmat)) { - BKE_report(op->reports, RPT_WARNING, - "Object has negative scale, sculpting may be unpredictable"); - } + paint_cursor_delete_textures(); - BKE_paint_init(scene, ePaintSculpt, PAINT_CURSOR_SCULPT); + /* VBO no longer valid */ + if (ob->derivedFinal) { + GPU_drawobject_free(ob->derivedFinal); + } +} - paint_cursor_start(C, sculpt_poll_view3d); +void ED_object_sculptmode_exit(bContext *C) +{ + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + EvaluationContext eval_ctx; + CTX_data_eval_ctx(C, &eval_ctx); + ED_object_sculptmode_exit_ex(&eval_ctx, scene, ob); +} - /* Check dynamic-topology flag; re-enter dynamic-topology mode when changing modes, - * As long as no data was added that is not supported. */ - if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) { - const char *message_unsupported = NULL; - if (me->totloop != me->totpoly * 3) { - message_unsupported = TIP_("non-triangle face"); - } - else if (mmd != NULL) { - message_unsupported = TIP_("multi-res modifier"); - } - else { - enum eDynTopoWarnFlag flag = sculpt_dynamic_topology_check(C); - if (flag == 0) { - /* pass */ - } - else if (flag & DYNTOPO_WARN_VDATA) { - message_unsupported = TIP_("vertex data"); - } - else if (flag & DYNTOPO_WARN_EDATA) { - message_unsupported = TIP_("edge data"); - } - else if (flag & DYNTOPO_WARN_LDATA) { - message_unsupported = TIP_("face data"); - } - else if (flag & DYNTOPO_WARN_MODIFIER) { - message_unsupported = TIP_("constructive modifier"); - } - else { - BLI_assert(0); - } - } +static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + const int mode_flag = OB_MODE_SCULPT; + const bool is_mode_set = (ob->mode & mode_flag) != 0; - if (message_unsupported == NULL) { - /* undo push is needed to prevent memory leak */ - sculpt_undo_push_begin("Dynamic topology enable"); - sculpt_dynamic_topology_enable(C); - sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN); - } - else { - BKE_reportf(op->reports, RPT_WARNING, - "Dynamic Topology found: %s, disabled", - message_unsupported); - me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY; - } + if (!is_mode_set) { + if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) { + return OPERATOR_CANCELLED; } } - if (ob->derivedFinal) /* VBO no longer valid */ - GPU_drawobject_free(ob->derivedFinal); + EvaluationContext eval_ctx; + CTX_data_eval_ctx(C, &eval_ctx); + + if (is_mode_set) { + ED_object_sculptmode_exit_ex(&eval_ctx, scene, ob); + } + else { + ED_object_sculptmode_enter_ex(&eval_ctx, scene, ob, op->reports); + } WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene); @@ -5839,7 +5904,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op)) } MEM_freeN(nodes); - sculpt_undo_push_end(C); + sculpt_undo_push_end(); /* force rebuild of pbvh for better BB placement */ sculpt_pbvh_clear(ob); @@ -5871,12 +5936,14 @@ static void sample_detail(bContext *C, int ss_co[2]) float ray_start[3], ray_end[3], ray_normal[3], depth; SculptDetailRaycastData srd; float mouse[2] = {ss_co[0], ss_co[1]}; - view3d_set_viewcontext(C, &vc); + ED_view3d_viewcontext_init(C, &vc); sd = CTX_data_tool_settings(C)->sculpt; ob = vc.obact; - sculpt_stroke_modifiers_check(C, ob); + Brush *brush = BKE_paint_brush(&sd->paint); + + sculpt_stroke_modifiers_check(C, ob, brush); depth = sculpt_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, false); diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 5fb9eee805f..ba39d51700d 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -60,10 +60,19 @@ bool sculpt_stroke_get_location(struct bContext *C, float out[3], const float mo /* Dynamic topology */ void sculpt_pbvh_clear(Object *ob); void sculpt_dyntopo_node_layers_add(struct SculptSession *ss); -void sculpt_update_after_dynamic_topology_toggle(struct bContext *C); -void sculpt_dynamic_topology_enable(struct bContext *C); -void sculpt_dynamic_topology_disable(struct bContext *C, - struct SculptUndoNode *unode); +void sculpt_update_after_dynamic_topology_toggle( + const struct EvaluationContext *eval_ctx, + struct Scene *scene, struct Object *ob); +void sculpt_dynamic_topology_enable_ex( + const struct EvaluationContext *eval_ctx, + struct Scene *scene, struct Object *ob); +void sculpt_dynamic_topology_enable(bContext *C); + +void sculpt_dynamic_topology_disable_ex( + const struct EvaluationContext *eval_ctx, + struct Scene *scene, struct Object *ob, + struct SculptUndoNode *unode); +void sculpt_dynamic_topology_disable(bContext *C, struct SculptUndoNode *unode); /* Undo */ @@ -116,6 +125,8 @@ typedef struct SculptUndoNode { /* shape keys */ char shapeName[sizeof(((KeyBlock *)0))->name]; + + size_t undo_size; } SculptUndoNode; /* Factor of brush to have rake point following behind @@ -342,7 +353,7 @@ void sculpt_cache_free(StrokeCache *cache); SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType type); SculptUndoNode *sculpt_undo_get_node(PBVHNode *node); void sculpt_undo_push_begin(const char *name); -void sculpt_undo_push_end(const struct bContext *C); +void sculpt_undo_push_end(void); void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3]); diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 63017a0e576..e12ef2df4ab 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -48,6 +48,9 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_mesh_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_workspace_types.h" #include "BKE_ccg.h" #include "BKE_context.h" @@ -56,6 +59,8 @@ #include "BKE_key.h" #include "BKE_mesh.h" #include "BKE_subsurf.h" +#include "BKE_undo_system.h" + #include "DEG_depsgraph.h" #include "WM_api.h" @@ -64,12 +69,22 @@ #include "GPU_buffers.h" #include "ED_paint.h" +#include "ED_object.h" +#include "ED_sculpt.h" +#include "ED_undo.h" #include "bmesh.h" #include "paint_intern.h" #include "sculpt_intern.h" -/************************** Undo *************************/ + +typedef struct UndoSculpt { + ListBase nodes; + + size_t undo_size; +} UndoSculpt; + +static UndoSculpt *sculpt_undo_get_nodes(void); static void update_cb(PBVHNode *node, void *rebuild) { @@ -368,8 +383,8 @@ static void sculpt_undo_bmesh_restore_generic(bContext *C, } /* Create empty sculpt BMesh and enable logging */ -static void sculpt_undo_bmesh_enable(Object *ob, - SculptUndoNode *unode) +static void sculpt_undo_bmesh_enable( + Object *ob, SculptUndoNode *unode) { SculptSession *ss = ob->sculpt; Mesh *me = ob->data; @@ -457,7 +472,7 @@ static int sculpt_undo_bmesh_restore(bContext *C, return false; } -static void sculpt_undo_restore(bContext *C, ListBase *lb) +static void sculpt_undo_restore_list(bContext *C, ListBase *lb) { Scene *scene = CTX_data_scene(C); Sculpt *sd = CTX_data_tool_settings(C)->sculpt; @@ -580,7 +595,7 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb) } } -static void sculpt_undo_free(ListBase *lb) +static void sculpt_undo_free_list(ListBase *lb) { SculptUndoNode *unode; int i; @@ -623,6 +638,8 @@ static void sculpt_undo_free(ListBase *lb) } } +/* Most likely we don't need this. */ +#if 0 static bool sculpt_undo_cleanup(bContext *C, ListBase *lb) { Object *ob = CTX_data_active_object(C); @@ -639,16 +656,17 @@ static bool sculpt_undo_cleanup(bContext *C, ListBase *lb) return false; } +#endif SculptUndoNode *sculpt_undo_get_node(PBVHNode *node) { - ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_MESH); + UndoSculpt *usculpt = sculpt_undo_get_nodes(); - if (!lb) { + if (usculpt == NULL) { return NULL; } - return BLI_findptr(lb, node, offsetof(SculptUndoNode, node)); + return BLI_findptr(&usculpt->nodes, node, offsetof(SculptUndoNode, node)); } static void sculpt_undo_alloc_and_store_hidden(PBVH *pbvh, @@ -674,10 +692,11 @@ static void sculpt_undo_alloc_and_store_hidden(PBVH *pbvh, } } -static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, - SculptUndoType type) +static SculptUndoNode *sculpt_undo_alloc_node( + Object *ob, PBVHNode *node, + SculptUndoType type) { - ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_MESH); + UndoSculpt *usculpt = sculpt_undo_get_nodes(); SculptUndoNode *unode; SculptSession *ss = ob->sculpt; int totvert, allvert, totgrid, maxgrid, gridsize, *grids; @@ -702,23 +721,23 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, /* general TODO, fix count_alloc */ switch (type) { case SCULPT_UNDO_COORDS: - unode->co = MEM_mapallocN(sizeof(float) * 3 * allvert, "SculptUndoNode.co"); - unode->no = MEM_mapallocN(sizeof(short) * 3 * allvert, "SculptUndoNode.no"); - undo_paint_push_count_alloc(UNDO_PAINT_MESH, - (sizeof(float) * 3 + - sizeof(short) * 3 + - sizeof(int)) * allvert); + unode->co = MEM_mapallocN(sizeof(float[3]) * allvert, "SculptUndoNode.co"); + unode->no = MEM_mapallocN(sizeof(short[3]) * allvert, "SculptUndoNode.no"); + + usculpt->undo_size = (sizeof(float[3]) + sizeof(short[3]) + sizeof(int)) * allvert; break; case SCULPT_UNDO_HIDDEN: if (maxgrid) sculpt_undo_alloc_and_store_hidden(ss->pbvh, unode); else unode->vert_hidden = BLI_BITMAP_NEW(allvert, "SculptUndoNode.vert_hidden"); - + break; case SCULPT_UNDO_MASK: unode->mask = MEM_mapallocN(sizeof(float) * allvert, "SculptUndoNode.mask"); - undo_paint_push_count_alloc(UNDO_PAINT_MESH, (sizeof(float) * sizeof(int)) * allvert); + + usculpt->undo_size += (sizeof(float) * sizeof(int)) * allvert; + break; case SCULPT_UNDO_DYNTOPO_BEGIN: case SCULPT_UNDO_DYNTOPO_END: @@ -727,7 +746,7 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, break; } - BLI_addtail(lb, unode); + BLI_addtail(&usculpt->nodes, unode); if (maxgrid) { /* multires */ @@ -804,12 +823,13 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, SculptUndoType type) { - ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_MESH); - SculptUndoNode *unode = lb->first; + UndoSculpt *usculpt = sculpt_undo_get_nodes(); SculptSession *ss = ob->sculpt; PBVHVertexIter vd; - if (!lb->first) { + SculptUndoNode *unode = usculpt->nodes.first; + + if (unode == NULL) { unode = MEM_callocN(sizeof(*unode), __func__); BLI_strncpy(unode->idname, ob->id.name, sizeof(unode->idname)); @@ -848,7 +868,7 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, unode->bm_entry = BM_log_entry_add(ss->bm_log); } - BLI_addtail(lb, unode); + BLI_addtail(&usculpt->nodes, unode); } if (node) { @@ -889,14 +909,15 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, return unode; } -SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, - SculptUndoType type) +SculptUndoNode *sculpt_undo_push_node( + Object *ob, PBVHNode *node, + SculptUndoType type) { SculptSession *ss = ob->sculpt; SculptUndoNode *unode; /* list is manipulated by multiple threads, so we lock */ - BLI_lock_thread(LOCK_CUSTOM1); + BLI_thread_lock(LOCK_CUSTOM1); if (ss->bm || ELEM(type, @@ -906,17 +927,17 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, /* Dynamic topology stores only one undo node per stroke, * regardless of the number of PBVH nodes modified */ unode = sculpt_undo_bmesh_push(ob, node, type); - BLI_unlock_thread(LOCK_CUSTOM1); + BLI_thread_unlock(LOCK_CUSTOM1); return unode; } else if ((unode = sculpt_undo_get_node(node))) { - BLI_unlock_thread(LOCK_CUSTOM1); + BLI_thread_unlock(LOCK_CUSTOM1); return unode; } unode = sculpt_undo_alloc_node(ob, node, type); - BLI_unlock_thread(LOCK_CUSTOM1); + BLI_thread_unlock(LOCK_CUSTOM1); /* copy threaded, hopefully this is the performance critical part */ @@ -960,17 +981,18 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, void sculpt_undo_push_begin(const char *name) { - ED_undo_paint_push_begin(UNDO_PAINT_MESH, name, - sculpt_undo_restore, sculpt_undo_free, sculpt_undo_cleanup); + UndoStack *ustack = ED_undo_stack_get(); + bContext *C = NULL; /* special case, we never read from this. */ + BKE_undosys_step_push_init_with_type(ustack, C, name, BKE_UNDOSYS_TYPE_SCULPT); } -void sculpt_undo_push_end(const bContext *C) +void sculpt_undo_push_end(void) { - ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_MESH); + UndoSculpt *usculpt = sculpt_undo_get_nodes(); SculptUndoNode *unode; /* we don't need normals in the undo stack */ - for (unode = lb->first; unode; unode = unode->next) { + for (unode = usculpt->nodes.first; unode; unode = unode->next) { if (unode->no) { MEM_freeN(unode->no); unode->no = NULL; @@ -980,7 +1002,97 @@ void sculpt_undo_push_end(const bContext *C) BKE_pbvh_node_layer_disp_free(unode->node); } - ED_undo_paint_push_end(UNDO_PAINT_MESH); + UndoStack *ustack = ED_undo_stack_get(); + BKE_undosys_step_push(ustack, NULL, NULL); +} + +/* -------------------------------------------------------------------- */ +/** \name Implements ED Undo System + * \{ */ + +typedef struct SculptUndoStep { + UndoStep step; + /* note: will split out into list for multi-object-sculpt-mode. */ + UndoSculpt data; +} SculptUndoStep; + +static bool sculpt_undosys_poll(bContext *C) +{ + ScrArea *sa = CTX_wm_area(C); + if (sa && (sa->spacetype == SPACE_VIEW3D)) { + Object *obact = CTX_data_active_object(C); + if (obact && (obact->mode & OB_MODE_SCULPT)) { + return true; + } + } + return false; +} - WM_file_tag_modified(C); +static void sculpt_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep *us_p) +{ + SculptUndoStep *us = (SculptUndoStep *)us_p; + /* dummy, memory is cleared anyway. */ + BLI_listbase_clear(&us->data.nodes); } + +static bool sculpt_undosys_step_encode(struct bContext *UNUSED(C), UndoStep *us_p) +{ + /* dummy, encoding is done along the way by adding tiles + * to the current 'SculptUndoStep' added by encode_init. */ + SculptUndoStep *us = (SculptUndoStep *)us_p; + us->step.data_size = us->data.undo_size; + return true; +} + +static void sculpt_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir)) +{ + /* TODO(campbell): undo_system: use low-level API to set mode. */ + ED_object_mode_set(C, OB_MODE_SCULPT); + BLI_assert(sculpt_undosys_poll(C)); + + SculptUndoStep *us = (SculptUndoStep *)us_p; + sculpt_undo_restore_list(C, &us->data.nodes); +} + +static void sculpt_undosys_step_free(UndoStep *us_p) +{ + SculptUndoStep *us = (SculptUndoStep *)us_p; + sculpt_undo_free_list(&us->data.nodes); +} + +/* Export for ED_undo_sys. */ +void ED_sculpt_undosys_type(UndoType *ut) +{ + ut->name = "Sculpt"; + ut->poll = sculpt_undosys_poll; + ut->step_encode_init = sculpt_undosys_step_encode_init; + ut->step_encode = sculpt_undosys_step_encode; + ut->step_decode = sculpt_undosys_step_decode; + ut->step_free = sculpt_undosys_step_free; + + ut->mode = BKE_UNDOTYPE_MODE_ACCUMULATE; + ut->use_context = true; + + ut->step_size = sizeof(SculptUndoStep); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Utilities + * \{ */ + +static UndoSculpt *sculpt_undosys_step_get_nodes(UndoStep *us_p) +{ + SculptUndoStep *us = (SculptUndoStep *)us_p; + return &us->data; +} + +static UndoSculpt *sculpt_undo_get_nodes(void) +{ + UndoStack *ustack = ED_undo_stack_get(); + UndoStep *us = BKE_undosys_stack_init_or_active_with_type(ustack, BKE_UNDOSYS_TYPE_SCULPT); + return sculpt_undosys_step_get_nodes(us); +} + +/** \} */ diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c index c9453f94e61..6928610f280 100644 --- a/source/blender/editors/sculpt_paint/sculpt_uv.c +++ b/source/blender/editors/sculpt_paint/sculpt_uv.c @@ -650,9 +650,9 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm /* we need to find the active island here */ if (do_island_optimization) { UvElement *element; - NearestHit hit; + UvNearestHit hit = UV_NEAREST_HIT_INIT; Image *ima = CTX_data_edit_image(C); - uv_find_nearest_vert(scene, ima, em, co, NULL, &hit); + uv_find_nearest_vert(scene, ima, obedit, co, 0.0f, &hit); element = BM_uv_element_get(data->elementMap, hit.efa, hit.l); island_index = element->island; @@ -759,7 +759,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm MEM_freeN(uniqueUv); /* Allocate connectivity data, we allocate edges once */ - data->uvedges = MEM_mallocN(sizeof(*data->uvedges) * BLI_ghash_size(edgeHash), "uv_brush_edge_connectivity_data"); + data->uvedges = MEM_mallocN(sizeof(*data->uvedges) * BLI_ghash_len(edgeHash), "uv_brush_edge_connectivity_data"); if (!data->uvedges) { BLI_ghash_free(edgeHash, NULL, NULL); MEM_freeN(edges); @@ -772,7 +772,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm GHASH_ITER (gh_iter, edgeHash) { data->uvedges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(&gh_iter)); } - data->totalUvEdges = BLI_ghash_size(edgeHash); + data->totalUvEdges = BLI_ghash_len(edgeHash); /* cleanup temporary stuff */ BLI_ghash_free(edgeHash, NULL, NULL); diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c index daeb7823a43..a01b4aa1b18 100644 --- a/source/blender/editors/sound/sound_ops.c +++ b/source/blender/editors/sound/sound_ops.c @@ -311,7 +311,6 @@ static int sound_bake_animation_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); struct Depsgraph *depsgraph = CTX_data_depsgraph(C); int oldfra = scene->r.cfra; int cfra; @@ -320,11 +319,11 @@ static int sound_bake_animation_exec(bContext *C, wmOperator *UNUSED(op)) for (cfra = (scene->r.sfra > 0) ? (scene->r.sfra - 1) : 0; cfra <= scene->r.efra + 1; cfra++) { scene->r.cfra = cfra; - BKE_scene_graph_update_for_newframe(bmain->eval_ctx, depsgraph, bmain, scene, view_layer); + BKE_scene_graph_update_for_newframe(depsgraph, bmain); } scene->r.cfra = oldfra; - BKE_scene_graph_update_for_newframe(bmain->eval_ctx, depsgraph, bmain, scene, view_layer); + BKE_scene_graph_update_for_newframe(depsgraph, bmain); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_action/action_buttons.c b/source/blender/editors/space_action/action_buttons.c index 80ec9107984..3ba59b3be75 100644 --- a/source/blender/editors/space_action/action_buttons.c +++ b/source/blender/editors/space_action/action_buttons.c @@ -49,8 +49,6 @@ #include "BKE_context.h" #include "BKE_curve.h" #include "BKE_fcurve.h" -#include "BKE_main.h" -#include "BKE_global.h" #include "BKE_screen.h" #include "BKE_unit.h" diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c index 29b3c6f2f6c..f1153b5bed0 100644 --- a/source/blender/editors/space_action/action_data.c +++ b/source/blender/editors/space_action/action_data.c @@ -54,10 +54,8 @@ #include "BKE_animsys.h" #include "BKE_action.h" #include "BKE_fcurve.h" -#include "BKE_global.h" #include "BKE_library.h" #include "BKE_key.h" -#include "BKE_main.h" #include "BKE_nla.h" #include "BKE_scene.h" #include "BKE_context.h" @@ -568,11 +566,11 @@ void ED_animedit_unlink_action(bContext *C, ID *id, AnimData *adt, bAction *act, if (strip->act == act) { /* Remove this strip, and the track too if it doesn't have anything else */ - free_nlastrip(&nlt->strips, strip); + BKE_nlastrip_free(&nlt->strips, strip); if (nlt->strips.first == NULL) { BLI_assert(nstrip == NULL); - free_nlatrack(&adt->nla_tracks, nlt); + BKE_nlatrack_free(&adt->nla_tracks, nlt); } } } diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c index 72b1245ca8a..1c15a7c5950 100644 --- a/source/blender/editors/space_action/action_edit.c +++ b/source/blender/editors/space_action/action_edit.c @@ -59,7 +59,6 @@ #include "BKE_global.h" #include "BKE_library.h" #include "BKE_key.h" -#include "BKE_main.h" #include "BKE_nla.h" #include "BKE_context.h" #include "BKE_report.h" diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index 110c4d1789d..2b974ac73d7 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -36,7 +36,7 @@ #include "BLI_blenlib.h" #include "BLI_dlrbTree.h" -#include "BLI_lasso.h" +#include "BLI_lasso_2d.h" #include "BLI_utildefines.h" #include "DNA_anim_types.h" @@ -220,7 +220,7 @@ static void borderselect_action(bAnimContext *ac, const rcti rect, short mode, s UI_view2d_region_to_view(v2d, rect.xmax, rect.ymax - 2, &rectf.xmax, &rectf.ymax); /* filter data */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS); + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); /* get beztriple editing/validation funcs */ @@ -262,7 +262,7 @@ static void borderselect_action(bAnimContext *ac, const rcti rect, short mode, s { /* loop over data selecting */ switch (ale->type) { -#if 0 /* XXXX: Keyframes are not currently shown here */ +#if 0 /* XXX: Keyframes are not currently shown here */ case ANIMTYPE_GPDATABLOCK: { bGPdata *gpd = ale->data; @@ -401,7 +401,7 @@ static void region_select_action_keys(bAnimContext *ac, const rctf *rectf_view, UI_view2d_region_to_view_rctf(v2d, rectf_view, &rectf); /* filter data */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS); + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); /* get beztriple editing/validation funcs */ @@ -466,6 +466,7 @@ static void region_select_action_keys(bAnimContext *ac, const rctf *rectf_view, { /* loop over data selecting */ switch (ale->type) { +#if 0 /* XXX: Keyframes are not currently shown here */ case ANIMTYPE_GPDATABLOCK: { bGPdata *gpd = ale->data; @@ -475,6 +476,7 @@ static void region_select_action_keys(bAnimContext *ac, const rctf *rectf_view, } break; } +#endif case ANIMTYPE_GPLAYER: { ED_gplayer_frames_select_region(&ked, ale->data, mode, selectmode); @@ -718,8 +720,6 @@ static void columnselect_action_keys(bAnimContext *ac, short mode) KeyframeEditFunc select_cb, ok_cb; KeyframeEditData ked = {{NULL}}; - /* initialize keyframe editing data */ - /* build list of columns */ switch (mode) { case ACTKEYS_COLUMNSEL_KEYS: /* list of selected keys */ diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c index 60b6bd0cd0b..2f85b915813 100644 --- a/source/blender/editors/space_api/spacetypes.c +++ b/source/blender/editors/space_api/spacetypes.c @@ -62,6 +62,7 @@ #include "ED_space_api.h" #include "ED_sound.h" #include "ED_uvedit.h" +#include "ED_lattice.h" #include "ED_mball.h" #include "ED_logic.h" #include "ED_clip.h" @@ -109,6 +110,7 @@ void ED_spacetypes_init(void) ED_operatortypes_animchannels(); ED_operatortypes_gpencil(); ED_operatortypes_object(); + ED_operatortypes_lattice(); ED_operatortypes_mesh(); ED_operatortypes_sculpt(); ED_operatortypes_uvedit(); @@ -198,7 +200,8 @@ void ED_spacetypes_keymap(wmKeyConfig *keyconf) ED_keymap_anim(keyconf); ED_keymap_animchannels(keyconf); ED_keymap_gpencil(keyconf); - ED_keymap_object(keyconf); /* defines lattice also */ + ED_keymap_object(keyconf); + ED_keymap_lattice(keyconf); ED_keymap_mesh(keyconf); ED_keymap_uvedit(keyconf); ED_keymap_curve(keyconf); diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c index fc1b6877f5e..2a703ebb46c 100644 --- a/source/blender/editors/space_buttons/buttons_ops.c +++ b/source/blender/editors/space_buttons/buttons_ops.c @@ -51,7 +51,7 @@ #include "WM_types.h" #include "ED_screen.h" -#include "ED_util.h" +#include "ED_undo.h" #include "RNA_access.h" diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c index 036db87e846..809480baece 100644 --- a/source/blender/editors/space_buttons/buttons_texture.c +++ b/source/blender/editors/space_buttons/buttons_texture.c @@ -45,7 +45,7 @@ #include "DNA_material_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" -#include "DNA_object_force.h" +#include "DNA_object_force_types.h" #include "DNA_particle_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" @@ -351,18 +351,20 @@ static void buttons_texture_users_from_context(ListBase *users, const bContext * workspace = (WorkSpace *)workspace; } - if (!scene) + if (!scene) { scene = CTX_data_scene(C); + } - if (!pinid || GS(pinid->name) == ID_SCE) { - wrld = scene->world; + const ID_Type id_type = pinid != NULL ? GS(pinid->name) : -1; + if (!pinid || ELEM(id_type, ID_SCE, ID_WS)) { brush = BKE_paint_brush(BKE_paint_get_active_from_context(C)); - linestyle = BKE_linestyle_active_from_scene(scene); - } - else if (!pinid || GS(pinid->name) == ID_WS) { - if (!workspace) { + + if (workspace == NULL) { + wrld = scene->world; + linestyle = BKE_linestyle_active_from_scene(scene); workspace = CTX_wm_workspace(C); } + ViewLayer *view_layer = BKE_view_layer_from_workspace_get(scene, workspace); ob = OBACT(view_layer); } @@ -480,7 +482,7 @@ void buttons_texture_context_compute(const bContext *C, SpaceButs *sbuts) } else { /* set one user as active based on active index */ - if (ct->index >= BLI_listbase_count_ex(&ct->users, ct->index + 1)) + if (ct->index >= BLI_listbase_count_at_most(&ct->users, ct->index + 1)) ct->index = 0; ct->user = BLI_findlink(&ct->users, ct->index); diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c index 09d225fc1b8..5962bfe33f3 100644 --- a/source/blender/editors/space_clip/clip_draw.c +++ b/source/blender/editors/space_clip/clip_draw.c @@ -157,7 +157,7 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Sc MovieTrackingReconstruction *reconstruction = BKE_tracking_get_active_reconstruction(tracking); glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); /* cache background */ ED_region_cache_draw_background(ar); @@ -314,7 +314,7 @@ static void draw_movieclip_buffer(const bContext *C, SpaceClip *sc, ARegion *ar, /* checkerboard for case alpha */ if (ibuf->planes == 32) { glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); imm_draw_box_checker_2d(x, y, x + zoomx * ibuf->x, y + zoomy * ibuf->y); } @@ -1126,11 +1126,12 @@ static void draw_plane_marker_image(Scene *scene, if (plane_track->image_opacity != 1.0f || ibuf->planes == 32) { transparent = true; glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } glGenTextures(1, (GLuint *)&texid); + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texid); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -1148,7 +1149,7 @@ static void draw_plane_marker_image(Scene *scene, immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_COLOR); immUniformColor4f(1.0f, 1.0f, 1.0f, plane_track->image_opacity); - immUniform1i("image", GL_TEXTURE0); + immUniform1i("image", 0); immBegin(GWN_PRIM_TRI_FAN, 4); diff --git a/source/blender/editors/space_clip/clip_toolbar.c b/source/blender/editors/space_clip/clip_toolbar.c index 1504ce1a7ba..d2a7244eded 100644 --- a/source/blender/editors/space_clip/clip_toolbar.c +++ b/source/blender/editors/space_clip/clip_toolbar.c @@ -49,7 +49,7 @@ #include "WM_api.h" #include "ED_screen.h" -#include "ED_util.h" +#include "ED_undo.h" #include "UI_interface.h" #include "UI_resources.h" diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c index 7f9d9bf577c..9f79e8ffd6b 100644 --- a/source/blender/editors/space_clip/clip_utils.c +++ b/source/blender/editors/space_clip/clip_utils.c @@ -302,7 +302,7 @@ void clip_draw_sfra_efra(View2D *v2d, Scene *scene) UI_view2d_view_ortho(v2d); /* currently clip editor supposes that editing clip length is equal to scene frame range */ - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c index 4ca2b54eaaf..f2bf817f502 100644 --- a/source/blender/editors/space_clip/tracking_ops.c +++ b/source/blender/editors/space_clip/tracking_ops.c @@ -1859,7 +1859,7 @@ static bool is_track_clean(MovieTrackingTrack *track, int frames, int del) } } - if (count == 0) { + if (del && count == 0) { ok = 0; } diff --git a/source/blender/editors/space_clip/tracking_ops_orient.c b/source/blender/editors/space_clip/tracking_ops_orient.c index 8e3871836e4..583beef5001 100644 --- a/source/blender/editors/space_clip/tracking_ops_orient.c +++ b/source/blender/editors/space_clip/tracking_ops_orient.c @@ -42,7 +42,6 @@ #include "BKE_context.h" #include "BKE_constraint.h" #include "BKE_tracking.h" -#include "BKE_global.h" #include "BKE_layer.h" #include "BKE_object.h" #include "BKE_report.h" @@ -71,7 +70,7 @@ static Object *get_camera_with_movieclip(Scene *scene, MovieClip *clip) return camera; } - FOREACH_SCENE_OBJECT(scene, ob) + FOREACH_SCENE_OBJECT_BEGIN(scene, ob) { if (ob->type == OB_CAMERA) { if (BKE_object_movieclip_get(scene, ob, false) == clip) { @@ -80,7 +79,7 @@ static Object *get_camera_with_movieclip(Scene *scene, MovieClip *clip) } } } - FOREACH_SCENE_OBJECT_END + FOREACH_SCENE_OBJECT_END; return camera; } diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c index 4ee85ace271..ecbc1f5ae1e 100644 --- a/source/blender/editors/space_clip/tracking_select.c +++ b/source/blender/editors/space_clip/tracking_select.c @@ -37,7 +37,7 @@ #include "BLI_utildefines.h" #include "BLI_math.h" #include "BLI_rect.h" -#include "BLI_lasso.h" +#include "BLI_lasso_2d.h" #include "BKE_context.h" #include "BKE_tracking.h" diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index c1e298c426f..043f32c56e7 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -52,6 +52,8 @@ #include "BLT_translation.h" +#include "BLF_api.h" + #include "IMB_imbuf_types.h" #include "DNA_userdef_types.h" @@ -375,7 +377,7 @@ static void file_draw_preview( xco = sx + (int)dx; yco = sy - layout->prv_h + (int)dy; - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); /* shadow */ if (use_dropshadow) { @@ -607,6 +609,8 @@ void file_draw_list(const bContext *C, ARegion *ar) } } + BLF_batch_draw_begin(); + for (i = offset; (i < numfiles) && (i < offset + numfiles_layout); i++) { unsigned int file_selflag; char path[FILE_MAX_LIBEXTRA]; @@ -626,7 +630,7 @@ void file_draw_list(const bContext *C, ARegion *ar) int colorid = (file_selflag & FILE_SEL_SELECTED) ? TH_HILITE : TH_BACK; int shade = (params->highlight_file == i) || (file_selflag & FILE_SEL_HIGHLIGHTED) ? 35 : 0; - BLI_assert(i > 0 || FILENAME_IS_CURRPAR(file->relpath)); + BLI_assert(i == 0 || !FILENAME_IS_CURRPAR(file->relpath)); draw_tile(sx, sy - 1, layout->tile_w + 4, sfile->layout->tile_h + layout->tile_border_y, colorid, shade); } @@ -736,6 +740,8 @@ void file_draw_list(const bContext *C, ARegion *ar) } } + BLF_batch_draw_end(); + UI_block_end(C, block); UI_block_draw(C, block); diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 3f26604c23a..0fe51ea1c70 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -189,6 +189,9 @@ static SpaceLink *file_duplicate(SpaceLink *sl) /* clear or remove stuff from old */ sfilen->op = NULL; /* file window doesn't own operators */ + sfilen->previews_timer = NULL; + sfilen->smoothscroll_timer = NULL; + if (sfileo->params) { sfilen->files = filelist_new(sfileo->params->type); sfilen->params = MEM_dupallocN(sfileo->params); @@ -289,8 +292,9 @@ static void file_refresh(const bContext *C, ScrArea *sa) file_tools_region(sa); ED_area_initialize(wm, CTX_wm_window(C), sa); - ED_area_tag_redraw(sa); } + + ED_area_tag_redraw(sa); } static void file_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn, Scene *UNUSED(scene), @@ -304,16 +308,13 @@ static void file_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn, Sce switch (wmn->data) { case ND_SPACE_FILE_LIST: ED_area_tag_refresh(sa); - ED_area_tag_redraw(sa); break; case ND_SPACE_FILE_PARAMS: ED_area_tag_refresh(sa); - ED_area_tag_redraw(sa); break; case ND_SPACE_FILE_PREVIEW: if (sfile->files && filelist_cache_previews_update(sfile->files)) { ED_area_tag_refresh(sa); - ED_area_tag_redraw(sa); } break; } @@ -372,6 +373,15 @@ static void file_main_region_message_subscribe( .notify = ED_area_do_msg_notify_tag_refresh, }; + /* SpaceFile itself. */ + { + PointerRNA ptr; + RNA_pointer_create(&screen->id, &RNA_SpaceFileBrowser, sfile, &ptr); + + /* All properties for this space type. */ + WM_msg_subscribe_rna(mbus, &ptr, NULL, &msg_sub_value_area_tag_refresh, __func__); + } + /* FileSelectParams */ { PointerRNA ptr; diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c index 49f498b3419..c79652795ac 100644 --- a/source/blender/editors/space_graph/graph_buttons.c +++ b/source/blender/editors/space_graph/graph_buttons.c @@ -64,7 +64,7 @@ #include "ED_anim_api.h" #include "ED_keyframing.h" #include "ED_screen.h" -#include "ED_util.h" +#include "ED_undo.h" #include "UI_interface.h" #include "UI_resources.h" diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c index d917e3b85a2..26a3f110d36 100644 --- a/source/blender/editors/space_graph/graph_draw.c +++ b/source/blender/editors/space_graph/graph_draw.c @@ -323,8 +323,12 @@ static void draw_fcurve_handles(SpaceIpo *sipo, FCurve *fcu) { int sel, b; - unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + Gwn_VertFormat *format = immVertexFormat(); + unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT); + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + + immBeginAtMost(GWN_PRIM_LINES, 4 * 2 * fcu->totvert); /* slightly hacky, but we want to draw unselected points before selected ones * so that selected points are clearly visible @@ -334,7 +338,7 @@ static void draw_fcurve_handles(SpaceIpo *sipo, FCurve *fcu) int basecol = (sel) ? TH_HANDLE_SEL_FREE : TH_HANDLE_FREE; const float *fp; unsigned char col[4]; - + for (b = 0; b < fcu->totvert; b++, prevbezt = bezt, bezt++) { /* if only selected keyframes can get their handles shown, * check that keyframe is selected @@ -352,24 +356,20 @@ static void draw_fcurve_handles(SpaceIpo *sipo, FCurve *fcu) if ((!prevbezt && (bezt->ipo == BEZT_IPO_BEZ)) || (prevbezt && (prevbezt->ipo == BEZT_IPO_BEZ))) { UI_GetThemeColor3ubv(basecol + bezt->h1, col); col[3] = fcurve_display_alpha(fcu) * 255; - immUniformColor4ubv(col); - - immBegin(GWN_PRIM_LINES, 2); + immAttrib4ubv(color, col); immVertex2fv(pos, fp); + immAttrib4ubv(color, col); immVertex2fv(pos, fp + 3); - immEnd(); } /* only draw second handle if this segment is bezier */ if (bezt->ipo == BEZT_IPO_BEZ) { UI_GetThemeColor3ubv(basecol + bezt->h2, col); col[3] = fcurve_display_alpha(fcu) * 255; - immUniformColor4ubv(col); - - immBegin(GWN_PRIM_LINES, 2); + immAttrib4ubv(color, col); immVertex2fv(pos, fp + 3); + immAttrib4ubv(color, col); immVertex2fv(pos, fp + 6); - immEnd(); } } else { @@ -380,12 +380,10 @@ static void draw_fcurve_handles(SpaceIpo *sipo, FCurve *fcu) fp = bezt->vec[0]; UI_GetThemeColor3ubv(basecol + bezt->h1, col); col[3] = fcurve_display_alpha(fcu) * 255; - immUniformColor4ubv(col); - - immBegin(GWN_PRIM_LINES, 2); + immAttrib4ubv(color, col); immVertex2fv(pos, fp); + immAttrib4ubv(color, col); immVertex2fv(pos, fp + 3); - immEnd(); } /* only draw second handle if this segment is bezier, and selection is ok */ @@ -395,17 +393,16 @@ static void draw_fcurve_handles(SpaceIpo *sipo, FCurve *fcu) fp = bezt->vec[1]; UI_GetThemeColor3ubv(basecol + bezt->h2, col); col[3] = fcurve_display_alpha(fcu) * 255; - immUniformColor4ubv(col); - - immBegin(GWN_PRIM_LINES, 2); + immAttrib4ubv(color, col); immVertex2fv(pos, fp); + immAttrib4ubv(color, col); immVertex2fv(pos, fp + 3); - immEnd(); } } } } + immEnd(); immUnbindProgram(); } @@ -1232,7 +1229,7 @@ void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar) y = (float)ACHANNEL_FIRST(ac); /* set blending again, as may not be set in previous step */ - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); for (ale = anim_data.first, i = 0; ale; ale = ale->next, i++) { diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index ce6ce802a5b..29e3f99e1d4 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -2824,7 +2824,7 @@ void GRAPH_OT_driver_delete_invalid(wmOperatorType *ot) /* identifiers */ ot->name = "Delete Invalid Drivers"; ot->idname = "GRAPH_OT_driver_delete_invalid"; - ot->description = "Deletes all visible drivers considered invalid"; + ot->description = "Delete all visible drivers considered invalid"; /* api callbacks */ ot->exec = graph_driver_delete_invalid_exec; diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index 392db4ef4b5..0b7ce7d7310 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -37,7 +37,7 @@ #include "BLI_blenlib.h" #include "BLI_math.h" #include "BLI_utildefines.h" -#include "BLI_lasso.h" +#include "BLI_lasso_2d.h" #include "DNA_anim_types.h" #include "DNA_screen_types.h" diff --git a/source/blender/editors/space_graph/graph_utils.c b/source/blender/editors/space_graph/graph_utils.c index 0e56dc817e4..907f346c931 100644 --- a/source/blender/editors/space_graph/graph_utils.c +++ b/source/blender/editors/space_graph/graph_utils.c @@ -171,8 +171,8 @@ int graphop_editable_keyframes_poll(bContext *C) /* editable curves must fulfill the following criteria: * - it has bezier keyframes - * - it must not be protected from editing (this is already checked for with the foredit flag - * - F-Curve modifiers do not interfere with the result too much + * - it must not be protected from editing (this is already checked for with the edit flag + * - F-Curve modifiers do not interfere with the result too much * (i.e. the modifier-control drawing check returns false) */ if (fcu->bezt == NULL) diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c index 4b89c8db9e6..a424084f6b1 100644 --- a/source/blender/editors/space_graph/space_graph.c +++ b/source/blender/editors/space_graph/space_graph.c @@ -699,13 +699,14 @@ static void graph_refresh(const bContext *C, ScrArea *sa) static void graph_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) { SpaceIpo *sgraph = (SpaceIpo *)slink; - - if (!ELEM(GS(old_id->name), ID_GR)) { - return; - } - - if (sgraph->ads && (ID *)sgraph->ads->filter_grp == old_id) { - sgraph->ads->filter_grp = (Group *)new_id; + + if (sgraph->ads) { + if ((ID *)sgraph->ads->filter_grp == old_id) { + sgraph->ads->filter_grp = (Group *)new_id; + } + if ((ID *)sgraph->ads->source == old_id) { + sgraph->ads->source = new_id; + } } } diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index 20f9658020d..c105f40f1d6 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -762,7 +762,7 @@ static void uiblock_layer_pass_buttons( } /* view */ - if (BLI_listbase_count_ex(&rr->views, 2) > 1 && + if (BLI_listbase_count_at_most(&rr->views, 2) > 1 && ((!show_stereo) || (!RE_RenderResult_is_stereo(rr)))) { rview = BLI_findlink(&rr->views, iuser->view); diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c index 23c4fbbe45e..43d5348da3e 100644 --- a/source/blender/editors/space_image/image_draw.c +++ b/source/blender/editors/space_image/image_draw.c @@ -170,7 +170,7 @@ void ED_image_draw_info(Scene *scene, ARegion *ar, bool color_manage, bool use_d float hue = 0, sat = 0, val = 0, lum = 0, u = 0, v = 0; float col[4], finalcol[4]; - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT); @@ -482,8 +482,6 @@ static void draw_image_buffer(const bContext *C, SpaceImage *sima, ARegion *ar, { int x, y; - glaDefine2DArea(&ar->winrct); - /* find window pixel coordinates of origin */ UI_view2d_view_to_region(&ar->v2d, fx, fy, &x, &y); @@ -506,7 +504,7 @@ static void draw_image_buffer(const bContext *C, SpaceImage *sima, ARegion *ar, imm_draw_box_checker_2d(x, y, x + ibuf->x * zoomx, y + ibuf->y * zoomy); glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } /* If RGBA display with color management */ @@ -733,7 +731,7 @@ static void draw_image_paint_helpers(const bContext *C, ARegion *ar, Scene *scen } glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR); immDrawPixelsTex(&state, x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST, display_buffer, zoomx, zoomy, col); @@ -794,7 +792,7 @@ void draw_image_main(const bContext *C, ARegion *ar) * other images are not modifying in such a way so they does not require * lock (sergey) */ - BLI_lock_thread(LOCK_DRAW_IMAGE); + BLI_thread_lock(LOCK_DRAW_IMAGE); } if (show_stereo3d) { @@ -838,7 +836,7 @@ void draw_image_main(const bContext *C, ARegion *ar) draw_image_paint_helpers(C, ar, scene, zoomx, zoomy); if (show_viewer) { - BLI_unlock_thread(LOCK_DRAW_IMAGE); + BLI_thread_unlock(LOCK_DRAW_IMAGE); } /* render info */ @@ -879,7 +877,7 @@ void draw_image_cache(const bContext *C, ARegion *ar) } glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); /* Draw cache background. */ ED_region_cache_draw_background(ar); diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c index 587689eda78..c719af9e0e2 100644 --- a/source/blender/editors/space_image/image_edit.c +++ b/source/blender/editors/space_image/image_edit.c @@ -44,6 +44,8 @@ #include "IMB_imbuf_types.h" +#include "DEG_depsgraph.h" + #include "ED_image.h" /* own include */ #include "ED_mesh.h" #include "ED_screen.h" @@ -374,7 +376,7 @@ bool ED_space_image_show_uvedit(SpaceImage *sima, Object *obedit) } /* matches clip function */ -bool ED_space_image_check_show_maskedit(ViewLayer *view_layer, SpaceImage *sima) +bool ED_space_image_check_show_maskedit(SpaceImage *sima, ViewLayer *view_layer) { /* check editmode - this is reserved for UV editing */ Object *ob = OBACT(view_layer); @@ -391,7 +393,7 @@ int ED_space_image_maskedit_poll(bContext *C) if (sima) { ViewLayer *view_layer = CTX_data_view_layer(C); - return ED_space_image_check_show_maskedit(view_layer, sima); + return ED_space_image_check_show_maskedit(sima, view_layer); } return false; diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 6c0ab33dd2c..9162b8b76a9 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -279,8 +279,9 @@ static int space_image_main_area_not_uv_brush_poll(bContext *C) Scene *scene = CTX_data_scene(C); ToolSettings *toolsettings = scene->toolsettings; - if (sima && !toolsettings->uvsculpt && !scene->obedit) + if (sima && !toolsettings->uvsculpt && (CTX_data_edit_object(C) == NULL)) { return 1; + } return 0; } @@ -814,7 +815,7 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_CANCELLED; } } - else if (ED_space_image_check_show_maskedit(view_layer, sima)) { + else if (ED_space_image_check_show_maskedit(sima, view_layer)) { if (!ED_mask_selected_minmax(C, min, max)) { return OPERATOR_CANCELLED; } @@ -1857,7 +1858,7 @@ static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI /* we need renderresult for exr and rendered multiview */ scene = CTX_data_scene(C); rr = BKE_image_acquire_renderresult(scene, ima); - bool is_mono = rr ? BLI_listbase_count_ex(&rr->views, 2) < 2 : BLI_listbase_count_ex(&ima->views, 2) < 2; + bool is_mono = rr ? BLI_listbase_count_at_most(&rr->views, 2) < 2 : BLI_listbase_count_at_most(&ima->views, 2) < 2; bool is_exr_rr = rr && ELEM(imf->imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) && RE_HasFloatPixels(rr); /* error handling */ @@ -2458,7 +2459,7 @@ static int image_new_exec(bContext *C, wmOperator *op) SpaceImage *sima_other = (SpaceImage *)sl; if (!sima_other->pin) { - ED_space_image_set(sima_other, scene, scene->obedit, ima); + ED_space_image_set(sima_other, scene, obedit, ima); } } } @@ -2623,8 +2624,7 @@ static int image_invert_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; if (support_undo) { - ED_undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name, - ED_image_undo_restore, ED_image_undo_free, NULL); + ED_image_undo_push_begin(op->type->name); /* not strictly needed, because we only imapaint_dirty_region to invalidate all tiles * but better do this right in case someone copies this for a tool that uses partial redraw better */ ED_imapaint_clear_partial_redraw(); @@ -2665,8 +2665,9 @@ static int image_invert_exec(bContext *C, wmOperator *op) if (ibuf->mipmap[0]) ibuf->userflags |= IB_MIPMAP_INVALID; - if (support_undo) - ED_undo_paint_push_end(UNDO_PAINT_IMAGE); + if (support_undo) { + ED_image_undo_push_end(); + } /* force GPU reupload, all image is invalid */ GPU_free_image(ima); diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index a89ae2b869a..54037059cc3 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -800,14 +800,14 @@ static void image_main_region_draw(const bContext *C, ARegion *ar) /* ED_space_image_get* will acquire image buffer which requires * lock here by the same reason why lock is needed in draw_image_main */ - BLI_lock_thread(LOCK_DRAW_IMAGE); + BLI_thread_lock(LOCK_DRAW_IMAGE); } ED_space_image_get_size(sima, &width, &height); ED_space_image_get_aspect(sima, &aspx, &aspy); if (show_viewer) - BLI_unlock_thread(LOCK_DRAW_IMAGE); + BLI_thread_unlock(LOCK_DRAW_IMAGE); ED_mask_draw_region(mask, ar, sima->mask_info.draw_flag, diff --git a/source/blender/editors/space_info/info_report.c b/source/blender/editors/space_info/info_report.c index 31df9b199ea..a6b3dad239c 100644 --- a/source/blender/editors/space_info/info_report.c +++ b/source/blender/editors/space_info/info_report.c @@ -133,9 +133,6 @@ static int select_report_pick_invoke(bContext *C, wmOperator *op, const wmEvent ReportList *reports = CTX_wm_reports(C); Report *report; - /* uses opengl */ - wmSubWindowSet(CTX_wm_window(C), ar->swinid); - report = info_text_pick(sinfo, ar, reports, event->mval[1]); RNA_int_set(op->ptr, "report_index", BLI_findindex(&reports->list, report)); diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c index 3cf833756ef..c7d4fa1465b 100644 --- a/source/blender/editors/space_info/info_stats.c +++ b/source/blender/editors/space_info/info_stats.c @@ -53,6 +53,7 @@ #include "BKE_paint.h" #include "BKE_particle.h" #include "BKE_editmesh.h" +#include "BKE_object.h" #include "ED_info.h" #include "ED_armature.h" @@ -365,28 +366,30 @@ static void stats_dupli_object(Base *base, Object *ob, SceneStats *stats) } } -static bool stats_is_object_dynamic_topology_sculpt(Object *ob) +static bool stats_is_object_dynamic_topology_sculpt(Object *ob, const eObjectMode object_mode) { - return (ob && (ob->mode & OB_MODE_SCULPT) && + return (ob && + (object_mode & OB_MODE_SCULPT) && ob->sculpt && ob->sculpt->bm); } /* Statistics displayed in info header. Called regularly on scene changes. */ -static void stats_update(Scene *scene, ViewLayer *view_layer) +static void stats_update(ViewLayer *view_layer) { SceneStats stats = {0}; - Object *ob = (view_layer->basact) ? view_layer->basact->object : NULL; + Object *ob = OBACT(view_layer); + Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer); Base *base; - - if (scene->obedit) { + + if (obedit) { /* Edit Mode */ - stats_object_edit(scene->obedit, &stats); + stats_object_edit(ob, &stats); } else if (ob && (ob->mode & OB_MODE_POSE)) { /* Pose Mode */ stats_object_pose(ob, &stats); } - else if (stats_is_object_dynamic_topology_sculpt(ob)) { + else if (ob && stats_is_object_dynamic_topology_sculpt(ob, ob->mode)) { /* Dynamic-topology sculpt mode */ stats_object_sculpt_dynamic_topology(ob, &stats); } @@ -405,12 +408,14 @@ static void stats_update(Scene *scene, ViewLayer *view_layer) *(view_layer->stats) = stats; } -static void stats_string(Scene *scene, ViewLayer *view_layer) +static void stats_string(ViewLayer *view_layer) { #define MAX_INFO_MEM_LEN 64 SceneStats *stats = view_layer->stats; SceneStatsFmt stats_fmt; - Object *ob = (view_layer->basact) ? view_layer->basact->object : NULL; + Object *ob = OBACT(view_layer); + Object *obedit = OBEDIT_FROM_OBACT(ob); + eObjectMode object_mode = ob ? ob->mode : OB_MODE_OBJECT; uintptr_t mem_in_use, mmap_in_use; char memstr[MAX_INFO_MEM_LEN]; char gpumemstr[MAX_INFO_MEM_LEN] = ""; @@ -471,17 +476,17 @@ static void stats_string(Scene *scene, ViewLayer *view_layer) ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, "%s | ", versionstr); - if (scene->obedit) { - if (BKE_keyblock_from_object(scene->obedit)) + if (obedit) { + if (BKE_keyblock_from_object(obedit)) ofs += BLI_strncpy_rlen(s + ofs, IFACE_("(Key) "), MAX_INFO_LEN - ofs); - if (scene->obedit->type == OB_MESH) { + if (obedit->type == OB_MESH) { ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%s/%s | Edges:%s/%s | Faces:%s/%s | Tris:%s"), stats_fmt.totvertsel, stats_fmt.totvert, stats_fmt.totedgesel, stats_fmt.totedge, stats_fmt.totfacesel, stats_fmt.totface, stats_fmt.tottri); } - else if (scene->obedit->type == OB_ARMATURE) { + else if (obedit->type == OB_ARMATURE) { ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%s/%s | Bones:%s/%s"), stats_fmt.totvertsel, stats_fmt.totvert, stats_fmt.totbonesel, stats_fmt.totbone); } @@ -493,11 +498,11 @@ static void stats_string(Scene *scene, ViewLayer *view_layer) ofs += BLI_strncpy_rlen(s + ofs, memstr, MAX_INFO_LEN - ofs); ofs += BLI_strncpy_rlen(s + ofs, gpumemstr, MAX_INFO_LEN - ofs); } - else if (ob && (ob->mode & OB_MODE_POSE)) { + else if (ob && (object_mode & OB_MODE_POSE)) { ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Bones:%s/%s %s%s"), stats_fmt.totbonesel, stats_fmt.totbone, memstr, gpumemstr); } - else if (stats_is_object_dynamic_topology_sculpt(ob)) { + else if (stats_is_object_dynamic_topology_sculpt(ob, object_mode)) { ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%s | Tris:%s%s"), stats_fmt.totvert, stats_fmt.tottri, gpumemstr); } @@ -525,12 +530,11 @@ void ED_info_stats_clear(ViewLayer *view_layer) } } -const char *ED_info_stats_string(Scene *scene, ViewLayer *view_layer) +const char *ED_info_stats_string(Scene *UNUSED(scene), ViewLayer *view_layer) { if (!view_layer->stats) { - stats_update(scene, view_layer); + stats_update(view_layer); } - stats_string(scene, view_layer); - + stats_string(view_layer); return view_layer->stats->infostr; } diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c index 3eb0158e7b5..3f35cadd820 100644 --- a/source/blender/editors/space_info/textview.c +++ b/source/blender/editors/space_info/textview.c @@ -82,7 +82,7 @@ static void console_draw_sel(const char *str, const int sel[2], const int xy[2], const int end = txt_utf8_offset_to_column(str, min_ii(sel[1], str_len_draw)); glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); Gwn_VertFormat *format = immVertexFormat(); unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT); diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c index c6fd70a60dd..9bdc92f98ab 100644 --- a/source/blender/editors/space_logic/logic_window.c +++ b/source/blender/editors/space_logic/logic_window.c @@ -56,7 +56,7 @@ #include "BKE_main.h" #include "BKE_sca.h" -#include "ED_util.h" +#include "ED_undo.h" #include "BLT_translation.h" diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c index 89bf57fdb6c..1cc3d5142f5 100644 --- a/source/blender/editors/space_nla/nla_channels.c +++ b/source/blender/editors/space_nla/nla_channels.c @@ -594,12 +594,12 @@ bool nlaedit_add_tracks_existing(bAnimContext *ac, bool above_sel) */ if (above_sel) { /* just add a new one above this one */ - add_nlatrack(adt, nlt); + BKE_nlatrack_add(adt, nlt); added = true; } else if ((lastAdt == NULL) || (adt != lastAdt)) { /* add one track to the top of the owning AnimData's stack, then don't add anymore to this stack */ - add_nlatrack(adt, NULL); + BKE_nlatrack_add(adt, NULL); lastAdt = adt; added = true; } @@ -634,7 +634,7 @@ bool nlaedit_add_tracks_empty(bAnimContext *ac) /* ensure it is empty */ if (BLI_listbase_is_empty(&adt->nla_tracks)) { /* add new track to this AnimData block then */ - add_nlatrack(adt, NULL); + BKE_nlatrack_add(adt, NULL); added = true; } } @@ -729,7 +729,7 @@ static int nlaedit_delete_tracks_exec(bContext *C, wmOperator *UNUSED(op)) adt->flag &= ~ADT_NLA_SOLO_TRACK; /* call delete on this track - deletes all strips too */ - free_nlatrack(&adt->nla_tracks, nlt); + BKE_nlatrack_free(&adt->nla_tracks, nlt); } } diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c index cb20b76a3ee..a7773aaaed5 100644 --- a/source/blender/editors/space_nla/nla_draw.c +++ b/source/blender/editors/space_nla/nla_draw.c @@ -316,18 +316,20 @@ static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc, uns float cfra; /* plot the curve (over the strip's main region) */ - immBegin(GWN_PRIM_LINE_STRIP, abs((int)(strip->end - strip->start) + 1)); + if (fcu) { + immBegin(GWN_PRIM_LINE_STRIP, abs((int)(strip->end - strip->start) + 1)); - /* sample at 1 frame intervals, and draw - * - min y-val is yminc, max is y-maxc, so clamp in those regions - */ - for (cfra = strip->start; cfra <= strip->end; cfra += 1.0f) { - float y = evaluate_fcurve(fcu, cfra); /* assume this to be in 0-1 range */ - CLAMP(y, 0.0f, 1.0f); - immVertex2f(pos, cfra, ((y * yheight) + yminc)); - } + /* sample at 1 frame intervals, and draw + * - min y-val is yminc, max is y-maxc, so clamp in those regions + */ + for (cfra = strip->start; cfra <= strip->end; cfra += 1.0f) { + float y = evaluate_fcurve(fcu, cfra); /* assume this to be in 0-1 range */ + CLAMP(y, 0.0f, 1.0f); + immVertex2f(pos, cfra, ((y * yheight) + yminc)); + } - immEnd(); + immEnd(); + } } else { /* use blend in/out values only if both aren't zero */ @@ -408,7 +410,7 @@ static void nla_draw_strip(SpaceNla *snla, AnimData *adt, NlaTrack *nlt, NlaStri */ if ((strip->extendmode != NLASTRIP_EXTEND_NOTHING) && (non_solo == 0)) { /* enable transparency... */ - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); switch (strip->extendmode) { @@ -709,7 +711,7 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar) /* just draw a semi-shaded rect spanning the width of the viewable area if there's data, * and a second darker rect within which we draw keyframe indicator dots if there's data */ - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); /* get colors for drawing */ @@ -826,7 +828,7 @@ void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *ar) y = (float)(-NLACHANNEL_HEIGHT(snla)); /* set blending again, as may not be set in previous step */ - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); /* loop through channels, and set up drawing depending on their type */ diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c index 31524f8450a..c86e9872c0a 100644 --- a/source/blender/editors/space_nla/nla_edit.c +++ b/source/blender/editors/space_nla/nla_edit.c @@ -645,7 +645,7 @@ static int nlaedit_add_actionclip_exec(bContext *C, wmOperator *op) } /* create a new strip, and offset it to start on the current frame */ - strip = add_nlastrip(act); + strip = BKE_nlastrip_new(act); strip->end += (cfra - strip->start); strip->start = cfra; @@ -655,7 +655,7 @@ static int nlaedit_add_actionclip_exec(bContext *C, wmOperator *op) /* trying to add to the current failed (no space), * so add a new track to the stack, and add to that... */ - nlt = add_nlatrack(adt, NULL); + nlt = BKE_nlatrack_add(adt, NULL); BKE_nlatrack_add_strip(nlt, strip); } @@ -858,7 +858,7 @@ static int nlaedit_add_sound_exec(bContext *C, wmOperator *UNUSED(op)) continue; /* create a new strip, and offset it to start on the current frame */ - strip = add_nla_soundstrip(ac.scene, ob->data); + strip = BKE_nla_add_soundstrip(ac.scene, ob->data); strip->start += cfra; strip->end += cfra; @@ -868,7 +868,7 @@ static int nlaedit_add_sound_exec(bContext *C, wmOperator *UNUSED(op)) /* trying to add to the current failed (no space), * so add a new track to the stack, and add to that... */ - nlt = add_nlatrack(adt, NULL); + nlt = BKE_nlatrack_add(adt, NULL); BKE_nlatrack_add_strip(nlt, strip); } @@ -1057,7 +1057,7 @@ static int nlaedit_duplicate_exec(bContext *C, wmOperator *op) /* if selected, split the strip at its midpoint */ if (strip->flag & NLASTRIP_FLAG_SELECT) { /* make a copy (assume that this is possible) */ - nstrip = copy_nlastrip(strip, linked); + nstrip = BKE_nlastrip_copy(strip, linked); /* in case there's no space in the track above, or we haven't got a reference to it yet, try adding */ if (BKE_nlatrack_add_strip(nlt->next, nstrip) == 0) { @@ -1065,7 +1065,7 @@ static int nlaedit_duplicate_exec(bContext *C, wmOperator *op) * - if the current one is the last one, nlt->next will be NULL, which defaults to adding * at the top of the stack anyway... */ - track = add_nlatrack(adt, nlt->next); + track = BKE_nlatrack_add(adt, nlt->next); BKE_nlatrack_add_strip(track, nstrip); } @@ -1160,14 +1160,14 @@ static int nlaedit_delete_exec(bContext *C, wmOperator *UNUSED(op)) if (strip->flag & NLASTRIP_FLAG_SELECT) { /* if a strip either side of this was a transition, delete those too */ if ((strip->prev) && (strip->prev->type == NLASTRIP_TYPE_TRANSITION)) - free_nlastrip(&nlt->strips, strip->prev); + BKE_nlastrip_free(&nlt->strips, strip->prev); if ((nstrip) && (nstrip->type == NLASTRIP_TYPE_TRANSITION)) { nstrip = nstrip->next; - free_nlastrip(&nlt->strips, strip->next); + BKE_nlastrip_free(&nlt->strips, strip->next); } /* finally, delete this strip */ - free_nlastrip(&nlt->strips, strip); + BKE_nlastrip_free(&nlt->strips, strip); } } } @@ -1242,7 +1242,7 @@ static void nlaedit_split_strip_actclip(AnimData *adt, NlaTrack *nlt, NlaStrip * /* make a copy (assume that this is possible) and append * it immediately after the current strip */ - nstrip = copy_nlastrip(strip, true); + nstrip = BKE_nlastrip_copy(strip, true); BLI_insertlinkafter(&nlt->strips, strip, nstrip); /* set the endpoint of the first strip and the start of the new strip @@ -1501,7 +1501,7 @@ static int nlaedit_swap_exec(bContext *C, wmOperator *op) NlaStrip *mstrip = (NlaStrip *)nlt->strips.first; if ((mstrip->flag & NLASTRIP_FLAG_TEMP_META) && - (BLI_listbase_count_ex(&mstrip->strips, 3) == 2)) + (BLI_listbase_count_at_most(&mstrip->strips, 3) == 2)) { /* remove this temp meta, so that we can see the strips inside */ BKE_nlastrips_clear_metas(&nlt->strips, 0, 1); @@ -2186,7 +2186,7 @@ static int nlaedit_snap_exec(bContext *C, wmOperator *op) /* in case there's no space in the current track, try adding */ if (BKE_nlatrack_add_strip(nlt, strip) == 0) { /* need to add a new track above the current one */ - track = add_nlatrack(adt, nlt); + track = BKE_nlatrack_add(adt, nlt); BKE_nlatrack_add_strip(track, strip); /* clear temp meta-strips on this new track, as we may not be able to get back to it */ diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c index f6068087f02..08ac7c8973e 100644 --- a/source/blender/editors/space_nla/space_nla.c +++ b/source/blender/editors/space_nla/space_nla.c @@ -517,13 +517,14 @@ static void nla_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn, Scen static void nla_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) { SpaceNla *snla = (SpaceNla *)slink; - - if (!ELEM(GS(old_id->name), ID_GR)) { - return; - } - - if ((ID *)snla->ads->filter_grp == old_id) { - snla->ads->filter_grp = (Group *)new_id; + + if (snla->ads) { + if ((ID *)snla->ads->filter_grp == old_id) { + snla->ads->filter_grp = (Group *)new_id; + } + if ((ID *)snla->ads->source == old_id) { + snla->ads->source = new_id; + } } } diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 1bee2716e65..1cb9c57404a 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -53,6 +53,7 @@ #include "BIF_glutil.h" #include "GPU_draw.h" +#include "GPU_batch.h" #include "GPU_immediate.h" #include "GPU_matrix.h" @@ -986,7 +987,7 @@ static void node_shader_buts_normal_map(uiLayout *layout, bContext *C, PointerRN { uiItemR(layout, ptr, "space", 0, "", 0); - if (RNA_enum_get(ptr, "space") == SHD_NORMAL_MAP_TANGENT) { + if (RNA_enum_get(ptr, "space") == SHD_SPACE_TANGENT) { PointerRNA obptr = CTX_data_pointer_get(C, "active_object"); if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) { @@ -998,6 +999,11 @@ static void node_shader_buts_normal_map(uiLayout *layout, bContext *C, PointerRN } } +static void node_shader_buts_displacement(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "space", 0, "", 0); +} + static void node_shader_buts_tangent(uiLayout *layout, bContext *C, PointerRNA *ptr) { uiLayout *split, *row; @@ -1027,6 +1033,12 @@ static void node_shader_buts_glossy(uiLayout *layout, bContext *UNUSED(C), Point uiItemR(layout, ptr, "distribution", 0, "", ICON_NONE); } +static void node_shader_buts_principled(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "distribution", 0, "", ICON_NONE); + uiItemR(layout, ptr, "subsurface_method", 0, "", ICON_NONE); +} + static void node_shader_buts_anisotropic(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "distribution", 0, "", ICON_NONE); @@ -1189,15 +1201,21 @@ static void node_shader_set_butfunc(bNodeType *ntype) case SH_NODE_NORMAL_MAP: ntype->draw_buttons = node_shader_buts_normal_map; break; + case SH_NODE_DISPLACEMENT: + case SH_NODE_VECTOR_DISPLACEMENT: + ntype->draw_buttons = node_shader_buts_displacement; + break; case SH_NODE_TANGENT: ntype->draw_buttons = node_shader_buts_tangent; break; case SH_NODE_BSDF_GLOSSY: case SH_NODE_BSDF_GLASS: case SH_NODE_BSDF_REFRACTION: - case SH_NODE_BSDF_PRINCIPLED: ntype->draw_buttons = node_shader_buts_glossy; break; + case SH_NODE_BSDF_PRINCIPLED: + ntype->draw_buttons = node_shader_buts_principled; + break; case SH_NODE_BSDF_ANISOTROPIC: ntype->draw_buttons = node_shader_buts_anisotropic; break; @@ -2999,7 +3017,7 @@ static const float std_node_socket_colors[][4] = { {0.70, 0.65, 0.19, 1.0}, /* SOCK_BOOLEAN */ {0.0, 0.0, 0.0, 1.0}, /*__SOCK_MESH (deprecated) */ {0.06, 0.52, 0.15, 1.0}, /* SOCK_INT */ - {1.0, 1.0, 1.0, 1.0}, /* SOCK_STRING */ + {0.39, 0.39, 0.39, 1.0}, /* SOCK_STRING */ }; /* common color callbacks for standard types */ @@ -3086,20 +3104,11 @@ static void std_node_socket_draw(bContext *C, uiLayout *layout, PointerRNA *ptr, uiTemplateComponentMenu(layout, ptr, "default_value", text); break; case SOCK_RGBA: - { - uiLayout *row = uiLayoutRow(layout, false); - uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_LEFT); - /* draw the socket name right of the actual button */ - uiItemR(row, ptr, "default_value", 0, "", 0); - uiItemL(row, text, 0); - break; - } case SOCK_STRING: { - uiLayout *row = uiLayoutRow(layout, true); - /* draw the socket name right of the actual button */ - uiItemR(row, ptr, "default_value", 0, "", 0); + uiLayout *row = uiLayoutSplit(layout, 0.5f, false); uiItemL(row, text, 0); + uiItemR(row, ptr, "default_value", 0, "", 0); break; } default: @@ -3133,11 +3142,6 @@ static void std_node_socket_interface_draw(bContext *UNUSED(C), uiLayout *layout uiItemR(row, ptr, "max_value", 0, IFACE_("Max"), 0); break; } - case SOCK_BOOLEAN: - { - uiItemR(layout, ptr, "default_value", 0, NULL, 0); - break; - } case SOCK_VECTOR: { uiLayout *row; @@ -3147,11 +3151,8 @@ static void std_node_socket_interface_draw(bContext *UNUSED(C), uiLayout *layout uiItemR(row, ptr, "max_value", 0, IFACE_("Max"), 0); break; } + case SOCK_BOOLEAN: case SOCK_RGBA: - { - uiItemR(layout, ptr, "default_value", 0, NULL, 0); - break; - } case SOCK_STRING: { uiItemR(layout, ptr, "default_value", 0, NULL, 0); @@ -3205,8 +3206,6 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode, b gpuPushMatrix(); /* somehow the offset has to be calculated inverse */ - - glaDefine2DArea(&ar->winrct); wmOrtho2_region_pixelspace(ar); x = (ar->winx - snode->zoom * ibuf->x) / 2 + snode->xof; @@ -3239,7 +3238,7 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode, b } else if (snode->flag & SNODE_USE_ALPHA) { glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glaDrawImBuf_glsl_ctx(C, ibuf, x, y, GL_NEAREST, snode->zoom, snode->zoom); @@ -3294,11 +3293,10 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode, b BKE_image_release_ibuf(ima, ibuf, lock); } - -/* if v2d not NULL, it clips and returns 0 if not visible */ -bool node_link_bezier_points(View2D *v2d, SpaceNode *snode, bNodeLink *link, float coord_array[][2], int resol) +/* return quadratic beziers points for a given nodelink and clip if v2d is not NULL. */ +static bool node_link_bezier_handles(View2D *v2d, SpaceNode *snode, bNodeLink *link, float vec[4][2]) { - float dist, vec[4][2]; + float dist; float deltax, deltay; float cursor[2] = {0.0f, 0.0f}; int toreroute, fromreroute; @@ -3366,13 +3364,23 @@ bool node_link_bezier_points(View2D *v2d, SpaceNode *snode, bNodeLink *link, flo vec[2][0] = vec[3][0] - dist; vec[2][1] = vec[3][1]; } + if (v2d && min_ffff(vec[0][0], vec[1][0], vec[2][0], vec[3][0]) > v2d->cur.xmax) { - /* clipped */ + return 0; /* clipped */ } else if (v2d && max_ffff(vec[0][0], vec[1][0], vec[2][0], vec[3][0]) < v2d->cur.xmin) { - /* clipped */ + return 0; /* clipped */ } - else { + + return 1; +} + +/* if v2d not NULL, it clips and returns 0 if not visible */ +bool node_link_bezier_points(View2D *v2d, SpaceNode *snode, bNodeLink *link, float coord_array[][2], int resol) +{ + float vec[4][2]; + + if (node_link_bezier_handles(v2d, snode, link, vec)) { /* always do all three, to prevent data hanging around */ BKE_curve_forward_diff_bezier(vec[0][0], vec[1][0], vec[2][0], vec[3][0], coord_array[0] + 0, resol, sizeof(float) * 2); @@ -3384,135 +3392,242 @@ bool node_link_bezier_points(View2D *v2d, SpaceNode *snode, bNodeLink *link, flo return 0; } +#define NODELINK_GROUP_SIZE 256 #define LINK_RESOL 24 -#define LINK_ARROW 12 /* position of arrow on the link, LINK_RESOL/2 */ -#define ARROW_SIZE (7 * UI_DPI_FAC) -void node_draw_link_bezier(View2D *v2d, SpaceNode *snode, bNodeLink *link, - int th_col1, bool do_shaded, int th_col2, bool do_triple, int th_col3) -{ - float coord_array[LINK_RESOL + 1][2]; - - if (node_link_bezier_points(v2d, snode, link, coord_array, LINK_RESOL)) { - float dist, spline_step = 0.0f; - int i; - int drawarrow; - /* store current linewidth */ - float linew; - float arrow[2], arrow1[2], arrow2[2]; - glGetFloatv(GL_LINE_WIDTH, &linew); - unsigned int pos; - - /* we can reuse the dist variable here to increment the GL curve eval amount*/ - dist = 1.0f / (float)LINK_RESOL; - - glEnable(GL_LINE_SMOOTH); - - drawarrow = ((link->tonode && (link->tonode->type == NODE_REROUTE)) && - (link->fromnode && (link->fromnode->type == NODE_REROUTE))); - - if (drawarrow) { - /* draw arrow in line segment LINK_ARROW */ - float d_xy[2], len; - - sub_v2_v2v2(d_xy, coord_array[LINK_ARROW], coord_array[LINK_ARROW - 1]); - len = len_v2(d_xy); - mul_v2_fl(d_xy, ARROW_SIZE / len); - arrow1[0] = coord_array[LINK_ARROW][0] - d_xy[0] + d_xy[1]; - arrow1[1] = coord_array[LINK_ARROW][1] - d_xy[1] - d_xy[0]; - arrow2[0] = coord_array[LINK_ARROW][0] - d_xy[0] - d_xy[1]; - arrow2[1] = coord_array[LINK_ARROW][1] - d_xy[1] + d_xy[0]; - arrow[0] = coord_array[LINK_ARROW][0]; - arrow[1] = coord_array[LINK_ARROW][1]; +#define LINK_WIDTH (2.5f * UI_DPI_FAC) +#define ARROW_SIZE (7 * UI_DPI_FAC) + +static float arrow_verts[3][2] = {{-1.0f, 1.0f}, {0.0f, 0.0f}, {-1.0f, -1.0f}}; +static float arrow_expand_axis[3][2] = {{0.7071f, 0.7071f}, {M_SQRT2, 0.0f}, {0.7071f, -0.7071f}}; + +struct { + Gwn_Batch *batch; /* for batching line together */ + Gwn_Batch *batch_single; /* for single line */ + Gwn_VertBuf *inst_vbo; + unsigned int p0_id, p1_id, p2_id, p3_id; + unsigned int colid_id; + Gwn_VertBufRaw p0_step, p1_step, p2_step, p3_step; + Gwn_VertBufRaw colid_step; + unsigned int count; + bool enabled; +} g_batch_link = {0}; + +static void nodelink_batch_reset(void) +{ + GWN_vertbuf_attr_get_raw_data(g_batch_link.inst_vbo, g_batch_link.p0_id, &g_batch_link.p0_step); + GWN_vertbuf_attr_get_raw_data(g_batch_link.inst_vbo, g_batch_link.p1_id, &g_batch_link.p1_step); + GWN_vertbuf_attr_get_raw_data(g_batch_link.inst_vbo, g_batch_link.p2_id, &g_batch_link.p2_step); + GWN_vertbuf_attr_get_raw_data(g_batch_link.inst_vbo, g_batch_link.p3_id, &g_batch_link.p3_step); + GWN_vertbuf_attr_get_raw_data(g_batch_link.inst_vbo, g_batch_link.colid_id, &g_batch_link.colid_step); + g_batch_link.count = 0; +} + +static void set_nodelink_vertex( + Gwn_VertBuf *vbo, + unsigned int uv_id, unsigned int pos_id, unsigned int exp_id, unsigned int v, + const unsigned char uv[2], const float pos[2], const float exp[2]) +{ + GWN_vertbuf_attr_set(vbo, uv_id, v, uv); + GWN_vertbuf_attr_set(vbo, pos_id, v, pos); + GWN_vertbuf_attr_set(vbo, exp_id, v, exp); +} + +static void nodelink_batch_init(void) +{ + Gwn_VertFormat format = {0}; + unsigned int uv_id = GWN_vertformat_attr_add(&format, "uv", GWN_COMP_U8, 2, GWN_FETCH_INT_TO_FLOAT_UNIT); + unsigned int pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + unsigned int expand_id = GWN_vertformat_attr_add(&format, "expand", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format_ex(&format, GWN_USAGE_STATIC); + int vcount = LINK_RESOL * 2; /* curve */ + vcount += 2; /* restart strip */ + vcount += 3*2; /* arrow */ + vcount *= 2; /* shadow */ + vcount += 2; /* restart strip */ + GWN_vertbuf_data_alloc(vbo, vcount); + int v = 0; + + for (int k = 0; k < 2; ++k) { + unsigned char uv[2] = {0, 0}; + float pos[2] = {0.0f, 0.0f}; + float exp[2] = {0.0f, 1.0f}; + + /* restart */ + if (k == 1) + set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp); + + /* curve strip */ + for (int i = 0; i < LINK_RESOL; ++i) { + uv[0] = 255 * (i / (float)(LINK_RESOL-1)); + uv[1] = 0; + set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp); + uv[1] = 255; + set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp); } - - if (do_triple || drawarrow || (!do_shaded)) { - pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + /* restart */ + set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp); + + uv[0] = 127; + uv[1] = 0; + copy_v2_v2(pos, arrow_verts[0]); + copy_v2_v2(exp, arrow_expand_axis[0]); + set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp); + /* arrow */ + for (int i = 0; i < 3; ++i) { + uv[1] = 0; + copy_v2_v2(pos, arrow_verts[i]); + copy_v2_v2(exp, arrow_expand_axis[i]); + set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp); + + uv[1] = 255; + set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp); } - if (do_triple) { - immUniformThemeColorShadeAlpha(th_col3, -80, -120); - glLineWidth(4.0f); + /* restart */ + if (k == 0) + set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp); + } - immBegin(GWN_PRIM_LINE_STRIP, (LINK_RESOL + 1)); + g_batch_link.batch = GWN_batch_create_ex(GWN_PRIM_TRI_STRIP, vbo, NULL, GWN_BATCH_OWNS_VBO); + gpu_batch_presets_register(g_batch_link.batch); - for (i = 0; i <= LINK_RESOL; i++) { - immVertex2fv(pos, coord_array[i]); - } + g_batch_link.batch_single = GWN_batch_create_ex(GWN_PRIM_TRI_STRIP, vbo, NULL, 0); + gpu_batch_presets_register(g_batch_link.batch_single); - immEnd(); + /* Instances data */ + Gwn_VertFormat format_inst = {0}; + g_batch_link.p0_id = GWN_vertformat_attr_add(&format_inst, "P0", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + g_batch_link.p1_id = GWN_vertformat_attr_add(&format_inst, "P1", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + g_batch_link.p2_id = GWN_vertformat_attr_add(&format_inst, "P2", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + g_batch_link.p3_id = GWN_vertformat_attr_add(&format_inst, "P3", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + g_batch_link.colid_id = GWN_vertformat_attr_add(&format_inst, "colid_doarrow", GWN_COMP_U8, 4, GWN_FETCH_INT); + g_batch_link.inst_vbo = GWN_vertbuf_create_with_format_ex(&format_inst, GWN_USAGE_STREAM); + GWN_vertbuf_data_alloc(g_batch_link.inst_vbo, NODELINK_GROUP_SIZE); /* Alloc max count but only draw the range we need. */ - if (drawarrow) { - immBegin(GWN_PRIM_LINE_STRIP, 3); - immVertex2fv(pos, arrow1); - immVertex2fv(pos, arrow); - immVertex2fv(pos, arrow2); - immEnd(); - } - } + GWN_batch_instbuf_set(g_batch_link.batch, g_batch_link.inst_vbo, true); - glLineWidth(1.5f); + nodelink_batch_reset(); +} - if (drawarrow) { - immUniformThemeColorBlend(th_col1, th_col2, 0.5f); +static char nodelink_get_color_id(int th_col) +{ + switch (th_col) { + case TH_WIRE: return 1; + case TH_WIRE_INNER: return 2; + case TH_ACTIVE: return 3; + case TH_EDGE_SELECT: return 4; + case TH_REDALERT: return 5; + } + return 0; +} - immBegin(GWN_PRIM_LINE_STRIP, 3); - immVertex2fv(pos, arrow1); - immVertex2fv(pos, arrow); - immVertex2fv(pos, arrow2); - immEnd(); - } +static void nodelink_batch_draw(SpaceNode *snode) +{ + if (g_batch_link.count == 0) + return; - if (!do_shaded) { - immUniformThemeColor(th_col1); + glEnable(GL_BLEND); - immBegin(GWN_PRIM_LINE_STRIP, (LINK_RESOL + 1)); + float colors[6][4] = {{0.0f}}; + UI_GetThemeColor4fv(TH_WIRE_INNER, colors[nodelink_get_color_id(TH_WIRE_INNER)]); + UI_GetThemeColor4fv(TH_WIRE, colors[nodelink_get_color_id(TH_WIRE)]); + UI_GetThemeColor4fv(TH_ACTIVE, colors[nodelink_get_color_id(TH_ACTIVE)]); + UI_GetThemeColor4fv(TH_EDGE_SELECT, colors[nodelink_get_color_id(TH_EDGE_SELECT)]); + UI_GetThemeColor4fv(TH_REDALERT, colors[nodelink_get_color_id(TH_REDALERT)]); - for (i = 0; i <= LINK_RESOL; i++) { - immVertex2fv(pos, coord_array[i]); - } + GWN_vertbuf_vertex_count_set(g_batch_link.inst_vbo, g_batch_link.count); + GWN_vertbuf_use(g_batch_link.inst_vbo); /* force update. */ - immEnd(); - } + GWN_batch_program_set_builtin(g_batch_link.batch, GPU_SHADER_2D_NODELINK_INST); + GWN_batch_uniform_4fv_array(g_batch_link.batch, "colors", 6, (float *)colors); + GWN_batch_uniform_1f(g_batch_link.batch, "expandSize", snode->aspect * LINK_WIDTH); + GWN_batch_uniform_1f(g_batch_link.batch, "arrowSize", ARROW_SIZE); + GWN_batch_draw(g_batch_link.batch); - if (do_triple || drawarrow || (!do_shaded)) { - immUnbindProgram(); - } + nodelink_batch_reset(); - if (do_shaded) { - unsigned char col[3]; + glDisable(GL_BLEND); +} + +void nodelink_batch_start(SpaceNode *UNUSED(snode)) +{ + g_batch_link.enabled = true; +} - Gwn_VertFormat *format = immVertexFormat(); - pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT); +void nodelink_batch_end(SpaceNode *snode) +{ + nodelink_batch_draw(snode); + g_batch_link.enabled = false; +} - immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); +static void nodelink_batch_add_link( + SpaceNode *snode, + const float p0[2], const float p1[2], const float p2[2], const float p3[2], + int th_col1, int th_col2, int th_col3, bool drawarrow) +{ + /* Only allow these colors. If more is needed, you need to modify the shader accordingly. */ + BLI_assert(ELEM(th_col1, TH_WIRE_INNER, TH_WIRE, TH_ACTIVE, TH_EDGE_SELECT, TH_REDALERT)); + BLI_assert(ELEM(th_col2, TH_WIRE_INNER, TH_WIRE, TH_ACTIVE, TH_EDGE_SELECT, TH_REDALERT)); + BLI_assert(ELEM(th_col3, TH_WIRE, -1)); - immBegin(GWN_PRIM_LINE_STRIP, (LINK_RESOL + 1)); + g_batch_link.count++; + copy_v2_v2(GWN_vertbuf_raw_step(&g_batch_link.p0_step), p0); + copy_v2_v2(GWN_vertbuf_raw_step(&g_batch_link.p1_step), p1); + copy_v2_v2(GWN_vertbuf_raw_step(&g_batch_link.p2_step), p2); + copy_v2_v2(GWN_vertbuf_raw_step(&g_batch_link.p3_step), p3); + char *colid = GWN_vertbuf_raw_step(&g_batch_link.colid_step); + colid[0] = nodelink_get_color_id(th_col1); + colid[1] = nodelink_get_color_id(th_col2); + colid[2] = nodelink_get_color_id(th_col3); + colid[3] = drawarrow; - for (i = 0; i <= LINK_RESOL; i++) { - UI_GetThemeColorBlend3ubv(th_col1, th_col2, spline_step, col); - immAttrib3ubv(color, col); + if (g_batch_link.count == NODELINK_GROUP_SIZE) { + nodelink_batch_draw(snode); + } +} - immVertex2fv(pos, coord_array[i]); +/* don't do shadows if th_col3 is -1. */ +void node_draw_link_bezier(View2D *v2d, SpaceNode *snode, bNodeLink *link, + int th_col1, int th_col2, int th_col3) +{ + float vec[4][2]; - spline_step += dist; - } + if (node_link_bezier_handles(v2d, snode, link, vec)) { + int drawarrow = ((link->tonode && (link->tonode->type == NODE_REROUTE)) && + (link->fromnode && (link->fromnode->type == NODE_REROUTE))); - immEnd(); + if (g_batch_link.batch == NULL) { + nodelink_batch_init(); + } - immUnbindProgram(); + if (g_batch_link.enabled) { + /* Add link to batch. */ + nodelink_batch_add_link(snode, vec[0], vec[1], vec[2], vec[3], th_col1, th_col2, th_col3, drawarrow); + } + else { + /* Draw single link. */ + float colors[3][4] = {{0.0f}}; + if (th_col3 != -1) { + UI_GetThemeColor4fv(th_col3, colors[0]); + } + UI_GetThemeColor4fv(th_col1, colors[1]); + UI_GetThemeColor4fv(th_col2, colors[2]); + + Gwn_Batch *batch = g_batch_link.batch_single; + GWN_batch_program_set_builtin(batch, GPU_SHADER_2D_NODELINK); + GWN_batch_uniform_2fv_array(batch, "bezierPts", 4, (float *)vec); + GWN_batch_uniform_4fv_array(batch, "colors", 3, (float *)colors); + GWN_batch_uniform_1f(batch, "expandSize", snode->aspect * LINK_WIDTH); + GWN_batch_uniform_1f(batch, "arrowSize", ARROW_SIZE); + GWN_batch_uniform_1i(batch, "doArrow", drawarrow); + GWN_batch_draw(batch); } - - glDisable(GL_LINE_SMOOTH); } } /* note; this is used for fake links in groups too */ void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link) { - bool do_shaded = false; - bool do_triple = false; int th_col1 = TH_WIRE_INNER, th_col2 = TH_WIRE_INNER, th_col3 = TH_WIRE; if (link->fromsock == NULL && link->tosock == NULL) @@ -3520,8 +3635,7 @@ void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link) /* new connection */ if (!link->fromsock || !link->tosock) { - th_col1 = TH_ACTIVE; - do_triple = true; + th_col1 = th_col2 = TH_ACTIVE; } else { /* going to give issues once... */ @@ -3542,15 +3656,14 @@ void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link) if (link->tonode && link->tonode->flag & SELECT) th_col2 = TH_EDGE_SELECT; } - do_shaded = true; - do_triple = true; } else { - th_col1 = TH_REDALERT; + th_col1 = th_col2 = TH_REDALERT; + // th_col3 = -1; /* no shadow */ } } - node_draw_link_bezier(v2d, snode, link, th_col1, do_shaded, th_col2, do_triple, th_col3); + node_draw_link_bezier(v2d, snode, link, th_col1, th_col2, th_col3); // node_draw_link_straight(v2d, snode, link, th_col1, do_shaded, th_col2, do_triple, th_col3); } diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c index 231039b2e22..c82c56ea648 100644 --- a/source/blender/editors/space_node/node_draw.c +++ b/source/blender/editors/space_node/node_draw.c @@ -359,6 +359,8 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node) dy -= NODE_DYS / 2; /* output sockets */ + bool add_output_space = false; + for (nsock = node->outputs.first; nsock; nsock = nsock->next) { if (nodeSocketIsHidden(nsock)) continue; @@ -391,6 +393,12 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node) dy = buty; if (nsock->next) dy -= NODE_SOCKDY; + + add_output_space = true; + } + + if (add_output_space) { + dy -= NODE_DY / 4; } node->prvr.xmin = locx + NODE_DYS; @@ -613,13 +621,11 @@ static void node_draw_mute_line(View2D *v2d, SpaceNode *snode, bNode *node) bNodeLink *link; glEnable(GL_BLEND); - glEnable(GL_LINE_SMOOTH); for (link = node->internal_links.first; link; link = link->next) - node_draw_link_bezier(v2d, snode, link, TH_REDALERT, 0, TH_WIRE, 0, TH_WIRE); + node_draw_link_bezier(v2d, snode, link, TH_REDALERT, TH_REDALERT, -1); glDisable(GL_BLEND); - glDisable(GL_LINE_SMOOTH); } static void node_socket_circle_draw(const bContext *C, bNodeTree *ntree, PointerRNA node_ptr, bNodeSocket *sock, unsigned pos, unsigned col) @@ -705,7 +711,7 @@ static void node_draw_preview(bNodePreview *preview, rctf *prv) node_draw_preview_background(BLI_rctf_size_x(prv) / 10.0f, &draw_rect); glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); /* premul graphics */ + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); /* premul graphics */ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR); immDrawPixelsTex(&state, draw_rect.xmin, draw_rect.ymin, preview->xsize, preview->ysize, GL_RGBA, GL_UNSIGNED_BYTE, GL_LINEAR, preview->rect, @@ -1238,12 +1244,12 @@ void node_draw_nodetree(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeT /* node lines */ glEnable(GL_BLEND); - glEnable(GL_LINE_SMOOTH); + nodelink_batch_start(snode); for (link = ntree->links.first; link; link = link->next) { if (!nodeLinkIsHidden(link)) node_draw_link(&ar->v2d, snode, link); } - glDisable(GL_LINE_SMOOTH); + nodelink_batch_end(snode); glDisable(GL_BLEND); /* draw foreground nodes, last nodes in front */ @@ -1336,7 +1342,7 @@ void drawnodespace(const bContext *C, ARegion *ar) ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW); /* only set once */ - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); /* nodes */ snode_set_context(C); @@ -1404,7 +1410,6 @@ void drawnodespace(const bContext *C, ARegion *ar) gpuPushMatrix(); gpuLoadIdentity(); - glaDefine2DArea(&ar->winrct); wmOrtho2_pixelspace(ar->winx, ar->winy); WM_manipulatormap_draw(ar->manipulator_map, C, WM_MANIPULATORMAP_DRAWSTEP_2D); diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h index 7138b63364a..1235133f8ac 100644 --- a/source/blender/editors/space_node/node_intern.h +++ b/source/blender/editors/space_node/node_intern.h @@ -130,8 +130,11 @@ void NODE_OT_backimage_fit(struct wmOperatorType *ot); void NODE_OT_backimage_sample(struct wmOperatorType *ot); /* drawnode.c */ +void nodelink_batch_start(struct SpaceNode *snode); +void nodelink_batch_end(struct SpaceNode *snode); + void node_draw_link(struct View2D *v2d, struct SpaceNode *snode, struct bNodeLink *link); -void node_draw_link_bezier(struct View2D *v2d, struct SpaceNode *snode, struct bNodeLink *link, int th_col1, bool do_shaded, int th_col2, bool do_triple, int th_col3); +void node_draw_link_bezier(struct View2D *v2d, struct SpaceNode *snode, struct bNodeLink *link, int th_col1, int th_col2, int th_col3); bool node_link_bezier_points(struct View2D *v2d, struct SpaceNode *snode, struct bNodeLink *link, float coord_array[][2], int resol); // void node_draw_link_straight(View2D *v2d, SpaceNode *snode, bNodeLink *link, int th_col1, int do_shaded, int th_col2, int do_triple, int th_col3 ); void draw_nodespace_back_pix(const struct bContext *C, struct ARegion *ar, struct SpaceNode *snode, bNodeInstanceKey parent_key); diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c index dc7863bb354..4b4add0e698 100644 --- a/source/blender/editors/space_node/node_select.c +++ b/source/blender/editors/space_node/node_select.c @@ -34,7 +34,7 @@ #include "BLI_utildefines.h" #include "BLI_rect.h" -#include "BLI_lasso.h" +#include "BLI_lasso_2d.h" #include "BLI_math.h" #include "BLI_string.h" #include "BLI_string_utf8.h" diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c index c791b9f6eae..241ab60fe43 100644 --- a/source/blender/editors/space_node/node_templates.c +++ b/source/blender/editors/space_node/node_templates.c @@ -53,7 +53,7 @@ #include "ED_node.h" /* own include */ -#include "ED_util.h" +#include "ED_undo.h" /************************* Node Socket Manipulation **************************/ @@ -482,10 +482,10 @@ static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname) } NODE_TYPES_END - qsort(sorted_ntypes, BLI_array_count(sorted_ntypes), sizeof(bNodeType *), ui_node_item_name_compare); + qsort(sorted_ntypes, BLI_array_len(sorted_ntypes), sizeof(bNodeType *), ui_node_item_name_compare); /* generate UI */ - for (int j = 0; j < BLI_array_count(sorted_ntypes); j++) { + for (int j = 0; j < BLI_array_len(sorted_ntypes); j++) { bNodeType *ntype = sorted_ntypes[j]; NodeLinkItem *items; int totitems; diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index 8999555521a..7c3bccd1385 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -37,6 +37,7 @@ #include "DEG_depsgraph_build.h" #include "DNA_group_types.h" +#include "DNA_object_types.h" #include "ED_screen.h" @@ -91,6 +92,30 @@ static int view_layer_editor_poll(bContext *C) return (so != NULL) && (so->outlinevis == SO_VIEW_LAYER); } +static int outliner_either_collection_editor_poll(bContext *C) +{ + SpaceOops *so = CTX_wm_space_outliner(C); + return (so != NULL) && (ELEM(so->outlinevis, SO_VIEW_LAYER, SO_COLLECTIONS)); +} + +static int outliner_objects_collection_poll(bContext *C) +{ + SpaceOops *so = CTX_wm_space_outliner(C); + if (so == NULL) { + return 0; + } + + /* Groups don't support filtering. */ + if ((so->outlinevis != SO_GROUPS) && + ((so->filter & (SO_FILTER_ENABLE | SO_FILTER_NO_COLLECTION)) == + (SO_FILTER_ENABLE | SO_FILTER_NO_COLLECTION))) + { + return 0; + } + + return ELEM(so->outlinevis, SO_VIEW_LAYER, SO_COLLECTIONS, SO_GROUPS); +} + /* -------------------------------------------------------------------- */ /* collection manager operators */ @@ -317,7 +342,8 @@ 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); + SceneCollection *scene_collection_parent = BKE_collection_master(&scene->id); + SceneCollection *scene_collection = BKE_collection_add(&scene->id, scene_collection_parent, COLLECTION_TYPE_NONE, NULL); BKE_collection_link(view_layer, scene_collection); DEG_relations_tag_update(bmain); @@ -468,7 +494,7 @@ static int collection_objects_add_exec(bContext *C, wmOperator *op) CTX_DATA_BEGIN (C, struct Object *, ob, selected_objects) { - BLI_LISTBASE_FOREACH (LinkData *, link, &data.scene_collections_array) { + LISTBASE_FOREACH (LinkData *, link, &data.scene_collections_array) { SceneCollection *scene_collection = link->data; BKE_collection_object_add( &scene->id, @@ -523,7 +549,7 @@ static int collection_objects_remove_exec(bContext *C, wmOperator *op) CTX_DATA_BEGIN (C, struct Object *, ob, selected_objects) { - BLI_LISTBASE_FOREACH (LinkData *, link, &data.scene_collections_array) { + LISTBASE_FOREACH (LinkData *, link, &data.scene_collections_array) { SceneCollection *scene_collection = link->data; BKE_collection_object_remove( bmain, @@ -557,6 +583,139 @@ void OUTLINER_OT_collection_objects_remove(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +static TreeElement *outliner_collection_parent_element_get(TreeElement *te) +{ + TreeElement *te_parent = te; + while ((te_parent = te_parent->parent)) { + if (outliner_scene_collection_from_tree_element(te->parent)) { + return te_parent; + } + } + return NULL; +} + +static int object_collection_remove_exec(bContext *C, wmOperator *UNUSED(op)) +{ + SpaceOops *soops = CTX_wm_space_outliner(C); + Main *bmain = CTX_data_main(C); + + struct ObjectsSelectedData data = { + .objects_selected_array = {NULL, NULL}, + }; + + outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_selected_objects, &data); + + LISTBASE_FOREACH (LinkData *, link, &data.objects_selected_array) { + TreeElement *te = (TreeElement *)link->data; + Object *ob = (Object *)TREESTORE(te)->id; + SceneCollection *scene_collection = NULL; + + TreeElement *te_parent = outliner_collection_parent_element_get(te); + if (te_parent != NULL) { + scene_collection = outliner_scene_collection_from_tree_element(te_parent); + ID *owner_id = TREESTORE(te_parent)->id; + BKE_collection_object_remove(bmain, owner_id, scene_collection, ob, true); + DEG_id_tag_update(owner_id, DEG_TAG_BASE_FLAGS_UPDATE); + } + } + + BLI_freelistN(&data.objects_selected_array); + + outliner_cleanup_tree(soops); + DEG_relations_tag_update(bmain); + + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + WM_main_add_notifier(NC_SCENE | ND_OB_ACTIVE, NULL); + WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, NULL); + + return OPERATOR_FINISHED; +} + +void OUTLINER_OT_object_remove_from_collection(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Remove Object from Collection"; + ot->idname = "OUTLINER_OT_object_remove_from_collection"; + ot->description = "Remove selected objects from their respective collection"; + + /* api callbacks */ + ot->exec = object_collection_remove_exec; + ot->poll = outliner_objects_collection_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +static int object_add_to_new_collection_exec(bContext *C, wmOperator *op) +{ + int operator_result = OPERATOR_CANCELLED; + + SpaceOops *soops = CTX_wm_space_outliner(C); + Main *bmain = CTX_data_main(C); + + SceneCollection *scene_collection_parent, *scene_collection_new; + TreeElement *te_active, *te_parent; + + struct ObjectsSelectedData data = {{NULL}}, active = {{NULL}}; + + outliner_tree_traverse(soops, &soops->tree, 0, TSE_HIGHLIGHTED, outliner_find_selected_objects, &active); + if (BLI_listbase_is_empty(&active.objects_selected_array)) { + BKE_report(op->reports, RPT_ERROR, "No object is selected"); + goto cleanup; + } + + outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_selected_objects, &data); + if (BLI_listbase_is_empty(&data.objects_selected_array)) { + BKE_report(op->reports, RPT_ERROR, "No objects are selected"); + goto cleanup; + } + + /* Heuristic to get the "active" / "last object" */ + te_active = ((LinkData *)active.objects_selected_array.first)->data; + te_parent = outliner_collection_parent_element_get(te_active); + + if (te_parent == NULL) { + BKE_reportf(op->reports, RPT_ERROR, "Couldn't find collection of \"%s\" object", te_active->name); + goto cleanup; + } + + ID *owner_id = TREESTORE(te_parent)->id; + scene_collection_parent = outliner_scene_collection_from_tree_element(te_parent); + scene_collection_new = BKE_collection_add(owner_id, scene_collection_parent, scene_collection_parent->type, NULL); + + LISTBASE_FOREACH (LinkData *, link, &data.objects_selected_array) { + TreeElement *te = (TreeElement *)link->data; + Object *ob = (Object *)TREESTORE(te)->id; + BKE_collection_object_add(owner_id, scene_collection_new, ob); + } + + outliner_cleanup_tree(soops); + DEG_relations_tag_update(bmain); + + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + + operator_result = OPERATOR_FINISHED; +cleanup: + BLI_freelistN(&active.objects_selected_array); + BLI_freelistN(&data.objects_selected_array); + return operator_result; +} + +void OUTLINER_OT_object_add_to_new_collection(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Objects to New Collection"; + ot->idname = "OUTLINER_OT_object_add_to_new_collection"; + ot->description = "Add objects to a new collection"; + + /* api callbacks */ + ot->exec = object_add_to_new_collection_exec; + ot->poll = outliner_objects_collection_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + struct CollectionDeleteData { Scene *scene; SpaceOops *soops; @@ -757,3 +916,139 @@ void OUTLINER_OT_collection_toggle(wmOperatorType *ot) #undef ACTION_TOGGLE #undef ACTION_ENABLE #undef ACTION_DISABLE + +struct CollectionObjectsSelectData { + bool error; + LayerCollection *layer_collection; +}; + +static TreeTraversalAction outliner_find_first_selected_layer_collection(TreeElement *te, void *customdata) +{ + struct CollectionObjectsSelectData *data = customdata; + TreeStoreElem *tselem = TREESTORE(te); + + switch (tselem->type) { + case TSE_LAYER_COLLECTION: + data->layer_collection = te->directdata; + return TRAVERSE_BREAK; + case TSE_LAYER_COLLECTION_BASE: + return TRAVERSE_CONTINUE; + default: + return TRAVERSE_SKIP_CHILDS; + } +} + +static LayerCollection *outliner_active_layer_collection(bContext *C) +{ + SpaceOops *soops = CTX_wm_space_outliner(C); + + struct CollectionObjectsSelectData data = { + .layer_collection = NULL, + }; + + outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_first_selected_layer_collection, &data); + return data.layer_collection; +} + +static int collection_objects_select_exec(bContext *C, wmOperator *UNUSED(op)) +{ + LayerCollection *layer_collection = outliner_active_layer_collection(C); + + if (layer_collection == NULL) { + return OPERATOR_CANCELLED; + } + + BKE_layer_collection_objects_select(layer_collection); + WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, CTX_data_scene(C)); + + return OPERATOR_FINISHED; +} + +void OUTLINER_OT_collection_objects_select(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Objects"; + ot->idname = "OUTLINER_OT_collection_objects_select"; + ot->description = "Select all the collection objects"; + + /* api callbacks */ + ot->exec = collection_objects_select_exec; + ot->poll = view_layer_editor_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +struct CollectionDuplicateData { + TreeElement *te; +}; + +static TreeTraversalAction outliner_find_first_selected_collection(TreeElement *te, void *customdata) +{ + struct CollectionDuplicateData *data = customdata; + TreeStoreElem *tselem = TREESTORE(te); + + switch (tselem->type) { + case TSE_LAYER_COLLECTION: + case TSE_SCENE_COLLECTION: + data->te = te; + return TRAVERSE_BREAK; + case TSE_LAYER_COLLECTION_BASE: + default: + return TRAVERSE_CONTINUE; + } +} + +static TreeElement *outliner_active_collection(bContext *C) +{ + SpaceOops *soops = CTX_wm_space_outliner(C); + + struct CollectionDuplicateData data = { + .te = NULL, + }; + + outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_first_selected_collection, &data); + return data.te; +} + +static int collection_duplicate_exec(bContext *C, wmOperator *op) +{ + SpaceOops *soops = CTX_wm_space_outliner(C); + TreeElement *te = outliner_active_collection(C); + + BLI_assert(te != NULL); + if (BKE_collection_master(TREESTORE(te)->id) == outliner_scene_collection_from_tree_element(te)) { + BKE_report(op->reports, RPT_ERROR, "You can't duplicate the master collection"); + return OPERATOR_CANCELLED; + } + + switch (soops->outlinevis) { + case SO_COLLECTIONS: + BKE_collection_duplicate(TREESTORE(te)->id, (SceneCollection *)te->directdata); + break; + case SO_VIEW_LAYER: + case SO_GROUPS: + BKE_layer_collection_duplicate(TREESTORE(te)->id, (LayerCollection *)te->directdata); + break; + } + + DEG_relations_tag_update(CTX_data_main(C)); + WM_main_add_notifier(NC_SCENE | ND_LAYER, CTX_data_scene(C)); + + return OPERATOR_FINISHED; +} + +void OUTLINER_OT_collection_duplicate(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Duplicate Collection"; + ot->idname = "OUTLINER_OT_collection_duplicate"; + ot->description = "Duplicate collection"; + + /* api callbacks */ + ot->exec = collection_duplicate_exec; + ot->poll = outliner_either_collection_editor_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 45459bdb030..0f9723dea4b 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -409,7 +409,8 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname) case TSE_LAYER_COLLECTION: { SceneCollection *sc = outliner_scene_collection_from_tree_element(te); - BKE_collection_rename(scene, sc, te->name); + BKE_collection_rename(tselem->id, sc, te->name); + WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); break; } } @@ -671,7 +672,7 @@ static void outliner_draw_userbuts(uiBlock *block, ARegion *ar, SpaceOops *soops } } -static void UNUSED_FUNCTION(outliner_draw_rnacols)(ARegion *ar, int sizex) +static void outliner_draw_rnacols(ARegion *ar, int sizex) { View2D *v2d = &ar->v2d; @@ -697,7 +698,6 @@ static void UNUSED_FUNCTION(outliner_draw_rnacols)(ARegion *ar, int sizex) immUnbindProgram(); } -#if 0 static void outliner_draw_rnabuts(uiBlock *block, ARegion *ar, SpaceOops *soops, int sizex, ListBase *lb) { TreeElement *te; @@ -742,7 +742,6 @@ static void outliner_draw_rnabuts(uiBlock *block, ARegion *ar, SpaceOops *soops, UI_block_emboss_set(block, UI_EMBOSS); } -#endif static void outliner_buttons(const bContext *C, uiBlock *block, ARegion *ar, TreeElement *te) { @@ -1241,8 +1240,9 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto #undef ICON_DRAW } -static void outliner_draw_iconrow(bContext *C, uiBlock *block, Scene *scene, ViewLayer *view_layer, SpaceOops *soops, - ListBase *lb, int level, int xmax, int *offsx, int ys, float alpha_fac) +static void outliner_draw_iconrow( + bContext *C, uiBlock *block, Scene *scene, ViewLayer *view_layer, Object *obedit, SpaceOops *soops, + ListBase *lb, int level, int xmax, int *offsx, int ys, float alpha_fac) { TreeElement *te; TreeStoreElem *tselem; @@ -1263,7 +1263,7 @@ static void outliner_draw_iconrow(bContext *C, uiBlock *block, Scene *scene, Vie if (te->idcode == ID_OB) { active = (OBACT(view_layer) == (Object *)tselem->id) ? OL_DRAWSEL_NORMAL : OL_DRAWSEL_NONE; } - else if (scene->obedit && scene->obedit->data == tselem->id) { + else if (obedit && obedit->data == tselem->id) { active = OL_DRAWSEL_NORMAL; } else { @@ -1303,7 +1303,9 @@ static void outliner_draw_iconrow(bContext *C, uiBlock *block, Scene *scene, Vie /* this tree element always has same amount of branches, so don't draw */ if (tselem->type != TSE_R_LAYER) - outliner_draw_iconrow(C, block, scene, view_layer, soops, &te->subtree, level + 1, xmax, offsx, ys, alpha_fac); + outliner_draw_iconrow( + C, block, scene, view_layer, obedit, soops, + &te->subtree, level + 1, xmax, offsx, ys, alpha_fac); } } @@ -1327,7 +1329,7 @@ static void outliner_set_coord_tree_element(TreeElement *te, int startx, int sta static void outliner_draw_tree_element( - bContext *C, uiBlock *block, const uiFontStyle *fstyle, Scene *scene, ViewLayer *view_layer, + bContext *C, uiBlock *block, const uiFontStyle *fstyle, Scene *scene, ViewLayer *view_layer, Object *obedit, ARegion *ar, SpaceOops *soops, TreeElement *te, bool draw_grayed_out, int startx, int *starty, TreeElement **te_edit, TreeElement **te_floating) { @@ -1391,7 +1393,7 @@ static void outliner_draw_tree_element( } } - else if (scene->obedit && scene->obedit->data == tselem->id) { + else if (obedit && obedit->data == tselem->id) { rgba_float_args_set(color, 1.0f, 1.0f, 1.0f, alpha); active = OL_DRAWSEL_ACTIVE; } @@ -1521,8 +1523,9 @@ static void outliner_draw_tree_element( immUnbindProgram(); } - outliner_draw_iconrow(C, block, scene, view_layer, soops, &te->subtree, 0, xmax, &tempx, - *starty, alpha_fac); + outliner_draw_iconrow( + C, block, scene, view_layer, obedit, soops, &te->subtree, 0, xmax, &tempx, + *starty, alpha_fac); glDisable(GL_BLEND); } @@ -1541,8 +1544,10 @@ static void outliner_draw_tree_element( /* check if element needs to be drawn grayed out, but also gray out * childs of a grayed out parent (pass on draw_grayed_out to childs) */ bool draw_childs_grayed_out = draw_grayed_out || (ten->drag_data != NULL); - outliner_draw_tree_element(C, block, fstyle, scene, view_layer, ar, soops, ten, draw_childs_grayed_out, - startx + UI_UNIT_X, starty, te_edit, te_floating); + outliner_draw_tree_element( + C, block, fstyle, scene, view_layer, obedit, + ar, soops, ten, draw_childs_grayed_out, + startx + UI_UNIT_X, starty, te_edit, te_floating); } } else { @@ -1781,15 +1786,15 @@ static void outliner_draw_highlights(ARegion *ar, SpaceOops *soops, int startx, } static void outliner_draw_tree( - bContext *C, uiBlock *block, Scene *scene, ViewLayer *view_layer, ARegion *ar, - SpaceOops *soops, const bool has_restrict_icons, + bContext *C, uiBlock *block, Scene *scene, ViewLayer *view_layer, Object *obedit, + ARegion *ar, SpaceOops *soops, const bool has_restrict_icons, TreeElement **te_edit) { const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; TreeElement *te_floating = NULL; int starty, startx; - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // only once + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // only once if (soops->outlinevis == SO_DATABLOCKS) { /* struct marks */ @@ -1822,8 +1827,10 @@ static void outliner_draw_tree( starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET; startx = 0; for (TreeElement *te = soops->tree.first; te; te = te->next) { - outliner_draw_tree_element(C, block, fstyle, scene, view_layer, ar, soops, te, te->drag_data != NULL, - startx, &starty, te_edit, &te_floating); + outliner_draw_tree_element( + C, block, fstyle, scene, view_layer, obedit, + ar, soops, te, te->drag_data != NULL, + startx, &starty, te_edit, &te_floating); } if (te_floating && te_floating->drag_data->insert_handle) { outliner_draw_tree_element_floating(ar, te_floating); @@ -1898,9 +1905,12 @@ static void outliner_draw_restrictcols(ARegion *ar) void draw_outliner(const bContext *C) { + EvaluationContext eval_ctx; + CTX_data_eval_ctx(C, &eval_ctx); Main *mainvar = CTX_data_main(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); + Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer); ARegion *ar = CTX_wm_region(C); View2D *v2d = &ar->v2d; SpaceOops *soops = CTX_wm_space_outliner(C); @@ -1960,9 +1970,16 @@ void draw_outliner(const bContext *C) /* draw outliner stuff (background, hierarchy lines and names) */ outliner_back(ar); block = UI_block_begin(C, ar, __func__, UI_EMBOSS); - outliner_draw_tree((bContext *)C, block, scene, view_layer, ar, soops, has_restrict_icons, &te_edit); + outliner_draw_tree( + (bContext *)C, block, scene, view_layer, obedit, + ar, soops, has_restrict_icons, &te_edit); - if ((soops->outlinevis == SO_ID_ORPHANS) && has_restrict_icons) { + if (soops->outlinevis == SO_DATABLOCKS) { + /* draw rna buttons */ + outliner_draw_rnacols(ar, sizex_rna); + outliner_draw_rnabuts(block, ar, soops, sizex_rna, &soops->tree); + } + else if ((soops->outlinevis == SO_ID_ORPHANS) && has_restrict_icons) { /* draw user toggle columns */ outliner_draw_restrictcols(ar); outliner_draw_userbuts(block, ar, soops, &soops->tree); diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index fc0e30c78ce..f5d117922c0 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -51,7 +51,6 @@ #include "BKE_animsys.h" #include "BKE_context.h" -#include "BKE_global.h" #include "BKE_idcode.h" #include "BKE_layer.h" #include "BKE_library.h" diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index 30ede0a5e55..13567c2a5a2 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -37,6 +37,7 @@ /* internal exports only */ struct ARegion; +struct ListBase; struct wmOperatorType; struct TreeElement; struct TreeStoreElem; @@ -50,7 +51,7 @@ struct bPoseChannel; struct EditBone; struct wmEvent; struct wmKeyConfig; - +struct EvaluationContext; typedef enum TreeElementInsertType { TE_INSERT_BEFORE, @@ -191,8 +192,16 @@ void outliner_cleanup_tree(struct SpaceOops *soops); void outliner_free_tree_element(TreeElement *element, ListBase *parent_subtree); void outliner_remove_treestore_element(struct SpaceOops *soops, TreeStoreElem *tselem); -void outliner_build_tree(struct Main *mainvar, struct Scene *scene, struct ViewLayer *view_layer, - struct SpaceOops *soops, struct ARegion *ar); +void outliner_build_tree( + struct Main *mainvar, + struct Scene *scene, struct ViewLayer *view_layer, + struct SpaceOops *soops, struct ARegion *ar); + +typedef struct ObjectsSelectedData { + struct ListBase objects_selected_array; +} ObjectsSelectedData; + +TreeTraversalAction outliner_find_selected_objects(struct TreeElement *te, void *customdata); /* outliner_draw.c ---------------------------------------------- */ @@ -344,7 +353,11 @@ void OUTLINER_OT_collection_toggle(struct wmOperatorType *ot); void OUTLINER_OT_collection_link(struct wmOperatorType *ot); void OUTLINER_OT_collection_unlink(struct wmOperatorType *ot); void OUTLINER_OT_collection_new(struct wmOperatorType *ot); +void OUTLINER_OT_collection_duplicate(struct wmOperatorType *ot); void OUTLINER_OT_collection_objects_remove(struct wmOperatorType *ot); +void OUTLINER_OT_collection_objects_select(struct wmOperatorType *ot); +void OUTLINER_OT_object_add_to_new_collection(struct wmOperatorType *ot); +void OUTLINER_OT_object_remove_from_collection(struct wmOperatorType *ot); void OUTLINER_OT_collection_objects_add(struct wmOperatorType *ot); void OUTLINER_OT_collection_nested_new(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index 52f27b9708e..ba501ac7db5 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -474,11 +474,15 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_collection_link); WM_operatortype_append(OUTLINER_OT_collection_unlink); WM_operatortype_append(OUTLINER_OT_collection_new); + WM_operatortype_append(OUTLINER_OT_collection_duplicate); WM_operatortype_append(OUTLINER_OT_collection_nested_new); WM_operatortype_append(OUTLINER_OT_collection_delete_selected); WM_operatortype_append(OUTLINER_OT_collection_objects_add); WM_operatortype_append(OUTLINER_OT_collection_objects_remove); + WM_operatortype_append(OUTLINER_OT_collection_objects_select); + WM_operatortype_append(OUTLINER_OT_object_add_to_new_collection); + WM_operatortype_append(OUTLINER_OT_object_remove_from_collection); } static wmKeyMap *outliner_item_drag_drop_modal_keymap(wmKeyConfig *keyconf) diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index b9222e62bb0..2f44420f3b7 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -57,7 +57,7 @@ #include "ED_object.h" #include "ED_screen.h" #include "ED_sequencer.h" -#include "ED_util.h" +#include "ED_undo.h" #include "WM_api.h" #include "WM_types.h" @@ -194,8 +194,8 @@ static eOLDrawState tree_element_set_active_object( } } - if (ob != scene->obedit) - ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO); + if (ob != OBEDIT_FROM_VIEW_LAYER(view_layer)) + ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO); return OL_DRAWSEL_NORMAL; } @@ -547,7 +547,7 @@ static eOLDrawState tree_element_active_bone( /* ebones only draw in editmode armature */ -static void tree_element_active_ebone__sel(bContext *C, Scene *scene, bArmature *arm, EditBone *ebone, short sel) +static void tree_element_active_ebone__sel(bContext *C, Object *obedit, bArmature *arm, EditBone *ebone, short sel) { if (sel) { ebone->flag |= BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL; @@ -561,34 +561,34 @@ static void tree_element_active_ebone__sel(bContext *C, Scene *scene, bArmature if (ebone->parent && (ebone->flag & BONE_CONNECTED)) ebone->parent->flag &= ~BONE_TIPSEL; } - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_ACTIVE, scene->obedit); + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_ACTIVE, obedit); } static eOLDrawState tree_element_active_ebone( - bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tselem), const eOLSetState set, bool recursive) + bContext *C, TreeElement *te, TreeStoreElem *UNUSED(tselem), const eOLSetState set, bool recursive) { - BLI_assert(scene->obedit != NULL); - - bArmature *arm = scene->obedit->data; + Object *obedit = CTX_data_edit_object(C); + BLI_assert(obedit != NULL); + bArmature *arm = obedit->data; EditBone *ebone = te->directdata; eOLDrawState status = OL_DRAWSEL_NONE; if (set != OL_SETSEL_NONE) { if (set == OL_SETSEL_NORMAL) { if (!(ebone->flag & BONE_HIDDEN_A)) { - ED_armature_deselect_all(scene->obedit); - tree_element_active_ebone__sel(C, scene, arm, ebone, true); + ED_armature_deselect_all(obedit); + tree_element_active_ebone__sel(C, obedit, arm, ebone, true); status = OL_DRAWSEL_NORMAL; } } else if (set == OL_SETSEL_EXTEND) { if (!(ebone->flag & BONE_HIDDEN_A)) { if (!(ebone->flag & BONE_SELECTED)) { - tree_element_active_ebone__sel(C, scene, arm, ebone, true); + tree_element_active_ebone__sel(C, obedit, arm, ebone, true); status = OL_DRAWSEL_NORMAL; } else { /* entirely selected, so de-select */ - tree_element_active_ebone__sel(C, scene, arm, ebone, false); + tree_element_active_ebone__sel(C, obedit, arm, ebone, false); status = OL_DRAWSEL_NONE; } } @@ -656,7 +656,7 @@ static eOLDrawState tree_element_active_text( } static eOLDrawState tree_element_active_pose( - bContext *C, Scene *scene, ViewLayer *view_layer, TreeElement *UNUSED(te), TreeStoreElem *tselem, const eOLSetState set) + bContext *C, ViewLayer *view_layer, TreeElement *UNUSED(te), TreeStoreElem *tselem, const eOLSetState set) { Object *ob = (Object *)tselem->id; Base *base = BKE_view_layer_base_find(view_layer, ob); @@ -667,13 +667,16 @@ static eOLDrawState tree_element_active_pose( } if (set != OL_SETSEL_NONE) { - if (scene->obedit) - ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO); + if (OBEDIT_FROM_VIEW_LAYER(view_layer)) { + ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO); + } - if (ob->mode & OB_MODE_POSE) - ED_armature_exit_posemode(C, base); - else - ED_armature_enter_posemode(C, base); + if (ob->mode & OB_MODE_POSE) { + ED_object_posemode_exit(C, ob); + } + else { + ED_object_posemode_enter(C, ob); + } } else { if (ob->mode & OB_MODE_POSE) { @@ -847,7 +850,7 @@ eOLDrawState tree_element_type_active( case TSE_BONE: return tree_element_active_bone(C, view_layer, te, tselem, set, recursive); case TSE_EBONE: - return tree_element_active_ebone(C, scene, te, tselem, set, recursive); + return tree_element_active_ebone(C, te, tselem, set, recursive); case TSE_MODIFIER: return tree_element_active_modifier(C, scene, view_layer, te, tselem, set); case TSE_LINKED_OB: @@ -861,7 +864,7 @@ eOLDrawState tree_element_type_active( case TSE_LINKED_PSYS: return tree_element_active_psys(C, scene, te, tselem, set); case TSE_POSE_BASE: - return tree_element_active_pose(C, scene, view_layer, te, tselem, set); + return tree_element_active_pose(C, view_layer, te, tselem, set); case TSE_POSE_CHANNEL: return tree_element_active_posechannel(C, scene, view_layer, te, tselem, set, recursive); case TSE_CONSTRAINT: @@ -921,7 +924,7 @@ static void do_outliner_item_activate_tree_element( if (extend) { int sel = BA_SELECT; - FOREACH_GROUP_BASE(gr, base) + FOREACH_GROUP_BASE_BEGIN(gr, base) { if (base->flag & BASE_SELECTED) { sel = BA_DESELECT; @@ -930,16 +933,16 @@ static void do_outliner_item_activate_tree_element( } FOREACH_GROUP_BASE_END - FOREACH_GROUP_OBJECT(gr, object) + FOREACH_GROUP_OBJECT_BEGIN(gr, object) { ED_object_base_select(BKE_view_layer_base_find(view_layer, object), sel); } - FOREACH_GROUP_OBJECT_END + FOREACH_GROUP_OBJECT_END; } else { BKE_view_layer_base_deselect_all(view_layer); - FOREACH_GROUP_OBJECT(gr, object) + FOREACH_GROUP_OBJECT_BEGIN(gr, object) { Base *base = BKE_view_layer_base_find(view_layer, object); /* Object may not be in this scene */ @@ -949,7 +952,7 @@ static void do_outliner_item_activate_tree_element( } } } - FOREACH_GROUP_OBJECT_END + 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 eaa3267e99d..735e2b5a37a 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -73,7 +73,7 @@ #include "ED_scene.h" #include "ED_screen.h" #include "ED_sequencer.h" -#include "ED_util.h" +#include "ED_undo.h" #include "WM_api.h" #include "WM_types.h" @@ -419,9 +419,9 @@ static void object_delete_cb( } // check also library later - if (scene->obedit == ob) - ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO); - + if (ob == CTX_data_edit_object(C)) { + ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO); + } ED_object_base_free_and_unlink(CTX_data_main(C), scene, ob); /* leave for ED_outliner_id_unref to handle */ #if 0 @@ -541,7 +541,7 @@ static void group_linkobs2scene_cb( Group *group = (Group *)tselem->id; Base *base; - FOREACH_GROUP_OBJECT(group, object) + FOREACH_GROUP_OBJECT_BEGIN(group, object) { base = BKE_view_layer_base_find(view_layer, object); if (!base) { @@ -553,7 +553,7 @@ static void group_linkobs2scene_cb( base->flag |= BASE_SELECTED; } - FOREACH_GROUP_OBJECT_END + FOREACH_GROUP_OBJECT_END; } static void group_instance_cb( @@ -675,7 +675,9 @@ typedef enum eOutliner_PropModifierOps { typedef enum eOutliner_PropCollectionOps { OL_COLLECTION_OP_OBJECTS_ADD = 1, OL_COLLECTION_OP_OBJECTS_REMOVE, + OL_COLLECTION_OP_OBJECTS_SELECT, OL_COLLECTION_OP_COLLECTION_NEW, + OL_COLLECTION_OP_COLLECTION_COPY, OL_COLLECTION_OP_COLLECTION_DEL, OL_COLLECTION_OP_COLLECTION_UNLINK, OL_COLLECTION_OP_GROUP_CREATE, @@ -860,6 +862,10 @@ static void collection_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tsel WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); te->store_elem->flag &= ~TSE_SELECTED; } + else if (event == OL_COLLECTION_OP_OBJECTS_SELECT) { + BKE_layer_collection_objects_select(lc); + WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, scene); + } else if (event == OL_COLLECTION_OP_COLLECTION_NEW) { if (GS(id->name) == ID_GR) { BKE_collection_add(id, sc, COLLECTION_TYPE_GROUP_INTERNAL, NULL); @@ -870,6 +876,11 @@ static void collection_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tsel } WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); } + else if (event == OL_COLLECTION_OP_COLLECTION_COPY) { + BKE_layer_collection_duplicate(id, lc); + DEG_relations_tag_update(CTX_data_main(C)); + WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); + } else if (event == OL_COLLECTION_OP_COLLECTION_UNLINK) { ViewLayer *view_layer = CTX_data_view_layer(C); @@ -969,7 +980,7 @@ static void object_delete_hierarchy_cb( { ViewLayer *view_layer = CTX_data_view_layer(C); Base *base = (Base *)te->directdata; - Object *obedit = scene->obedit; + Object *obedit = CTX_data_edit_object(C); if (!base) { base = BKE_view_layer_base_find(view_layer, (Object *)tselem->id); @@ -978,7 +989,7 @@ static void object_delete_hierarchy_cb( /* Check also library later. */ for (; obedit && (obedit != base->object); obedit = obedit->parent); if (obedit == base->object) { - ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO); + ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO); } outline_delete_hierarchy(C, reports, scene, base); @@ -1016,9 +1027,6 @@ static const EnumPropertyItem prop_object_op_types[] = { {OL_OP_DELETE_HIERARCHY, "DELETE_HIERARCHY", 0, "Delete Hierarchy", ""}, {OL_OP_REMAP, "REMAP", 0, "Remap Users", "Make all users of selected data-blocks to use instead a new chosen one"}, - {OL_OP_TOGVIS, "TOGVIS", 0, "Toggle Visible", ""}, - {OL_OP_TOGSEL, "TOGSEL", 0, "Toggle Selectable", ""}, - {OL_OP_TOGREN, "TOGREN", 0, "Toggle Renderable", ""}, {OL_OP_RENAME, "RENAME", 0, "Rename", ""}, {0, NULL, 0, NULL, NULL} }; @@ -1844,39 +1852,18 @@ void OUTLINER_OT_modifier_operation(wmOperatorType *ot) /* ******************** */ -static EnumPropertyItem prop_collection_op_none_types[] = { +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_OBJECTS_SELECT, "OBJECTS_SELECT", ICON_RESTRICT_SELECT_OFF, "Select Objects", "Select collection objects"}, {OL_COLLECTION_OP_COLLECTION_NEW, "COLLECTION_NEW", ICON_NEW, "New Collection", "Add a new nested collection"}, + {OL_COLLECTION_OP_COLLECTION_COPY, "COLLECTION_DUPLI", ICON_NONE, "Duplicate Collection", "Duplicate the 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_VIEW_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); @@ -1895,6 +1882,31 @@ static int outliner_collection_operation_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +static int outliner_collection_operation_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + SpaceOops *soops = CTX_wm_space_outliner(C); + wmOperatorType *ot = op->type; + EnumPropertyItem *prop = &prop_collection_op_types[0]; + + uiPopupMenu *pup = UI_popup_menu_begin(C, "Collection", ICON_NONE); + uiLayout *layout = UI_popup_menu_layout(pup); + + for (int i = 0; i < (ARRAY_SIZE(prop_collection_op_types) - 1); i++, prop++) { + if (soops->outlinevis != SO_GROUPS || + !ELEM(prop->value, + OL_COLLECTION_OP_OBJECTS_SELECT, + OL_COLLECTION_OP_COLLECTION_UNLINK, + OL_COLLECTION_OP_GROUP_CREATE)) + { + uiItemEnumO_ptr(layout, ot, NULL, prop->icon, "type", prop->value); + } + } + + UI_popup_menu_end(C, pup); + + return OPERATOR_INTERFACE; +} + void OUTLINER_OT_collection_operation(wmOperatorType *ot) { PropertyRNA *prop; @@ -1905,14 +1917,13 @@ void OUTLINER_OT_collection_operation(wmOperatorType *ot) ot->description = ""; /* callbacks */ - ot->invoke = WM_menu_invoke; + ot->invoke = outliner_collection_operation_invoke; ot->exec = outliner_collection_operation_exec; ot->poll = ED_operator_outliner_active; ot->flag = 0; - prop = RNA_def_enum(ot->srna, "type", DummyRNA_NULL_items, 0, "Collection Operation", ""); - RNA_def_enum_funcs(prop, outliner_collection_operation_type_itemf); + prop = RNA_def_enum(ot->srna, "type", prop_collection_op_types, OL_COLLECTION_OP_OBJECTS_ADD, "Collection Operation", ""); RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); ot->prop = prop; } @@ -2051,7 +2062,7 @@ static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOops *soop } } else if (objectlevel) { - WM_operator_name_call(C, "OUTLINER_OT_object_operation", WM_OP_INVOKE_REGION_WIN, NULL); + WM_menu_name_call(C, "OUTLINER_MT_context_object", WM_OP_INVOKE_REGION_WIN); } else if (idlevel) { if (idlevel == -1 || datalevel) { diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 205f70e58dc..9f44b5bfc02 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -130,7 +130,7 @@ static void outliner_storage_cleanup(SpaceOops *soops) } if (unused) { - if (BLI_mempool_count(ts) == unused) { + if (BLI_mempool_len(ts) == unused) { BLI_mempool_destroy(ts); soops->treestore = NULL; if (soops->treehash) { @@ -140,7 +140,7 @@ static void outliner_storage_cleanup(SpaceOops *soops) } else { TreeStoreElem *tsenew; - BLI_mempool *new_ts = BLI_mempool_create(sizeof(TreeStoreElem), BLI_mempool_count(ts) - unused, + BLI_mempool *new_ts = BLI_mempool_create(sizeof(TreeStoreElem), BLI_mempool_len(ts) - unused, 512, BLI_MEMPOOL_ALLOW_ITER); BLI_mempool_iternew(ts, &iter); while ((tselem = BLI_mempool_iterstep(&iter))) { @@ -416,11 +416,7 @@ static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *s #endif } -struct ObjectsSelectedData { - ListBase objects_selected_array; -}; - -static TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *customdata) +TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *customdata) { struct ObjectsSelectedData *data = customdata; TreeStoreElem *tselem = TREESTORE(te); @@ -466,7 +462,7 @@ static void outliner_object_reorder( TREESTORE(insert_element)->flag |= TSE_SELECTED; outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_selected_objects, &data); - BLI_LISTBASE_FOREACH (LinkData *, link, &data.objects_selected_array) { + LISTBASE_FOREACH (LinkData *, link, &data.objects_selected_array) { TreeElement *ten_selected = (TreeElement *)link->data; Object *ob = (Object *)TREESTORE(ten_selected)->id; @@ -2183,7 +2179,7 @@ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, Spa { TreeElement *te = NULL, *ten; TreeStoreElem *tselem; - int show_opened = !soops->treestore || !BLI_mempool_count(soops->treestore); /* on first view, we open scenes */ + int show_opened = !soops->treestore || !BLI_mempool_len(soops->treestore); /* on first view, we open scenes */ /* Are we looking for something - we want to tag parents to filter child matches * - NOT in datablocks view - searching all datablocks takes way too long to be useful @@ -2330,11 +2326,11 @@ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, Spa } else if (soops->outlinevis == SO_COLLECTIONS) { if ((soops->filter & SO_FILTER_ENABLE) && (soops->filter & SO_FILTER_NO_COLLECTION)) { - FOREACH_SCENE_OBJECT(scene, ob) + FOREACH_SCENE_OBJECT_BEGIN(scene, ob) { outliner_add_element(soops, &soops->tree, ob, NULL, 0, 0); } - FOREACH_SCENE_OBJECT_END + FOREACH_SCENE_OBJECT_END; outliner_make_hierarchy(&soops->tree); } else { diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 04dbab0b853..8e5863fd514 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -58,7 +58,6 @@ #include "BIF_glutil.h" -#include "GPU_compositing.h" #include "GPU_immediate.h" #include "GPU_immediate_util.h" #include "GPU_matrix.h" @@ -330,7 +329,7 @@ static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1, } glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); for (seq = seqbase->first; seq; seq = seq->next) { chan_min = min_ii(chan_min, seq->machine); @@ -435,7 +434,7 @@ static void draw_seq_handle(View2D *v2d, Sequence *seq, const float handsize_cla { glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); if (seq->flag & whichsel) { immUniformColor4ub(0, 0, 0, 80); @@ -620,7 +619,7 @@ static void draw_sequence_extensions(Scene *scene, ARegion *ar, Sequence *seq, u if (seq->startofs || seq->endofs) { glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); color3ubv_from_seq(scene, seq, col); @@ -664,7 +663,7 @@ static void draw_sequence_extensions(Scene *scene, ARegion *ar, Sequence *seq, u if (seq->startstill || seq->endstill) { glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); color3ubv_from_seq(scene, seq, col); UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.5f, 60); @@ -730,7 +729,7 @@ static void draw_seq_strip(const bContext *C, SpaceSeq *sseq, Scene *scene, AReg background_col[3] = 128; glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } else { background_col[3] = 255; @@ -842,7 +841,7 @@ static void draw_seq_strip(const bContext *C, SpaceSeq *sseq, Scene *scene, AReg col[3] = 96; glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); immUniformColor4ubv(col); } @@ -924,12 +923,6 @@ ImBuf *sequencer_ibuf_get(struct Main *bmain, Scene *scene, SpaceSeq *sseq, int rectx, recty, proxy_size, &context); context.view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname); - if (scene->r.seq_flag & R_SEQ_CAMERA_DOF) { - if (sseq->compositor == NULL) { - sseq->compositor = GPU_fx_compositor_create(); - } - context.gpu_fx = sseq->compositor; - } /* sequencer could start rendering, in this case we need to be sure it wouldn't be canceled * by Esc pressed somewhere in the past @@ -1226,7 +1219,7 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq if (sseq->mainb == SEQ_DRAW_IMG_IMBUF && sseq->flag & SEQ_USE_ALPHA) { glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } /* Format needs to be created prior to any immBindProgram call. @@ -1316,6 +1309,7 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq glGenTextures(1, (GLuint *)&texid); + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texid); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -1329,7 +1323,7 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq if (!glsl_used) { immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_COLOR); immUniformColor3f(1.0f, 1.0f, 1.0f); - immUniform1i("image", GL_TEXTURE0); + immUniform1i("image", 0); } immBegin(GWN_PRIM_TRI_FAN, 4); diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index cb0c5bd3717..9a0578fe220 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -671,6 +671,9 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe) Sequence *seqn = NULL; bool skip_dup = false; + /* Unlike soft-cut, it's important to use the same value for both strips. */ + const bool is_end_exact = ((seq->start + seq->len) == cutframe); + /* backup values */ ts.start = seq->start; ts.machine = seq->machine; @@ -683,7 +686,7 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe) ts.anim_startofs = seq->anim_startofs; ts.anim_endofs = seq->anim_endofs; ts.len = seq->len; - + /* First Strip! */ /* strips with extended stillfames before */ @@ -695,6 +698,8 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe) BKE_sequence_calc(scene, seq); } + /* Important to offset the start when 'cutframe == seq->start' + * because we need at least one frame of content after start/end still have clipped it. */ if ((seq->startstill) && (cutframe <= seq->start)) { /* don't do funny things with METAs ... */ if (seq->type == SEQ_TYPE_META) { @@ -709,13 +714,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 ((is_end_exact == false) && + ((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) || + else if ((is_end_exact == true) || (((seq->start + seq->len) < cutframe) && (seq->endstill))) { seq->endstill -= seq->enddisp - cutframe; @@ -735,7 +742,11 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe) if (seqn) { seqn->flag |= SELECT; - + + /* Important not to re-assign this (unlike soft-cut) */ +#if 0 + is_end_exact = ((seqn->start + seqn->len) == cutframe); +#endif /* Second Strip! */ /* strips with extended stillframes before */ if ((seqn->startstill) && (cutframe == seqn->start + 1)) { @@ -744,9 +755,11 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe) seqn->anim_endofs = ts.anim_endofs; seqn->endstill = ts.endstill; } - + /* normal strip */ - else if ((cutframe >= seqn->start) && (cutframe < (seqn->start + seqn->len))) { + else if ((is_end_exact == false) && + ((cutframe >= seqn->start) && (cutframe <= (seqn->start + seqn->len)))) + { seqn->start = cutframe; seqn->startstill = 0; seqn->startofs = 0; @@ -755,9 +768,9 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe) seqn->anim_endofs = ts.anim_endofs; seqn->endstill = ts.endstill; } - + /* strips with extended stillframes after */ - else if (((seqn->start + seqn->len) == cutframe) || + else if ((is_end_exact == true) || (((seqn->start + seqn->len) < cutframe) && (seqn->endstill))) { seqn->start = cutframe; @@ -766,7 +779,7 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe) seqn->endstill = ts.enddisp - cutframe - 1; seqn->startstill = 0; } - + BKE_sequence_reload_new_file(scene, seqn, false); BKE_sequence_calc(scene, seqn); } @@ -779,6 +792,8 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe) Sequence *seqn = NULL; bool skip_dup = false; + bool is_end_exact = ((seq->start + seq->len) == cutframe); + /* backup values */ ts.start = seq->start; ts.machine = seq->machine; @@ -791,10 +806,12 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe) ts.anim_startofs = seq->anim_startofs; ts.anim_endofs = seq->anim_endofs; ts.len = seq->len; - + /* First Strip! */ /* strips with extended stillfames before */ - + + /* Important to offset the start when 'cutframe == seq->start' + * because we need at least one frame of content after start/end still have clipped it. */ if ((seq->startstill) && (cutframe <= seq->start)) { /* don't do funny things with METAs ... */ if (seq->type == SEQ_TYPE_META) { @@ -809,11 +826,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 ((is_end_exact == false) && + (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) || + else if ((is_end_exact == true) || (((seq->start + seq->len) < cutframe) && (seq->endstill))) { seq->endstill -= seq->enddisp - cutframe; @@ -832,7 +851,9 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe) if (seqn) { seqn->flag |= SELECT; - + + is_end_exact = ((seqn->start + seqn->len) == cutframe); + /* Second Strip! */ /* strips with extended stillframes before */ if ((seqn->startstill) && (cutframe == seqn->start + 1)) { @@ -843,15 +864,17 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe) } /* normal strip */ - if ((cutframe >= seqn->start) && (cutframe < (seqn->start + seqn->len))) { + else if ((is_end_exact == false) && + (cutframe >= seqn->start) && (cutframe <= (seqn->start + seqn->len))) + { seqn->startstill = 0; seqn->startofs = cutframe - ts.start; seqn->endofs = ts.endofs; seqn->endstill = ts.endstill; } - + /* strips with extended stillframes after */ - else if (((seqn->start + seqn->len) == cutframe) || + else if ((is_end_exact == true) || (((seqn->start + seqn->len) < cutframe) && (seqn->endstill))) { seqn->start = cutframe - ts.len + 1; @@ -859,7 +882,7 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe) seqn->endstill = ts.enddisp - cutframe - 1; seqn->startstill = 0; } - + BKE_sequence_calc(scene, seqn); } return seqn; @@ -2785,7 +2808,7 @@ static int sequencer_view_zoom_ratio_exec(bContext *C, wmOperator *op) float facx = BLI_rcti_size_x(&v2d->mask) / winx; float facy = BLI_rcti_size_y(&v2d->mask) / winy; - BLI_rctf_resize(&v2d->cur, floorf(winx * facx / ratio + 0.5f), floorf(winy * facy / ratio + 0.5f)); + BLI_rctf_resize(&v2d->cur, ceilf(winx * facx / ratio + 0.5f), ceilf(winy * facy / ratio + 0.5f)); ED_region_tag_redraw(CTX_wm_region(C)); diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index 23387f291e6..da16ac5acaa 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -60,8 +60,6 @@ #include "IMB_imbuf.h" -#include "GPU_compositing.h" - #include "sequencer_intern.h" // own include /**************************** common state *****************************/ @@ -220,11 +218,6 @@ static void sequencer_free(SpaceLink *sl) if (scopes->histogram_ibuf) IMB_freeImBuf(scopes->histogram_ibuf); - - if (sseq->compositor != NULL) { - GPU_fx_compositor_destroy(sseq->compositor); - sseq->compositor = NULL; - } } diff --git a/source/blender/editors/space_text/CMakeLists.txt b/source/blender/editors/space_text/CMakeLists.txt index 39b48f5b52c..91420a5d63a 100644 --- a/source/blender/editors/space_text/CMakeLists.txt +++ b/source/blender/editors/space_text/CMakeLists.txt @@ -48,6 +48,7 @@ set(SRC text_format_py.c text_header.c text_ops.c + text_undo.c text_format.h text_intern.h diff --git a/source/blender/editors/space_text/text_autocomplete.c b/source/blender/editors/space_text/text_autocomplete.c index da5fa9da046..9163831c333 100644 --- a/source/blender/editors/space_text/text_autocomplete.c +++ b/source/blender/editors/space_text/text_autocomplete.c @@ -241,7 +241,7 @@ static void get_suggest_prefix(Text *text, int offset) texttool_suggest_prefix(line + i, len); } -static void confirm_suggestion(Text *text) +static void confirm_suggestion(Text *text, TextUndoBuf *utxt) { SuggItem *sel; int i, over = 0; @@ -260,7 +260,7 @@ static void confirm_suggestion(Text *text) // for (i = 0; i < skipleft; i++) // txt_move_left(text, 0); BLI_assert(memcmp(sel->name, &line[i], over) == 0); - txt_insert_buf(text, sel->name + over); + txt_insert_buf(text, utxt, sel->name + over); // for (i = 0; i < skipleft; i++) // txt_move_right(text, 0); @@ -284,7 +284,8 @@ static int text_autocomplete_invoke(bContext *C, wmOperator *op, const wmEvent * ED_area_tag_redraw(CTX_wm_area(C)); if (texttool_suggest_first() == texttool_suggest_last()) { - confirm_suggestion(st->text); + TextUndoBuf *utxt = NULL; // FIXME + confirm_suggestion(st->text, utxt); text_update_line_edited(st->text->curl); text_autocomplete_free(C, op); return OPERATOR_FINISHED; @@ -314,6 +315,8 @@ static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *e (void)text; + TextUndoBuf *utxt = NULL; // FIXME + if (st->doplugins && texttool_text_is_active(st->text)) { if (texttool_suggest_first()) tools |= TOOL_SUGG_LIST; if (texttool_docs_get()) tools |= TOOL_DOCUMENT; @@ -340,7 +343,7 @@ static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *e case MIDDLEMOUSE: if (event->val == KM_PRESS) { if (text_do_suggest_select(st, ar)) { - confirm_suggestion(st->text); + confirm_suggestion(st->text, utxt); text_update_line_edited(st->text->curl); swallow = 1; } @@ -375,7 +378,7 @@ static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *e case PADENTER: if (event->val == KM_PRESS) { if (tools & TOOL_SUGG_LIST) { - confirm_suggestion(st->text); + confirm_suggestion(st->text, utxt); text_update_line_edited(st->text->curl); swallow = 1; draw = 1; diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c index 62fde49cade..3949aa928c9 100644 --- a/source/blender/editors/space_text/text_draw.c +++ b/source/blender/editors/space_text/text_draw.c @@ -1207,7 +1207,7 @@ static void draw_text_decoration(SpaceText *st, ARegion *ar) immUniformColor4ub(255, 255, 255, 32); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); immRecti(pos, x1 - 4, y1, x2, y2); glDisable(GL_BLEND); diff --git a/source/blender/editors/space_text/text_format_pov.c b/source/blender/editors/space_text/text_format_pov.c index 1ef3322711c..4c9abecedd6 100644 --- a/source/blender/editors/space_text/text_format_pov.c +++ b/source/blender/editors/space_text/text_format_pov.c @@ -486,7 +486,7 @@ static int txtfmt_pov_find_specialvar(const char *string) { int i, len; /* Modifiers */ - if (STR_LITERAL_STARTSWITH(string, "dispersion_samples", len)) i = len; + if (STR_LITERAL_STARTSWITH(string, "dispersion_samples", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "projected_through", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "double_illuminate", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "expand_thresholds", len)) i = len; @@ -498,7 +498,7 @@ static int txtfmt_pov_find_specialvar(const char *string) else if (STR_LITERAL_STARTSWITH(string, "max_trace_level", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "gray_threshold", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "pretrace_start", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "normal_indices", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "normal_indices", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "normal_vectors", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "vertex_vectors", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "noise_generator", len)) i = len; @@ -577,7 +577,7 @@ static int txtfmt_pov_find_specialvar(const char *string) else if (STR_LITERAL_STARTSWITH(string, "autostop", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "caustics", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "octaves", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "aa_level", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "aa_level", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "frequency", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "fog_offset", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "modulation", len)) i = len; @@ -642,45 +642,45 @@ static int txtfmt_pov_find_specialvar(const char *string) else if (STR_LITERAL_STARTSWITH(string, "radius", len)) i = len; /* Camera Types and options*/ else if (STR_LITERAL_STARTSWITH(string, "omni_directional_stereo", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "lambert_cylindrical", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "miller_cylindrical", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "lambert_azimuthal", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "ultra_wide_angle", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "camera_direction", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "camera_location ", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "van_der_grinten", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "aitoff_hammer", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "smyth_craster", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "orthographic", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "camera_right", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "blur_samples", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "plate_carree", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "camera_type", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "perspective", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "mesh_camera", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "focal_point", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "balthasart", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "confidence", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "parallaxe", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "hobo_dyer", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "camera_up", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "panoramic", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "eckert_vi", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "eckert_iv", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "mollweide", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "aperture", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "behrmann", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "variance", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "stereo", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "icosa", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "tetra", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "octa", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "mercator", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "omnimax", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "fisheye", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "edwards", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "peters", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "gall", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "lambert_cylindrical", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "miller_cylindrical", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "lambert_azimuthal", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ultra_wide_angle", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "camera_direction", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "camera_location ", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "van_der_grinten", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "aitoff_hammer", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "smyth_craster", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "orthographic", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "camera_right", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "blur_samples", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "plate_carree", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "camera_type", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "perspective", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "mesh_camera", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "focal_point", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "balthasart", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "confidence", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "parallaxe", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "hobo_dyer", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "camera_up", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "panoramic", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "eckert_vi", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "eckert_iv", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "mollweide", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "aperture", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "behrmann", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "variance", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "stereo", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "icosa", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "tetra", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "octa", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "mercator", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "omnimax", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "fisheye", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "edwards", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "peters", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gall", len)) i = len; else i = 0; /* If next source char is an identifier (eg. 'i' in "definate") no match */ diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index 772cd6bd419..4f332c09ce2 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -731,7 +731,8 @@ static int text_paste_exec(bContext *C, wmOperator *op) text_drawcache_tag_update(CTX_wm_space_text(C), 0); - txt_insert_buf(text, buf); + TextUndoBuf *utxt = ED_text_undo_push_init(C); + txt_insert_buf(text, utxt, buf); text_update_edited(text); MEM_freeN(buf); @@ -756,7 +757,10 @@ void TEXT_OT_paste(wmOperatorType *ot) /* api callbacks */ ot->exec = text_paste_exec; ot->poll = text_edit_poll; - + + /* flags */ + ot->flag = OPTYPE_UNDO; + /* properties */ RNA_def_boolean(ot->srna, "selection", 0, "Selection", "Paste text selected elsewhere rather than copied (X11 only)"); } @@ -766,9 +770,11 @@ void TEXT_OT_paste(wmOperatorType *ot) static int text_duplicate_line_exec(bContext *C, wmOperator *UNUSED(op)) { Text *text = CTX_data_edit_text(C); - - txt_duplicate_line(text); - + + TextUndoBuf *utxt = ED_text_undo_push_init(C); + + txt_duplicate_line(text, utxt); + WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text); /* run the script while editing, evil but useful */ @@ -785,10 +791,13 @@ void TEXT_OT_duplicate_line(wmOperatorType *ot) ot->name = "Duplicate Line"; ot->idname = "TEXT_OT_duplicate_line"; ot->description = "Duplicate the current line"; - + /* api callbacks */ ot->exec = text_duplicate_line_exec; ot->poll = text_edit_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; } /******************* copy operator *********************/ @@ -838,7 +847,9 @@ static int text_cut_exec(bContext *C, wmOperator *UNUSED(op)) text_drawcache_tag_update(CTX_wm_space_text(C), 0); txt_copy_clipboard(text); - txt_delete_selected(text); + + TextUndoBuf *utxt = ED_text_undo_push_init(C); + txt_delete_selected(text, utxt); text_update_cursor_moved(C); WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text); @@ -860,6 +871,9 @@ void TEXT_OT_cut(wmOperatorType *ot) /* api callbacks */ ot->exec = text_cut_exec; ot->poll = text_edit_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; } /******************* indent operator *********************/ @@ -870,12 +884,15 @@ static int text_indent_exec(bContext *C, wmOperator *UNUSED(op)) text_drawcache_tag_update(CTX_wm_space_text(C), 0); + TextUndoBuf *utxt = ED_text_undo_push_init(C); + if (txt_has_sel(text)) { txt_order_cursors(text, false); - txt_indent(text); + txt_indent(text, utxt); + } + else { + txt_add_char(text, utxt, '\t'); } - else - txt_add_char(text, '\t'); text_update_edited(text); @@ -895,6 +912,9 @@ void TEXT_OT_indent(wmOperatorType *ot) /* api callbacks */ ot->exec = text_indent_exec; ot->poll = text_edit_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; } /******************* unindent operator *********************/ @@ -905,8 +925,10 @@ static int text_unindent_exec(bContext *C, wmOperator *UNUSED(op)) text_drawcache_tag_update(CTX_wm_space_text(C), 0); + TextUndoBuf *utxt = ED_text_undo_push_init(C); + txt_order_cursors(text, false); - txt_unindent(text); + txt_unindent(text, utxt); text_update_edited(text); @@ -926,6 +948,9 @@ void TEXT_OT_unindent(wmOperatorType *ot) /* api callbacks */ ot->exec = text_unindent_exec; ot->poll = text_edit_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; } /******************* line break operator *********************/ @@ -941,14 +966,15 @@ static int text_line_break_exec(bContext *C, wmOperator *UNUSED(op)) // double check tabs/spaces before splitting the line curts = txt_setcurr_tab_spaces(text, space); - txt_split_curline(text); + TextUndoBuf *utxt = ED_text_undo_push_init(C); + txt_split_curline(text, utxt); for (a = 0; a < curts; a++) { if (text->flags & TXT_TABSTOSPACES) { - txt_add_char(text, ' '); + txt_add_char(text, utxt, ' '); } else { - txt_add_char(text, '\t'); + txt_add_char(text, utxt, '\t'); } } @@ -961,7 +987,7 @@ static int text_line_break_exec(bContext *C, wmOperator *UNUSED(op)) text_update_cursor_moved(C); WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text); - return OPERATOR_CANCELLED; + return OPERATOR_FINISHED; } void TEXT_OT_line_break(wmOperatorType *ot) @@ -970,10 +996,13 @@ void TEXT_OT_line_break(wmOperatorType *ot) ot->name = "Line Break"; ot->idname = "TEXT_OT_line_break"; ot->description = "Insert line break at cursor position"; - + /* api callbacks */ ot->exec = text_line_break_exec; ot->poll = text_edit_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; } /******************* comment operator *********************/ @@ -985,8 +1014,10 @@ static int text_comment_exec(bContext *C, wmOperator *UNUSED(op)) if (txt_has_sel(text)) { text_drawcache_tag_update(CTX_wm_space_text(C), 0); + TextUndoBuf *utxt = ED_text_undo_push_init(C); + txt_order_cursors(text, false); - txt_comment(text); + txt_comment(text, utxt); text_update_edited(text); text_update_cursor_moved(C); @@ -1003,10 +1034,13 @@ void TEXT_OT_comment(wmOperatorType *ot) ot->name = "Comment"; ot->idname = "TEXT_OT_comment"; ot->description = "Convert selected text to comment"; - + /* api callbacks */ ot->exec = text_comment_exec; ot->poll = text_edit_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; } /******************* uncomment operator *********************/ @@ -1018,8 +1052,10 @@ static int text_uncomment_exec(bContext *C, wmOperator *UNUSED(op)) if (txt_has_sel(text)) { text_drawcache_tag_update(CTX_wm_space_text(C), 0); + TextUndoBuf *utxt = ED_text_undo_push_init(C); + txt_order_cursors(text, false); - txt_uncomment(text); + txt_uncomment(text, utxt); text_update_edited(text); text_update_cursor_moved(C); @@ -1041,6 +1077,9 @@ void TEXT_OT_uncomment(wmOperatorType *ot) /* api callbacks */ ot->exec = text_uncomment_exec; ot->poll = text_edit_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; } /******************* convert whitespace operator *********************/ @@ -1174,6 +1213,9 @@ void TEXT_OT_convert_whitespace(wmOperatorType *ot) ot->exec = text_convert_whitespace_exec; ot->poll = text_edit_poll; + /* flags */ + ot->flag = OPTYPE_UNDO; + /* properties */ RNA_def_enum(ot->srna, "type", whitespace_type_items, TO_SPACES, "Type", "Type of whitespace to convert to"); } @@ -1265,8 +1307,10 @@ static int move_lines_exec(bContext *C, wmOperator *op) { Text *text = CTX_data_edit_text(C); const int direction = RNA_enum_get(op->ptr, "direction"); - - txt_move_lines(text, direction); + + TextUndoBuf *utxt = ED_text_undo_push_init(C); + + txt_move_lines(text, utxt, direction); text_update_cursor_moved(C); WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text); @@ -1295,6 +1339,9 @@ void TEXT_OT_move_lines(wmOperatorType *ot) ot->exec = move_lines_exec; ot->poll = text_edit_poll; + /* flags */ + ot->flag = OPTYPE_UNDO; + /* properties */ RNA_def_enum(ot->srna, "direction", direction_items, 1, "Direction", ""); } @@ -1936,6 +1983,7 @@ static int text_delete_exec(bContext *C, wmOperator *op) Text *text = CTX_data_edit_text(C); int type = RNA_enum_get(op->ptr, "type"); + text_drawcache_tag_update(st, 0); /* behavior could be changed here, @@ -1945,11 +1993,13 @@ static int text_delete_exec(bContext *C, wmOperator *op) else if (type == DEL_NEXT_WORD) type = DEL_NEXT_CHAR; } + TextUndoBuf *utxt = ED_text_undo_push_init(C); + if (type == DEL_PREV_WORD) { if (txt_cursor_is_line_start(text)) { - txt_backspace_char(text); + txt_backspace_char(text, utxt); } - txt_backspace_word(text); + txt_backspace_word(text, utxt); } else if (type == DEL_PREV_CHAR) { @@ -1965,13 +2015,13 @@ static int text_delete_exec(bContext *C, wmOperator *op) } } - txt_backspace_char(text); + txt_backspace_char(text, utxt); } else if (type == DEL_NEXT_WORD) { if (txt_cursor_is_line_end(text)) { - txt_delete_char(text); + txt_delete_char(text, utxt); } - txt_delete_word(text); + txt_delete_word(text, utxt); } else if (type == DEL_NEXT_CHAR) { @@ -1987,7 +2037,7 @@ static int text_delete_exec(bContext *C, wmOperator *op) } } - txt_delete_char(text); + txt_delete_char(text, utxt); } text_update_line_edited(text->curl); @@ -2840,16 +2890,18 @@ static int text_insert_exec(bContext *C, wmOperator *op) str = RNA_string_get_alloc(op->ptr, "text", NULL, 0); + TextUndoBuf *utxt = ED_text_undo_push_init(C); + if (st && st->overwrite) { while (str[i]) { code = BLI_str_utf8_as_unicode_step(str, &i); - done |= txt_replace_char(text, code); + done |= txt_replace_char(text, utxt, code); } } else { while (str[i]) { code = BLI_str_utf8_as_unicode_step(str, &i); - done |= txt_add_char(text, code); + done |= txt_add_char(text, utxt, code); } } @@ -2919,6 +2971,9 @@ void TEXT_OT_insert(wmOperatorType *ot) ot->invoke = text_insert_invoke; ot->poll = text_edit_poll; + /* flags */ + ot->flag = OPTYPE_UNDO; + /* properties */ prop = RNA_def_string(ot->srna, "text", NULL, 0, "Text", "Text to insert at the cursor position"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); @@ -2955,7 +3010,8 @@ static int text_find_and_replace(bContext *C, wmOperator *op, short mode) if (found) { if (mode == TEXT_REPLACE) { - txt_insert_buf(text, st->replacestr); + TextUndoBuf *utxt = ED_text_undo_push_init(C); + txt_insert_buf(text, utxt, st->replacestr); if (text->curl && text->curl->format) { MEM_freeN(text->curl->format); text->curl->format = NULL; @@ -3024,6 +3080,9 @@ void TEXT_OT_replace(wmOperatorType *ot) /* api callbacks */ ot->exec = text_replace_exec; ot->poll = text_space_edit_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; } /******************* find set selected *********************/ @@ -3081,6 +3140,9 @@ void TEXT_OT_replace_set_selected(wmOperatorType *ot) /* api callbacks */ ot->exec = text_replace_set_selected_exec; ot->poll = text_space_edit_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; } /****************** resolve conflict operator ******************/ @@ -3201,26 +3263,3 @@ void TEXT_OT_to_3d_object(wmOperatorType *ot) /* properties */ RNA_def_boolean(ot->srna, "split_lines", 0, "Split Lines", "Create one object per line in the text"); } - - -/************************ undo ******************************/ - -void ED_text_undo_step(bContext *C, int step) -{ - Text *text = CTX_data_edit_text(C); - - if (!text) - return; - - if (step == 1) - txt_do_undo(text); - else if (step == -1) - txt_do_redo(text); - - text_update_edited(text); - - text_update_cursor_moved(C); - text_drawcache_tag_update(CTX_wm_space_text(C), 1); - WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text); -} - diff --git a/source/blender/editors/space_text/text_undo.c b/source/blender/editors/space_text/text_undo.c new file mode 100644 index 00000000000..729522cc8f4 --- /dev/null +++ b/source/blender/editors/space_text/text_undo.c @@ -0,0 +1,185 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/space_text/text_undo.c + * \ingroup sptext + */ + +#include <string.h> +#include <errno.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_text_types.h" + +#include "BLI_listbase.h" +#include "BLI_array_utils.h" + +#include "BLT_translation.h" + +#include "PIL_time.h" + +#include "BKE_context.h" +#include "BKE_library.h" +#include "BKE_report.h" +#include "BKE_text.h" +#include "BKE_undo_system.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_text.h" +#include "ED_curve.h" +#include "ED_screen.h" +#include "ED_undo.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "text_intern.h" +#include "text_format.h" + +/* TODO(campbell): undo_system: move text undo out of text block. */ + +/* -------------------------------------------------------------------- */ +/** \name Implements ED Undo System + * \{ */ + +typedef struct TextUndoStep { + UndoStep step; + UndoRefID_Text text_ref; + TextUndoBuf data; +} TextUndoStep; + +static bool text_undosys_poll(bContext *C) +{ + Text *text = CTX_data_edit_text(C); + if (text == NULL) { + return false; + } + if (ID_IS_LINKED(text)) { + return false; + } + return true; +} + +static void text_undosys_step_encode_init(struct bContext *C, UndoStep *us_p) +{ + TextUndoStep *us = (TextUndoStep *)us_p; + BLI_assert(BLI_array_is_zeroed(&us->data, 1)); + + UNUSED_VARS(C); + /* XXX, use to set the undo type only. */ + + us->data.buf = NULL; + us->data.len = 0; + us->data.pos = -1; +} + +static bool text_undosys_step_encode(struct bContext *C, UndoStep *us_p) +{ + TextUndoStep *us = (TextUndoStep *)us_p; + + Text *text = CTX_data_edit_text(C); + + /* No undo data was generated. Hint, use global undo here. */ + if ((us->data.pos == -1) || (us->data.buf == NULL)) { + return false; + } + + us->text_ref.ptr = text; + + us->step.data_size = us->data.len; + + return true; +} + +static void text_undosys_step_decode(struct bContext *C, UndoStep *us_p, int dir) +{ + TextUndoStep *us = (TextUndoStep *)us_p; + Text *text = us->text_ref.ptr; + + if (dir < 0) { + TextUndoBuf data = us->data; + txt_do_undo(text, &data); + } + else { + TextUndoBuf data = us->data; + data.pos = -1; + txt_do_redo(text, &data); + } + + text_update_edited(text); + text_update_cursor_moved(C); + text_drawcache_tag_update(CTX_wm_space_text(C), 1); + WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text); +} + +static void text_undosys_step_free(UndoStep *us_p) +{ + TextUndoStep *us = (TextUndoStep *)us_p; + MEM_SAFE_FREE(us->data.buf); +} + +static void text_undosys_foreach_ID_ref( + UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data) +{ + TextUndoStep *us = (TextUndoStep *)us_p; + foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->text_ref)); +} + +/* Export for ED_undo_sys. */ + +void ED_text_undosys_type(UndoType *ut) +{ + ut->name = "Text"; + ut->poll = text_undosys_poll; + ut->step_encode_init = text_undosys_step_encode_init; + ut->step_encode = text_undosys_step_encode; + ut->step_decode = text_undosys_step_decode; + ut->step_free = text_undosys_step_free; + + ut->step_foreach_ID_ref = text_undosys_foreach_ID_ref; + + ut->mode = BKE_UNDOTYPE_MODE_ACCUMULATE; + ut->use_context = false; + + ut->step_size = sizeof(TextUndoStep); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Utilities + * \{ */ + +/* Use operator system to finish the undo step. */ +TextUndoBuf *ED_text_undo_push_init(bContext *C) +{ + UndoStack *ustack = ED_undo_stack_get(); + UndoStep *us_p = BKE_undosys_step_push_init_with_type(ustack, C, NULL, BKE_UNDOSYS_TYPE_TEXT); + TextUndoStep *us = (TextUndoStep *)us_p; + return &us->data; +} + +/** \} */ diff --git a/source/blender/editors/space_time/space_time.c b/source/blender/editors/space_time/space_time.c index 283dbf3b4e2..42027f10fe6 100644 --- a/source/blender/editors/space_time/space_time.c +++ b/source/blender/editors/space_time/space_time.c @@ -83,7 +83,7 @@ static void time_draw_sfra_efra(Scene *scene, View2D *v2d) /* draw darkened area outside of active timeline * frame range used is preview range or scene range */ - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); Gwn_VertFormat *format = immVertexFormat(); diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c index f8f2d5598de..0d4ec4d42d1 100644 --- a/source/blender/editors/space_view3d/drawmesh.c +++ b/source/blender/editors/space_view3d/drawmesh.c @@ -177,7 +177,7 @@ void draw_mesh_face_select(RegionView3D *rv3d, Mesh *me, DerivedMesh *dm, bool d /* Draw Selected Faces */ if (me->drawflag & ME_DRAWFACES) { glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); /* dull unselected faces so as not to get in the way of seeing color */ glColor4ub(96, 96, 96, 64); dm->drawMappedFaces(dm, draw_mesh_face_select__drawFaceOptsInv, NULL, NULL, (void *)me, DM_DRAW_SKIP_HIDDEN); diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 51dc56bafaf..93bcbc3ea0c 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -727,7 +727,7 @@ static void draw_empty_image(Object *ob, const short dflag, const unsigned char if (use_blend) { glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } Gwn_VertFormat *format = immVertexFormat(); @@ -752,8 +752,6 @@ static void draw_empty_image(Object *ob, const short dflag, const unsigned char immEnd(); immUnbindProgram(); - - glBindTexture(GL_TEXTURE_2D, 0); /* necessary? */ } /* Draw the image outline */ @@ -777,7 +775,7 @@ static void draw_empty_image(Object *ob, const short dflag, const unsigned char if (!use_blend) { glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } imm_draw_box_wire_2d(pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax); @@ -1184,7 +1182,7 @@ static void draw_transp_spot_volume(Lamp *la, float x, float z, unsigned pos) draw_spot_cone(la, x, z, pos); /* restore state */ - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_BLEND); glDepthMask(GL_TRUE); glDisable(GL_CULL_FACE); @@ -1228,7 +1226,7 @@ static void draw_transp_sun_volume(Lamp *la, unsigned pos) imm_draw_box(box, true, pos); /* restore state */ - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_BLEND); glDepthMask(GL_TRUE); glDisable(GL_CULL_FACE); @@ -1324,7 +1322,7 @@ void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, GPU_enable_program_point_size(); glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA); immUniform1f("size", lampdot_size); @@ -4567,7 +4565,7 @@ static bool draw_mesh_object( const char dt, const unsigned char ob_wire_col[4], const short dflag) { Object *ob = base->object; - Object *obedit = scene->obedit; + Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer); Mesh *me = ob->data; BMEditMesh *em = me->edit_btmesh; bool do_alpha_after = false, drawlinked = false, retval = false; @@ -4707,8 +4705,10 @@ static void make_color_variations(const unsigned char base_ubyte[4], float low[4 high[3] = base[3]; } -static void draw_mesh_fancy_new(EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base, - const char dt, const unsigned char ob_wire_col[4], const short dflag, const bool other_obedit) +static void draw_mesh_fancy_new( + const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, + ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base, + const char dt, const unsigned char ob_wire_col[4], const short dflag, const bool other_obedit) { if (dflag & (DRAW_PICKING | DRAW_CONSTCOLOR)) { /* too complicated! use existing methods */ @@ -5025,22 +5025,20 @@ static void draw_mesh_fancy_new(EvaluationContext *eval_ctx, Scene *scene, ViewL dm->release(dm); } -static bool UNUSED_FUNCTION(draw_mesh_object_new)(const bContext *C, Scene *scene, ViewLayer *view_layer, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base, - const char dt, const unsigned char ob_wire_col[4], const short dflag) +static bool UNUSED_FUNCTION(draw_mesh_object_new)( + const EvaluationContext *eval_ctx, Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base, + const char dt, const unsigned char ob_wire_col[4], const short dflag) { - EvaluationContext eval_ctx; Object *ob = base->object; - Object *obedit = scene->obedit; Mesh *me = ob->data; BMEditMesh *em = me->edit_btmesh; bool do_alpha_after = false, drawlinked = false, retval = false; - CTX_data_eval_ctx(C, &eval_ctx); - if (v3d->flag2 & V3D_RENDER_SHADOW) { /* TODO: handle shadow pass separately */ return true; } + Object *obedit = OBEDIT_FROM_VIEW_LAYER(eval_ctx->view_layer); if (obedit && ob != obedit && ob->data == obedit->data) { if (BKE_key_from_object(ob) || BKE_key_from_object(obedit)) {} @@ -5066,7 +5064,7 @@ static bool UNUSED_FUNCTION(draw_mesh_object_new)(const bContext *C, Scene *scen } else { cageDM = editbmesh_get_derived_cage_and_final( - &eval_ctx, scene, ob, em, scene->customdata_mask, + eval_ctx, scene, ob, em, scene->customdata_mask, &finalDM); } @@ -5085,9 +5083,9 @@ static bool UNUSED_FUNCTION(draw_mesh_object_new)(const bContext *C, Scene *scen DM_update_materials(cageDM, ob); } - const bool glsl = draw_glsl_material(scene, view_layer, ob, v3d, dt); + const bool glsl = draw_glsl_material(scene, eval_ctx->view_layer, ob, v3d, dt); - GPU_begin_object_materials(v3d, rv3d, scene, view_layer, ob, glsl, NULL); + GPU_begin_object_materials(v3d, rv3d, scene, eval_ctx->view_layer, ob, glsl, NULL); } draw_em_fancy_new(scene, ar, v3d, ob, me, em, cageDM, finalDM, dt); @@ -5103,18 +5101,18 @@ static bool UNUSED_FUNCTION(draw_mesh_object_new)(const bContext *C, Scene *scen /* ob->bb was set by derived mesh system, do NULL check just to be sure */ if (me->totpoly <= 4 || (!ob->bb || ED_view3d_boundbox_clip(rv3d, ob->bb))) { if (solid) { - const bool glsl = draw_glsl_material(scene, view_layer, ob, v3d, dt); + const bool glsl = draw_glsl_material(scene, eval_ctx->view_layer, ob, v3d, dt); if (dt == OB_SOLID || glsl) { const bool check_alpha = check_alpha_pass(base); - GPU_begin_object_materials(v3d, rv3d, scene, view_layer, ob, glsl, + GPU_begin_object_materials(v3d, rv3d, scene, eval_ctx->view_layer, ob, glsl, (check_alpha) ? &do_alpha_after : NULL); } } const bool other_obedit = obedit && (obedit != ob); - draw_mesh_fancy_new(&eval_ctx, scene, view_layer, ar, v3d, rv3d, base, dt, ob_wire_col, dflag, other_obedit); + draw_mesh_fancy_new(eval_ctx, scene, eval_ctx->view_layer, ar, v3d, rv3d, base, dt, ob_wire_col, dflag, other_obedit); GPU_end_object_materials(); @@ -5939,7 +5937,7 @@ static void draw_new_particle_system( if (pars == NULL) return; /* don't draw normal paths in edit mode */ - if (psys_in_edit_mode(eval_ctx->view_layer, psys) && (pset->flag & PE_DRAW_PART) == 0) + if (psys_in_edit_mode(eval_ctx->depsgraph, psys) && (pset->flag & PE_DRAW_PART) == 0) return; if (part->draw_as == PART_DRAW_REND) @@ -5955,6 +5953,8 @@ static void draw_new_particle_system( curvemapping_changed_all(psys->part->clumpcurve); if ((psys->part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && psys->part->roughcurve) curvemapping_changed_all(psys->part->roughcurve); + if ((psys->part->child_flag & PART_CHILD_USE_TWIST_CURVE) && psys->part->twistcurve) + curvemapping_changed_all(psys->part->twistcurve); /* 2. */ sim.eval_ctx = eval_ctx; @@ -6594,10 +6594,10 @@ static void draw_new_particle_system( } static void draw_update_ptcache_edit( - const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, Object *ob, PTCacheEdit *edit) + const EvaluationContext *eval_ctx, Scene *scene, Object *ob, PTCacheEdit *edit) { if (edit->psys && edit->psys->flag & PSYS_HAIR_UPDATED) - PE_update_object(eval_ctx, scene, view_layer, ob, 0); + PE_update_object(eval_ctx, scene, ob, 0); /* create path and child path cache if it doesn't exist already */ if (edit->pathcache == NULL) { @@ -8322,7 +8322,8 @@ static void draw_object_selected_outline( glDepthMask(GL_TRUE); } -static void draw_wire_extra(Scene *scene, RegionView3D *rv3d, Object *ob, const unsigned char ob_wire_col[4]) +static void draw_wire_extra( + RegionView3D *rv3d, Object *ob, const bool is_obedit, const unsigned char ob_wire_col[4]) { if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL)) { unsigned char wire_edit_col[4]; @@ -8339,13 +8340,13 @@ static void draw_wire_extra(Scene *scene, RegionView3D *rv3d, Object *ob, const drawCurveDMWired(ob); } else { - drawDispListwire(&ob->curve_cache->disp, ob->type, (scene->obedit == ob) ? wire_edit_col : ob_wire_col); + drawDispListwire(&ob->curve_cache->disp, ob->type, is_obedit ? wire_edit_col : ob_wire_col); } } } else if (ob->type == OB_MBALL) { if (BKE_mball_is_basis(ob)) { - drawDispListwire(&ob->curve_cache->disp, ob->type, (scene->obedit == ob) ? wire_edit_col : ob_wire_col); + drawDispListwire(&ob->curve_cache->disp, ob->type, is_obedit ? wire_edit_col : ob_wire_col); } } @@ -8423,7 +8424,7 @@ static void draw_rigid_body_pivot(bRigidBodyJointConstraint *data, immUnbindProgram(); } -void draw_object_wire_color(Scene *scene, ViewLayer *view_layer, Base *base, unsigned char r_ob_wire_col[4]) +void draw_object_wire_color(ViewLayer *view_layer, Base *base, unsigned char r_ob_wire_col[4]) { Object *ob = base->object; int colindex = 0; @@ -8435,7 +8436,7 @@ void draw_object_wire_color(Scene *scene, ViewLayer *view_layer, Base *base, uns int theme_id = is_edit ? TH_WIRE_EDIT : TH_WIRE; int theme_shade = 0; - if ((scene->obedit == NULL) && + if (((ob->mode & OB_MODE_EDIT) == 0) && (G.moving & G_TRANSFORM_OBJ) && ((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL))) { @@ -8578,14 +8579,17 @@ void draw_object( unsigned char _ob_wire_col[4]; /* dont initialize this */ const unsigned char *ob_wire_col = NULL; /* dont initialize this, use NULL crashes as a way to find invalid use */ bool zbufoff = false, is_paint = false, empty_object = false; - const bool is_obact = (ob == OBACT(view_layer)); + Object *ob_active = OBACT(view_layer); + const bool is_obact = (ob == ob_active); + /* this could be moved to a 'dflag'. */ + const bool is_obedit = (is_obact && (ob == OBEDIT_FROM_OBACT(ob_active))); const bool render_override = (v3d->flag2 & V3D_RENDER_OVERRIDE) != 0; const bool is_picking = (G.f & G_PICKSEL) != 0; const bool has_particles = (ob->particlesystem.first != NULL); bool skip_object = false; /* Draw particles but not their emitter object. */ SmokeModifierData *smd = NULL; - if (ob != scene->obedit) { + if (is_obedit == false) { if (ob->restrictflag & OB_RESTRICT_VIEW) return; @@ -8666,7 +8670,7 @@ void draw_object( /* no return after this point, otherwise leaks */ /* only once set now, will be removed too, should become a global standard */ - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); /* reset here to avoid having to call all over */ glLineWidth(1.0f); @@ -8695,7 +8699,7 @@ void draw_object( ED_view3d_project_base(ar, base); - draw_object_wire_color(scene, view_layer, base, _ob_wire_col); + draw_object_wire_color(view_layer, base, _ob_wire_col); ob_wire_col = _ob_wire_col; //glColor3ubv(ob_wire_col); @@ -8929,7 +8933,7 @@ afterdraw: /* code for new particle system */ if ((ob->particlesystem.first) && - (ob != scene->obedit)) + (is_obedit == false)) { ParticleSystem *psys; @@ -8944,7 +8948,7 @@ afterdraw: if (ob->mode & OB_MODE_PARTICLE_EDIT && is_obact) { PTCacheEdit *edit = PE_create_current(eval_ctx, scene, ob); if (edit && edit->psys == psys) - draw_update_ptcache_edit(eval_ctx, scene, view_layer, ob, edit); + draw_update_ptcache_edit(eval_ctx, scene, ob, edit); } draw_new_particle_system(eval_ctx, scene, v3d, rv3d, base, psys, dt, dflag); @@ -8959,14 +8963,14 @@ afterdraw: /* draw edit particles last so that they can draw over child particles */ if ((dflag & DRAW_PICKING) == 0 && - (!scene->obedit)) + (is_obedit == false)) { if (ob->mode & OB_MODE_PARTICLE_EDIT && is_obact) { PTCacheEdit *edit = PE_create_current(eval_ctx, scene, ob); if (edit) { gpuLoadMatrix(rv3d->viewmat); - draw_update_ptcache_edit(eval_ctx, scene, view_layer, ob, edit); + draw_update_ptcache_edit(eval_ctx, scene, ob, edit); draw_ptcache_edit(scene, v3d, edit); gpuMultMatrix(ob->obmat); } @@ -9108,7 +9112,7 @@ afterdraw: } if ((dtx & OB_DRAWWIRE) && dt >= OB_SOLID) { if ((dflag & DRAW_CONSTCOLOR) == 0) { - draw_wire_extra(scene, rv3d, ob, ob_wire_col); + draw_wire_extra(rv3d, ob, is_obedit, ob_wire_col); } } } @@ -9212,11 +9216,11 @@ afterdraw: immUniformColor3ubv(ob_wire_col); /* draw hook center and offset line */ - if (ob != scene->obedit) + if (is_obedit == false) draw_hooks(ob, pos); /* help lines and so */ - if (ob != scene->obedit && ob->parent) { + if ((is_obedit == false) && ob->parent) { const eObjectVisibilityCheck mode = eval_ctx->mode != DAG_EVAL_VIEWPORT ? OB_VISIBILITY_CHECK_FOR_RENDER : OB_VISIBILITY_CHECK_FOR_VIEWPORT; @@ -9591,7 +9595,7 @@ static void bbs_mesh_face(BMEditMesh *em, DerivedMesh *UNUSED(dm), const bool us GPU_select_index_get(0, &selcol); batch = DRW_mesh_batch_cache_get_triangles_with_select_mask(me, true); GWN_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR_U32); - GWN_batch_uniform_1i(batch, "color", selcol); + GWN_batch_uniform_1ui(batch, "color", selcol); GWN_batch_draw(batch); } } @@ -9721,7 +9725,7 @@ static void bbs_mesh_solid_verts(const EvaluationContext *UNUSED(eval_ctx), Scen GPU_select_index_get(0, &selcol); batch = DRW_mesh_batch_cache_get_triangles_with_select_mask(me, true); GWN_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR_U32); - GWN_batch_uniform_1i(batch, "color", selcol); + GWN_batch_uniform_1ui(batch, "color", selcol); GWN_batch_draw(batch); } @@ -9960,7 +9964,7 @@ void ED_draw_object_facemap( immUniformColor4fv(col); /* XXX, alpha isn't working yet, not sure why. */ - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); MVert *mvert; diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index fb5b9386dde..74087e6f27b 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -59,12 +59,13 @@ #include "ED_screen.h" #include "ED_transform.h" -#include "GPU_compositing.h" #include "GPU_framebuffer.h" #include "GPU_material.h" #include "GPU_viewport.h" #include "GPU_matrix.h" +#include "DRW_engine.h" + #include "WM_api.h" #include "WM_types.h" #include "WM_message.h" @@ -296,7 +297,7 @@ void ED_view3d_stop_render_preview(wmWindowManager *wm, ARegion *ar) } } -void ED_view3d_shade_update(Main *bmain, Scene *scene, View3D *v3d, ScrArea *sa) +void ED_view3d_shade_update(Main *bmain, View3D *v3d, ScrArea *sa) { wmWindowManager *wm = bmain->wm.first; @@ -308,10 +309,6 @@ void ED_view3d_shade_update(Main *bmain, Scene *scene, View3D *v3d, ScrArea *sa) ED_view3d_stop_render_preview(wm, ar); } } - else if (scene->obedit != NULL && scene->obedit->type == OB_MESH) { - /* Tag mesh to load edit data. */ - DEG_id_tag_update(scene->obedit->data, 0); - } } /* ******************** default callbacks for view3d space ***************** */ @@ -573,14 +570,10 @@ static void view3d_main_region_exit(wmWindowManager *wm, ARegion *ar) rv3d->gpuoffscreen = NULL; } - if (rv3d->compositor) { - GPU_fx_compositor_destroy(rv3d->compositor); - rv3d->compositor = NULL; - } - if (rv3d->viewport) { + DRW_opengl_context_enable(); GPU_viewport_free(rv3d->viewport); - MEM_freeN(rv3d->viewport); + DRW_opengl_context_disable(); rv3d->viewport = NULL; } } @@ -760,12 +753,10 @@ static void view3d_main_region_free(ARegion *ar) if (rv3d->gpuoffscreen) { GPU_offscreen_free(rv3d->gpuoffscreen); } - if (rv3d->compositor) { - GPU_fx_compositor_destroy(rv3d->compositor); - } if (rv3d->viewport) { + DRW_opengl_context_enable(); GPU_viewport_free(rv3d->viewport); - MEM_freeN(rv3d->viewport); + DRW_opengl_context_disable(); } MEM_freeN(rv3d); @@ -922,10 +913,16 @@ static void view3d_main_region_listener( case ND_SELECT: { WM_manipulatormap_tag_refresh(mmap); - if (scene->obedit) { - Object *ob = scene->obedit; + + ID *ob_data = wmn->reference; + if (ob_data == NULL) { + BLI_assert(wmn->window); // Use `WM_event_add_notifier` instead of `WM_main_add_notifier` + ViewLayer *view_layer = WM_window_get_active_view_layer(wmn->window); + ob_data = OBEDIT_FROM_VIEW_LAYER(view_layer)->data; + } + if (ob_data) { /* TODO(sergey): Notifiers shouldn't really be doing DEG tags. */ - DEG_id_tag_update((ID *)ob->data, DEG_TAG_SELECT_UPDATE); + DEG_id_tag_update(ob_data, DEG_TAG_SELECT_UPDATE); } ATTR_FALLTHROUGH; } @@ -1075,7 +1072,7 @@ static void view3d_main_region_message_subscribe( * * 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}; + wmMsgParams_RNA msg_key_params = {{{0}}}; /* Only subscribe to types. */ StructRNA *type_array[] = { @@ -1139,9 +1136,9 @@ static void view3d_main_region_message_subscribe( /* concept is to retrieve cursor type context-less */ static void view3d_main_region_cursor(wmWindow *win, ScrArea *UNUSED(sa), ARegion *UNUSED(ar)) { - const Scene *scene = WM_window_get_active_scene(win); - - if (scene->obedit) { + ViewLayer *view_layer = WM_window_get_active_view_layer(win); + Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer); + if (obedit) { WM_cursor_set(win, CURSOR_EDIT); } else { diff --git a/source/blender/editors/space_view3d/view3d_camera_control.c b/source/blender/editors/space_view3d/view3d_camera_control.c index c39057431c2..5962f1ed2ff 100644 --- a/source/blender/editors/space_view3d/view3d_camera_control.c +++ b/source/blender/editors/space_view3d/view3d_camera_control.c @@ -31,10 +31,10 @@ * * Typical view-control usage: * - * - acquire a view-control (#ED_view3d_control_acquire). + * - acquire a view-control (#ED_view3d_cameracontrol_acquire). * - modify ``rv3d->ofs``, ``rv3d->viewquat``. - * - update the view data (#ED_view3d_control_acquire) - within a loop which draws the viewport. - * - finish and release the view-control (#ED_view3d_control_release), + * - update the view data (#ED_view3d_cameracontrol_acquire) - within a loop which draws the viewport. + * - finish and release the view-control (#ED_view3d_cameracontrol_release), * either keeping the current view or restoring the initial view. * * Notes: diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index f734bb085d0..4a0ee31a2b7 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -35,7 +35,7 @@ #include "BLI_rect.h" #include "BLI_string.h" #include "BLI_threads.h" -#include "BLI_jitter.h" +#include "BLI_jitter_2d.h" #include "BIF_gl.h" #include "BIF_glutil.h" @@ -78,7 +78,6 @@ #include "GPU_immediate_util.h" #include "GPU_material.h" #include "GPU_viewport.h" -#include "GPU_compositing.h" #include "MEM_guardedalloc.h" @@ -99,15 +98,15 @@ /* ******************** general functions ***************** */ -static bool use_depth_doit(Scene *scene, View3D *v3d) +static bool use_depth_doit(View3D *v3d, Object *obedit) { if (v3d->drawtype > OB_WIRE) return true; /* special case (depth for wire color) */ if (v3d->drawtype <= OB_WIRE) { - if (scene->obedit && scene->obedit->type == OB_MESH) { - Mesh *me = scene->obedit->data; + if (obedit && obedit->type == OB_MESH) { + Mesh *me = obedit->data; if (me->drawflag & ME_DRAWEIGHT) { return true; } @@ -268,28 +267,28 @@ static void view3d_stereo3d_setup( data = (Camera *)v3d->camera->data; shiftx = data->shiftx; - BLI_lock_thread(LOCK_VIEW3D); + BLI_thread_lock(LOCK_VIEW3D); data->shiftx = BKE_camera_multiview_shift_x(&scene->r, v3d->camera, viewname); BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat); view3d_main_region_setup_view(eval_ctx, scene, v3d, ar, viewmat, NULL, rect); data->shiftx = shiftx; - BLI_unlock_thread(LOCK_VIEW3D); + BLI_thread_unlock(LOCK_VIEW3D); } else { /* SCE_VIEWS_FORMAT_MULTIVIEW */ float viewmat[4][4]; Object *view_ob = v3d->camera; Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname); - BLI_lock_thread(LOCK_VIEW3D); + BLI_thread_lock(LOCK_VIEW3D); v3d->camera = camera; BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat); view3d_main_region_setup_view(eval_ctx, scene, v3d, ar, viewmat, NULL, rect); v3d->camera = view_ob; - BLI_unlock_thread(LOCK_VIEW3D); + BLI_thread_unlock(LOCK_VIEW3D); } } @@ -494,7 +493,7 @@ static void drawviewborder(Scene *scene, const Depsgraph *depsgraph, ARegion *ar float alpha = 1.0f; if (ca->passepartalpha != 1.0f) { - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); alpha = ca->passepartalpha; } @@ -1422,7 +1421,7 @@ static void drawcursor(Scene *scene, ARegion *ar, View3D *v3d) } } -static void draw_view_axis(RegionView3D *rv3d, rcti *rect) +static void draw_view_axis(RegionView3D *rv3d, const rcti *rect) { const float k = U.rvisize * U.pixelsize; /* axis size */ const int bright = - 20 * (10 - U.rvibright); /* axis alpha offset (rvibright has range 0-10) */ @@ -1455,7 +1454,7 @@ static void draw_view_axis(RegionView3D *rv3d, rcti *rect) glLineWidth(2.0f); glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); Gwn_VertFormat *format = immVertexFormat(); unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); @@ -1469,6 +1468,7 @@ static void draw_view_axis(RegionView3D *rv3d, rcti *rect) immAttrib4ubv(col, axis_col[i]); immVertex2f(pos, startx, starty); + immAttrib4ubv(col, axis_col[i]); immVertex2fv(pos, axis_pos[i]); } @@ -1498,7 +1498,7 @@ static void UNUSED_FUNCTION(draw_rotation_guide)(RegionView3D *rv3d) negate_v3_v3(o, rv3d->ofs); glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glDepthMask(GL_FALSE); /* don't overwrite zbuf */ Gwn_VertFormat *format = immVertexFormat(); @@ -1689,7 +1689,7 @@ static const char *view3d_get_name(View3D *v3d, RegionView3D *rv3d) return name; } -static void draw_viewport_name(ARegion *ar, View3D *v3d, rcti *rect) +static void draw_viewport_name(ARegion *ar, View3D *v3d, const rcti *rect) { RegionView3D *rv3d = ar->regiondata; const char *name = view3d_get_name(v3d, rv3d); @@ -1850,6 +1850,8 @@ void view3d_draw_region_info(const bContext *C, ARegion *ar, const int offset) view3d_draw_border(C, ar); view3d_draw_grease_pencil(C); + BLF_batch_draw_begin(); + if (U.uiflag & USER_SHOW_ROTVIEWICON) { draw_view_axis(rv3d, &rect); } @@ -1866,6 +1868,7 @@ void view3d_draw_region_info(const bContext *C, ARegion *ar, const int offset) Object *ob = OBACT(view_layer); draw_selected_name(scene, ob, &rect); } + #if 0 /* TODO */ if (grid_unit) { /* draw below the viewport name */ char numstr[32] = ""; @@ -1880,6 +1883,7 @@ void view3d_draw_region_info(const bContext *C, ARegion *ar, const int offset) numstr[0] ? numstr : grid_unit, sizeof(numstr)); } #endif + BLF_batch_draw_end(); } static void view3d_draw_view(const bContext *C, ARegion *ar) @@ -1916,6 +1920,13 @@ void view3d_main_region_draw(const bContext *C, ARegion *ar) view3d_draw_view(C, ar); GPU_viewport_unbind(rv3d->viewport); + rcti rect = ar->winrct; + BLI_rcti_translate(&rect, -ar->winrct.xmin, -ar->winrct.ymin); + GPU_viewport_draw_to_screen(rv3d->viewport, &rect); + + GPU_free_images_old(); + GPU_pass_cache_garbage_collect(); + v3d->flag |= V3D_INVALID_BACKBUF; } @@ -1946,9 +1957,12 @@ static void view3d_stereo3d_setup_offscreen( } } -void ED_view3d_draw_offscreen_init(const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, View3D *v3d) +void ED_view3d_draw_offscreen_init(const EvaluationContext *eval_ctx, + Scene *scene, + ViewLayer *view_layer, + RenderEngineType *engine_type, + View3D *v3d) { - 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)) { @@ -1976,14 +1990,14 @@ static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar) * stuff like shadow buffers */ void ED_view3d_draw_offscreen( - const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, + const EvaluationContext *eval_ctx, Scene *scene, + ViewLayer *view_layer, RenderEngineType *engine_type, View3D *v3d, ARegion *ar, int winx, int winy, float viewmat[4][4], float winmat[4][4], - bool do_bgpic, bool do_sky, bool is_persp, const char *viewname, - GPUFX *fx, GPUFXSettings *fx_settings, + bool do_bgpic, bool do_sky, bool UNUSED(is_persp), const char *viewname, + GPUFXSettings *UNUSED(fx_settings), GPUOffScreen *ofs, GPUViewport *viewport) { - bool do_compositing = false; RegionView3D *rv3d = ar->regiondata; /* set temporary new size */ @@ -2016,51 +2030,16 @@ void ED_view3d_draw_offscreen( gpuPushMatrix(); gpuLoadIdentity(); - /* clear opengl buffers */ - if (do_sky) { - view3d_main_region_clear(scene, v3d, ar); - } - else { - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } - if ((viewname != NULL && viewname[0] != '\0') && (viewmat == NULL) && rv3d->persp == RV3D_CAMOB && v3d->camera) view3d_stereo3d_setup_offscreen(eval_ctx, scene, v3d, ar, winmat, viewname); else view3d_main_region_setup_view(eval_ctx, scene, v3d, ar, viewmat, winmat, NULL); - /* XXX, should take depsgraph as arg */ - Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, false); - BLI_assert(depsgraph != NULL); + Depsgraph *depsgraph = eval_ctx->depsgraph; /* main drawing call */ - 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) { - GPUSSAOSettings *ssao = NULL; - - if (v3d->drawtype < OB_SOLID) { - ssao = v3d->fx_settings.ssao; - v3d->fx_settings.ssao = NULL; - } - - do_compositing = GPU_fx_compositor_initialize_passes(fx, &ar->winrct, NULL, fx_settings); - - if (ssao) - v3d->fx_settings.ssao = ssao; - } - - VP_deprecated_view3d_draw_objects(NULL, eval_ctx, scene, v3d, ar, NULL, do_bgpic, true, do_compositing ? fx : NULL); - - /* post process */ - if (do_compositing) { - if (!winmat) - is_persp = rv3d->is_persp; - GPU_fx_do_composite_pass(fx, winmat, is_persp, scene, ofs); - } + VP_deprecated_view3d_draw_objects(NULL, eval_ctx, scene, v3d, ar, NULL, do_bgpic, true); if ((v3d->flag2 & V3D_RENDER_SHADOW) == 0) { /* draw grease-pencil stuff */ @@ -2076,7 +2055,9 @@ void ED_view3d_draw_offscreen( } } else { - DRW_draw_render_loop_offscreen(depsgraph, eval_ctx->engine_type, ar, v3d, do_sky, ofs, viewport); + DRW_draw_render_loop_offscreen( + depsgraph, engine_type, ar, v3d, + do_sky, ofs, viewport); } /* restore size */ @@ -2099,12 +2080,13 @@ void ED_view3d_draw_offscreen( * (avoids re-creating when doing multiple GL renders). */ ImBuf *ED_view3d_draw_offscreen_imbuf( - const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, + const EvaluationContext *eval_ctx, Scene *scene, + ViewLayer *view_layer, RenderEngineType *engine_type, View3D *v3d, ARegion *ar, int sizex, int sizey, unsigned int flag, unsigned int draw_flags, int alpha_mode, int samples, const char *viewname, /* output vars */ - GPUFX *fx, GPUOffScreen *ofs, char err_out[256]) + GPUOffScreen *ofs, char err_out[256]) { const Depsgraph *depsgraph = eval_ctx->depsgraph; RegionView3D *rv3d = ar->regiondata; @@ -2123,16 +2105,18 @@ ImBuf *ED_view3d_draw_offscreen_imbuf( } const bool own_ofs = (ofs == NULL); + DRW_opengl_context_enable(); if (own_ofs) { /* bind */ - ofs = GPU_offscreen_create(sizex, sizey, use_full_sample ? 0 : samples, false, err_out); + ofs = GPU_offscreen_create(sizex, sizey, use_full_sample ? 0 : samples, true, false, err_out); if (ofs == NULL) { + DRW_opengl_context_disable(); return NULL; } } - ED_view3d_draw_offscreen_init(eval_ctx, scene, view_layer, v3d); + ED_view3d_draw_offscreen_init(eval_ctx, scene, view_layer, engine_type, v3d); GPU_offscreen_bind(ofs, true); @@ -2174,9 +2158,10 @@ ImBuf *ED_view3d_draw_offscreen_imbuf( if ((samples && use_full_sample) == 0) { /* Single-pass render, common case */ ED_view3d_draw_offscreen( - eval_ctx, scene, view_layer, v3d, ar, sizex, sizey, NULL, winmat, + eval_ctx, scene, view_layer, engine_type, + v3d, ar, sizex, sizey, NULL, winmat, draw_background, draw_sky, !is_ortho, viewname, - fx, &fx_settings, ofs, NULL); + &fx_settings, ofs, NULL); if (ibuf->rect_float) { GPU_offscreen_read_pixels(ofs, GL_FLOAT, ibuf->rect_float); @@ -2198,9 +2183,10 @@ ImBuf *ED_view3d_draw_offscreen_imbuf( /* first sample buffer, also initializes 'rv3d->persmat' */ ED_view3d_draw_offscreen( - eval_ctx, scene, view_layer, v3d, ar, sizex, sizey, NULL, winmat, + eval_ctx, scene, view_layer, engine_type, + v3d, ar, sizex, sizey, NULL, winmat, draw_background, draw_sky, !is_ortho, viewname, - fx, &fx_settings, ofs, viewport); + &fx_settings, ofs, viewport); GPU_offscreen_read_pixels(ofs, GL_FLOAT, accum_buffer); /* skip the first sample */ @@ -2212,9 +2198,10 @@ ImBuf *ED_view3d_draw_offscreen_imbuf( (jit_ofs[j][1] * 2.0f) / sizey); ED_view3d_draw_offscreen( - eval_ctx, scene, view_layer, v3d, ar, sizex, sizey, NULL, winmat_jitter, + eval_ctx, scene, view_layer, engine_type, + v3d, ar, sizex, sizey, NULL, winmat_jitter, draw_background, draw_sky, !is_ortho, viewname, - fx, &fx_settings, ofs, viewport); + &fx_settings, ofs, viewport); GPU_offscreen_read_pixels(ofs, GL_FLOAT, rect_temp); unsigned int i = sizex * sizey * 4; @@ -2227,7 +2214,6 @@ ImBuf *ED_view3d_draw_offscreen_imbuf( /* don't free data owned by 'ofs' */ GPU_viewport_clear_from_offscreen(viewport); GPU_viewport_free(viewport); - MEM_freeN(viewport); } if (ibuf->rect_float == NULL) { @@ -2259,6 +2245,8 @@ ImBuf *ED_view3d_draw_offscreen_imbuf( GPU_offscreen_free(ofs); } + DRW_opengl_context_disable(); + if (ibuf->rect_float && ibuf->rect) IMB_rect_from_float(ibuf); @@ -2274,11 +2262,12 @@ ImBuf *ED_view3d_draw_offscreen_imbuf( * \note used by the sequencer */ ImBuf *ED_view3d_draw_offscreen_imbuf_simple( - const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, + const EvaluationContext *eval_ctx, Scene *scene, + ViewLayer *view_layer, RenderEngineType *engine_type, Object *camera, int width, int height, unsigned int flag, unsigned int draw_flags, int drawtype, int alpha_mode, int samples, const char *viewname, - GPUFX *fx, GPUOffScreen *ofs, char err_out[256]) + GPUOffScreen *ofs, char err_out[256]) { View3D v3d = {NULL}; ARegion ar = {NULL}; @@ -2336,8 +2325,9 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple( invert_m4_m4(rv3d.persinv, rv3d.viewinv); return ED_view3d_draw_offscreen_imbuf( - eval_ctx, scene, view_layer, &v3d, &ar, width, height, flag, - draw_flags, alpha_mode, samples, viewname, fx, ofs, err_out); + eval_ctx, scene, view_layer, engine_type, + &v3d, &ar, width, height, flag, + draw_flags, alpha_mode, samples, viewname, ofs, err_out); } /** \} */ @@ -2359,12 +2349,12 @@ void VP_legacy_drawcursor(Scene *scene, ViewLayer *view_layer, ARegion *ar, View } } -void VP_legacy_draw_view_axis(RegionView3D *rv3d, rcti *rect) +void VP_legacy_draw_view_axis(RegionView3D *rv3d, const rcti *rect) { draw_view_axis(rv3d, rect); } -void VP_legacy_draw_viewport_name(ARegion *ar, View3D *v3d, rcti *rect) +void VP_legacy_draw_viewport_name(ARegion *ar, View3D *v3d, const rcti *rect) { draw_viewport_name(ar, v3d, rect); } @@ -2401,9 +2391,9 @@ void VP_legacy_view3d_stereo3d_setup(const EvaluationContext *eval_ctx, Scene *s view3d_stereo3d_setup(eval_ctx, scene, v3d, ar, NULL); } -bool VP_legacy_use_depth(Scene *scene, View3D *v3d) +bool VP_legacy_use_depth(View3D *v3d, Object *obedit) { - return use_depth_doit(scene, v3d); + return use_depth_doit(v3d, obedit); } void VP_drawviewborder(Scene *scene, const struct Depsgraph *depsgraph, ARegion *ar, View3D *v3d) diff --git a/source/blender/editors/space_view3d/view3d_draw_legacy.c b/source/blender/editors/space_view3d/view3d_draw_legacy.c index 7cb362ffb92..7272fc6b408 100644 --- a/source/blender/editors/space_view3d/view3d_draw_legacy.c +++ b/source/blender/editors/space_view3d/view3d_draw_legacy.c @@ -48,7 +48,7 @@ #include "BLI_blenlib.h" #include "BLI_math.h" -#include "BLI_jitter.h" +#include "BLI_jitter_2d.h" #include "BLI_utildefines.h" #include "BLI_endian_switch.h" #include "BLI_threads.h" @@ -100,7 +100,6 @@ #include "GPU_framebuffer.h" #include "GPU_lamp.h" #include "GPU_material.h" -#include "GPU_compositing.h" #include "GPU_extensions.h" #include "GPU_immediate.h" #include "GPU_immediate_util.h" @@ -202,7 +201,7 @@ static void draw_view_icon(RegionView3D *rv3d, rcti *rect) else return; glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); UI_icon_draw(5.0 + rect->xmin, 5.0 + rect->ymin, icon); @@ -211,31 +210,32 @@ static void draw_view_icon(RegionView3D *rv3d, rcti *rect) /* *********************** backdraw for selection *************** */ -static void backdrawview3d(const struct EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, wmWindow *win, ARegion *ar, View3D *v3d) +static void backdrawview3d( + const struct EvaluationContext *eval_ctx, Scene *scene, + ARegion *ar, View3D *v3d, + Object *obact, Object *obedit) { RegionView3D *rv3d = ar->regiondata; - struct Base *base = view_layer->basact; - int multisample_enabled; BLI_assert(ar->regiontype == RGN_TYPE_WINDOW); - if (base && (base->object->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT) || - BKE_paint_select_face_test(base->object))) + if (obact && (obact->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT) || + BKE_paint_select_face_test(obact))) { /* do nothing */ } /* texture paint mode sampling */ - else if (base && (base->object->mode & OB_MODE_TEXTURE_PAINT) && + else if (obact && (obact->mode & OB_MODE_TEXTURE_PAINT) && (v3d->drawtype > OB_WIRE)) { /* do nothing */ } - else if ((base && (base->object->mode & OB_MODE_PARTICLE_EDIT)) && + else if ((obact && (obact->mode & OB_MODE_PARTICLE_EDIT)) && V3D_IS_ZBUF(v3d)) { /* do nothing */ } - else if (scene->obedit && + else if ((obedit && (obedit->mode & OB_MODE_EDIT)) && V3D_IS_ZBUF(v3d)) { /* do nothing */ @@ -262,14 +262,13 @@ static void backdrawview3d(const struct EvaluationContext *eval_ctx, Scene *scen /* dithering and AA break color coding, so disable */ glDisable(GL_DITHER); - multisample_enabled = glIsEnabled(GL_MULTISAMPLE); - if (multisample_enabled) - glDisable(GL_MULTISAMPLE); - - if (win->multisamples != USER_MULTISAMPLE_NONE) { + if (false) { /* for multisample we use an offscreen FBO. multisample drawing can fail * with color coded selection drawing, and reading back depths from such - * a buffer can also cause a few seconds freeze on OS X / NVidia. */ + * a buffer can also cause a few seconds freeze on OS X / NVidia. + * + * NOTE: code is no longer used now, but offscreen drawing is likely + * what we will always want to do for the new viewport. */ int w = BLI_rcti_size_x(&ar->winrct); int h = BLI_rcti_size_y(&ar->winrct); char error[256]; @@ -284,7 +283,7 @@ static void backdrawview3d(const struct EvaluationContext *eval_ctx, Scene *scen } if (!rv3d->gpuoffscreen) { - rv3d->gpuoffscreen = GPU_offscreen_create(w, h, 0, false, error); + rv3d->gpuoffscreen = GPU_offscreen_create(w, h, 0, true, false, error); if (!rv3d->gpuoffscreen) fprintf(stderr, "Failed to create offscreen selection buffer for multisample: %s\n", error); @@ -310,10 +309,11 @@ static void backdrawview3d(const struct EvaluationContext *eval_ctx, Scene *scen ED_view3d_clipping_set(rv3d); G.f |= G_BACKBUFSEL; - - if (base && ((base->flag & BASE_VISIBLED) != 0)) - draw_object_backbufsel(eval_ctx, scene, v3d, rv3d, base->object); - + + if (obact && ((obact->base_flag & BASE_VISIBLED) != 0)) { + draw_object_backbufsel(eval_ctx, scene, v3d, rv3d, obact); + } + if (rv3d->gpuoffscreen) GPU_offscreen_unbind(rv3d->gpuoffscreen, true); else @@ -325,8 +325,6 @@ static void backdrawview3d(const struct EvaluationContext *eval_ctx, Scene *scen v3d->zbuf = false; glDisable(GL_DEPTH_TEST); glEnable(GL_DITHER); - if (multisample_enabled) - glEnable(GL_MULTISAMPLE); if (rv3d->rflag & RV3D_CLIPPING) ED_view3d_clipping_disable(); @@ -356,7 +354,7 @@ static void view3d_opengl_read_Z_pixels(ARegion *ar, int x, int y, int w, int h, void ED_view3d_backbuf_validate(const struct EvaluationContext *eval_ctx, ViewContext *vc) { if (vc->v3d->flag & V3D_INVALID_BACKBUF) { - backdrawview3d(eval_ctx, vc->scene, vc->view_layer, vc->win, vc->ar, vc->v3d); + backdrawview3d(eval_ctx, vc->scene, vc->ar, vc->v3d, vc->obact, vc->obedit); } } @@ -734,7 +732,7 @@ static void view3d_draw_bgpic(Scene *scene, const Depsgraph *depsgraph, glDepthMask(GL_FALSE); glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); gpuPushProjectionMatrix(); gpuPushMatrix(); @@ -1302,7 +1300,7 @@ void ED_view3d_draw_select_loop( for (base = view_layer->object_bases.first; base; base = base->next) { if ((base->flag & BASE_VISIBLED) != 0) { if (((base->flag & BASE_SELECTABLED) == 0) || - (use_obedit_skip && (scene->obedit->data == base->object->data))) + (use_obedit_skip && (vc->obedit->data == base->object->data))) { base->object->select_color = 0; } @@ -1422,11 +1420,14 @@ static void gpu_update_lamps_shadows_world(const EvaluationContext *eval_ctx, Sc mul_m4_m4m4(rv3d.persmat, rv3d.winmat, rv3d.viewmat); invert_m4_m4(rv3d.persinv, rv3d.viewinv); + RenderEngineType *engine_type = RE_engines_find(scene->view_render.engine_id); + /* no need to call ED_view3d_draw_offscreen_init since shadow buffers were already updated */ ED_view3d_draw_offscreen( - eval_ctx, scene, eval_ctx->view_layer, v3d, &ar, winsize, winsize, viewmat, winmat, + eval_ctx, scene, eval_ctx->view_layer, engine_type, + v3d, &ar, winsize, winsize, viewmat, winmat, false, false, true, - NULL, NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL); GPU_lamp_shadow_buffer_unbind(shadow->lamp); v3d->drawtype = drawtype; @@ -1500,18 +1501,18 @@ static void view3d_draw_objects( const EvaluationContext *eval_ctx, Scene *scene, View3D *v3d, ARegion *ar, const char **grid_unit, - const bool do_bgpic, const bool draw_offscreen, GPUFX *fx) + const bool do_bgpic, const bool draw_offscreen) { ViewLayer *view_layer = C ? CTX_data_view_layer(C) : BKE_view_layer_from_scene_get(scene); Depsgraph *depsgraph = CTX_data_depsgraph(C); RegionView3D *rv3d = ar->regiondata; Base *base; + Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer); const bool do_camera_frame = !draw_offscreen; const bool draw_grids = !draw_offscreen && (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0; const bool draw_floor = (rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO); /* only draw grids after in solid modes, else it hovers over mesh wires */ - const bool draw_grids_after = draw_grids && draw_floor && (v3d->drawtype > OB_WIRE) && fx; - bool do_composite_xray = false; + const bool draw_grids_after = draw_grids && draw_floor && (v3d->drawtype > OB_WIRE); bool xrayclear = true; if (!draw_offscreen) { @@ -1522,7 +1523,7 @@ static void view3d_draw_objects( view3d_draw_clipping(rv3d); /* set zbuffer after we draw clipping region */ - v3d->zbuf = VP_legacy_use_depth(scene, v3d); + v3d->zbuf = VP_legacy_use_depth(v3d, obedit); if (v3d->zbuf) { glEnable(GL_DEPTH_TEST); @@ -1599,7 +1600,7 @@ static void view3d_draw_objects( draw_dupli_objects(eval_ctx, scene, view_layer, ar, v3d, base); } if ((base->flag & BASE_SELECTED) == 0) { - if (base->object != scene->obedit) + if (base->object != obedit) draw_object(eval_ctx, scene, view_layer, ar, v3d, base, 0); } } @@ -1611,7 +1612,7 @@ static void view3d_draw_objects( /* draw selected and editmode */ for (base = view_layer->object_bases.first; base; base = base->next) { if ((base->flag & BASE_VISIBLED) != 0) { - if (base->object == scene->obedit || (base->flag & BASE_SELECTED)) { + if (base->object == obedit || (base->flag & BASE_SELECTED)) { draw_object(eval_ctx, scene, view_layer, ar, v3d, base, 0); } } @@ -1636,19 +1637,9 @@ static void view3d_draw_objects( /* transp and X-ray afterdraw stuff */ if (v3d->afterdraw_transp.first) view3d_draw_transp(eval_ctx, scene, view_layer, ar, v3d); - /* always do that here to cleanup depth buffers if none needed */ - if (fx) { - do_composite_xray = v3d->zbuf && (v3d->afterdraw_xray.first || v3d->afterdraw_xraytransp.first); - GPU_fx_compositor_setup_XRay_pass(fx, do_composite_xray); - } - if (v3d->afterdraw_xray.first) view3d_draw_xray(eval_ctx, scene, view_layer, ar, v3d, &xrayclear); if (v3d->afterdraw_xraytransp.first) view3d_draw_xraytransp(eval_ctx, scene, view_layer, ar, v3d, xrayclear); - if (fx && do_composite_xray) { - GPU_fx_compositor_XRay_resolve(fx); - } - if (!draw_offscreen) { ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW); } @@ -1956,9 +1947,6 @@ static void view3d_main_region_draw_objects(const bContext *C, Scene *scene, Vie CTX_data_eval_ctx(C, &eval_ctx); - /* post processing */ - bool do_compositing = false; - /* shadow buffers, before we setup matrices */ if (draw_glsl_material(scene, view_layer, NULL, v3d, v3d->drawtype)) gpu_update_lamps_shadows_world(&eval_ctx, scene, v3d); @@ -1986,40 +1974,9 @@ static void view3d_main_region_draw_objects(const bContext *C, Scene *scene, Vie update_lods(scene, rv3d->viewinv[3]); } #endif - - /* framebuffer fx needed, we need to draw offscreen first */ - if (v3d->fx_settings.fx_flag && v3d->drawtype >= OB_SOLID) { - BKE_screen_gpu_fx_validate(&v3d->fx_settings); - GPUFXSettings fx_settings = v3d->fx_settings; - if (!rv3d->compositor) - rv3d->compositor = GPU_fx_compositor_create(); - - if (rv3d->persp == RV3D_CAMOB && v3d->camera) - BKE_camera_to_gpu_dof(v3d->camera, &fx_settings); - else { - fx_settings.dof = NULL; - } - - do_compositing = GPU_fx_compositor_initialize_passes(rv3d->compositor, &ar->winrct, &ar->drawrct, &fx_settings); - } - /* enables anti-aliasing for 3D view drawing */ - if (win->multisamples != USER_MULTISAMPLE_NONE) { - glEnable(GL_MULTISAMPLE); - } - /* main drawing call */ - view3d_draw_objects(C, &eval_ctx, scene, v3d, ar, grid_unit, true, false, do_compositing ? rv3d->compositor : NULL); - - /* post process */ - if (do_compositing) { - GPU_fx_do_composite_pass(rv3d->compositor, rv3d->winmat, rv3d->is_persp, scene, NULL); - } - - /* Disable back anti-aliasing */ - if (win->multisamples != USER_MULTISAMPLE_NONE) { - glDisable(GL_MULTISAMPLE); - } + view3d_draw_objects(C, &eval_ctx, scene, v3d, ar, grid_unit, true, false); if (v3d->lay_used != lay_used) { /* happens when loading old files or loading with UI load */ /* find header and force tag redraw */ @@ -2176,9 +2133,9 @@ void VP_deprecated_view3d_draw_objects( const EvaluationContext *eval_ctx, Scene *scene, View3D *v3d, ARegion *ar, const char **grid_unit, - const bool do_bgpic, const bool draw_offscreen, GPUFX *fx) + const bool do_bgpic, const bool draw_offscreen) { - view3d_draw_objects(C, eval_ctx, scene, v3d, ar, grid_unit, do_bgpic, draw_offscreen, fx); + view3d_draw_objects(C, eval_ctx, scene, v3d, ar, grid_unit, do_bgpic, draw_offscreen); } void VP_deprecated_gpu_update_lamps_shadows_world(const EvaluationContext *eval_ctx, Scene *scene, View3D *v3d) diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 1e368e2d171..0ae69debf18 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -57,6 +57,7 @@ #include "BKE_object.h" #include "BKE_paint.h" #include "BKE_report.h" +#include "BKE_scene.h" #include "BKE_screen.h" #include "BKE_action.h" @@ -77,61 +78,123 @@ #include "ED_gpencil.h" #include "ED_view3d.h" - #include "UI_resources.h" -#include "PIL_time.h" /* smoothview */ +#include "PIL_time.h" #include "view3d_intern.h" /* own include */ /* -------------------------------------------------------------------- */ +/** \name Generic View Operator Properties + * \{ */ + +enum eV3D_OpPropFlag { + V3D_OP_PROP_MOUSE_CO = (1 << 0), + V3D_OP_PROP_DELTA = (1 << 1), + V3D_OP_PROP_USE_ALL_REGIONS = (1 << 2), + V3D_OP_PROP_USE_MOUSE_INIT = (1 << 3), +}; + +static void view3d_operator_properties_common(wmOperatorType *ot, const enum eV3D_OpPropFlag flag) +{ + if (flag & V3D_OP_PROP_MOUSE_CO) { + PropertyRNA *prop; + prop = RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Region Position X", "", 0, INT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN); + prop = RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Region Position Y", "", 0, INT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN); + } + if (flag & V3D_OP_PROP_DELTA) { + RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX); + } + if (flag & V3D_OP_PROP_USE_ALL_REGIONS) { + PropertyRNA *prop; + prop = RNA_def_boolean(ot->srna, "use_all_regions", 0, "All Regions", "View selected for all regions"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + } + if (flag & V3D_OP_PROP_USE_MOUSE_INIT) { + /* Disable when view operators are initialized from buttons. */ + PropertyRNA *prop; + prop = RNA_def_boolean(ot->srna, "use_mouse_init", true, "Mouse Init", "Use initial mouse position"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Generic View Operator Custom-Data * \{ */ typedef struct ViewOpsData { - /* context pointers (assigned by viewops_data_alloc) */ - const Depsgraph *depsgraph; + /** Context pointers (assigned by #viewops_data_alloc). */ Scene *scene; ScrArea *sa; ARegion *ar; View3D *v3d; RegionView3D *rv3d; + Depsgraph *depsgraph; - /* needed for continuous zoom */ + /** Needed for continuous zoom. */ wmTimer *timer; - double timer_lastdraw; - float oldquat[4]; - float viewquat[4]; /* working copy of rv3d->viewquat */ - float trackvec[3]; - float mousevec[3]; /* dolly only */ + /** Viewport state on initialization, don't change afterwards. */ + struct { + float dist; + float camzoom; + float quat[4]; + /** #wmEvent.x, y. */ + int event_xy[2]; + /** Offset to use when #VIEWOPS_FLAG_USE_MOUSE_INIT is not set. + * so we can simulate pressing in the middle of the screen. */ + int event_xy_offset[2]; + /** #wmEvent.type that triggered the operator. */ + int event_type; + float ofs[3]; + /** Initial distance to 'ofs'. */ + float zfac; + + /** Trackball rotation only. */ + float trackvec[3]; + /** Dolly only. */ + float mousevec[3]; + } init; + + /** Previous state (previous modal event handled). */ + struct { + int event_xy[2]; + /** For operators that use time-steps (continuous zoom). */ + double time; + } prev; + + /** Current state. */ + struct { + /** Working copy of #RegionView3D.viewquat, needed for rotation calculation + * so we can apply snap to the view-port while keeping the unsnapped rotation + * here to use when snap is disabled and for continued calculation. */ + float viewquat[4]; + } curr; + float reverse; - float dist_prev, camzoom_prev; - float grid, far; bool axis_snap; /* view rotate only */ - float zfac; - /* use for orbit selection and auto-dist */ - float ofs[3], dyn_ofs[3]; + /** Use for orbit selection and auto-dist. */ + float dyn_ofs[3]; bool use_dyn_ofs; - - int origx, origy, oldx, oldy; - int origkey; /* the key that triggered the operator */ - } ViewOpsData; #define TRACKBALLSIZE (1.1f) -static void calctrackballvec(const rcti *rect, int mx, int my, float vec[3]) +static void calctrackballvec(const rcti *rect, const int event_xy[2], float vec[3]) { const float radius = TRACKBALLSIZE; const float t = radius / (float)M_SQRT2; float x, y, z, d; /* normalize x and y */ - x = BLI_rcti_cent_x(rect) - mx; + x = BLI_rcti_cent_x(rect) - event_xy[0]; x /= (float)(BLI_rcti_size_x(rect) / 4); - y = BLI_rcti_cent_y(rect) - my; + y = BLI_rcti_cent_y(rect) - event_xy[1]; y /= (float)(BLI_rcti_size_y(rect) / 2); d = sqrtf(x * x + y * y); if (d < t) { /* Inside sphere */ @@ -164,7 +227,7 @@ static void viewops_data_alloc(bContext *C, wmOperator *op) } void view3d_orbit_apply_dyn_ofs( - float r_ofs[3], const float ofs_old[3], const float viewquat_old[4], + float r_ofs[3], const float ofs_init[3], const float viewquat_old[4], const float viewquat_new[4], const float dyn_ofs[3]) { float q[4]; @@ -173,7 +236,7 @@ void view3d_orbit_apply_dyn_ofs( invert_qt_normalized(q); - sub_v3_v3v3(r_ofs, ofs_old, dyn_ofs); + sub_v3_v3v3(r_ofs, ofs_init, dyn_ofs); mul_qt_v3(q, r_ofs); add_v3_v3(r_ofs, dyn_ofs); } @@ -262,48 +325,58 @@ static bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3]) return is_set; } -enum eViewOpsOrbit { - VIEWOPS_ORBIT_SELECT = (1 << 0), - VIEWOPS_ORBIT_DEPTH = (1 << 1), +enum eViewOpsFlag { + /** When enabled, rotate around the selection. */ + VIEWOPS_FLAG_ORBIT_SELECT = (1 << 0), + /** When enabled, use the depth under the cursor for navigation. */ + VIEWOPS_FLAG_DEPTH_NAVIGATE = (1 << 1), + /** + * When enabled run #ED_view3d_persp_ensure this may switch out of + * camera view when orbiting or switch from ortho to perspective when auto-persp is enabled. + * Some operations don't require this (view zoom/pan or ndof where subtle rotation is common + * so we don't want it to trigger auto-perspective). */ + VIEWOPS_FLAG_PERSP_ENSURE = (1 << 2), + /** When set, ignore any options that depend on initial cursor location. */ + VIEWOPS_FLAG_USE_MOUSE_INIT = (1 << 3), }; -static enum eViewOpsOrbit viewops_orbit_mode_ex(bool use_select, bool use_depth) +static enum eViewOpsFlag viewops_flag_from_args(bool use_select, bool use_depth) { - enum eViewOpsOrbit flag = 0; + enum eViewOpsFlag flag = 0; if (use_select) { - flag |= VIEWOPS_ORBIT_SELECT; + flag |= VIEWOPS_FLAG_ORBIT_SELECT; } if (use_depth) { - flag |= VIEWOPS_ORBIT_DEPTH; + flag |= VIEWOPS_FLAG_DEPTH_NAVIGATE; } return flag; } -static enum eViewOpsOrbit viewops_orbit_mode(void) +static enum eViewOpsFlag viewops_flag_from_prefs(void) { - return viewops_orbit_mode_ex( + return viewops_flag_from_args( (U.uiflag & USER_ORBIT_SELECTION) != 0, - (U.uiflag & USER_ZBUF_ORBIT) != 0); + (U.uiflag & USER_DEPTH_NAVIGATE) != 0); } /** * Calculate the values for #ViewOpsData - * - * \param use_ensure_persp: When enabled run #ED_view3d_persp_ensure this may switch out of - * camera view when orbiting or switch from ortho to perspective when auto-persp is enabled. - * Some operations don't require this (view zoom/pan or ndof where subtle rotation is common - * so we don't want it to trigger auto-perspective). */ -static void viewops_data_create_ex( +static void viewops_data_create( bContext *C, wmOperator *op, const wmEvent *event, - bool use_ensure_persp, enum eViewOpsOrbit orbit_mode) + enum eViewOpsFlag viewops_flag) { ViewOpsData *vod = op->customdata; RegionView3D *rv3d = vod->rv3d; + /* Could do this more nicely. */ + if ((viewops_flag & VIEWOPS_FLAG_USE_MOUSE_INIT) == 0) { + viewops_flag &= ~VIEWOPS_FLAG_DEPTH_NAVIGATE; + } + /* we need the depth info before changing any viewport options */ - if (orbit_mode & VIEWOPS_ORBIT_DEPTH) { + if (viewops_flag & VIEWOPS_FLAG_DEPTH_NAVIGATE) { EvaluationContext eval_ctx; struct Depsgraph *graph = CTX_data_depsgraph(C); float fallback_depth_pt[3]; @@ -322,7 +395,7 @@ static void viewops_data_create_ex( vod->use_dyn_ofs = false; } - if (use_ensure_persp) { + if (viewops_flag & VIEWOPS_FLAG_PERSP_ENSURE) { if (ED_view3d_persp_ensure(vod->v3d, vod->ar)) { /* If we're switching from camera view to the perspective one, * need to tag viewport update, so camera vuew and borders @@ -336,25 +409,37 @@ static void viewops_data_create_ex( * we may want to make this optional but for now its needed always */ ED_view3d_camera_lock_init(vod->v3d, vod->rv3d); - vod->dist_prev = rv3d->dist; - vod->camzoom_prev = rv3d->camzoom; - copy_qt_qt(vod->viewquat, rv3d->viewquat); - copy_qt_qt(vod->oldquat, rv3d->viewquat); - vod->origx = vod->oldx = event->x; - vod->origy = vod->oldy = event->y; - vod->origkey = event->type; /* the key that triggered the operator. */ - copy_v3_v3(vod->ofs, rv3d->ofs); + vod->init.dist = rv3d->dist; + vod->init.camzoom = rv3d->camzoom; + copy_qt_qt(vod->init.quat, rv3d->viewquat); + vod->init.event_xy[0] = vod->prev.event_xy[0] = event->x; + vod->init.event_xy[1] = vod->prev.event_xy[1] = event->y; - if (orbit_mode & VIEWOPS_ORBIT_SELECT) { + if (viewops_flag & VIEWOPS_FLAG_USE_MOUSE_INIT) { + vod->init.event_xy_offset[0] = 0; + vod->init.event_xy_offset[1] = 0; + } + else { + /* Simulate the event starting in the middle of the region. */ + vod->init.event_xy_offset[0] = BLI_rcti_cent_x(&vod->ar->winrct) - event->x; + vod->init.event_xy_offset[1] = BLI_rcti_cent_y(&vod->ar->winrct) - event->y; + } + + vod->init.event_type = event->type; + copy_v3_v3(vod->init.ofs, rv3d->ofs); + + copy_qt_qt(vod->curr.viewquat, rv3d->viewquat); + + if (viewops_flag & VIEWOPS_FLAG_ORBIT_SELECT) { float ofs[3]; if (view3d_orbit_calc_center(C, ofs) || (vod->use_dyn_ofs == false)) { vod->use_dyn_ofs = true; negate_v3_v3(vod->dyn_ofs, ofs); - orbit_mode &= ~VIEWOPS_ORBIT_DEPTH; + viewops_flag &= ~VIEWOPS_FLAG_DEPTH_NAVIGATE; } } - if (orbit_mode & VIEWOPS_ORBIT_DEPTH) { + if (viewops_flag & VIEWOPS_FLAG_DEPTH_NAVIGATE) { if (vod->use_dyn_ofs) { if (rv3d->is_persp) { float my_origin[3]; /* original G.vd->ofs */ @@ -381,7 +466,7 @@ static void viewops_data_create_ex( /* find a new ofs value that is along the view axis (rather than the mouse location) */ closest_to_line_v3(dvec, vod->dyn_ofs, my_pivot, my_origin); - vod->dist_prev = rv3d->dist = len_v3v3(my_pivot, dvec); + vod->init.dist = rv3d->dist = len_v3v3(my_pivot, dvec); negate_v3_v3(rv3d->ofs, dvec); } @@ -394,27 +479,26 @@ static void viewops_data_create_ex( negate_v3(rv3d->ofs); } negate_v3(vod->dyn_ofs); - copy_v3_v3(vod->ofs, rv3d->ofs); + copy_v3_v3(vod->init.ofs, rv3d->ofs); } } + /* For dolly */ + ED_view3d_win_to_vector(vod->ar, (const float[2]){UNPACK2(event->mval)}, vod->init.mousevec); + { - /* for dolly */ - const float mval_f[2] = {(float)event->mval[0], - (float)event->mval[1]}; - ED_view3d_win_to_vector(vod->ar, mval_f, vod->mousevec); + const int event_xy_offset[2] = { + event->x + vod->init.event_xy_offset[0], + event->y + vod->init.event_xy_offset[1], + }; + /* For rotation with trackball rotation. */ + calctrackballvec(&vod->ar->winrct, event_xy_offset, vod->init.trackvec); } - /* lookup, we don't pass on v3d to prevent confusement */ - vod->grid = vod->v3d->grid; - vod->far = vod->v3d->far; - - calctrackballvec(&vod->ar->winrct, event->x, event->y, vod->trackvec); - { float tvec[3]; negate_v3_v3(tvec, rv3d->ofs); - vod->zfac = ED_view3d_calc_zfac(rv3d, tvec, NULL); + vod->init.zfac = ED_view3d_calc_zfac(rv3d, tvec, NULL); } vod->reverse = 1.0f; @@ -424,12 +508,6 @@ static void viewops_data_create_ex( rv3d->rflag |= RV3D_NAVIGATING; } -static void viewops_data_create(bContext *C, wmOperator *op, const wmEvent *event, bool use_ensure_persp) -{ - enum eViewOpsOrbit orbit_mode = viewops_orbit_mode(); - viewops_data_create_ex(C, op, event, use_ensure_persp, orbit_mode); -} - static void viewops_data_free(bContext *C, wmOperator *op) { ARegion *ar; @@ -487,7 +565,7 @@ void viewrotate_modal_keymap(wmKeyConfig *keyconf) {VIEWROT_MODAL_AXIS_SNAP_ENABLE, "AXIS_SNAP_ENABLE", 0, "Enable Axis Snap", ""}, {VIEWROT_MODAL_AXIS_SNAP_DISABLE, "AXIS_SNAP_DISABLE", 0, "Disable Axis Snap", ""}, - + {VIEWROT_MODAL_SWITCH_ZOOM, "SWITCH_TO_ZOOM", 0, "Switch to Zoom"}, {VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"}, @@ -514,17 +592,16 @@ void viewrotate_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM); WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE); #endif - + /* assign map to operators */ WM_modalkeymap_assign(keymap, "VIEW3D_OT_rotate"); - } static void viewrotate_apply_dyn_ofs(ViewOpsData *vod, const float viewquat_new[4]) { if (vod->use_dyn_ofs) { RegionView3D *rv3d = vod->rv3d; - view3d_orbit_apply_dyn_ofs(rv3d->ofs, vod->ofs, vod->oldquat, viewquat_new, vod->dyn_ofs); + view3d_orbit_apply_dyn_ofs(rv3d->ofs, vod->init.ofs, vod->init.quat, viewquat_new, vod->dyn_ofs); } } @@ -540,7 +617,7 @@ static void viewrotate_apply_snap(ViewOpsData *vod) int x, y, z; bool found = false; - invert_qt_qt_normalized(viewquat_inv, vod->viewquat); + invert_qt_qt_normalized(viewquat_inv, vod->curr.viewquat); mul_qt_v3(viewquat_inv, zaxis); normalize_v3(zaxis); @@ -576,7 +653,7 @@ static void viewrotate_apply_snap(ViewOpsData *vod) * for testing roll */ rotation_between_vecs_to_quat(viewquat_align, zaxis_best, zaxis); normalize_qt(viewquat_align); - mul_qt_qtqt(viewquat_align, vod->viewquat, viewquat_align); + mul_qt_qtqt(viewquat_align, vod->curr.viewquat, viewquat_align); normalize_qt(viewquat_align); invert_qt_qt_normalized(viewquat_align_inv, viewquat_align); @@ -630,7 +707,7 @@ static void viewrotate_apply_snap(ViewOpsData *vod) } } -static void viewrotate_apply(ViewOpsData *vod, int x, int y) +static void viewrotate_apply(ViewOpsData *vod, const int event_xy[2]) { RegionView3D *rv3d = vod->rv3d; @@ -640,9 +717,15 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y) float axis[3], q1[4], dvec[3], newvec[3]; float angle; - calctrackballvec(&vod->ar->winrct, x, y, newvec); + { + const int event_xy_offset[2] = { + event_xy[0] + vod->init.event_xy_offset[0], + event_xy[1] + vod->init.event_xy_offset[1], + }; + calctrackballvec(&vod->ar->winrct, event_xy_offset, newvec); + } - sub_v3_v3v3(dvec, newvec, vod->trackvec); + sub_v3_v3v3(dvec, newvec, vod->init.trackvec); angle = (len_v3(dvec) / (2.0f * TRACKBALLSIZE)) * (float)M_PI; @@ -653,12 +736,12 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y) * so that the angle of rotation is linearly proportional to * the distance that the mouse is dragged. */ - cross_v3_v3v3(axis, vod->trackvec, newvec); + cross_v3_v3v3(axis, vod->init.trackvec, newvec); axis_angle_to_quat(q1, axis, angle); - mul_qt_qtqt(vod->viewquat, q1, vod->oldquat); + mul_qt_qtqt(vod->curr.viewquat, q1, vod->init.quat); - viewrotate_apply_dyn_ofs(vod, vod->viewquat); + viewrotate_apply_dyn_ofs(vod, vod->curr.viewquat); } else { /* New turntable view code by John Aughey */ @@ -675,7 +758,7 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y) const float sensitivity = 0.007f; /* Get the 3x3 matrix and its inverse from the quaternion */ - quat_to_mat3(m, vod->viewquat); + quat_to_mat3(m, vod->curr.viewquat); invert_m3_m3(m_inv, m); /* avoid gimble lock */ @@ -702,30 +785,30 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y) /* This can likely be computed directly from the quaternion. */ /* Perform the up/down rotation */ - axis_angle_to_quat(quat_local_x, xaxis, sensitivity * -(y - vod->oldy)); - mul_qt_qtqt(quat_local_x, vod->viewquat, quat_local_x); + axis_angle_to_quat(quat_local_x, xaxis, sensitivity * -(event_xy[1] - vod->prev.event_xy[1])); + mul_qt_qtqt(quat_local_x, vod->curr.viewquat, quat_local_x); /* Perform the orbital rotation */ - axis_angle_to_quat_single(quat_global_z, 'Z', sensitivity * vod->reverse * (x - vod->oldx)); - mul_qt_qtqt(vod->viewquat, quat_local_x, quat_global_z); + axis_angle_to_quat_single(quat_global_z, 'Z', sensitivity * vod->reverse * (event_xy[0] - vod->prev.event_xy[0])); + mul_qt_qtqt(vod->curr.viewquat, quat_local_x, quat_global_z); - viewrotate_apply_dyn_ofs(vod, vod->viewquat); + viewrotate_apply_dyn_ofs(vod, vod->curr.viewquat); } /* avoid precision loss over time */ - normalize_qt(vod->viewquat); + normalize_qt(vod->curr.viewquat); /* use a working copy so view rotation locking doesnt overwrite the locked * rotation back into the view we calculate with */ - copy_qt_qt(rv3d->viewquat, vod->viewquat); + copy_qt_qt(rv3d->viewquat, vod->curr.viewquat); /* check for view snap, * note: don't apply snap to vod->viewquat so the view wont jam up */ if (vod->axis_snap) { viewrotate_apply_snap(vod); } - vod->oldx = x; - vod->oldy = y; + vod->prev.event_xy[0] = event_xy[0]; + vod->prev.event_xy[1] = event_xy[1]; ED_view3d_camera_lock_sync(vod->v3d, rv3d); @@ -766,12 +849,12 @@ static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event) break; } } - else if (event->type == vod->origkey && event->val == KM_RELEASE) { + else if (event->type == vod->init.event_type && event->val == KM_RELEASE) { event_code = VIEW_CONFIRM; } if (event_code == VIEW_APPLY) { - viewrotate_apply(vod, event->x, event->y); + viewrotate_apply(vod, &event->x); if (ED_screen_animation_playing(CTX_wm_manager(C))) { use_autokey = true; } @@ -797,6 +880,8 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ViewOpsData *vod; + const bool use_mouse_init = RNA_boolean_get(op->ptr, "use_mouse_init"); + /* makes op->customdata */ viewops_data_alloc(C, op); vod = op->customdata; @@ -809,29 +894,33 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event) ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar); - viewops_data_create(C, op, event, true); + viewops_data_create( + C, op, event, + viewops_flag_from_prefs() | + VIEWOPS_FLAG_PERSP_ENSURE | + (use_mouse_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0)); if (ELEM(event->type, MOUSEPAN, MOUSEROTATE)) { /* Rotate direction we keep always same */ - int x, y; + int event_xy[2]; if (event->type == MOUSEPAN) { if (U.uiflag2 & USER_TRACKPAD_NATURAL) { - x = 2 * event->x - event->prevx; - y = 2 * event->y - event->prevy; + event_xy[0] = 2 * event->x - event->prevx; + event_xy[1] = 2 * event->y - event->prevy; } else { - x = event->prevx; - y = event->prevy; + event_xy[0] = event->prevx; + event_xy[1] = event->prevy; } } else { /* MOUSEROTATE performs orbital rotation, so y axis delta is set to 0 */ - x = event->prevx; - y = event->y; + event_xy[0] = event->prevx; + event_xy[1] = event->y; } - viewrotate_apply(vod, x, y); + viewrotate_apply(vod, event_xy); ED_view3d_depth_tag_update(vod->rv3d); viewops_data_free(C, op); @@ -894,6 +983,8 @@ void VIEW3D_OT_rotate(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR; + + view3d_operator_properties_common(ot, V3D_OP_PROP_USE_MOUSE_INIT); } /** \} */ @@ -1062,7 +1153,6 @@ static void view3d_ndof_orbit( axis_angle_to_quat_single(quat, 'Z', angle); mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, quat); - } else { float quat[4]; @@ -1213,7 +1303,6 @@ void view3d_ndof_fly( static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (event->type != NDOF_MOTION) { return OPERATOR_CANCELLED; } @@ -1225,9 +1314,9 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event) const wmNDOFMotionData *ndof = event->customdata; viewops_data_alloc(C, op); - viewops_data_create_ex( + viewops_data_create( C, op, event, - false, viewops_orbit_mode_ex((U.uiflag & USER_ORBIT_SELECTION) != 0, false)); + viewops_flag_from_args((U.uiflag & USER_ORBIT_SELECTION) != 0, false)); vod = op->customdata; ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar); @@ -1282,7 +1371,6 @@ void VIEW3D_OT_ndof_orbit(struct wmOperatorType *ot) static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (event->type != NDOF_MOTION) { return OPERATOR_CANCELLED; } @@ -1294,9 +1382,9 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev const wmNDOFMotionData *ndof = event->customdata; viewops_data_alloc(C, op); - viewops_data_create_ex( + viewops_data_create( C, op, event, - false, viewops_orbit_mode_ex((U.uiflag & USER_ORBIT_SELECTION) != 0, false)); + viewops_flag_from_args((U.uiflag & USER_ORBIT_SELECTION) != 0, false)); vod = op->customdata; @@ -1487,7 +1575,7 @@ void viewmove_modal_keymap(wmKeyConfig *keyconf) { static const EnumPropertyItem modal_items[] = { {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, - + {VIEWROT_MODAL_SWITCH_ZOOM, "SWITCH_TO_ZOOM", 0, "Switch to Zoom"}, {VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"}, @@ -1511,7 +1599,7 @@ void viewmove_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM); WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); #endif - + /* assign map to operators */ WM_modalkeymap_assign(keymap, "VIEW3D_OT_move"); } @@ -1520,13 +1608,13 @@ void viewmove_modal_keymap(wmKeyConfig *keyconf) static void viewmove_apply(ViewOpsData *vod, int x, int y) { if (ED_view3d_offset_lock_check(vod->v3d, vod->rv3d)) { - vod->rv3d->ofs_lock[0] -= ((vod->oldx - x) * 2.0f) / (float)vod->ar->winx; - vod->rv3d->ofs_lock[1] -= ((vod->oldy - y) * 2.0f) / (float)vod->ar->winy; + vod->rv3d->ofs_lock[0] -= ((vod->prev.event_xy[0] - x) * 2.0f) / (float)vod->ar->winx; + vod->rv3d->ofs_lock[1] -= ((vod->prev.event_xy[1] - y) * 2.0f) / (float)vod->ar->winy; } else if ((vod->rv3d->persp == RV3D_CAMOB) && !ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)) { const float zoomfac = BKE_screen_view3d_zoom_to_fac(vod->rv3d->camzoom) * 2.0f; - vod->rv3d->camdx += (vod->oldx - x) / (vod->ar->winx * zoomfac); - vod->rv3d->camdy += (vod->oldy - y) / (vod->ar->winy * zoomfac); + vod->rv3d->camdx += (vod->prev.event_xy[0] - x) / (vod->ar->winx * zoomfac); + vod->rv3d->camdy += (vod->prev.event_xy[1] - y) / (vod->ar->winy * zoomfac); CLAMP(vod->rv3d->camdx, -1.0f, 1.0f); CLAMP(vod->rv3d->camdy, -1.0f, 1.0f); } @@ -1534,9 +1622,9 @@ static void viewmove_apply(ViewOpsData *vod, int x, int y) float dvec[3]; float mval_f[2]; - mval_f[0] = x - vod->oldx; - mval_f[1] = y - vod->oldy; - ED_view3d_win_to_delta(vod->ar, mval_f, dvec, vod->zfac); + mval_f[0] = x - vod->prev.event_xy[0]; + mval_f[1] = y - vod->prev.event_xy[1]; + ED_view3d_win_to_delta(vod->ar, mval_f, dvec, vod->init.zfac); add_v3_v3(vod->rv3d->ofs, dvec); @@ -1545,8 +1633,8 @@ static void viewmove_apply(ViewOpsData *vod, int x, int y) } } - vod->oldx = x; - vod->oldy = y; + vod->prev.event_xy[0] = x; + vod->prev.event_xy[1] = y; ED_view3d_camera_lock_sync(vod->v3d, vod->rv3d); @@ -1581,7 +1669,7 @@ static int viewmove_modal(bContext *C, wmOperator *op, const wmEvent *event) break; } } - else if (event->type == vod->origkey && event->val == KM_RELEASE) { + else if (event->type == vod->init.event_type && event->val == KM_RELEASE) { event_code = VIEW_CONFIRM; } @@ -1612,9 +1700,14 @@ static int viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ViewOpsData *vod; + const bool use_mouse_init = RNA_boolean_get(op->ptr, "use_mouse_init"); + /* makes op->customdata */ viewops_data_alloc(C, op); - viewops_data_create(C, op, event, false); + viewops_data_create( + C, op, event, + viewops_flag_from_prefs() | + (use_mouse_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0)); vod = op->customdata; ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar); @@ -1623,9 +1716,9 @@ static int viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *event) /* invert it, trackpad scroll follows same principle as 2d windows this way */ viewmove_apply(vod, 2 * event->x - event->prevx, 2 * event->y - event->prevy); ED_view3d_depth_tag_update(vod->rv3d); - + viewops_data_free(C, op); - + return OPERATOR_FINISHED; } else { @@ -1657,6 +1750,9 @@ void VIEW3D_OT_move(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR; + + /* properties */ + view3d_operator_properties_common(ot, V3D_OP_PROP_USE_MOUSE_INIT); } /** \} */ @@ -1671,7 +1767,7 @@ void viewzoom_modal_keymap(wmKeyConfig *keyconf) { static const EnumPropertyItem modal_items[] = { {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, - + {VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"}, {VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"}, @@ -1695,14 +1791,17 @@ void viewzoom_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE); #endif - + /* assign map to operators */ WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom"); } -static void view_zoom_mouseloc_camera( +/** + * \param zoom_xy: Optionally zoom to window location (coords compatible w/ #wmEvent.x, y). Use when not NULL. + */ +static void view_zoom_to_window_xy_camera( Scene *scene, const Depsgraph *depsgraph, View3D *v3d, - ARegion *ar, float dfac, int mx, int my) + ARegion *ar, float dfac, const int zoom_xy[2]) { RegionView3D *rv3d = ar->regiondata; const float zoomfac = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom); @@ -1710,12 +1809,12 @@ static void view_zoom_mouseloc_camera( const float camzoom_new = BKE_screen_view3d_zoom_from_fac(zoomfac_new); - if (U.uiflag & USER_ZOOM_TO_MOUSEPOS) { + if (zoom_xy != NULL) { float zoomfac_px; rctf camera_frame_old; rctf camera_frame_new; - const float pt_src[2] = {mx, my}; + const float pt_src[2] = {zoom_xy[0], zoom_xy[1]}; float pt_dst[2]; float delta_px[2]; @@ -1746,12 +1845,15 @@ static void view_zoom_mouseloc_camera( } } -static void view_zoom_mouseloc_3d(ARegion *ar, float dfac, int mx, int my) +/** + * \param zoom_xy: Optionally zoom to window location (coords compatible w/ #wmEvent.x, y). Use when not NULL. + */ +static void view_zoom_to_window_xy_3d(ARegion *ar, float dfac, const int zoom_xy[2]) { RegionView3D *rv3d = ar->regiondata; const float dist_new = rv3d->dist * dfac; - if (U.uiflag & USER_ZOOM_TO_MOUSEPOS) { + if (zoom_xy != NULL) { float dvec[3]; float tvec[3]; float tpos[3]; @@ -1761,8 +1863,8 @@ static void view_zoom_mouseloc_3d(ARegion *ar, float dfac, int mx, int my) negate_v3_v3(tpos, rv3d->ofs); - mval_f[0] = (float)(((mx - ar->winrct.xmin) * 2) - ar->winx) / 2.0f; - mval_f[1] = (float)(((my - ar->winrct.ymin) * 2) - ar->winy) / 2.0f; + mval_f[0] = (float)(((zoom_xy[0] - ar->winrct.xmin) * 2) - ar->winx) / 2.0f; + mval_f[1] = (float)(((zoom_xy[1] - ar->winrct.ymin) * 2) - ar->winy) / 2.0f; /* Project cursor position into 3D space */ zfac = ED_view3d_calc_zfac(rv3d, tpos, NULL); @@ -1788,7 +1890,7 @@ static float viewzoom_scale_value( const rcti *winrct, const short viewzoom, const bool zoom_invert, const bool zoom_invert_force, - const int xy[2], const int xy_orig[2], + const int xy_curr[2], const int xy_init[2], const float val, const float val_orig, double *r_timer_lastdraw) { @@ -1800,10 +1902,10 @@ static float viewzoom_scale_value( float fac; if (U.uiflag & USER_ZOOM_HORIZ) { - fac = (float)(xy_orig[0] - xy[0]); + fac = (float)(xy_init[0] - xy_curr[0]); } else { - fac = (float)(xy_orig[1] - xy[1]); + fac = (float)(xy_init[1] - xy_curr[1]); } if (zoom_invert != zoom_invert_force) { @@ -1821,8 +1923,8 @@ static float viewzoom_scale_value( BLI_rcti_cent_x(winrct), BLI_rcti_cent_y(winrct), }; - float len_new = 5 + len_v2v2_int(ctr, xy); - float len_old = 5 + len_v2v2_int(ctr, xy_orig); + float len_new = 5 + len_v2v2_int(ctr, xy_curr); + float len_old = 5 + len_v2v2_int(ctr, xy_init); /* intentionally ignore 'zoom_invert' for scale */ if (zoom_invert_force) { @@ -1836,12 +1938,12 @@ static float viewzoom_scale_value( float len_old = 5; if (U.uiflag & USER_ZOOM_HORIZ) { - len_new += (winrct->xmax - xy[0]); - len_old += (winrct->xmax - xy_orig[0]); + len_new += (winrct->xmax - (xy_curr[0])); + len_old += (winrct->xmax - (xy_init[0])); } else { - len_new += (winrct->ymax - xy[1]); - len_old += (winrct->ymax - xy_orig[1]); + len_new += (winrct->ymax - (xy_curr[1])); + len_old += (winrct->ymax - (xy_init[1])); } if (zoom_invert != zoom_invert_force) { @@ -1855,25 +1957,48 @@ static float viewzoom_scale_value( return zfac; } +static float viewzoom_scale_value_offset( + const rcti *winrct, + const short viewzoom, + const bool zoom_invert, const bool zoom_invert_force, + const int xy_curr[2], const int xy_init[2], const int xy_offset[2], + const float val, const float val_orig, + double *r_timer_lastdraw) +{ + const int xy_curr_offset[2] = { + xy_curr[0] + xy_offset[0], + xy_curr[1] + xy_offset[1], + }; + const int xy_init_offset[2] = { + xy_init[0] + xy_offset[0], + xy_init[1] + xy_offset[1], + }; + return viewzoom_scale_value( + winrct, viewzoom, zoom_invert, zoom_invert_force, + xy_curr_offset, xy_init_offset, + val, val_orig, r_timer_lastdraw); +} + static void viewzoom_apply_camera( ViewOpsData *vod, const int xy[2], - const short viewzoom, const bool zoom_invert) + const short viewzoom, const bool zoom_invert, const bool zoom_to_pos) { float zfac; - float zoomfac_prev = BKE_screen_view3d_zoom_to_fac(vod->camzoom_prev) * 2.0f; + float zoomfac_prev = BKE_screen_view3d_zoom_to_fac(vod->init.camzoom) * 2.0f; float zoomfac = BKE_screen_view3d_zoom_to_fac(vod->rv3d->camzoom) * 2.0f; - zfac = viewzoom_scale_value( - &vod->ar->winrct, viewzoom, zoom_invert, true, xy, &vod->origx, + zfac = viewzoom_scale_value_offset( + &vod->ar->winrct, viewzoom, zoom_invert, true, + xy, vod->init.event_xy, vod->init.event_xy_offset, zoomfac, zoomfac_prev, - &vod->timer_lastdraw); + &vod->prev.time); if (zfac != 1.0f && zfac != 0.0f) { /* calculate inverted, then invert again (needed because of camera zoom scaling) */ zfac = 1.0f / zfac; - view_zoom_mouseloc_camera( + view_zoom_to_window_xy_camera( vod->scene, vod->depsgraph, vod->v3d, - vod->ar, zfac, vod->oldx, vod->oldy); + vod->ar, zfac, zoom_to_pos ? vod->prev.event_xy : NULL); } ED_region_tag_redraw(vod->ar); @@ -1881,25 +2006,26 @@ static void viewzoom_apply_camera( static void viewzoom_apply_3d( ViewOpsData *vod, const int xy[2], - const short viewzoom, const bool zoom_invert) + const short viewzoom, const bool zoom_invert, const bool zoom_to_pos) { float zfac; float dist_range[2]; ED_view3d_dist_range_get(vod->v3d, dist_range); - zfac = viewzoom_scale_value( - &vod->ar->winrct, viewzoom, zoom_invert, false, xy, &vod->origx, - vod->rv3d->dist, vod->dist_prev, - &vod->timer_lastdraw); + zfac = viewzoom_scale_value_offset( + &vod->ar->winrct, viewzoom, zoom_invert, false, + xy, vod->init.event_xy, vod->init.event_xy_offset, + vod->rv3d->dist, vod->init.dist, + &vod->prev.time); if (zfac != 1.0f) { const float zfac_min = dist_range[0] / vod->rv3d->dist; const float zfac_max = dist_range[1] / vod->rv3d->dist; CLAMP(zfac, zfac_min, zfac_max); - view_zoom_mouseloc_3d( - vod->ar, zfac, vod->oldx, vod->oldy); + view_zoom_to_window_xy_3d( + vod->ar, zfac, zoom_to_pos ? vod->prev.event_xy : NULL); } /* these limits were in old code too */ @@ -1916,15 +2042,15 @@ static void viewzoom_apply_3d( static void viewzoom_apply( ViewOpsData *vod, const int xy[2], - const short viewzoom, const bool zoom_invert) + const short viewzoom, const bool zoom_invert, const bool zoom_to_pos) { if ((vod->rv3d->persp == RV3D_CAMOB) && (vod->rv3d->is_persp && ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)) == 0) { - viewzoom_apply_camera(vod, xy, viewzoom, zoom_invert); + viewzoom_apply_camera(vod, xy, viewzoom, zoom_invert, zoom_to_pos); } else { - viewzoom_apply_3d(vod, xy, viewzoom, zoom_invert); + viewzoom_apply_3d(vod, xy, viewzoom, zoom_invert, zoom_to_pos); } } @@ -1958,12 +2084,16 @@ static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event) break; } } - else if (event->type == vod->origkey && event->val == KM_RELEASE) { + else if (event->type == vod->init.event_type && event->val == KM_RELEASE) { event_code = VIEW_CONFIRM; } if (event_code == VIEW_APPLY) { - viewzoom_apply(vod, &event->x, U.viewzoom, (U.uiflag & USER_ZOOM_INVERT) != 0); + const bool use_mouse_init = RNA_boolean_get(op->ptr, "use_mouse_init"); + viewzoom_apply( + vod, &event->x, U.viewzoom, + (U.uiflag & USER_ZOOM_INVERT) != 0, + (use_mouse_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS))); if (ED_screen_animation_playing(CTX_wm_manager(C))) { use_autokey = true; } @@ -1997,7 +2127,7 @@ static int viewzoom_exec(bContext *C, wmOperator *op) float dist_range[2]; const int delta = RNA_int_get(op->ptr, "delta"); - int mx, my; + const bool use_mouse_init = RNA_boolean_get(op->ptr, "use_mouse_init"); if (op->customdata) { ViewOpsData *vod = op->customdata; @@ -2013,33 +2143,39 @@ static int viewzoom_exec(bContext *C, wmOperator *op) v3d = sa->spacedata.first; rv3d = ar->regiondata; - mx = RNA_struct_property_is_set(op->ptr, "mx") ? RNA_int_get(op->ptr, "mx") : ar->winx / 2; - my = RNA_struct_property_is_set(op->ptr, "my") ? RNA_int_get(op->ptr, "my") : ar->winy / 2; use_cam_zoom = (rv3d->persp == RV3D_CAMOB) && !(rv3d->is_persp && ED_view3d_camera_lock_check(v3d, rv3d)); + int zoom_xy_buf[2]; + const int *zoom_xy = NULL; + if (use_mouse_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) { + zoom_xy_buf[0] = RNA_struct_property_is_set(op->ptr, "mx") ? RNA_int_get(op->ptr, "mx") : ar->winx / 2; + zoom_xy_buf[1] = RNA_struct_property_is_set(op->ptr, "my") ? RNA_int_get(op->ptr, "my") : ar->winy / 2; + zoom_xy = zoom_xy_buf; + } + ED_view3d_dist_range_get(v3d, dist_range); if (delta < 0) { const float step = 1.2f; /* this min and max is also in viewmove() */ if (use_cam_zoom) { - view_zoom_mouseloc_camera(scene, depsgraph, v3d, ar, step, mx, my); + view_zoom_to_window_xy_camera(scene, depsgraph, v3d, ar, step, zoom_xy); } else { if (rv3d->dist < dist_range[1]) { - view_zoom_mouseloc_3d(ar, step, mx, my); + view_zoom_to_window_xy_3d(ar, step, zoom_xy); } } } else { const float step = 1.0f / 1.2f; if (use_cam_zoom) { - view_zoom_mouseloc_camera(scene, depsgraph, v3d, ar, step, mx, my); + view_zoom_to_window_xy_camera(scene, depsgraph, v3d, ar, step, zoom_xy); } else { if (rv3d->dist > dist_range[0]) { - view_zoom_mouseloc_3d(ar, step, mx, my); + view_zoom_to_window_xy_3d(ar, step, zoom_xy); } } } @@ -2065,9 +2201,14 @@ static int viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ViewOpsData *vod; + const bool use_mouse_init = RNA_boolean_get(op->ptr, "use_mouse_init"); + /* makes op->customdata */ viewops_data_alloc(C, op); - viewops_data_create(C, op, event, false); + viewops_data_create( + C, op, event, + viewops_flag_from_prefs() | + (use_mouse_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0)); vod = op->customdata; ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar); @@ -2085,14 +2226,16 @@ static int viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event) if (event->type == MOUSEZOOM || event->type == MOUSEPAN) { if (U.uiflag & USER_ZOOM_HORIZ) { - vod->origx = vod->oldx = event->x; - viewzoom_apply(vod, &event->prevx, USER_ZOOM_DOLLY, (U.uiflag & USER_ZOOM_INVERT) != 0); + vod->init.event_xy[0] = vod->prev.event_xy[0] = event->x; } else { /* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */ - vod->origy = vod->oldy = vod->origy + event->x - event->prevx; - viewzoom_apply(vod, &event->prevx, USER_ZOOM_DOLLY, (U.uiflag & USER_ZOOM_INVERT) != 0); + vod->init.event_xy[1] = vod->prev.event_xy[1] = vod->init.event_xy[1] + event->x - event->prevx; } + viewzoom_apply( + vod, &event->prevx, USER_ZOOM_DOLLY, + (U.uiflag & USER_ZOOM_INVERT) != 0, + (use_mouse_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS))); ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true); ED_view3d_depth_tag_update(vod->rv3d); @@ -2104,7 +2247,7 @@ static int viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event) if (U.viewzoom == USER_ZOOM_CONT) { /* needs a timer to continue redrawing */ vod->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f); - vod->timer_lastdraw = PIL_check_seconds_timer(); + vod->prev.time = PIL_check_seconds_timer(); } /* add temp handler */ @@ -2123,8 +2266,6 @@ static void viewzoom_cancel(bContext *C, wmOperator *op) void VIEW3D_OT_zoom(wmOperatorType *ot) { - PropertyRNA *prop; - /* identifiers */ ot->name = "Zoom View"; ot->description = "Zoom in/out in the view"; @@ -2140,11 +2281,10 @@ void VIEW3D_OT_zoom(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR; - RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX); - prop = RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Zoom Position X", "", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_HIDDEN); - prop = RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Zoom Position Y", "", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_HIDDEN); + /* properties */ + view3d_operator_properties_common( + ot, + V3D_OP_PROP_DELTA | V3D_OP_PROP_MOUSE_CO | V3D_OP_PROP_USE_MOUSE_INIT); } /** \} */ @@ -2186,7 +2326,7 @@ void viewdolly_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE); #endif - + /* assign map to operators */ WM_modalkeymap_assign(keymap, "VIEW3D_OT_dolly"); } @@ -2204,13 +2344,13 @@ static bool viewdolly_offset_lock_check(bContext *C, wmOperator *op) } } -static void view_dolly_mouseloc(ARegion *ar, float orig_ofs[3], float dvec[3], float dfac) +static void view_dolly_to_vector_3d(ARegion *ar, float orig_ofs[3], float dvec[3], float dfac) { RegionView3D *rv3d = ar->regiondata; madd_v3_v3v3fl(rv3d->ofs, orig_ofs, dvec, -(1.0f - dfac)); } -static void viewdolly_apply(ViewOpsData *vod, int x, int y, const short zoom_invert) +static void viewdolly_apply(ViewOpsData *vod, const int xy[2], const short zoom_invert) { float zfac = 1.0; @@ -2218,21 +2358,23 @@ static void viewdolly_apply(ViewOpsData *vod, int x, int y, const short zoom_inv float len1, len2; if (U.uiflag & USER_ZOOM_HORIZ) { - len1 = (vod->ar->winrct.xmax - x) + 5; - len2 = (vod->ar->winrct.xmax - vod->origx) + 5; + len1 = (vod->ar->winrct.xmax - xy[0]) + 5; + len2 = (vod->ar->winrct.xmax - vod->init.event_xy[0]) + 5; } else { - len1 = (vod->ar->winrct.ymax - y) + 5; - len2 = (vod->ar->winrct.ymax - vod->origy) + 5; + len1 = (vod->ar->winrct.ymax - xy[1]) + 5; + len2 = (vod->ar->winrct.ymax - vod->init.event_xy[1]) + 5; } - if (zoom_invert) + if (zoom_invert) { SWAP(float, len1, len2); + } zfac = 1.0f + ((len1 - len2) * 0.01f * vod->rv3d->dist); } - if (zfac != 1.0f) - view_dolly_mouseloc(vod->ar, vod->ofs, vod->mousevec, zfac); + if (zfac != 1.0f) { + view_dolly_to_vector_3d(vod->ar, vod->init.ofs, vod->init.mousevec, zfac); + } if (vod->rv3d->viewlock & RV3D_BOXVIEW) { view3d_boxview_sync(vod->sa, vod->ar); @@ -2270,12 +2412,12 @@ static int viewdolly_modal(bContext *C, wmOperator *op, const wmEvent *event) break; } } - else if (event->type == vod->origkey && event->val == KM_RELEASE) { + else if (event->type == vod->init.event_type && event->val == KM_RELEASE) { event_code = VIEW_CONFIRM; } if (event_code == VIEW_APPLY) { - viewdolly_apply(vod, event->x, event->y, (U.uiflag & USER_ZOOM_INVERT) != 0); + viewdolly_apply(vod, &event->x, (U.uiflag & USER_ZOOM_INVERT) != 0); if (ED_screen_animation_playing(CTX_wm_manager(C))) { use_autokey = true; } @@ -2312,7 +2454,7 @@ static int viewdolly_exec(bContext *C, wmOperator *op) sa = vod->sa; ar = vod->ar; - copy_v3_v3(mousevec, vod->mousevec); + copy_v3_v3(mousevec, vod->init.mousevec); } else { sa = CTX_wm_area(C); @@ -2324,17 +2466,14 @@ static int viewdolly_exec(bContext *C, wmOperator *op) v3d = sa->spacedata.first; rv3d = ar->regiondata; + const bool use_mouse_init = RNA_boolean_get(op->ptr, "use_mouse_init"); + /* overwrite the mouse vector with the view direction (zoom into the center) */ - if ((U.uiflag & USER_ZOOM_TO_MOUSEPOS) == 0) { + if ((use_mouse_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) == 0) { normalize_v3_v3(mousevec, rv3d->viewinv[2]); } - if (delta < 0) { - view_dolly_mouseloc(ar, rv3d->ofs, mousevec, 0.2f); - } - else { - view_dolly_mouseloc(ar, rv3d->ofs, mousevec, 1.8f); - } + view_dolly_to_vector_3d(ar, rv3d->ofs, mousevec, delta < 0 ? 0.2f : 1.8f); if (rv3d->viewlock & RV3D_BOXVIEW) { view3d_boxview_sync(sa, ar); @@ -2384,7 +2523,12 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event) ED_region_tag_redraw(vod->ar); } - viewops_data_create(C, op, event, false); + const bool use_mouse_init = RNA_boolean_get(op->ptr, "use_mouse_init"); + + viewops_data_create( + C, op, event, + viewops_flag_from_prefs() | + (use_mouse_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0)); /* if one or the other zoom position aren't set, set from event */ @@ -2398,24 +2542,22 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event) } else { /* overwrite the mouse vector with the view direction (zoom into the center) */ - if ((U.uiflag & USER_ZOOM_TO_MOUSEPOS) == 0) { - negate_v3_v3(vod->mousevec, vod->rv3d->viewinv[2]); - normalize_v3(vod->mousevec); + if ((use_mouse_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) == 0) { + negate_v3_v3(vod->init.mousevec, vod->rv3d->viewinv[2]); + normalize_v3(vod->init.mousevec); } if (event->type == MOUSEZOOM) { /* Bypass Zoom invert flag for track pads (pass false always) */ if (U.uiflag & USER_ZOOM_HORIZ) { - vod->origx = vod->oldx = event->x; - viewdolly_apply(vod, event->prevx, event->prevy, (U.uiflag & USER_ZOOM_INVERT) == 0); + vod->init.event_xy[0] = vod->prev.event_xy[0] = event->x; } else { - /* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */ - vod->origy = vod->oldy = vod->origy + event->x - event->prevx; - viewdolly_apply(vod, event->prevx, event->prevy, (U.uiflag & USER_ZOOM_INVERT) == 0); + vod->init.event_xy[1] = vod->prev.event_xy[1] = vod->init.event_xy[1] + event->x - event->prevx; } + viewdolly_apply(vod, &event->prevx, (U.uiflag & USER_ZOOM_INVERT) == 0); ED_view3d_depth_tag_update(vod->rv3d); viewops_data_free(C, op); @@ -2453,9 +2595,9 @@ void VIEW3D_OT_dolly(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR; - RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX); - RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Zoom Position X", "", 0, INT_MAX); - RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Zoom Position Y", "", 0, INT_MAX); + /* properties */ + view3d_operator_properties_common( + ot, V3D_OP_PROP_DELTA | V3D_OP_PROP_MOUSE_CO | V3D_OP_PROP_USE_MOUSE_INIT); } /** \} */ @@ -2465,9 +2607,11 @@ void VIEW3D_OT_dolly(wmOperatorType *ot) * * Move & Zoom the view to fit all of it's contents. * \{ */ -static void view3d_from_minmax(bContext *C, View3D *v3d, ARegion *ar, - const float min[3], const float max[3], - bool ok_dist, const int smooth_viewtx) + +static void view3d_from_minmax( + bContext *C, View3D *v3d, ARegion *ar, + const float min[3], const float max[3], + bool ok_dist, const int smooth_viewtx) { RegionView3D *rv3d = ar->regiondata; float afm[3]; @@ -2533,7 +2677,9 @@ static void view3d_from_minmax(bContext *C, View3D *v3d, ARegion *ar, /* smooth view does viewlock RV3D_BOXVIEW copy */ } -/* same as view3d_from_minmax but for all regions (except cameras) */ +/** + * Same as #view3d_from_minmax but for all regions (except cameras). + */ static void view3d_from_minmax_multi( bContext *C, View3D *v3d, const float min[3], const float max[3], @@ -2553,7 +2699,7 @@ static void view3d_from_minmax_multi( } } -static int view3d_all_exec(bContext *C, wmOperator *op) /* was view3d_home() in 2.4x */ +static int view3d_all_exec(bContext *C, wmOperator *op) { ARegion *ar = CTX_wm_region(C); View3D *v3d = CTX_wm_view3d(C); @@ -2618,8 +2764,6 @@ static int view3d_all_exec(bContext *C, wmOperator *op) /* was view3d_home() in void VIEW3D_OT_view_all(wmOperatorType *ot) { - PropertyRNA *prop; - /* identifiers */ ot->name = "View All"; ot->description = "View all objects in scene"; @@ -2632,8 +2776,8 @@ void VIEW3D_OT_view_all(wmOperatorType *ot) /* flags */ ot->flag = 0; - prop = RNA_def_boolean(ot->srna, "use_all_regions", 0, "All Regions", "View selected for all regions"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + /* properties */ + view3d_operator_properties_common(ot, V3D_OP_PROP_USE_ALL_REGIONS); RNA_def_boolean(ot->srna, "center", 0, "Center", ""); } @@ -2682,11 +2826,8 @@ static int viewselected_exec(bContext *C, wmOperator *op) break; } } - if (base) - ob = base->object; } - if (is_gp_edit) { CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) { @@ -2756,8 +2897,6 @@ static int viewselected_exec(bContext *C, wmOperator *op) void VIEW3D_OT_view_selected(wmOperatorType *ot) { - PropertyRNA *prop; - /* identifiers */ ot->name = "View Selected"; ot->description = "Move the view to the selection center"; @@ -2770,9 +2909,8 @@ void VIEW3D_OT_view_selected(wmOperatorType *ot) /* flags */ ot->flag = 0; - /* rna later */ - prop = RNA_def_boolean(ot->srna, "use_all_regions", 0, "All Regions", "View selected for all regions"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + /* properties */ + view3d_operator_properties_common(ot, V3D_OP_PROP_USE_ALL_REGIONS); } /** \} */ @@ -2825,7 +2963,6 @@ static int view_lock_to_active_exec(bContext *C, wmOperator *UNUSED(op)) Object *obact = CTX_data_active_object(C); if (v3d) { - ED_view3d_lock_clear(v3d); v3d->ob_centre = obact; /* can be NULL */ @@ -2881,7 +3018,7 @@ static int viewcenter_cursor_exec(bContext *C, wmOperator *op) View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = CTX_wm_region_view3d(C); Scene *scene = CTX_data_scene(C); - + if (rv3d) { ARegion *ar = CTX_wm_region(C); const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); @@ -2897,7 +3034,7 @@ static int viewcenter_cursor_exec(bContext *C, wmOperator *op) /* smooth view does viewlock RV3D_BOXVIEW copy */ } - + return OPERATOR_FINISHED; } @@ -2907,11 +3044,11 @@ void VIEW3D_OT_view_center_cursor(wmOperatorType *ot) ot->name = "Center View to Cursor"; ot->description = "Center the view so that the cursor is in the middle of the view"; ot->idname = "VIEW3D_OT_view_center_cursor"; - + /* api callbacks */ ot->exec = viewcenter_cursor_exec; ot->poll = ED_operator_view3d_active; - + /* flags */ ot->flag = 0; } @@ -3131,7 +3268,6 @@ static int render_border_exec(bContext *C, wmOperator *op) } return OPERATOR_FINISHED; - } void VIEW3D_OT_render_border(wmOperatorType *ot) @@ -3154,7 +3290,7 @@ void VIEW3D_OT_render_border(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* rna */ + /* properties */ WM_operator_properties_border(ot); prop = RNA_def_boolean(ot->srna, "camera_only", false, "Camera Only", @@ -3195,7 +3331,6 @@ static int clear_render_border_exec(bContext *C, wmOperator *UNUSED(op)) border->ymax = 1.0f; return OPERATOR_FINISHED; - } void VIEW3D_OT_clear_render_border(wmOperatorType *ot) @@ -3238,7 +3373,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) /* ZBuffer depth vars */ float depth_close = FLT_MAX; - float p[3]; + float cent[2], p[3]; /* note; otherwise opengl won't work */ view3d_operator_needs_opengl(C); @@ -3255,22 +3390,22 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) /* Get Z Depths, needed for perspective, nice for ortho */ ED_view3d_draw_depth(&eval_ctx, CTX_data_depsgraph(C), ar, v3d, true); - + { /* avoid allocating the whole depth buffer */ ViewDepths depth_temp = {0}; /* avoid view3d_update_depths() for speed. */ view3d_update_depths_rect(ar, &depth_temp, &rect); - + /* find the closest Z pixel */ depth_close = view3d_depth_near(&depth_temp); - + MEM_SAFE_FREE(depth_temp.depths); } - float centx = (((float)rect.xmin) + ((float)rect.xmax)) / 2; - float centy = (((float)rect.ymin) + ((float)rect.ymax)) / 2; + cent[0] = (((float)rect.xmin) + ((float)rect.xmax)) / 2; + cent[1] = (((float)rect.ymin) + ((float)rect.ymax)) / 2; if (rv3d->is_persp) { float p_corner[3]; @@ -3281,7 +3416,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } /* convert border to 3d coordinates */ - if ((!ED_view3d_unproject(ar, centx, centy, depth_close, p)) || + if ((!ED_view3d_unproject(ar, cent[0], cent[1], depth_close, p)) || (!ED_view3d_unproject(ar, rect.xmin, rect.ymin, depth_close, p_corner))) { return OPERATOR_CANCELLED; @@ -3303,7 +3438,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) new_dist = rv3d->dist; /* convert the drawn rectangle into 3d space */ - if (depth_close != FLT_MAX && ED_view3d_unproject(ar, centx, centy, depth_close, p)) { + if (depth_close != FLT_MAX && ED_view3d_unproject(ar, cent[0], cent[1], depth_close, p)) { negate_v3_v3(new_ofs, p); } else { @@ -3382,7 +3517,7 @@ void VIEW3D_OT_zoom_border(wmOperatorType *ot) /* flags */ ot->flag = 0; - /* rna */ + /* properties */ WM_operator_properties_gesture_border_zoom(ot); } @@ -3399,7 +3534,7 @@ static void view3d_set_1_to_1_viewborder(Scene *scene, const Depsgraph *depsgrap RegionView3D *rv3d = ar->regiondata; float size[2]; int im_width = (scene->r.size * scene->r.xsch) / 100; - + ED_view3d_calc_camera_border_size(scene, depsgraph, ar, v3d, rv3d, size); rv3d->camzoom = BKE_screen_view3d_zoom_from_fac((float)im_width / size[0]); @@ -3642,7 +3777,6 @@ static int viewnumpad_exec(bContext *C, wmOperator *op) &(const V3D_SmoothParams) { .camera = v3d->camera, .ofs = rv3d->ofs, .quat = rv3d->viewquat, .dist = &rv3d->dist, .lens = &v3d->lens}); - } else { /* return to settings of last view */ @@ -3687,6 +3821,8 @@ void VIEW3D_OT_viewnumpad(wmOperatorType *ot) /* -------------------------------------------------------------------- */ /** \name View Orbit Operator + * + * Rotate (orbit) in incremental steps. For interactive orbit see #VIEW3D_OT_rotate. * \{ */ static const EnumPropertyItem prop_view_orbit_items[] = { @@ -3803,7 +3939,7 @@ void VIEW3D_OT_view_orbit(wmOperatorType *ot) /* flags */ ot->flag = 0; - + /* properties */ prop = RNA_def_float(ot->srna, "angle", 0, -FLT_MAX, FLT_MAX, "Roll", "", -FLT_MAX, FLT_MAX); RNA_def_property_flag(prop, PROP_SKIP_SAVE); @@ -3842,15 +3978,15 @@ static void viewroll_apply(ViewOpsData *vod, int x, int UNUSED(y)) tot = vod->ar->winrct.xmax - vod->ar->winrct.xmin; len1 = (vod->ar->winrct.xmax - x) / tot; - len2 = (vod->ar->winrct.xmax - vod->origx) / tot; + len2 = (vod->ar->winrct.xmax - vod->init.event_xy[0]) / tot; angle = (len1 - len2) * (float)M_PI * 4.0f; } if (angle != 0.0f) - view_roll_angle(vod->ar, vod->rv3d->viewquat, vod->oldquat, vod->mousevec, angle); + view_roll_angle(vod->ar, vod->rv3d->viewquat, vod->init.quat, vod->init.mousevec, angle); if (vod->use_dyn_ofs) { - view3d_orbit_apply_dyn_ofs(vod->rv3d->ofs, vod->ofs, vod->oldquat, vod->rv3d->viewquat, vod->dyn_ofs); + view3d_orbit_apply_dyn_ofs(vod->rv3d->ofs, vod->init.ofs, vod->init.quat, vod->rv3d->viewquat, vod->dyn_ofs); } if (vod->rv3d->viewlock & RV3D_BOXVIEW) { @@ -3888,7 +4024,7 @@ static int viewroll_modal(bContext *C, wmOperator *op, const wmEvent *event) break; } } - else if (event->type == vod->origkey && event->val == KM_RELEASE) { + else if (event->type == vod->init.event_type && event->val == KM_RELEASE) { event_code = VIEW_CONFIRM; } @@ -3992,17 +4128,17 @@ static int viewroll_invoke(bContext *C, wmOperator *op, const wmEvent *event) else { /* makes op->customdata */ viewops_data_alloc(C, op); - viewops_data_create(C, op, event, false); + viewops_data_create(C, op, event, viewops_flag_from_prefs()); vod = op->customdata; ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar); /* overwrite the mouse vector with the view direction */ - normalize_v3_v3(vod->mousevec, vod->rv3d->viewinv[2]); - negate_v3(vod->mousevec); + normalize_v3_v3(vod->init.mousevec, vod->rv3d->viewinv[2]); + negate_v3(vod->init.mousevec); if (event->type == MOUSEROTATE) { - vod->origx = vod->oldx = event->x; + vod->init.event_xy[0] = vod->prev.event_xy[0] = event->x; viewroll_apply(vod, event->prevx, event->prevy); ED_view3d_depth_tag_update(vod->rv3d); @@ -4063,7 +4199,7 @@ static const EnumPropertyItem prop_view_pan_items[] = { /* -------------------------------------------------------------------- */ /** \name View Pan Operator * - * Move (pan) in incremental steps. + * Move (pan) in incremental steps. For interactive pan see #VIEW3D_OT_move. * \{ */ static int viewpan_invoke(bContext *C, wmOperator *op, const wmEvent *event) @@ -4077,10 +4213,10 @@ static int viewpan_invoke(bContext *C, wmOperator *op, const wmEvent *event) else if (pandir == V3D_VIEW_PANDOWN) { y = 25; } viewops_data_alloc(C, op); - viewops_data_create(C, op, event, false); + viewops_data_create(C, op, event, viewops_flag_from_prefs()); ViewOpsData *vod = op->customdata; - viewmove_apply(vod, vod->oldx + x, vod->oldy + y); + viewmove_apply(vod, vod->prev.event_xy[0] + x, vod->prev.event_xy[1] + y); ED_view3d_depth_tag_update(vod->rv3d); viewops_data_free(C, op); @@ -4101,7 +4237,7 @@ void VIEW3D_OT_view_pan(wmOperatorType *ot) /* flags */ ot->flag = 0; - + /* Properties */ ot->prop = RNA_def_enum(ot->srna, "type", prop_view_pan_items, 0, "Pan", "Direction of View Pan"); } @@ -4130,7 +4266,6 @@ static int viewpersportho_exec(bContext *C, wmOperator *UNUSED(op)) } return OPERATOR_FINISHED; - } void VIEW3D_OT_view_persportho(wmOperatorType *ot) @@ -4210,7 +4345,7 @@ static int background_image_add_invoke(bContext *C, wmOperator *op, const wmEven Camera *cam = CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data; Image *ima; CameraBGImage *bgpic; - + ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM); /* may be NULL, continue anyway */ @@ -4240,7 +4375,7 @@ void VIEW3D_OT_background_image_add(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_UNDO; - + /* properties */ RNA_def_string(ot->srna, "name", "Image", MAX_ID_NAME - 2, "Name", "Image name to assign"); WM_operator_properties_filesel( @@ -4271,13 +4406,11 @@ static int background_image_remove_exec(bContext *C, wmOperator *op) BKE_camera_background_image_remove(cam, bgpic_rem); WM_event_add_notifier(C, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, cam); - return OPERATOR_FINISHED; } else { return OPERATOR_CANCELLED; } - } void VIEW3D_OT_background_image_remove(wmOperatorType *ot) @@ -4293,7 +4426,7 @@ void VIEW3D_OT_background_image_remove(wmOperatorType *ot) /* flags */ ot->flag = 0; - + /* properties */ RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Background image index to remove", 0, INT_MAX); } @@ -4361,7 +4494,6 @@ static int view3d_clipping_invoke(bContext *C, wmOperator *op, const wmEvent *ev } } -/* toggles */ void VIEW3D_OT_clip_border(wmOperatorType *ot) { @@ -4381,7 +4513,7 @@ void VIEW3D_OT_clip_border(wmOperatorType *ot) /* flags */ ot->flag = 0; - /* rna */ + /* properties */ WM_operator_properties_border(ot); } @@ -4400,14 +4532,14 @@ void ED_view3d_cursor3d_position(bContext *C, float fp[3], const int mval[2]) RegionView3D *rv3d = ar->regiondata; bool flip; bool depth_used = false; - + /* normally the caller should ensure this, * but this is called from areas that aren't already dealing with the viewport */ if (rv3d == NULL) return; ED_view3d_calc_zfac(rv3d, fp, &flip); - + /* reset the depth based on the view offset (we _know_ the offset is infront of us) */ if (flip) { negate_v3_v3(fp, rv3d->ofs); @@ -4415,7 +4547,7 @@ void ED_view3d_cursor3d_position(bContext *C, float fp[3], const int mval[2]) ED_view3d_calc_zfac(rv3d, fp, NULL /* &flip */ ); } - if (U.uiflag & USER_ZBUF_CURSOR) { /* maybe this should be accessed some other way */ + if (U.uiflag & USER_DEPTH_CURSOR) { /* maybe this should be accessed some other way */ EvaluationContext eval_ctx; struct Depsgraph *graph = CTX_data_depsgraph(C); @@ -4496,9 +4628,6 @@ void VIEW3D_OT_cursor3d(wmOperatorType *ot) /* flags */ // ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; - - /* rna later */ - } /** \} */ @@ -4512,14 +4641,14 @@ static int enable_manipulator_invoke(bContext *C, wmOperator *op, const wmEvent View3D *v3d = CTX_wm_view3d(C); v3d->twtype = 0; - + if (RNA_boolean_get(op->ptr, "translate")) v3d->twtype |= V3D_MANIP_TRANSLATE; if (RNA_boolean_get(op->ptr, "rotate")) v3d->twtype |= V3D_MANIP_ROTATE; if (RNA_boolean_get(op->ptr, "scale")) v3d->twtype |= V3D_MANIP_SCALE; - + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); return OPERATOR_FINISHED; @@ -4533,12 +4662,12 @@ void VIEW3D_OT_enable_manipulator(wmOperatorType *ot) ot->name = "Enable 3D Manipulator"; ot->description = "Enable the transform manipulator for use"; ot->idname = "VIEW3D_OT_enable_manipulator"; - + /* api callbacks */ ot->invoke = enable_manipulator_invoke; ot->poll = ED_operator_view3d_active; - - /* rna later */ + + /* properties */ prop = RNA_def_boolean(ot->srna, "translate", 0, "Translate", "Enable the translate manipulator"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); prop = RNA_def_boolean(ot->srna, "rotate", 0, "Rotate", "Enable the rotate manipulator"); @@ -4563,7 +4692,7 @@ static int toggle_render_exec(bContext *C, wmOperator *UNUSED(op)) v3d->prev_drawtype = v3d->drawtype; v3d->drawtype = OB_RENDER; } - ED_view3d_shade_update(CTX_data_main(C), CTX_data_scene(C), v3d, CTX_wm_area(C)); + ED_view3d_shade_update(CTX_data_main(C), v3d, CTX_wm_area(C)); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index a1dc2a21477..3ed6c87b750 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -55,7 +55,7 @@ #include "WM_types.h" #include "ED_mesh.h" -#include "ED_util.h" +#include "ED_undo.h" #include "ED_screen.h" #include "UI_interface.h" @@ -95,14 +95,14 @@ static void handle_view3d_lock(bContext *C) * - uiTemplateLayers in interface/ code for buttons * - ED_view3d_view_layer_set for RNA */ -static void view3d_layers_editmode_ensure(Scene *scene, View3D *v3d) +static void view3d_layers_editmode_ensure(View3D *v3d, Object *obedit) { /* sanity check - when in editmode disallow switching the editmode layer off since its confusing * an alternative would be to always draw the editmode object. */ - if (scene->obedit && (scene->obedit->lay & v3d->lay) == 0) { + if (obedit && (obedit->lay & v3d->lay) == 0) { int bit; for (bit = 0; bit < 32; bit++) { - if (scene->obedit->lay & (1u << bit)) { + if (obedit->lay & (1u << bit)) { v3d->lay |= (1u << bit); break; } @@ -112,9 +112,9 @@ static void view3d_layers_editmode_ensure(Scene *scene, View3D *v3d) static int view3d_layers_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); ScrArea *sa = CTX_wm_area(C); View3D *v3d = sa->spacedata.first; + Object *obedit = CTX_data_edit_object(C); int nr = RNA_int_get(op->ptr, "nr"); const bool toggle = RNA_boolean_get(op->ptr, "toggle"); @@ -130,7 +130,7 @@ static int view3d_layers_exec(bContext *C, wmOperator *op) /* return to active layer only */ v3d->lay = v3d->lay_prev; - view3d_layers_editmode_ensure(scene, v3d); + view3d_layers_editmode_ensure(v3d, obedit); } else { v3d->lay_prev = v3d->lay; @@ -151,7 +151,7 @@ static int view3d_layers_exec(bContext *C, wmOperator *op) v3d->lay = (1 << nr); } - view3d_layers_editmode_ensure(scene, v3d); + view3d_layers_editmode_ensure(v3d, obedit); /* set active layer, ensure to always have one */ if (v3d->lay & (1 << nr)) @@ -288,8 +288,10 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C) bGPdata *gpd = CTX_data_gpencil_data(C); uiBlock *block; uiLayout *row; - bool is_paint = ob && !(gpd && (gpd->flag & GP_DATA_STROKE_EDITMODE)) && - ELEM(ob->mode, OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT, OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT); + bool is_paint = ( + ob && !(gpd && (gpd->flag & GP_DATA_STROKE_EDITMODE)) && + ELEM(ob->mode, + OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT, OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT)); RNA_pointer_create(&screen->id, &RNA_SpaceView3D, v3d, &v3dptr); RNA_pointer_create(&scene->id, &RNA_ToolSettings, ts, &toolsptr); diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index 5e34bc188f0..0f56f1265bc 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -160,7 +160,7 @@ bool draw_glsl_material(Scene *scene, struct ViewLayer *view_layer, struct Objec void draw_object_instance(const struct EvaluationContext *eval_ctx, Scene *scene, struct ViewLayer *view_layer, View3D *v3d, RegionView3D *rv3d, struct Object *ob, const char dt, int outline, const float wire_col[4]); void draw_object_backbufsel(const struct EvaluationContext *eval_ctx, Scene *scene, View3D *v3d, RegionView3D *rv3d, struct Object *ob); -void draw_object_wire_color(Scene *scene, struct ViewLayer *, Base *base, unsigned char r_ob_wire_col[4]); +void draw_object_wire_color(struct ViewLayer *, Base *base, unsigned char r_ob_wire_col[4]); void drawaxes(const float viewmat_local[4][4], float size, char drawtype, const unsigned char color[4]); void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, const char dt, const short dflag, const unsigned char ob_wire_col[4], @@ -368,8 +368,8 @@ extern bool view3d_camera_border_hack_test; /* temporary for legacy viewport to work */ void VP_legacy_drawcursor(Scene *scene, struct ViewLayer *view_layer, ARegion *ar, View3D *v3d); -void VP_legacy_draw_view_axis(RegionView3D *rv3d, rcti *rect); -void VP_legacy_draw_viewport_name(ARegion *ar, View3D *v3d, rcti *rect); +void VP_legacy_draw_view_axis(RegionView3D *rv3d, const rcti *rect); +void VP_legacy_draw_viewport_name(ARegion *ar, View3D *v3d, const rcti *rect); void VP_legacy_draw_selected_name(Scene *scene, struct Object *ob, rcti *rect); void VP_legacy_drawgrid(UnitSettings *unit, ARegion *ar, View3D *v3d, const char **grid_unit); void VP_legacy_drawfloor(Scene *scene, View3D *v3d, const char **grid_unit, bool write_depth); @@ -377,7 +377,7 @@ void VP_legacy_view3d_main_region_setup_view(const struct EvaluationContext *eva bool VP_legacy_view3d_stereo3d_active(struct wmWindow *win, Scene *scene, View3D *v3d, RegionView3D *rv3d); void VP_legacy_view3d_stereo3d_setup(const struct EvaluationContext *eval_ctx, Scene *scene, View3D *v3d, ARegion *ar); void draw_dupli_objects(const struct EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, ARegion *ar, View3D *v3d, Base *base); -bool VP_legacy_use_depth(Scene *scene, View3D *v3d); +bool VP_legacy_use_depth(View3D *v3d, struct Object *obedit); void VP_drawviewborder(Scene *scene, const struct Depsgraph *depsgraph, ARegion *ar, View3D *v3d); void VP_drawrenderborder(ARegion *ar, View3D *v3d); void VP_view3d_draw_background_none(void); @@ -391,6 +391,6 @@ void VP_deprecated_view3d_draw_objects( const struct EvaluationContext *eval_ctx, Scene *scene, View3D *v3d, ARegion *ar, const char **grid_unit, - const bool do_bgpic, const bool draw_offscreen, struct GPUFX *fx); + const bool do_bgpic, const bool draw_offscreen); #endif /* __VIEW3D_INTERN_H__ */ diff --git a/source/blender/editors/space_view3d/view3d_manipulator_camera.c b/source/blender/editors/space_view3d/view3d_manipulator_camera.c index 6a45ec5095f..3c826c69f3c 100644 --- a/source/blender/editors/space_view3d/view3d_manipulator_camera.c +++ b/source/blender/editors/space_view3d/view3d_manipulator_camera.c @@ -64,8 +64,14 @@ struct CameraWidgetGroup { static bool WIDGETGROUP_camera_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt)) { Object *ob = CTX_data_active_object(C); - - return (ob && ob->type == OB_CAMERA); + if (ob && ob->type == OB_CAMERA) { + Camera *camera = ob->data; + /* TODO: support overrides. */ + if (camera->id.lib == NULL) { + return true; + } + } + return false; } static void WIDGETGROUP_camera_setup(const bContext *C, wmManipulatorGroup *mgroup) @@ -332,10 +338,7 @@ static void manipulator_render_border_prop_matrix_set( static bool WIDGETGROUP_camera_view_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt)) { - ARegion *ar = CTX_wm_region(C); - RegionView3D *rv3d = ar->regiondata; Scene *scene = CTX_data_scene(C); - View3D *v3d = CTX_wm_view3d(C); /* This is just so the border isn't always in the way, * stealing mouse clicks from regular usage. @@ -347,9 +350,15 @@ static bool WIDGETGROUP_camera_view_poll(const bContext *C, wmManipulatorGroupTy } } + ARegion *ar = CTX_wm_region(C); + RegionView3D *rv3d = ar->regiondata; + View3D *v3d = CTX_wm_view3d(C); if (rv3d->persp == RV3D_CAMOB) { if (scene->r.mode & R_BORDER) { - return true; + /* TODO: support overrides. */ + if (scene->id.lib == NULL) { + return true; + } } } else if (v3d->flag2 & V3D_RENDER_BORDER) { diff --git a/source/blender/editors/space_view3d/view3d_manipulator_forcefield.c b/source/blender/editors/space_view3d/view3d_manipulator_forcefield.c index 6a34f493caf..e76be448be4 100644 --- a/source/blender/editors/space_view3d/view3d_manipulator_forcefield.c +++ b/source/blender/editors/space_view3d/view3d_manipulator_forcefield.c @@ -31,7 +31,7 @@ #include "BKE_object.h" #include "DNA_object_types.h" -#include "DNA_object_force.h" +#include "DNA_object_force_types.h" #include "ED_screen.h" #include "ED_manipulator_library.h" diff --git a/source/blender/editors/space_view3d/view3d_manipulator_navigate.c b/source/blender/editors/space_view3d/view3d_manipulator_navigate.c index 9f655fff8a1..6a5d63b180f 100644 --- a/source/blender/editors/space_view3d/view3d_manipulator_navigate.c +++ b/source/blender/editors/space_view3d/view3d_manipulator_navigate.c @@ -231,6 +231,16 @@ static void WIDGETGROUP_navigate_setup(const bContext *UNUSED(C), wmManipulatorG } } + /* Modal operators, don't use initial mouse location since we're clicking on a button. */ + { + int mpr_ids[] = {MPR_MOVE, MPR_ROTATE, MPR_ZOOM}; + for (int i = 0; i < ARRAY_SIZE(mpr_ids); i++) { + wmManipulator *mpr = navgroup->mpr_array[mpr_ids[i]]; + wmManipulatorOpElem *mpop = WM_manipulator_operator_get(mpr, 0); + RNA_boolean_set(&mpop->ptr, "use_mouse_init", false); + } + } + { wmManipulator *mpr = navgroup->mpr_array[MPR_ROTATE]; mpr->scale_basis = MANIPULATOR_SIZE / 2; diff --git a/source/blender/editors/space_view3d/view3d_manipulator_navigate_type.c b/source/blender/editors/space_view3d/view3d_manipulator_navigate_type.c index 424b5dae402..c3f8d92ed7f 100644 --- a/source/blender/editors/space_view3d/view3d_manipulator_navigate_type.c +++ b/source/blender/editors/space_view3d/view3d_manipulator_navigate_type.c @@ -131,7 +131,7 @@ static void axis_geom_draw( glDepthMask(GL_TRUE); glDepthFunc(GL_LEQUAL); glBlendFunc(GL_ONE, GL_ZERO); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); diff --git a/source/blender/editors/space_view3d/view3d_manipulator_ruler.c b/source/blender/editors/space_view3d/view3d_manipulator_ruler.c index e8d540bcc9d..f9955f29774 100644 --- a/source/blender/editors/space_view3d/view3d_manipulator_ruler.c +++ b/source/blender/editors/space_view3d/view3d_manipulator_ruler.c @@ -277,7 +277,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_type(C), 0, + CTX_data_main(C), CTX_data_scene(C), CTX_data_view_layer(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 79fa9e14dc1..8e6f5228b09 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -82,7 +82,7 @@ static int view3d_copybuffer_exec(bContext *C, wmOperator *op) CTX_DATA_END; for (Group *group = bmain->group.first; group; group = group->id.next) { - FOREACH_GROUP_OBJECT(group, object) + FOREACH_GROUP_OBJECT_BEGIN(group, object) { if (object && (object->id.tag & LIB_TAG_DOIT)) { BKE_copybuffer_tag_ID(&group->id); @@ -91,7 +91,7 @@ static int view3d_copybuffer_exec(bContext *C, wmOperator *op) break; } } - FOREACH_GROUP_OBJECT_END + 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 093425fc3bc..f61aad2806e 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_type(C), 0, + CTX_data_main(C), CTX_data_scene(C), CTX_data_view_layer(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 f51aad34c29..21219bced3c 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -49,7 +49,7 @@ #include "MEM_guardedalloc.h" #include "BLI_math.h" -#include "BLI_lasso.h" +#include "BLI_lasso_2d.h" #include "BLI_rect.h" #include "BLI_linklist.h" #include "BLI_listbase.h" @@ -85,6 +85,7 @@ #include "ED_armature.h" #include "ED_curve.h" +#include "ED_lattice.h" #include "ED_particle.h" #include "ED_mesh.h" #include "ED_object.h" @@ -109,7 +110,7 @@ float ED_view3d_select_dist_px(void) } /* TODO: should return whether there is valid context to continue */ -void view3d_set_viewcontext(bContext *C, ViewContext *vc) +void ED_view3d_viewcontext_init(bContext *C, ViewContext *vc) { memset(vc, 0, sizeof(ViewContext)); vc->ar = CTX_wm_region(C); @@ -226,9 +227,10 @@ typedef struct LassoSelectUserData { bool is_changed; } LassoSelectUserData; -static void view3d_userdata_lassoselect_init(LassoSelectUserData *r_data, - ViewContext *vc, const rcti *rect, const int (*mcords)[2], - const int moves, const bool select) +static void view3d_userdata_lassoselect_init( + LassoSelectUserData *r_data, + ViewContext *vc, const rcti *rect, const int (*mcords)[2], + const int moves, const bool select) { r_data->vc = vc; @@ -303,7 +305,8 @@ static bool edge_inside_rect(const rctf *rect, const float v1[2], const float v2 return 1; } -static void do_lasso_select_pose__doSelectBone(void *userData, struct bPoseChannel *pchan, const float screen_co_a[2], const float screen_co_b[2]) +static void do_lasso_select_pose__doSelectBone( + void *userData, struct bPoseChannel *pchan, const float screen_co_a[2], const float screen_co_b[2]) { LassoSelectUserData *data = userData; bArmature *arm = data->vc->obact->data; @@ -390,8 +393,9 @@ static void object_deselect_all_visible(ViewLayer *view_layer) } } -static void do_lasso_select_objects(ViewContext *vc, const int mcords[][2], const short moves, - const bool extend, const bool select) +static void do_lasso_select_objects( + ViewContext *vc, const int mcords[][2], const short moves, + const bool extend, const bool select) { Base *base; @@ -423,7 +427,8 @@ static void do_lasso_select_mesh__doSelectVert(void *userData, BMVert *eve, cons BM_vert_select_set(data->vc->em->bm, eve, data->select); } } -static void do_lasso_select_mesh__doSelectEdge(void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index) +static void do_lasso_select_mesh__doSelectEdge( + void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index) { LassoSelectUserData *data = userData; @@ -846,9 +851,10 @@ static void do_lasso_select_node(int mcords[][2], short moves, const bool select } #endif -static void view3d_lasso_select(bContext *C, ViewContext *vc, - const int mcords[][2], short moves, - bool extend, bool select) +static void view3d_lasso_select( + bContext *C, ViewContext *vc, + const int mcords[][2], short moves, + bool extend, bool select) { Object *ob = CTX_data_active_object(C); @@ -917,7 +923,7 @@ static int view3d_lasso_select_exec(bContext *C, wmOperator *op) view3d_operator_needs_opengl(C); /* setup view context for argument to callbacks */ - view3d_set_viewcontext(C, &vc); + ED_view3d_viewcontext_init(C, &vc); extend = RNA_boolean_get(op->ptr, "extend"); select = !RNA_boolean_get(op->ptr, "deselect"); @@ -949,61 +955,8 @@ void VIEW3D_OT_select_lasso(wmOperatorType *ot) WM_operator_properties_gesture_lasso_select(ot); } - -/* ************************************************* */ - -#if 0 -/* smart function to sample a rect spiralling outside, nice for backbuf selection */ -static unsigned int samplerect(unsigned int *buf, int size, unsigned int dontdo) -{ - Base *base; - unsigned int *bufmin, *bufmax; - int a, b, rc, tel, len, dirvec[4][2], maxob; - unsigned int retval = 0; - - base = LASTBASE; - if (base == 0) return 0; - maxob = base->object->select_color; - - len = (size - 1) / 2; - rc = 0; - - dirvec[0][0] = 1; - dirvec[0][1] = 0; - dirvec[1][0] = 0; - dirvec[1][1] = -size; - dirvec[2][0] = -1; - dirvec[2][1] = 0; - dirvec[3][0] = 0; - dirvec[3][1] = size; - - bufmin = buf; - bufmax = buf + size * size; - buf += len * size + len; - - for (tel = 1; tel <= size; tel++) { - - for (a = 0; a < 2; a++) { - for (b = 0; b < tel; b++) { - - if (*buf && *buf <= maxob && *buf != dontdo) return *buf; - if (*buf == dontdo) retval = dontdo; /* if only color dontdo is available, still return dontdo */ - - buf += (dirvec[rc][0] + dirvec[rc][1]); - - if (buf < bufmin || buf >= bufmax) return retval; - } - rc++; - rc &= 3; - } - } - return retval; -} -#endif - /* ************************** mouse select ************************* */ - /* The max number of menu items in an object select menu */ typedef struct SelMenuItemF { char idname[MAX_ID_NAME - 2]; @@ -1014,7 +967,8 @@ typedef struct SelMenuItemF { static SelMenuItemF object_mouse_select_menu_data[SEL_MENU_SIZE]; /* special (crappy) operator only for menu select */ -static const EnumPropertyItem *object_select_menu_enum_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) +static const EnumPropertyItem *object_select_menu_enum_itemf( + bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) { EnumPropertyItem *item = NULL, item_tmp = {0}; int totitem = 0; @@ -1199,7 +1153,7 @@ static Base *object_mouse_select_menu( } } -static bool selectbuffer_has_bones(const unsigned int *buffer, const unsigned int hits) +static bool selectbuffer_has_bones(const uint *buffer, const uint hits) { unsigned int i; for (i = 0; i < hits; i++) { @@ -1320,8 +1274,9 @@ finally: } /* returns basact */ -static Base *mouse_select_eval_buffer(ViewContext *vc, unsigned int *buffer, int hits, - Base *startbase, bool has_bones, bool do_nearest) +static Base *mouse_select_eval_buffer( + ViewContext *vc, const uint *buffer, int hits, + Base *startbase, bool has_bones, bool do_nearest) { ViewLayer *view_layer = vc->view_layer; Base *base, *basact = NULL; @@ -1417,7 +1372,7 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2]) view3d_operator_needs_opengl(C); CTX_data_eval_ctx(C, &eval_ctx); - view3d_set_viewcontext(C, &vc); + ED_view3d_viewcontext_init(C, &vc); hits = mixed_bones_object_selectbuffer(&eval_ctx, &vc, buffer, mval, false, false, &do_nearest); @@ -1468,7 +1423,7 @@ static bool ed_object_select_pick( /* setup view context for argument to callbacks */ CTX_data_eval_ctx(C, &eval_ctx); - view3d_set_viewcontext(C, &vc); + ED_view3d_viewcontext_init(C, &vc); is_obedit = (vc.obedit != NULL); if (object) { @@ -1493,8 +1448,9 @@ static bool ed_object_select_pick( while (base) { if (BASE_SELECTABLE(base)) { float screen_co[2]; - if (ED_view3d_project_float_global(ar, base->object->obmat[3], screen_co, - V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) + if (ED_view3d_project_float_global( + ar, base->object->obmat[3], screen_co, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) { float dist_temp = len_manhattan_v2v2(mval_fl, screen_co); if (base == BASACT(view_layer)) dist_temp += 10.0f; @@ -1593,7 +1549,7 @@ static bool ed_object_select_pick( } } } - else if (ED_do_pose_selectbuffer(scene, view_layer, basact, buffer, hits, extend, deselect, toggle, do_nearest)) { + else if (ED_do_pose_selectbuffer(view_layer, basact, buffer, hits, extend, deselect, toggle, do_nearest)) { /* then bone is found */ /* we make the armature selected: @@ -1680,8 +1636,9 @@ typedef struct BoxSelectUserData { bool is_changed; } BoxSelectUserData; -static void view3d_userdata_boxselect_init(BoxSelectUserData *r_data, - ViewContext *vc, const rcti *rect, const bool select) +static void view3d_userdata_boxselect_init( + BoxSelectUserData *r_data, + ViewContext *vc, const rcti *rect, const bool select) { r_data->vc = vc; @@ -1795,7 +1752,8 @@ static int do_paintvert_box_select( return OPERATOR_FINISHED; } -static void do_nurbs_box_select__doSelect(void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2]) +static void do_nurbs_box_select__doSelect( + void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2]) { BoxSelectUserData *data = userData; Object *obedit = data->vc->obedit; @@ -1914,7 +1872,8 @@ static void do_mesh_box_select__doSelectVert(void *userData, BMVert *eve, const BM_vert_select_set(data->vc->em->bm, eve, data->select); } } -static void do_mesh_box_select__doSelectEdge(void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index) +static void do_mesh_box_select__doSelectEdge( + void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index) { BoxSelectUserData *data = userData; @@ -2131,8 +2090,8 @@ static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, b EvaluationContext eval_ctx; Bone *bone; Object *ob = vc->obact; - unsigned int *vbuffer = NULL; /* selection buffer */ - unsigned int *col; /* color in buffer */ + unsigned int *vbuffer = NULL; /* selection buffer */ + unsigned int *col; /* color in buffer */ int bone_only; int bone_selected = 0; int totobj = MAXPICKBUF; /* XXX solve later */ @@ -2180,7 +2139,7 @@ static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, b qsort(vbuffer, hits, sizeof(uint[4]), opengl_select_buffer_cmp); /* - * Even though 'DRW_draw_select_loop' uses 'DEG_OBJECT_ITER', + * Even though 'DRW_draw_select_loop' uses 'DEG_OBJECT_ITER_BEGIN', * we can be sure the order remains the same between both. */ for (base = vc->view_layer->object_bases.first; base && hits; base = base->next) { @@ -2248,7 +2207,7 @@ static int view3d_borderselect_exec(bContext *C, wmOperator *op) /* setup view context for argument to callbacks */ CTX_data_eval_ctx(C, &eval_ctx); - view3d_set_viewcontext(C, &vc); + ED_view3d_viewcontext_init(C, &vc); select = !RNA_boolean_get(op->ptr, "deselect"); extend = RNA_boolean_get(op->ptr, "extend"); @@ -2513,8 +2472,9 @@ typedef struct CircleSelectUserData { bool is_changed; } CircleSelectUserData; -static void view3d_userdata_circleselect_init(CircleSelectUserData *r_data, - ViewContext *vc, const bool select, const int mval[2], const float rad) +static void view3d_userdata_circleselect_init( + CircleSelectUserData *r_data, + ViewContext *vc, const bool select, const int mval[2], const float rad) { r_data->vc = vc; r_data->select = select; @@ -2537,7 +2497,8 @@ static void mesh_circle_doSelectVert(void *userData, BMVert *eve, const float sc BM_vert_select_set(data->vc->em->bm, eve, data->select); } } -static void mesh_circle_doSelectEdge(void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int UNUSED(index)) +static void mesh_circle_doSelectEdge( + void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int UNUSED(index)) { CircleSelectUserData *data = userData; @@ -2655,7 +2616,8 @@ static void paint_vertsel_circle_select(const struct EvaluationContext *eval_ctx } -static void nurbscurve_circle_doSelect(void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2]) +static void nurbscurve_circle_doSelect( + void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2]) { CircleSelectUserData *data = userData; Object *obedit = data->vc->obedit; @@ -2766,7 +2728,8 @@ static bool pchan_circle_doSelectJoint(void *userData, bPoseChannel *pchan, cons } return 0; } -static void do_circle_select_pose__doSelectBone(void *userData, struct bPoseChannel *pchan, const float screen_co_a[2], const float screen_co_b[2]) +static void do_circle_select_pose__doSelectBone( + void *userData, struct bPoseChannel *pchan, const float screen_co_a[2], const float screen_co_b[2]) { CircleSelectUserData *data = userData; bArmature *arm = data->vc->obact->data; @@ -2852,7 +2815,8 @@ static bool armature_circle_doSelectJoint(void *userData, EditBone *ebone, const } return 0; } -static void do_circle_select_armature__doSelectBone(void *userData, struct EditBone *ebone, const float screen_co_a[2], const float screen_co_b[2]) +static void do_circle_select_armature__doSelectBone( + void *userData, struct EditBone *ebone, const float screen_co_a[2], const float screen_co_b[2]) { CircleSelectUserData *data = userData; bArmature *arm = data->vc->obedit->data; @@ -2977,8 +2941,9 @@ static bool object_circle_select(ViewContext *vc, const bool select, const int m for (base = FIRSTBASE(view_layer); base; base = base->next) { if (BASE_SELECTABLE(base) && ((base->flag & BASE_SELECTED) != select_flag)) { float screen_co[2]; - if (ED_view3d_project_float_global(vc->ar, base->object->obmat[3], screen_co, - V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) + if (ED_view3d_project_float_global( + vc->ar, base->object->obmat[3], screen_co, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) { if (len_squared_v2v2(mval_fl, screen_co) <= radius_squared) { ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT); @@ -3010,7 +2975,7 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op) view3d_operator_needs_opengl(C); CTX_data_eval_ctx(C, &eval_ctx); - view3d_set_viewcontext(C, &vc); + ED_view3d_viewcontext_init(C, &vc); if (CTX_data_edit_object(C)) { obedit_circle_select(&eval_ctx, &vc, select, mval, (float)radius); @@ -3034,7 +2999,7 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op) } else { ViewContext vc; - view3d_set_viewcontext(C, &vc); + ED_view3d_viewcontext_init(C, &vc); if (object_circle_select(&vc, select, mval, (float)radius)) { WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); diff --git a/source/blender/editors/space_view3d/view3d_toolbar.c b/source/blender/editors/space_view3d/view3d_toolbar.c index 5e3c783c1b6..dfa64bd2015 100644 --- a/source/blender/editors/space_view3d/view3d_toolbar.c +++ b/source/blender/editors/space_view3d/view3d_toolbar.c @@ -55,7 +55,7 @@ #include "RNA_access.h" #include "ED_screen.h" -#include "ED_util.h" +#include "ED_undo.h" #include "UI_interface.h" #include "UI_resources.h" diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c index 7bb3f443ac6..92b3ec19acb 100644 --- a/source/blender/editors/space_view3d/view3d_utils.c +++ b/source/blender/editors/space_view3d/view3d_utils.c @@ -161,7 +161,7 @@ void view3d_operator_needs_opengl(const bContext *C) view3d_region_operator_needs_opengl(win, ar); } -void view3d_region_operator_needs_opengl(wmWindow *win, ARegion *ar) +void view3d_region_operator_needs_opengl(wmWindow *UNUSED(win), ARegion *ar) { /* for debugging purpose, context should always be OK */ if ((ar == NULL) || (ar->regiontype != RGN_TYPE_WINDOW)) { @@ -170,7 +170,7 @@ void view3d_region_operator_needs_opengl(wmWindow *win, ARegion *ar) else { RegionView3D *rv3d = ar->regiondata; - wmSubWindowSet(win, ar->swinid); + wmViewport(&ar->winrct); // TODO: bad gpuLoadProjectionMatrix(rv3d->winmat); gpuLoadMatrix(rv3d->viewmat); } diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 0597f2806b3..1a547d07b80 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -861,6 +861,45 @@ void view3d_opengl_select_cache_end(void) GPU_select_cache_end(); } +#ifndef WITH_OPENGL_LEGACY +struct DrawSelectLoopUserData { + uint pass; + uint hits; + uint *buffer; + uint buffer_len; + const rcti *rect; + char gpu_select_mode; +}; + +static bool drw_select_loop_pass(eDRWSelectStage stage, void *user_data) +{ + bool continue_pass = false; + struct DrawSelectLoopUserData *data = user_data; + if (stage == DRW_SELECT_PASS_PRE) { + GPU_select_begin(data->buffer, data->buffer_len, data->rect, data->gpu_select_mode, data->hits); + /* always run POST after PRE. */ + continue_pass = true; + } + else if (stage == DRW_SELECT_PASS_POST) { + int hits = GPU_select_end(); + if (data->pass == 0) { + /* quirk of GPU_select_end, only take hits value from first call. */ + data->hits = hits; + } + if (data->gpu_select_mode == GPU_SELECT_NEAREST_FIRST_PASS) { + data->gpu_select_mode = GPU_SELECT_NEAREST_SECOND_PASS; + continue_pass = (hits > 0); + } + data->pass += 1; + } + else { + BLI_assert(0); + } + return continue_pass; + +} +#endif /* WITH_OPENGL_LEGACY */ + /** * \warning be sure to account for a negative return value * This is an error, "Too many objects in select buffer" @@ -879,7 +918,7 @@ int view3d_opengl_select( ARegion *ar = vc->ar; rcti rect; int hits; - const bool use_obedit_skip = (scene->obedit != NULL) && (vc->obedit == NULL); + const bool use_obedit_skip = (OBEDIT_FROM_VIEW_LAYER(vc->view_layer) != NULL) && (vc->obedit == NULL); const bool is_pick_select = (U.gpu_select_pick_deph != 0); const bool do_passes = ( (is_pick_select == false) && @@ -931,6 +970,11 @@ int view3d_opengl_select( goto finally; } +#ifndef WITH_OPENGL_LEGACY + /* All of the queries need to be perform on the drawing context. */ + DRW_opengl_context_enable(); +#endif + G.f |= G_PICKSEL; /* Important we use the 'viewmat' and don't re-calculate since @@ -941,43 +985,44 @@ int view3d_opengl_select( v3d->zbuf = true; glEnable(GL_DEPTH_TEST); } - + if (vc->rv3d->rflag & RV3D_CLIPPING) ED_view3d_clipping_set(vc->rv3d); - GPU_select_begin(buffer, bufsize, &rect, gpu_select_mode, 0); #ifdef WITH_OPENGL_LEGACY if (IS_VIEWPORT_LEGACY(vc->v3d)) { + GPU_select_begin(buffer, bufsize, &rect, gpu_select_mode, 0); ED_view3d_draw_select_loop(vc, scene, sl, v3d, ar, use_obedit_skip, use_nearest); + hits = GPU_select_end(); + + if (do_passes && (hits > 0)) { + GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits); + ED_view3d_draw_select_loop(vc, scene, sl, v3d, ar, use_obedit_skip, use_nearest); + GPU_select_end(); + } } else #else { - DRW_draw_select_loop(graph, ar, v3d, use_obedit_skip, use_nearest, &rect); + /* We need to call "GPU_select_*" API's inside DRW_draw_select_loop + * because the OpenGL context created & destroyed inside this function. */ + struct DrawSelectLoopUserData drw_select_loop_user_data = { + .pass = 0, + .hits = 0, + .buffer = buffer, + .buffer_len = bufsize, + .rect = &rect, + .gpu_select_mode = gpu_select_mode, + }; + DRW_draw_select_loop( + graph, ar, v3d, + use_obedit_skip, use_nearest, &rect, + drw_select_loop_pass, &drw_select_loop_user_data); + hits = drw_select_loop_user_data.hits; } #endif /* WITH_OPENGL_LEGACY */ - hits = GPU_select_end(); - - /* second pass, to get the closest object to camera */ - if (do_passes && (hits > 0)) { - GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits); - -#ifdef WITH_OPENGL_LEGACY - if (IS_VIEWPORT_LEGACY(vc->v3d)) { - ED_view3d_draw_select_loop(vc, scene, sl, v3d, ar, use_obedit_skip, use_nearest); - } - else -#else - { - DRW_draw_select_loop(graph, ar, v3d, use_obedit_skip, use_nearest, &rect); - } -#endif /* WITH_OPENGL_LEGACY */ - - GPU_select_end(); - } - G.f &= ~G_PICKSEL; ED_view3d_draw_setup_view(vc->win, eval_ctx, scene, ar, v3d, vc->rv3d->viewmat, NULL, NULL); @@ -989,7 +1034,12 @@ int view3d_opengl_select( if (vc->rv3d->rflag & RV3D_CLIPPING) ED_view3d_clipping_disable(); +#ifndef WITH_OPENGL_LEGACY + DRW_opengl_context_disable(); +#endif + finally: + if (hits < 0) printf("Too many objects in select buffer\n"); /* XXX make error message */ UI_Theme_Restore(&theme_state); @@ -1058,8 +1108,9 @@ static void game_engine_save_state(bContext *C, wmWindow *win) glPushAttrib(GL_ALL_ATTRIB_BITS); - if (obact && obact->mode & OB_MODE_TEXTURE_PAINT) + if (obact && obact->mode & OB_MODE_TEXTURE_PAINT) { GPU_paint_set_mipmap(1); + } queue_back = win->queue; @@ -1070,9 +1121,9 @@ static void game_engine_restore_state(bContext *C, wmWindow *win) { Object *obact = CTX_data_active_object(C); - if (obact && obact->mode & OB_MODE_TEXTURE_PAINT) + if (obact && obact->mode & OB_MODE_TEXTURE_PAINT) { GPU_paint_set_mipmap(0); - + } /* check because closing win can set to NULL */ if (win) { win->queue = queue_back; diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c index e65f9abae27..3bf0e579bb3 100644 --- a/source/blender/editors/space_view3d/view3d_walk.c +++ b/source/blender/editors/space_view3d/view3d_walk.c @@ -58,8 +58,6 @@ #include "GPU_immediate.h" -#include "RE_engine.h" - #include "DEG_depsgraph.h" #include "view3d_intern.h" /* own include */ @@ -254,7 +252,6 @@ typedef struct WalkInfo { const struct Depsgraph *depsgraph; Scene *scene; ViewLayer *view_layer; - RenderEngineType *engine_type; wmTimer *timer; /* needed for redraws */ @@ -522,7 +519,6 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op) walk->depsgraph = CTX_data_depsgraph(C); walk->scene = CTX_data_scene(C); walk->view_layer = CTX_data_view_layer(C); - walk->engine_type = CTX_data_engine_type(C); #ifdef NDOF_WALK_DEBUG puts("\n-- walk begin --"); @@ -611,7 +607,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_type, 0, + CTX_data_main(C), walk->scene, walk->view_layer, 0, walk->ar, walk->v3d); walk->v3d_camera_control = ED_view3d_cameracontrol_acquire( diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 9f7b438e338..3aeb38970d2 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -1707,20 +1707,10 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata) TransInfo *t = (TransInfo *)customdata; if (t->helpline != HLP_NONE) { - float vecrot[3], cent[2]; + float cent[2]; float mval[3] = { x, y, 0.0f }; - copy_v3_v3(vecrot, t->center); - if (t->flag & T_EDIT) { - Object *ob = t->obedit; - if (ob) mul_m4_v3(ob->obmat, vecrot); - } - else if (t->flag & T_POSE) { - Object *ob = t->poseobj; - if (ob) mul_m4_v3(ob->obmat, vecrot); - } - - projectFloatViewEx(t, vecrot, cent, V3D_PROJ_TEST_CLIP_ZERO); + projectFloatViewEx(t, t->center_global, cent, V3D_PROJ_TEST_CLIP_ZERO); gpuPushMatrix(); @@ -1890,7 +1880,7 @@ static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar) #endif /* autokey recording icon... */ - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); xco -= U.widget_unit; @@ -2624,9 +2614,6 @@ static void constraintTransLim(TransInfo *t, TransData *td) if (td->con) { const bConstraintTypeInfo *ctiLoc = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_LOCLIMIT); const bConstraintTypeInfo *ctiDist = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_DISTLIMIT); - EvaluationContext eval_ctx; - - CTX_data_eval_ctx(t->context, &eval_ctx); bConstraintOb cob = {NULL}; bConstraint *con; @@ -2676,7 +2663,7 @@ static void constraintTransLim(TransInfo *t, TransData *td) } /* get constraint targets if needed */ - BKE_constraint_targets_for_solving_get(&eval_ctx, con, &cob, &targets, ctime); + BKE_constraint_targets_for_solving_get(&t->eval_ctx, con, &cob, &targets, ctime); /* do constraint */ cti->evaluate_constraint(con, &cob, &targets); @@ -6883,7 +6870,7 @@ static void drawEdgeSlide(TransInfo *t) glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); gpuPushMatrix(); gpuMultMatrix(t->obedit->obmat); @@ -7495,7 +7482,7 @@ static void drawVertSlide(TransInfo *t) glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); gpuPushMatrix(); gpuMultMatrix(t->obedit->obmat); diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 8dc3bca7d38..40f6b64b055 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -41,6 +41,8 @@ #include "DNA_listBase.h" +#include "DEG_depsgraph.h" + /* ************************** Types ***************************** */ struct Depsgraph; @@ -66,6 +68,8 @@ struct EditBone; struct RenderEngineType; struct SnapObjectContext; +#include "DNA_object_enums.h" + /* transinfo->redraw */ typedef enum { TREDRAW_NOTHING = 0, @@ -465,6 +469,7 @@ typedef struct TransInfo { bool remove_on_cancel; /* remove elements if operator is canceled */ + EvaluationContext eval_ctx; void *view; struct bContext *context; /* Only valid (non null) during an operator called function. */ struct ScrArea *sa; @@ -650,7 +655,8 @@ void restoreBones(TransInfo *t); #define MANIPULATOR_AXIS_LINE_WIDTH 2.0f -bool gimbal_axis(struct Object *ob, float gmat[3][3]); /* return 0 when no gimbal for selection */ +/* return 0 when no gimbal for selection */ +bool gimbal_axis(struct Object *ob, float gmat[3][3]); /*********************** TransData Creation and General Handling *********** */ void createTransData(struct bContext *C, TransInfo *t); diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index 4e409e7f77f..f612dc0e474 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -999,7 +999,7 @@ static void setNearestAxis3d(TransInfo *t) * of two 2D points 30 pixels apart (that's the last factor in the formula) after * projecting them with ED_view3d_win_to_delta and then get the length of that vector. */ - zfac = mul_project_m4_v3_zfac(t->persmat, t->center); + zfac = mul_project_m4_v3_zfac(t->persmat, t->center_global); zfac = len_v3(t->persinv[0]) * 2.0f / t->ar->winx * zfac * 30.0f; for (i = 0; i < 3; i++) { diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 25c1f9eaddc..3a1c60e4a65 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -2124,7 +2124,7 @@ static void createTransParticleVerts(bContext *C, TransInfo *t) TransDataExtension *tx; Object *ob = CTX_data_active_object(C); ParticleEditSettings *pset = PE_settings(t->scene); - PTCacheEdit *edit = PE_get_current(t->scene, t->view_layer, ob); + PTCacheEdit *edit = PE_get_current(t->scene, ob); ParticleSystem *psys = NULL; ParticleSystemModifierData *psmd = NULL; PTCacheEditPoint *point; @@ -2241,7 +2241,7 @@ void flushTransParticles(TransInfo *t) Scene *scene = t->scene; ViewLayer *view_layer = t->view_layer; Object *ob = OBACT(view_layer); - PTCacheEdit *edit = PE_get_current(scene, view_layer, ob); + PTCacheEdit *edit = PE_get_current(scene, ob); ParticleSystem *psys = edit->psys; ParticleSystemModifierData *psmd = NULL; PTCacheEditPoint *point; @@ -2280,9 +2280,7 @@ void flushTransParticles(TransInfo *t) point->flag |= PEP_EDIT_RECALC; } - EvaluationContext eval_ctx; - CTX_data_eval_ctx(t->context, &eval_ctx); - PE_update_object(&eval_ctx, scene, view_layer, OBACT(view_layer), 1); + PE_update_object(&t->eval_ctx, scene, OBACT(view_layer), 1); } /* ********************* mesh ****************** */ @@ -2694,7 +2692,6 @@ static void createTransEditVerts(TransInfo *t) { TransData *tob = NULL; TransDataExtension *tx = NULL; - EvaluationContext eval_ctx; BMEditMesh *em = BKE_editmesh_from_object(t->obedit); Mesh *me = t->obedit->data; BMesh *bm = em->bm; @@ -2713,10 +2710,6 @@ static void createTransEditVerts(TransInfo *t) int island_info_tot; int *island_vert_map = NULL; - DEG_evaluation_context_init_from_scene(&eval_ctx, - t->scene, t->view_layer, t->engine_type, - DAG_EVAL_VIEWPORT); - /* Even for translation this is needed because of island-orientation, see: T51651. */ const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS); /* Original index of our connected vertex when connected distances are calculated. @@ -2800,7 +2793,7 @@ static void createTransEditVerts(TransInfo *t) if (modifiers_isCorrectableDeformed(t->scene, t->obedit)) { /* check if we can use deform matrices for modifier from the * start up to stack, they are more accurate than quats */ - totleft = BKE_crazyspace_get_first_deform_matrices_editbmesh(&eval_ctx, t->scene, t->obedit, em, &defmats, &defcos); + totleft = BKE_crazyspace_get_first_deform_matrices_editbmesh(&t->eval_ctx, t->scene, t->obedit, em, &defmats, &defcos); } /* if we still have more modifiers, also do crazyspace @@ -2813,7 +2806,7 @@ static void createTransEditVerts(TransInfo *t) if (totleft > 0) #endif { - mappedcos = BKE_crazyspace_get_mapped_editverts(&eval_ctx, t->scene, t->obedit); + mappedcos = BKE_crazyspace_get_mapped_editverts(&t->eval_ctx, t->scene, t->obedit); quats = MEM_mallocN(em->bm->totvert * sizeof(*quats), "crazy quats"); BKE_crazyspace_set_quats_editmesh(em, defcos, mappedcos, quats, !prop_mode); if (mappedcos) @@ -3207,7 +3200,7 @@ static void createTransUVs(bContext *C, TransInfo *t) BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { BMLoop *l; - if (!uvedit_face_visible_test(scene, ima, efa)) { + if (!uvedit_face_visible_test(scene, t->obedit, ima, efa)) { BM_elem_flag_disable(efa, BM_ELEM_TAG); continue; } @@ -3735,67 +3728,136 @@ static void posttrans_mask_clean(Mask *mask) } } +/* Time + Average value */ +typedef struct tRetainedKeyframe { + struct tRetainedKeyframe *next, *prev; + float frame; /* frame to cluster around */ + float val; /* average value */ + + size_t tot_count; /* number of keyframes that have been averaged */ + size_t del_count; /* number of keyframes of this sort that have been deleted so far */ +} tRetainedKeyframe; + /* Called during special_aftertrans_update to make sure selected keyframes replace * any other keyframes which may reside on that frame (that is not selected). */ static void posttrans_fcurve_clean(FCurve *fcu, const bool use_handle) { - float *selcache; /* cache for frame numbers of selected frames (fcu->totvert*sizeof(float)) */ - int len, index, i; /* number of frames in cache, item index */ - - /* allocate memory for the cache */ - // TODO: investigate using BezTriple columns instead? - if (fcu->totvert == 0 || fcu->bezt == NULL) + /* NOTE: We assume that all keys are sorted */ + ListBase retained_keys = {NULL, NULL}; + const bool can_average_points = ((fcu->flag & (FCURVE_INT_VALUES | FCURVE_DISCRETE_VALUES)) == 0); + + /* sanity checks */ + if ((fcu->totvert == 0) || (fcu->bezt == NULL)) return; - selcache = MEM_callocN(sizeof(float) * fcu->totvert, "FCurveSelFrameNums"); - len = 0; - index = 0; - - /* We do 2 loops, 1 for marking keyframes for deletion, one for deleting - * as there is no guarantee what order the keyframes are exactly, even though - * they have been sorted by time. + + /* 1) Identify selected keyframes, and average the values on those + * in case there are collisions due to multiple keys getting scaled + * to all end up on the same frame */ - - /* Loop 1: find selected keyframes */ - for (i = 0; i < fcu->totvert; i++) { + for (int i = 0; i < fcu->totvert; i++) { BezTriple *bezt = &fcu->bezt[i]; if (BEZT_ISSEL_ANY(bezt)) { - selcache[index] = bezt->vec[1][0]; - index++; - len++; + bool found = false; + + /* If there's another selected frame here, merge it */ + for (tRetainedKeyframe *rk = retained_keys.last; rk; rk = rk->prev) { + if (IS_EQT(rk->frame, bezt->vec[1][0], BEZT_BINARYSEARCH_THRESH)) { + rk->val += bezt->vec[1][1]; + rk->tot_count++; + + found = true; + break; + } + else if (rk->frame < bezt->vec[1][0]) { + /* Terminate early if have passed the supposed insertion point? */ + break; + } + } + + /* If nothing found yet, create a new one */ + if (found == false) { + tRetainedKeyframe *rk = MEM_callocN(sizeof(tRetainedKeyframe), "tRetainedKeyframe"); + + rk->frame = bezt->vec[1][0]; + rk->val = bezt->vec[1][1]; + rk->tot_count = 1; + + BLI_addtail(&retained_keys, rk); + } } } - - /* Loop 2: delete unselected keyframes on the same frames - * (if any keyframes were found, or the whole curve wasn't affected) + + if (BLI_listbase_is_empty(&retained_keys)) { + /* This may happen if none of the points were selected... */ + if (G.debug & G_DEBUG) { + printf("%s: nothing to do for FCurve %p (rna_path = '%s')\n", __func__, fcu, fcu->rna_path); + } + return; + } + else { + /* Compute the average values for each retained keyframe */ + for (tRetainedKeyframe *rk = retained_keys.first; rk; rk = rk->next) { + rk->val = rk->val / (float)rk->tot_count; + } + } + + /* 2) Delete all keyframes duplicating the "retained keys" found above + * - Most of these will be unselected keyframes + * - Some will be selected keyframes though. For those, we only keep the last one + * (or else everything is gone), and replace its value with the averaged value. */ - if ((len) && (len != fcu->totvert)) { - for (i = fcu->totvert - 1; i >= 0; i--) { - BezTriple *bezt = &fcu->bezt[i]; - - if (BEZT_ISSEL_ANY(bezt) == 0) { - /* check beztriple should be removed according to cache */ - for (index = 0; index < len; index++) { - if (IS_EQF(bezt->vec[1][0], selcache[index])) { + for (int i = fcu->totvert - 1; i >= 0; i--) { + BezTriple *bezt = &fcu->bezt[i]; + + /* Is this keyframe a candidate for deletion? */ + /* TODO: Replace loop with an O(1) lookup instead */ + for (tRetainedKeyframe *rk = retained_keys.last; rk; rk = rk->prev) { + if (IS_EQT(bezt->vec[1][0], rk->frame, BEZT_BINARYSEARCH_THRESH)) { + /* Selected keys are treated with greater care than unselected ones... */ + if (BEZT_ISSEL_ANY(bezt)) { + /* - If this is the last selected key left (based on rk->del_count) ==> UPDATE IT + * (or else we wouldn't have any keyframe left here) + * - Otherwise, there are still other selected keyframes on this frame + * to be merged down still ==> DELETE IT + */ + if (rk->del_count == rk->tot_count - 1) { + /* Update keyframe... */ + if (can_average_points) { + /* TODO: update handles too? */ + bezt->vec[1][1] = rk->val; + } + } + else { + /* Delete Keyframe */ delete_fcurve_key(fcu, i, 0); - break; } - else if (bezt->vec[1][0] < selcache[index]) - break; + + /* Update count of how many we've deleted + * - It should only matter that we're doing this for all but the last one + */ + rk->del_count++; } + else { + /* Always delete - Unselected keys don't matter */ + delete_fcurve_key(fcu, i, 0); + } + + /* Stop the RK search... we've found our match now */ + break; } } - - testhandles_fcurve(fcu, use_handle); } - - /* free cache */ - MEM_freeN(selcache); + + /* 3) Recalculate handles */ + testhandles_fcurve(fcu, use_handle); + + /* cleanup */ + BLI_freelistN(&retained_keys); } - /* Called by special_aftertrans_update to make sure selected keyframes replace * any other keyframes which may reside on that frame (that is not selected). * remake_action_ipos should have already been called @@ -5639,9 +5701,6 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob) Scene *scene = t->scene; bool constinv; bool skip_invert = false; - EvaluationContext eval_ctx; - - CTX_data_eval_ctx(t->context, &eval_ctx); if (t->mode != TFM_DUMMY && ob->rigidbody_object) { float rot[3][3], scale[3]; @@ -5689,11 +5748,11 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob) if (skip_invert == false && constinv == false) { ob->transflag |= OB_NO_CONSTRAINTS; /* BKE_object_where_is_calc_time checks this */ - BKE_object_where_is_calc(&eval_ctx, t->scene, ob); + BKE_object_where_is_calc(&t->eval_ctx, t->scene, ob); ob->transflag &= ~OB_NO_CONSTRAINTS; } else - BKE_object_where_is_calc(&eval_ctx, t->scene, ob); + BKE_object_where_is_calc(&t->eval_ctx, t->scene, ob); td->ob = ob; @@ -6334,14 +6393,11 @@ static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t) * */ void special_aftertrans_update(bContext *C, TransInfo *t) { - EvaluationContext eval_ctx; Object *ob; // short redrawipo=0, resetslowpar=1; const bool canceled = (t->state == TRANS_CANCEL); const bool duplicate = (t->mode == TFM_TIME_DUPLICATE); - CTX_data_eval_ctx(C, &eval_ctx); - /* early out when nothing happened */ if (t->total == 0 || t->mode == TFM_DUMMY) return; @@ -6680,7 +6736,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t) * we need to update the pose otherwise no updates get called during * transform and the auto-ik is not applied. see [#26164] */ struct Object *pose_ob = t->poseobj; - BKE_pose_where_is(&eval_ctx, t->scene, pose_ob); + BKE_pose_where_is(&t->eval_ctx, t->scene, pose_ob); } /* set BONE_TRANSFORM flags for autokey, manipulator draw might have changed them */ @@ -6725,7 +6781,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t) else if ((t->view_layer->basact) && (ob = t->view_layer->basact->object) && (ob->mode & OB_MODE_PARTICLE_EDIT) && - PE_get_current(t->scene, t->view_layer, ob)) + PE_get_current(t->scene, ob)) { /* do nothing */ } @@ -8484,7 +8540,7 @@ void createTransData(bContext *C, TransInfo *t) } } - else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) && PE_start_edit(PE_get_current(scene, view_layer, ob))) { + else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) && PE_start_edit(PE_get_current(scene, ob))) { createTransParticleVerts(C, t); t->flag |= T_POINTS; diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 83a8e978b0d..32cd02c59e6 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -280,7 +280,7 @@ static void animrecord_check_state(Scene *scene, ID *id, wmTimer *animtimer) /* only push down if action is more than 1-2 frames long */ calc_action_range(adt->action, &astart, &aend, 1); if (aend > astart + 2.0f) { - NlaStrip *strip = add_nlastrip_to_stack(adt, adt->action); + NlaStrip *strip = BKE_nlastack_add_strip(adt, adt->action); /* clear reference to action now that we've pushed it onto the stack */ id_us_min(&adt->action->id); @@ -715,9 +715,6 @@ static void recalcData_spaceclip(TransInfo *t) static void recalcData_objects(TransInfo *t) { Base *base = t->view_layer->basact; - EvaluationContext eval_ctx; - - CTX_data_eval_ctx(t->context, &eval_ctx); if (t->obedit) { if (ELEM(t->obedit->type, OB_CURVE, OB_SURF)) { @@ -907,9 +904,11 @@ static void recalcData_objects(TransInfo *t) BIK_clear_data(ob->pose); } else - BKE_pose_where_is(&eval_ctx, t->scene, ob); + BKE_pose_where_is(&t->eval_ctx, t->scene, ob); } - else if (base && (base->object->mode & OB_MODE_PARTICLE_EDIT) && PE_get_current(t->scene, t->view_layer, base->object)) { + else if (base && (base->object->mode & OB_MODE_PARTICLE_EDIT) && + PE_get_current(t->scene, base->object)) + { if (t->state != TRANS_CANCEL) { applyProject(t); } @@ -1120,6 +1119,7 @@ static int initTransInfo_edit_pet_to_flag(const int proportional) */ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event) { + CTX_data_eval_ctx(C, &t->eval_ctx); Depsgraph *depsgraph = CTX_data_depsgraph(C); Scene *sce = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); @@ -1921,14 +1921,6 @@ void calculateCenter(TransInfo *t) if (t->spacetype == SPACE_VIEW3D) { /* ED_view3d_calc_zfac() defines a factor for perspective depth correction, used in ED_view3d_win_to_delta() */ - float vec[3]; - if (t->flag & (T_EDIT | T_POSE)) { - Object *ob = t->obedit ? t->obedit : t->poseobj; - mul_v3_m4v3(vec, ob->obmat, t->center); - } - else { - copy_v3_v3(vec, t->center); - } /* zfac is only used convertViewVec only in cases operator was invoked in RGN_TYPE_WINDOW * and never used in other cases. @@ -1937,7 +1929,7 @@ void calculateCenter(TransInfo *t) * for a region different from RGN_TYPE_WINDOW. */ if (t->ar->regiontype == RGN_TYPE_WINDOW) { - t->zfac = ED_view3d_calc_zfac(t->ar->regiondata, vec, NULL); + t->zfac = ED_view3d_calc_zfac(t->ar->regiondata, t->center_global, NULL); } else { t->zfac = 0.0f; diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index 0643687c29a..8944817baca 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -63,6 +63,8 @@ #include "BIF_gl.h" +#include "DEG_depsgraph.h" + #include "WM_api.h" #include "WM_types.h" #include "WM_message.h" @@ -973,7 +975,7 @@ static int calc_manipulator_stats( /* pass */ } else if (ob && ob->mode & OB_MODE_PARTICLE_EDIT) { - PTCacheEdit *edit = PE_get_current(scene, view_layer, ob); + PTCacheEdit *edit = PE_get_current(scene, ob); PTCacheEditPoint *point; PTCacheEditKey *ek; int k; @@ -1065,7 +1067,7 @@ static void manipulator_prepare_mat( bGPdata *gpd = CTX_data_gpencil_data(C); Object *ob = OBACT(view_layer); - if (((v3d->around == V3D_AROUND_ACTIVE) && (scene->obedit == NULL)) && + if (((v3d->around == V3D_AROUND_ACTIVE) && (OBEDIT_FROM_OBACT(ob) == NULL)) && ((gpd == NULL) || !(gpd->flag & GP_DATA_STROKE_EDITMODE)) && (!(ob->mode & OB_MODE_POSE))) { diff --git a/source/blender/editors/transform/transform_manipulator2d.c b/source/blender/editors/transform/transform_manipulator2d.c index 6e2d0d8c5c0..a9414a7f4bf 100644 --- a/source/blender/editors/transform/transform_manipulator2d.c +++ b/source/blender/editors/transform/transform_manipulator2d.c @@ -353,6 +353,10 @@ void ED_widgetgroup_manipulator2d_draw_prepare(const bContext *C, wmManipulatorG */ bool ED_widgetgroup_manipulator2d_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt)) { + if ((U.manipulator_flag & USER_MANIPULATOR_DRAW) == 0) { + return false; + } + SpaceImage *sima = CTX_wm_space_image(C); Object *obedit = CTX_data_edit_object(C); @@ -368,7 +372,7 @@ bool ED_widgetgroup_manipulator2d_poll(const bContext *C, wmManipulatorGroupType /* check if there's a selected poly */ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, ima, efa)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index ab0e24671eb..d5d25888ec8 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -316,7 +316,8 @@ static void transformops_loopsel_hack(bContext *C, wmOperator *op) /* still switch if we were originally in face select mode */ if ((ts->selectmode != selectmode_orig) && (selectmode_orig != SCE_SELECT_FACE)) { - BMEditMesh *em = BKE_editmesh_from_object(scene->obedit); + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); em->selectmode = ts->selectmode = selectmode_orig; EDBM_selectmode_set(em); } diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index f8b11a0bcae..7b3f91b81da 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -911,7 +911,7 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3 } else if (is_next_sel) { /* A segment, add the edge normal */ - sub_v3_v3v3(tvec, bp->vec, bp_next->vec ); + sub_v3_v3v3(tvec, bp->vec, bp_next->vec); normalize_v3(tvec); add_v3_v3(normal, tvec); } diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 30aad46843d..5cb3f262ced 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -70,6 +70,8 @@ #include "ED_view3d.h" #include "ED_transform_snap_object_context.h" +#include "DEG_depsgraph.h" + #include "UI_resources.h" #include "UI_view2d.h" @@ -582,8 +584,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_type, 0, - t->ar, t->view); + G.main, t->scene, t->view_layer, 0, t->ar, t->view); ED_transform_snap_object_context_set_editmesh_callbacks( t->tsnap.object_context, diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 8f0590eb5b9..2a9b4790eaf 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -62,6 +62,10 @@ #include "transform.h" +/* -------------------------------------------------------------------- */ +/** Internal Data Types + * \{ */ + enum eViewProj { VIEW_PROJ_NONE = -1, VIEW_PROJ_ORTHO = 0, @@ -137,10 +141,8 @@ struct SnapObjectContext { /** \} */ - /* -------------------------------------------------------------------- */ - -/** Common utilities +/** Common Utilities * \{ */ @@ -260,9 +262,7 @@ static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt); /** \} */ - /* -------------------------------------------------------------------- */ - /** \name Ray Cast Funcs * \{ */ @@ -789,7 +789,6 @@ static void raycast_obj_cb(SnapObjectContext *sctx, bool is_obedit, Object *ob, * Walks through all objects in the scene to find the `hit` on object surface. * * \param sctx: Snap context to store data. - * \param snapdata: struct generated in `set_snapdata`. * \param snap_select : from enum eSnapSelect. * \param use_object_edit_cage : Uses the coordinates of BMesh(if any) to do the snapping. * \param obj_list: List with objects to snap (created in `create_object_list`). @@ -822,7 +821,7 @@ static bool raycastObjects( Object **r_ob, float r_obmat[4][4], ListBase *r_hit_list) { - Object *obedit = use_object_edit_cage ? sctx->scene->obedit : NULL; + Object *obedit = use_object_edit_cage ? OBEDIT_FROM_VIEW_LAYER(sctx->eval_ctx.view_layer) : NULL; struct RaycastObjUserData data = { .ray_start = ray_start, @@ -846,9 +845,7 @@ static bool raycastObjects( /** \} */ - /* -------------------------------------------------------------------- */ - /** Snap Nearest utilities * \{ */ @@ -1158,9 +1155,7 @@ static float dist_squared_to_projected_aabb_simple( /** \} */ - /* -------------------------------------------------------------------- */ - /** Walk DFS * \{ */ @@ -1256,7 +1251,6 @@ static bool cb_nearest_walk_order(const BVHTreeAxisRange *UNUSED(bounds), char a /** \} */ /* -------------------------------------------------------------------- */ - /** \name Internal Object Snapping API * \{ */ @@ -1358,7 +1352,7 @@ static bool snapArmature( static bool snapCurve( SnapData *snapdata, - Object *ob, Curve *cu, float obmat[4][4], + Curve *cu, float obmat[4][4], bool use_obedit, /* read/write args */ float *ray_depth, float *dist_px, /* return args */ @@ -1376,12 +1370,12 @@ static bool snapCurve( mul_m4_m4m4(lpmat, snapdata->pmat, obmat); dist_px_sq = SQUARE(*dist_px); - for (Nurb *nu = (ob->mode == OB_MODE_EDIT ? cu->editnurb->nurbs.first : cu->nurb.first); nu; nu = nu->next) { + for (Nurb *nu = (use_obedit ? cu->editnurb->nurbs.first : cu->nurb.first); nu; nu = nu->next) { for (int u = 0; u < nu->pntsu; u++) { switch (snapdata->snap_to) { case SCE_SNAP_MODE_VERTEX: { - if (ob->mode == OB_MODE_EDIT) { + if (use_obedit) { if (nu->bezt) { /* don't snap to selected (moving) or hidden */ if (nu->bezt[u].f2 & SELECT || nu->bezt[u].hide != 0) { @@ -1966,7 +1960,7 @@ static bool snapObject( else if (ob->type == OB_CURVE) { retval = snapCurve( snapdata, - ob, ob->data, obmat, + ob->data, obmat, use_obedit, ray_depth, dist_px, r_loc, r_no); } @@ -2060,7 +2054,7 @@ static bool snapObjectsRay( float r_loc[3], float r_no[3], Object **r_ob, float r_obmat[4][4]) { - Object *obedit = use_object_edit_cage ? sctx->scene->obedit : NULL; + Object *obedit = use_object_edit_cage ? OBEDIT_FROM_VIEW_LAYER(sctx->eval_ctx.view_layer) : NULL; struct SnapObjUserData data = { .snapdata = snapdata, @@ -2080,14 +2074,12 @@ static bool snapObjectsRay( /** \} */ - /* -------------------------------------------------------------------- */ - /** \name Public Object Snapping API * \{ */ SnapObjectContext *ED_transform_snap_object_context_create( - Main *bmain, Scene *scene, ViewLayer *view_layer, RenderEngineType *engine_type, int flag) + Main *bmain, Scene *scene, ViewLayer *view_layer, int flag) { SnapObjectContext *sctx = MEM_callocN(sizeof(*sctx), __func__); @@ -2096,7 +2088,8 @@ 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_type, DAG_EVAL_VIEWPORT); + DEG_evaluation_context_init_from_scene( + &sctx->eval_ctx, scene, view_layer, DAG_EVAL_VIEWPORT); sctx->cache.object_map = BLI_ghash_ptr_new(__func__); sctx->cache.mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); @@ -2105,11 +2098,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_type, int flag, + Main *bmain, Scene *scene, ViewLayer *view_layer, 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_type, flag); + SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, view_layer, flag); sctx->use_v3d = true; sctx->v3d_data.ar = ar; diff --git a/source/blender/editors/undo/CMakeLists.txt b/source/blender/editors/undo/CMakeLists.txt new file mode 100644 index 00000000000..89832604ed8 --- /dev/null +++ b/source/blender/editors/undo/CMakeLists.txt @@ -0,0 +1,45 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL LICENSE BLOCK ***** + +set(INC + ../include + ../../blenkernel + ../../blenlib + ../../blentranslation + ../../makesdna + ../../makesrna + ../../windowmanager + ../../../../intern/guardedalloc + ../../../../intern/clog +) + +set(SRC + ed_undo.c + memfile_undo.c + undo_system_types.c + + undo_intern.h +) + +if(WITH_INTERNATIONAL) + add_definitions(-DWITH_INTERNATIONAL) +endif() + +blender_add_lib(bf_editor_undo "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/undo/ed_undo.c index 9e28a5f84ec..d8b194e3336 100644 --- a/source/blender/editors/util/undo.c +++ b/source/blender/editors/undo/ed_undo.c @@ -25,17 +25,16 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/editors/util/undo.c - * \ingroup edutil +/** \file blender/editors/undo/ed_undo.c + * \ingroup edundo */ -#include <stdlib.h> #include <string.h> -#include <math.h> #include "MEM_guardedalloc.h" -#include "DNA_object_types.h" +#include "CLG_log.h" + #include "DNA_scene_types.h" #include "BLI_utildefines.h" @@ -45,22 +44,14 @@ #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" +#include "BKE_undo_system.h" -#include "ED_armature.h" -#include "ED_particle.h" -#include "ED_curve.h" #include "ED_gpencil.h" -#include "ED_mball.h" -#include "ED_mesh.h" -#include "ED_object.h" #include "ED_render.h" #include "ED_screen.h" -#include "ED_paint.h" -#include "ED_util.h" -#include "ED_text.h" +#include "ED_undo.h" #include "WM_api.h" #include "WM_types.h" @@ -71,63 +62,50 @@ #include "UI_interface.h" #include "UI_resources.h" -#include "util_intern.h" +/** We only need this locally. */ +static CLG_LogRef LOG = {"ed.undo"}; -/* ***************** generic undo system ********************* */ +/* -------------------------------------------------------------------- */ +/** \name Generic Undo System Access + * + * Non-operator undo editor functions. + * \{ */ void ED_undo_push(bContext *C, const char *str) { - Object *obedit = CTX_data_edit_object(C); - Object *obact = CTX_data_active_object(C); - - 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; - - if (obedit->type == OB_MESH) - undo_push_mesh(C, str); - else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) - undo_push_curve(C, str); - else if (obedit->type == OB_FONT) - undo_push_font(C, str); - else if (obedit->type == OB_MBALL) - undo_push_mball(C, str); - else if (obedit->type == OB_LATTICE) - undo_push_lattice(C, str); - else if (obedit->type == OB_ARMATURE) - undo_push_armature(C, str); - } - else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT) { - if (U.undosteps == 0) return; + CLOG_INFO(&LOG, 1, "name='%s'", str); + + const int steps = U.undosteps; - PE_undo_push(CTX_data_scene(C), CTX_data_view_layer(C), str); + if (steps <= 0) { + return; } - else if (obact && obact->mode & OB_MODE_SCULPT) { - /* do nothing for now */ + + wmWindowManager *wm = CTX_wm_manager(C); + + /* Only apply limit if this is the last undo step. */ + if (wm->undo_stack->step_active && (wm->undo_stack->step_active->next == NULL)) { + BKE_undosys_stack_limit_steps_and_memory(wm->undo_stack, steps - 1, 0); } - else { - BKE_undo_write(C, str); + + BKE_undosys_step_push(wm->undo_stack, C, str); + + if (U.undomemory != 0) { + const size_t memory_limit = (size_t)U.undomemory * 1024 * 1024; + BKE_undosys_stack_limit_steps_and_memory(wm->undo_stack, 0, memory_limit); } - WM_file_tag_modified(C); + WM_file_tag_modified(); } /* note: also check undo_history_exec() in bottom if you change notifiers */ static int ed_undo_step(bContext *C, int step, const char *undoname) { + CLOG_INFO(&LOG, 1, "name='%s', step=%d", undoname, step); wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win = CTX_wm_window(C); - Main *bmain = CTX_data_main(C); + // Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *obedit = CTX_data_edit_object(C); - Object *obact = CTX_data_active_object(C); - ScrArea *sa = CTX_wm_area(C); /* undo during jobs are running can easily lead to freeing data using by jobs, * or they can just lead to freezing job in some other cases */ @@ -135,100 +113,45 @@ static int ed_undo_step(bContext *C, int step, const char *undoname) return OPERATOR_CANCELLED; } + /* TODO(campbell): undo_system: use undo system */ /* grease pencil can be can be used in plenty of spaces, so check it first */ if (ED_gpencil_session_active()) { return ED_undo_gpencil_step(C, step, undoname); } - if (sa && (sa->spacetype == SPACE_IMAGE)) { - SpaceImage *sima = (SpaceImage *)sa->spacedata.first; - - if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) { - if (!ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step, undoname) && undoname) { - if (U.uiflag & USER_GLOBALUNDO) { - ED_viewport_render_kill_jobs(wm, bmain, true); - BKE_undo_name(C, undoname); - } - } - - WM_event_add_notifier(C, NC_WINDOW, NULL); - return OPERATOR_FINISHED; - } - } - - if (sa && (sa->spacetype == SPACE_TEXT)) { - ED_text_undo_step(C, step); - } - else if (obedit) { - if (OB_TYPE_SUPPORT_EDITMODE(obedit->type)) { - if (undoname) - undo_editmode_name(C, undoname); - else - undo_editmode_step(C, step); - - WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); - } - } - else { - /* Note: we used to do a fall-through here where if the - * mode-specific undo system had no more steps to undo (or - * redo), the global undo would run. - * - * That was inconsistent with editmode, and also makes for - * unecessarily tricky interaction with the other undo - * systems. */ - if (obact && obact->mode & OB_MODE_TEXTURE_PAINT) { - ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step, undoname); + /* Undo System */ + { + if (undoname) { + UndoStep *step_data = BKE_undosys_step_find_by_name(wm->undo_stack, undoname); + BKE_undosys_step_undo_with_data(wm->undo_stack, C, step_data); } - else if (obact && obact->mode & OB_MODE_SCULPT) { - ED_undo_paint_step(C, UNDO_PAINT_MESH, step, undoname); - } - else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT) { - if (step == 1) - PE_undo(scene, view_layer); - else - PE_redo(scene, view_layer); - } - else if (U.uiflag & USER_GLOBALUNDO) { - // note python defines not valid here anymore. - //#ifdef WITH_PYTHON - // XXX BPY_scripts_clear_pyobjects(); - //#endif - - /* for global undo/redo we should just clear the editmode stack */ - /* for example, texface stores image pointers */ - undo_editmode_clear(); - - ED_viewport_render_kill_jobs(wm, bmain, true); - - if (undoname) - BKE_undo_name(C, undoname); - else - BKE_undo_step(C, step); - - scene = CTX_data_scene(C); - - WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene); + else { + BKE_undosys_step_undo_compat_only(wm->undo_stack, C, step); } } - + WM_event_add_notifier(C, NC_WINDOW, NULL); WM_event_add_notifier(C, NC_WM | ND_UNDO, NULL); if (win) { win->addmousemove = true; } - + return OPERATOR_FINISHED; } void ED_undo_grouped_push(bContext *C, const char *str) { /* do nothing if previous undo task is the same as this one (or from the same undo group) */ - const char *last_undo = BKE_undo_get_name_last(); + { + wmWindowManager *wm = CTX_wm_manager(C); + if (wm->undo_stack->steps.last) { + const UndoStep *us = wm->undo_stack->steps.last; + if (STREQ(str, us->name)) { + return; + } + } - if (last_undo && STREQ(str, last_undo)) { - return; } /* push as usual */ @@ -269,49 +192,29 @@ void ED_undo_pop_op(bContext *C, wmOperator *op) /* name optionally, function used to check for operator redo panel */ bool ED_undo_is_valid(const bContext *C, const char *undoname) { - Object *obedit = CTX_data_edit_object(C); - Object *obact = CTX_data_active_object(C); - ScrArea *sa = CTX_wm_area(C); - - if (sa && sa->spacetype == SPACE_IMAGE) { - SpaceImage *sima = (SpaceImage *)sa->spacedata.first; - - if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) { - return 1; - } - } - - if (sa && (sa->spacetype == SPACE_TEXT)) { - return 1; - } - else if (obedit) { - if (OB_TYPE_SUPPORT_EDITMODE(obedit->type)) { - return undo_editmode_is_valid(undoname); - } - } - else { - - /* if below tests fail, global undo gets executed */ - - if (obact && obact->mode & OB_MODE_TEXTURE_PAINT) { - if (ED_undo_paint_is_valid(UNDO_PAINT_IMAGE, undoname)) - return 1; - } - else if (obact && obact->mode & OB_MODE_SCULPT) { - if (ED_undo_paint_is_valid(UNDO_PAINT_MESH, undoname)) - return 1; - } - else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT) { - return PE_undo_is_valid(CTX_data_scene(C), CTX_data_view_layer(C)); - } - - if (U.uiflag & USER_GLOBALUNDO) { - return BKE_undo_is_valid(undoname); - } - } - return 0; + wmWindowManager *wm = CTX_wm_manager(C); + return BKE_undosys_stack_has_undo(wm->undo_stack, undoname); +} + +/** + * Ideally we wont access the stack directly, + * this is needed for modes which handle undo themselves (bypassing #ED_undo_push). + * + * Using global isn't great, this just avoids doing inline, + * causing 'BKE_global.h' & 'BKE_main.h' includes. + */ +UndoStack *ED_undo_stack_get(void) +{ + wmWindowManager *wm = G.main->wm.first; + return wm->undo_stack; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Undo, Undo Push & Redo Operators + * \{ */ + static int ed_undo_exec(bContext *C, wmOperator *UNUSED(op)) { /* "last operator" should disappear, later we can tie this with undo stack nicer */ @@ -342,19 +245,17 @@ static int ed_undo_redo_exec(bContext *C, wmOperator *UNUSED(op)) static int ed_undo_redo_poll(bContext *C) { wmOperator *last_op = WM_operator_last_redo(C); - return last_op && ED_operator_screenactive(C) && + return last_op && ED_operator_screenactive(C) && WM_operator_check_ui_enabled(C, last_op->type->name); } -/* ********************** */ - void ED_OT_undo(wmOperatorType *ot) { /* identifiers */ ot->name = "Undo"; ot->description = "Undo previous action"; ot->idname = "ED_OT_undo"; - + /* api callbacks */ ot->exec = ed_undo_exec; ot->poll = ED_operator_screenactive; @@ -366,7 +267,7 @@ void ED_OT_undo_push(wmOperatorType *ot) ot->name = "Undo Push"; ot->description = "Add an undo state (internal use only)"; ot->idname = "ED_OT_undo_push"; - + /* api callbacks */ ot->exec = ed_undo_push_exec; @@ -381,7 +282,7 @@ void ED_OT_redo(wmOperatorType *ot) ot->name = "Redo"; ot->description = "Redo previous action"; ot->idname = "ED_OT_redo"; - + /* api callbacks */ ot->exec = ed_redo_exec; ot->poll = ED_operator_screenactive; @@ -393,18 +294,25 @@ void ED_OT_undo_redo(wmOperatorType *ot) ot->name = "Undo and Redo"; ot->description = "Undo and redo previous action"; ot->idname = "ED_OT_undo_redo"; - + /* api callbacks */ ot->exec = ed_undo_redo_exec; ot->poll = ed_undo_redo_poll; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Operator Repeat + * \{ */ + /* ui callbacks should call this rather than calling WM_operator_repeat() themselves */ int ED_undo_operator_repeat(bContext *C, struct wmOperator *op) { int ret = 0; if (op) { + CLOG_INFO(&LOG, 1, "idname='%s'", op->type->idname); wmWindowManager *wm = CTX_wm_manager(C); struct Scene *scene = CTX_data_scene(C); @@ -465,9 +373,7 @@ int ED_undo_operator_repeat(bContext *C, struct wmOperator *op) CTX_wm_region_set(C, ar); } else { - if (G.debug & G_DEBUG) { - printf("redo_cb: ED_undo_operator_repeat called with NULL 'op'\n"); - } + CLOG_WARN(&LOG, "called with NULL 'op'"); } return ret; @@ -484,114 +390,50 @@ void ED_undo_operator_repeat_cb_evt(bContext *C, void *arg_op, int UNUSED(arg_ev ED_undo_operator_repeat(C, (wmOperator *)arg_op); } +/** \} */ -/* ************************** */ - -enum { - UNDOSYSTEM_GLOBAL = 1, - UNDOSYSTEM_EDITMODE = 2, - UNDOSYSTEM_PARTICLE = 3, - UNDOSYSTEM_IMAPAINT = 4, - UNDOSYSTEM_SCULPT = 5, -}; - -static int get_undo_system(bContext *C) -{ - Object *obact = CTX_data_active_object(C); - Object *obedit = CTX_data_edit_object(C); - ScrArea *sa = CTX_wm_area(C); - - /* first check for editor undo */ - if (sa && (sa->spacetype == SPACE_IMAGE)) { - SpaceImage *sima = (SpaceImage *)sa->spacedata.first; - - if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) { - if (!ED_undo_paint_empty(UNDO_PAINT_IMAGE)) - return UNDOSYSTEM_IMAPAINT; - } - } - /* find out which undo system */ - if (obedit) { - if (OB_TYPE_SUPPORT_EDITMODE(obedit->type)) { - return UNDOSYSTEM_EDITMODE; - } - } - else { - if (obact) { - if (obact->mode & OB_MODE_PARTICLE_EDIT) - return UNDOSYSTEM_PARTICLE; - else if (obact->mode & OB_MODE_TEXTURE_PAINT) { - if (!ED_undo_paint_empty(UNDO_PAINT_IMAGE)) - return UNDOSYSTEM_IMAPAINT; - } - else if (obact->mode & OB_MODE_SCULPT) { - if (!ED_undo_paint_empty(UNDO_PAINT_MESH)) - return UNDOSYSTEM_SCULPT; - } - } - if (U.uiflag & USER_GLOBALUNDO) - return UNDOSYSTEM_GLOBAL; - } - - return 0; -} +/* -------------------------------------------------------------------- */ +/** \name Undo History Operator + * \{ */ /* create enum based on undo items */ -static const EnumPropertyItem *rna_undo_itemf(bContext *C, int undosys, int *totitem) +static const EnumPropertyItem *rna_undo_itemf(bContext *C, int *totitem) { EnumPropertyItem item_tmp = {0}, *item = NULL; int i = 0; - bool active; - - while (true) { - const char *name = NULL; - - if (undosys == UNDOSYSTEM_PARTICLE) { - name = PE_undo_get_name(CTX_data_scene(C), CTX_data_view_layer(C), i, &active); - } - else if (undosys == UNDOSYSTEM_EDITMODE) { - name = undo_editmode_get_name(C, i, &active); - } - else if (undosys == UNDOSYSTEM_IMAPAINT) { - name = ED_undo_paint_get_name(C, UNDO_PAINT_IMAGE, i, &active); - } - else if (undosys == UNDOSYSTEM_SCULPT) { - name = ED_undo_paint_get_name(C, UNDO_PAINT_MESH, i, &active); - } - else { - name = BKE_undo_get_name(i, &active); - } - - if (name) { - item_tmp.identifier = name; - /* XXX This won't work with non-default contexts (e.g. operators) :/ */ - item_tmp.name = IFACE_(name); - if (active) + + wmWindowManager *wm = CTX_wm_manager(C); + if (wm->undo_stack == NULL) { + return NULL; + } + + for (UndoStep *us = wm->undo_stack->steps.first; us; us = us->next, i++) { + if (us->skip == false) { + item_tmp.identifier = us->name; + item_tmp.name = IFACE_(us->name); + if (us == wm->undo_stack->step_active) { item_tmp.icon = ICON_RESTRICT_VIEW_OFF; - else + } + else { item_tmp.icon = ICON_NONE; - item_tmp.value = i++; + } + item_tmp.value = i; RNA_enum_item_add(&item, totitem, &item_tmp); } - else - break; } - RNA_enum_item_end(&item, totitem); - + return item; } static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - int undosys, totitem = 0; - - undosys = get_undo_system(C); - - if (undosys) { - const EnumPropertyItem *item = rna_undo_itemf(C, undosys, &totitem); - + int totitem = 0; + + { + const EnumPropertyItem *item = rna_undo_itemf(C, &totitem); + if (totitem > 0) { uiPopupMenu *pup = UI_popup_menu_begin(C, RNA_struct_ui_name(op->type->srna), ICON_NONE); uiLayout *layout = UI_popup_menu_layout(pup); @@ -600,7 +442,7 @@ static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE const int col_size = 20 + totitem / 12; int i, c; bool add_col = true; - + for (c = 0, i = totitem; i--;) { if (add_col && !(c % col_size)) { column = uiLayoutColumn(split, false); @@ -612,12 +454,12 @@ static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE add_col = true; } } - + MEM_freeN((void *)item); - + UI_popup_menu_end(C, pup); } - + } return OPERATOR_CANCELLED; } @@ -625,30 +467,12 @@ static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE /* note: also check ed_undo_step() in top if you change notifiers */ static int undo_history_exec(bContext *C, wmOperator *op) { - if (RNA_struct_property_is_set(op->ptr, "item")) { - int undosys = get_undo_system(C); - int item = RNA_int_get(op->ptr, "item"); - - if (undosys == UNDOSYSTEM_PARTICLE) { - PE_undo_number(CTX_data_scene(C), CTX_data_view_layer(C), item); - } - else if (undosys == UNDOSYSTEM_EDITMODE) { - undo_editmode_number(C, item + 1); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); - } - else if (undosys == UNDOSYSTEM_IMAPAINT) { - ED_undo_paint_step_num(C, UNDO_PAINT_IMAGE, item); - } - else if (undosys == UNDOSYSTEM_SCULPT) { - ED_undo_paint_step_num(C, UNDO_PAINT_MESH, item); - } - else { - ED_viewport_render_kill_jobs(CTX_wm_manager(C), CTX_data_main(C), true); - BKE_undo_number(C, item); - WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, CTX_data_scene(C)); - } + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "item"); + if (RNA_property_is_set(op->ptr, prop)) { + int item = RNA_property_int_get(op->ptr, prop); + wmWindowManager *wm = CTX_wm_manager(C); + BKE_undosys_step_undo_from_index(wm->undo_stack, C, item); WM_event_add_notifier(C, NC_WINDOW, NULL); - return OPERATOR_FINISHED; } return OPERATOR_CANCELLED; @@ -660,14 +484,14 @@ void ED_OT_undo_history(wmOperatorType *ot) ot->name = "Undo History"; ot->description = "Redo specific action in history"; ot->idname = "ED_OT_undo_history"; - + /* api callbacks */ ot->invoke = undo_history_invoke; ot->exec = undo_history_exec; ot->poll = ED_operator_screenactive; - + RNA_def_int(ot->srna, "item", 0, 0, INT_MAX, "Item", "", 0, INT_MAX); } - +/** \} */ diff --git a/source/blender/editors/undo/memfile_undo.c b/source/blender/editors/undo/memfile_undo.c new file mode 100644 index 00000000000..511f4bc72f1 --- /dev/null +++ b/source/blender/editors/undo/memfile_undo.c @@ -0,0 +1,151 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/undo/memfile_undo.c + * \ingroup edundo + * + * Wrapper between 'ED_undo.h' and 'BKE_undo_system.h' API's. + */ + +#include "BLI_utildefines.h" +#include "BLI_sys_types.h" + +#include "DNA_object_enums.h" + +#include "BKE_blender_undo.h" +#include "BKE_context.h" +#include "BKE_undo_system.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_object.h" +#include "ED_undo.h" +#include "ED_render.h" + + +#include "../blenloader/BLO_undofile.h" + +#include "undo_intern.h" + +/* -------------------------------------------------------------------- */ +/** \name Implements ED Undo System + * \{ */ + +typedef struct MemFileUndoStep { + UndoStep step; + MemFileUndoData *data; +} MemFileUndoStep; + +static bool memfile_undosys_poll(bContext *UNUSED(C)) +{ + /* other poll functions must run first, this is a catch-all. */ + + if ((U.uiflag & USER_GLOBALUNDO) == 0) { + return false; + } + return true; +} + +static bool memfile_undosys_step_encode(struct bContext *C, UndoStep *us_p) +{ + MemFileUndoStep *us = (MemFileUndoStep *)us_p; + + /* Important we only use 'main' from the context (see: BKE_undosys_stack_init_from_main). */ + struct Main *bmain = CTX_data_main(C); + UndoStack *ustack = ED_undo_stack_get(); + + /* can be NULL, use when set. */ + MemFileUndoStep *us_prev = (MemFileUndoStep *)BKE_undosys_step_find_by_type(ustack, BKE_UNDOSYS_TYPE_MEMFILE); + us->data = BKE_memfile_undo_encode(bmain, us_prev ? us_prev->data : NULL); + us->step.data_size = us->data->undo_size; + + return true; +} + +static void memfile_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir)) +{ + /* Loading the content will correctly switch into compatible non-object modes. */ + ED_object_mode_set(C, OB_MODE_OBJECT); + + /* This is needed so undoing/redoing doesn't crash with threaded previews going */ + ED_viewport_render_kill_jobs(CTX_wm_manager(C), CTX_data_main(C), true); + MemFileUndoStep *us = (MemFileUndoStep *)us_p; + BKE_memfile_undo_decode(us->data, C); + + WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, CTX_data_scene(C)); +} + +static void memfile_undosys_step_free(UndoStep *us_p) +{ + /* To avoid unnecessary slow down, free backwards (so we don't need to merge when clearing all). */ + MemFileUndoStep *us = (MemFileUndoStep *)us_p; + if (us_p->next != NULL) { + UndoStep *us_next_p = BKE_undosys_step_same_type_next(us_p); + if (us_next_p != NULL) { + MemFileUndoStep *us_next = (MemFileUndoStep *)us_next_p; + BLO_memfile_merge(&us->data->memfile, &us_next->data->memfile); + } + } + + BKE_memfile_undo_free(us->data); +} + +/* Export for ED_undo_sys. */ +void ED_memfile_undosys_type(UndoType *ut) +{ + ut->name = "Global Undo"; + ut->poll = memfile_undosys_poll; + ut->step_encode = memfile_undosys_step_encode; + ut->step_decode = memfile_undosys_step_decode; + ut->step_free = memfile_undosys_step_free; + + ut->mode = BKE_UNDOTYPE_MODE_STORE; + ut->use_context = true; + + ut->step_size = sizeof(MemFileUndoStep); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Utilities + * \{ */ + +/** + * Ideally we wouldn't need to export global undo internals, there are some cases where it's needed though. + */ +static struct MemFile *ed_undosys_step_get_memfile(UndoStep *us_p) +{ + MemFileUndoStep *us = (MemFileUndoStep *)us_p; + return &us->data->memfile; +} + +struct MemFile *ED_undosys_stack_memfile_get_active(UndoStack *ustack) +{ + UndoStep *us = BKE_undosys_stack_active_with_type(ustack, BKE_UNDOSYS_TYPE_MEMFILE); + if (us) { + return ed_undosys_step_get_memfile(us); + } + return NULL; +} + + +/** \} */ diff --git a/source/blender/editors/util/util_intern.h b/source/blender/editors/undo/undo_intern.h index 0f650330951..671f9637d65 100644 --- a/source/blender/editors/util/util_intern.h +++ b/source/blender/editors/undo/undo_intern.h @@ -15,32 +15,21 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2008 Blender Foundation. - * All rights reserved. - * - * - * Contributor(s): Blender Foundation - * * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/editors/util/util_intern.h - * \ingroup edutil +/** \file blender/editors/undo/undo_intern.h + * \ingroup edundo */ - -#ifndef __UTIL_INTERN_H__ -#define __UTIL_INTERN_H__ +#ifndef __UNDO_INTERN_H__ +#define __UNDO_INTERN_H__ /* internal exports only */ -/* editmode_undo.c */ -void undo_editmode_name(struct bContext *C, const char *undoname); -bool undo_editmode_is_valid(const char *undoname); -const char *undo_editmode_get_name(struct bContext *C, int nr, bool *r_active); -void *undo_editmode_get_prev(struct Object *ob); -void undo_editmode_step(struct bContext *C, int step); -void undo_editmode_number(struct bContext *C, int nr); +struct UndoType; -#endif /* __UTIL_INTERN_H__ */ +/* memfile_undo.c */ +void ED_memfile_undosys_type(struct UndoType *ut); +#endif /* __UNDO_INTERN_H__ */ diff --git a/source/blender/editors/undo/undo_system_types.c b/source/blender/editors/undo/undo_system_types.c new file mode 100644 index 00000000000..75c3d2cc1b7 --- /dev/null +++ b/source/blender/editors/undo/undo_system_types.c @@ -0,0 +1,74 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/undo/undo_system_types.c + * \ingroup edundo + */ + +#include <string.h> + +#include "BLI_utildefines.h" + + +#include "ED_armature.h" +#include "ED_curve.h" +#include "ED_lattice.h" +#include "ED_mball.h" +#include "ED_mesh.h" +#include "ED_paint.h" +#include "ED_particle.h" +#include "ED_sculpt.h" +#include "ED_text.h" +#include "ED_undo.h" +#include "undo_intern.h" + +/* Keep last */ +#include "BKE_undo_system.h" + +void ED_undosys_type_init(void) +{ + /* Edit Modes */ + BKE_undosys_type_append(ED_armature_undosys_type); + BKE_undosys_type_append(ED_curve_undosys_type); + BKE_undosys_type_append(ED_font_undosys_type); + BKE_undosys_type_append(ED_lattice_undosys_type); + BKE_undosys_type_append(ED_mball_undosys_type); + BKE_undosys_type_append(ED_mesh_undosys_type); + + /* Paint Modes */ + BKE_UNDOSYS_TYPE_IMAGE = BKE_undosys_type_append(ED_image_undosys_type); + + BKE_UNDOSYS_TYPE_SCULPT = BKE_undosys_type_append(ED_sculpt_undosys_type); + + BKE_UNDOSYS_TYPE_PARTICLE = BKE_undosys_type_append(ED_particle_undosys_type); + + BKE_UNDOSYS_TYPE_PAINTCURVE = BKE_undosys_type_append(ED_paintcurve_undosys_type); + + /* Text editor */ + BKE_UNDOSYS_TYPE_TEXT = BKE_undosys_type_append(ED_text_undosys_type); + + /* Keep global undo last (as a fallback). */ + BKE_UNDOSYS_TYPE_MEMFILE = BKE_undosys_type_append(ED_memfile_undosys_type); +} + +void ED_undosys_type_free(void) +{ + BKE_undosys_type_free_all(); +} diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt index 71a3322cb50..24cfde90804 100644 --- a/source/blender/editors/util/CMakeLists.txt +++ b/source/blender/editors/util/CMakeLists.txt @@ -31,6 +31,7 @@ set(INC ../../makesrna ../../windowmanager ../../../../intern/guardedalloc + ../../../../intern/clog ../../../../intern/glew-mx ) @@ -41,11 +42,8 @@ set(INC_SYS set(SRC ed_transverts.c ed_util.c - editmode_undo.c numinput.c - undo.c - util_intern.h # general includes ../include/BIF_gl.h ../include/BIF_glutil.h diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c index b52cc20f71f..d3a9c22bc73 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -35,6 +35,7 @@ #include "MEM_guardedalloc.h" +#include "DNA_armature_types.h" #include "DNA_mesh_types.h" #include "DNA_object_types.h" #include "DNA_screen_types.h" @@ -58,6 +59,9 @@ #include "BKE_packedFile.h" #include "BKE_paint.h" #include "BKE_screen.h" +#include "BKE_workspace.h" +#include "BKE_layer.h" +#include "BKE_undo_system.h" #include "ED_armature.h" #include "ED_buttons.h" @@ -85,12 +89,12 @@ void ED_editors_init(bContext *C) { - wmWindowManager *wm = CTX_wm_manager(C); Main *bmain = CTX_data_main(C); - Scene *sce = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *ob, *obact = (view_layer && view_layer->basact) ? view_layer->basact->object : NULL; - ID *data; + wmWindowManager *wm = CTX_wm_manager(C); + + if (wm->undo_stack == NULL) { + wm->undo_stack = BKE_undosys_stack_create(); + } /* This is called during initialization, so we don't want to store any reports */ ReportList *reports = CTX_wm_reports(C); @@ -101,24 +105,30 @@ void ED_editors_init(bContext *C) /* toggle on modes for objects that were saved with these enabled. for * e.g. linked objects we have to ensure that they are actually the * active object in this scene. */ - for (ob = bmain->object.first; ob; ob = ob->id.next) { - int mode = ob->mode; + Object *obact = CTX_data_active_object(C); + if (obact != NULL) { + for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { + int mode = ob->mode; - if (mode == OB_MODE_OBJECT) { - /* pass */ - } - else { - data = ob->data; - ob->mode = OB_MODE_OBJECT; - if ((ob == obact) && !ID_IS_LINKED(ob) && !(data && ID_IS_LINKED(data))) { - ED_object_toggle_modes(C, mode); + if (mode == OB_MODE_OBJECT) { + /* pass */ + } + else { + ID *data = ob->data; + ob->mode = OB_MODE_OBJECT; + if ((ob == obact) && !ID_IS_LINKED(ob) && !(data && ID_IS_LINKED(data))) { + ED_object_mode_toggle(C, mode); + } } } } /* image editor paint mode */ - if (sce) { - ED_space_image_paint_update(wm, sce); + { + Scene *sce = CTX_data_scene(C); + if (sce) { + ED_space_image_paint_update(wm, sce); + } } SWAP(int, reports->flag, reports_flag_prev); @@ -128,31 +138,33 @@ void ED_editors_init(bContext *C) void ED_editors_exit(bContext *C) { Main *bmain = CTX_data_main(C); - Scene *sce; if (!bmain) return; - + /* frees all editmode undos */ - undo_editmode_clear(); - ED_undo_paint_free(); - - for (sce = bmain->scene.first; sce; sce = sce->id.next) { - if (sce->obedit) { - Object *ob = sce->obedit; - - if (ob) { - if (ob->type == OB_MESH) { - Mesh *me = ob->data; - if (me->edit_btmesh) { - EDBM_mesh_free(me->edit_btmesh); - MEM_freeN(me->edit_btmesh); - me->edit_btmesh = NULL; - } - } - else if (ob->type == OB_ARMATURE) { - ED_armature_edit_free(ob->data); - } + if (G.main->wm.first) { + wmWindowManager *wm = G.main->wm.first; + /* normally we don't check for NULL undo stack, do here since it may run in different context. */ + if (wm->undo_stack) { + BKE_undosys_stack_destroy(wm->undo_stack); + wm->undo_stack = NULL; + } + } + + for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { + if (ob->type == OB_MESH) { + Mesh *me = ob->data; + if (me->edit_btmesh) { + EDBM_mesh_free(me->edit_btmesh); + MEM_freeN(me->edit_btmesh); + me->edit_btmesh = NULL; + } + } + else if (ob->type == OB_ARMATURE) { + bArmature *arm = ob->data; + if (arm->edbo) { + ED_armature_edit_free(ob->data); } } } @@ -175,18 +187,22 @@ bool ED_editors_flush_edits(const bContext *C, bool for_render) * objects can exist at the same time */ for (ob = bmain->object.first; ob; ob = ob->id.next) { if (ob->mode & OB_MODE_SCULPT) { - /* flush multires changes (for sculpt) */ - multires_force_update(ob); - has_edited = true; - - if (for_render) { - /* flush changes from dynamic topology sculpt */ - BKE_sculptsession_bm_to_me_for_render(ob); - } - else { - /* Set reorder=false so that saving the file doesn't reorder - * the BMesh's elements */ - BKE_sculptsession_bm_to_me(ob, false); + /* Don't allow flushing while in the middle of a stroke (frees data in use). + * Auto-save prevents this from happening but scripts may cause a flush on saving: T53986. */ + if ((ob->sculpt && ob->sculpt->cache) == 0) { + /* flush multires changes (for sculpt) */ + multires_force_update(ob); + has_edited = true; + + if (for_render) { + /* flush changes from dynamic topology sculpt */ + BKE_sculptsession_bm_to_me_for_render(ob); + } + else { + /* Set reorder=false so that saving the file doesn't reorder + * the BMesh's elements */ + BKE_sculptsession_bm_to_me(ob, false); + } } } else if (ob->mode & OB_MODE_EDIT) { diff --git a/source/blender/editors/util/editmode_undo.c b/source/blender/editors/util/editmode_undo.c deleted file mode 100644 index d9f777771a8..00000000000 --- a/source/blender/editors/util/editmode_undo.c +++ /dev/null @@ -1,361 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2004 Blender Foundation - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/util/editmode_undo.c - * \ingroup edutil - */ - -#include <stdlib.h> -#include <string.h> -#include <math.h> - -#include "MEM_guardedalloc.h" - -#include "DNA_object_types.h" - -#include "BLI_blenlib.h" -#include "BLI_utildefines.h" - -#include "BKE_blender_undo.h" -#include "BKE_context.h" -#include "BKE_global.h" - -#include "DEG_depsgraph.h" - -#include "ED_util.h" -#include "ED_mesh.h" - - -#include "util_intern.h" - -/* ***************** generic editmode undo system ********************* */ -/* - * Add this in your local code: - * - * void undo_editmode_push(bContext *C, const char *name, - * void * (*getdata)(bContext *C), // use context to retrieve current editdata - * void (*freedata)(void *), // pointer to function freeing data - * void (*to_editmode)(void *, void *), // data to editmode conversion - * void * (*from_editmode)(void *)) // editmode to data conversion - * int (*validate_undo)(void *, void *)) // check if undo data is still valid - * - * - * Further exported for UI is: - * - * void undo_editmode_step(bContext *C, int step); // undo and redo - * void undo_editmode_clear(void) // free & clear all data - * void undo_editmode_menu(void) // history menu - */ - -/* ********************************************************************* */ - -/* ****** XXX ***** */ -static void error(const char *UNUSED(arg)) {} -/* ****** XXX ***** */ - -typedef struct UndoElem { - struct UndoElem *next, *prev; - ID id; // copy of editmode object ID - Object *ob; // pointer to edited object - int type; // type of edited object - void *undodata; - uintptr_t undosize; - char name[BKE_UNDO_STR_MAX]; - void * (*getdata)(bContext * C); - void (*freedata)(void *); - void (*to_editmode)(void *, void *, void *); - void * (*from_editmode)(void *, void *); - int (*validate_undo)(void *, void *); -} UndoElem; - -static ListBase undobase = {NULL, NULL}; -static UndoElem *curundo = NULL; - - -/* ********************* xtern api calls ************* */ - -static void undo_restore(UndoElem *undo, void *editdata, void *obdata) -{ - if (undo) { - undo->to_editmode(undo->undodata, editdata, obdata); - } -} - -/* name can be a dynamic string */ -void undo_editmode_push(bContext *C, const char *name, - void * (*getdata)(bContext * C), - void (*freedata)(void *), - void (*to_editmode)(void *, void *, void *), - void *(*from_editmode)(void *, void *), - int (*validate_undo)(void *, void *)) -{ - UndoElem *uel; - Object *obedit = CTX_data_edit_object(C); - void *editdata; - int nr; - uintptr_t memused, totmem, maxmem; - - /* at first here was code to prevent an "original" key to be inserted twice - * this was giving conflicts for example when mesh changed due to keys or apply */ - - /* remove all undos after (also when curundo == NULL) */ - while (undobase.last != curundo) { - uel = undobase.last; - uel->freedata(uel->undodata); - BLI_freelinkN(&undobase, uel); - } - - /* make new */ - curundo = uel = MEM_callocN(sizeof(UndoElem), "undo editmode"); - BLI_strncpy(uel->name, name, sizeof(uel->name)); - BLI_addtail(&undobase, uel); - - uel->getdata = getdata; - uel->freedata = freedata; - uel->to_editmode = to_editmode; - uel->from_editmode = from_editmode; - uel->validate_undo = validate_undo; - - /* limit amount to the maximum amount*/ - nr = 0; - uel = undobase.last; - while (uel) { - nr++; - if (nr == U.undosteps) break; - uel = uel->prev; - } - if (uel) { - while (undobase.first != uel) { - UndoElem *first = undobase.first; - first->freedata(first->undodata); - BLI_freelinkN(&undobase, first); - } - } - - /* copy */ - memused = MEM_get_memory_in_use(); - editdata = getdata(C); - curundo->undodata = curundo->from_editmode(editdata, obedit->data); - curundo->undosize = MEM_get_memory_in_use() - memused; - curundo->ob = obedit; - curundo->id = obedit->id; - curundo->type = obedit->type; - - if (U.undomemory != 0) { - /* limit to maximum memory (afterwards, we can't know in advance) */ - totmem = 0; - maxmem = ((uintptr_t)U.undomemory) * 1024 * 1024; - - uel = undobase.last; - while (uel && uel->prev) { - totmem += uel->undosize; - if (totmem > maxmem) break; - uel = uel->prev; - } - - if (uel) { - if (uel->prev && uel->prev->prev) - uel = uel->prev; - - while (undobase.first != uel) { - UndoElem *first = undobase.first; - first->freedata(first->undodata); - BLI_freelinkN(&undobase, first); - } - } - } -} - -/* helper to remove clean other objects from undo stack */ -static void undo_clean_stack(bContext *C) -{ - UndoElem *uel, *next; - Object *obedit = CTX_data_edit_object(C); - - /* global undo changes pointers, so we also allow identical names */ - /* side effect: when deleting/renaming object and start editing new one with same name */ - - uel = undobase.first; - while (uel) { - void *editdata = uel->getdata(C); - bool is_valid = false; - next = uel->next; - - /* for when objects are converted, renamed, or global undo changes pointers... */ - if (uel->type == obedit->type) { - if (STREQ(uel->id.name, obedit->id.name)) { - if (uel->validate_undo == NULL) - is_valid = true; - else if (uel->validate_undo(uel->undodata, editdata)) - is_valid = true; - } - } - if (is_valid) - uel->ob = obedit; - else { - if (uel == curundo) - curundo = NULL; - - uel->freedata(uel->undodata); - BLI_freelinkN(&undobase, uel); - } - - uel = next; - } - - if (curundo == NULL) curundo = undobase.last; -} - -/* 1 = an undo, -1 is a redo. we have to make sure 'curundo' remains at current situation */ -void undo_editmode_step(bContext *C, int step) -{ - Object *obedit = CTX_data_edit_object(C); - - /* prevent undo to happen on wrong object, stack can be a mix */ - undo_clean_stack(C); - - if (step == 0) { - undo_restore(curundo, curundo->getdata(C), obedit->data); - } - else if (step == 1) { - - if (curundo == NULL || curundo->prev == NULL) { - error("No more steps to undo"); - } - else { - if (G.debug & G_DEBUG) printf("undo %s\n", curundo->name); - curundo = curundo->prev; - undo_restore(curundo, curundo->getdata(C), obedit->data); - } - } - else { - /* curundo has to remain current situation! */ - - if (curundo == NULL || curundo->next == NULL) { - error("No more steps to redo"); - } - else { - undo_restore(curundo->next, curundo->getdata(C), obedit->data); - curundo = curundo->next; - if (G.debug & G_DEBUG) printf("redo %s\n", curundo->name); - } - } - - /* special case for editmesh, mode must be copied back to the scene */ - if (obedit->type == OB_MESH) { - EDBM_selectmode_to_scene(C); - } - - DEG_id_tag_update(&obedit->id, OB_RECALC_DATA); - - /* XXX notifiers */ -} - -void undo_editmode_clear(void) -{ - UndoElem *uel; - - uel = undobase.first; - while (uel) { - uel->freedata(uel->undodata); - uel = uel->next; - } - BLI_freelistN(&undobase); - curundo = NULL; -} - -/* based on index nr it does a restore */ -void undo_editmode_number(bContext *C, int nr) -{ - UndoElem *uel; - int a = 1; - - for (uel = undobase.first; uel; uel = uel->next, a++) { - if (a == nr) break; - } - curundo = uel; - undo_editmode_step(C, 0); -} - -void undo_editmode_name(bContext *C, const char *undoname) -{ - UndoElem *uel; - - for (uel = undobase.last; uel; uel = uel->prev) { - if (STREQ(undoname, uel->name)) - break; - } - if (uel && uel->prev) { - curundo = uel->prev; - undo_editmode_step(C, 0); - } -} - -/* undoname optionally, if NULL it just checks for existing undo steps */ -bool undo_editmode_is_valid(const char *undoname) -{ - if (undoname) { - UndoElem *uel; - - for (uel = undobase.last; uel; uel = uel->prev) { - if (STREQ(undoname, uel->name)) - break; - } - return uel != NULL; - } - return undobase.last != undobase.first; -} - - -/* get name of undo item, return null if no item with this index */ -/* if active pointer, set it to 1 if true */ -const char *undo_editmode_get_name(bContext *C, int nr, bool *r_active) -{ - UndoElem *uel; - - /* prevent wrong numbers to be returned */ - undo_clean_stack(C); - - if (r_active) *r_active = false; - - uel = BLI_findlink(&undobase, nr); - if (uel) { - if (r_active && (uel == curundo)) { - *r_active = true; - } - return uel->name; - } - return NULL; -} - - -void *undo_editmode_get_prev(Object *ob) -{ - UndoElem *ue = undobase.last; - if (ue && ue->prev && ue->prev->ob == ob) return ue->prev->undodata; - return NULL; -} diff --git a/source/blender/editors/util/numinput.c b/source/blender/editors/util/numinput.c index 0f3240946fd..a139f0e3c87 100644 --- a/source/blender/editors/util/numinput.c +++ b/source/blender/editors/util/numinput.c @@ -478,9 +478,9 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event) /* At this point, our value has changed, try to interpret it with python (if str is not empty!). */ if (n->str[0]) { const float val_prev = n->val[idx]; + double val; #ifdef WITH_PYTHON Scene *sce = CTX_data_scene(C); - double val; char str_unit_convert[NUM_STR_REP_LEN * 6]; /* Should be more than enough! */ const char *default_unit = NULL; @@ -506,8 +506,9 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event) n->val_flag[idx] |= NUM_INVALID; } #else /* Very unlikely, but does not harm... */ - n->val[idx] = (float)atof(n->str); - (void)C; + val = atof(n->str); + n->val[idx] = (float)val; + UNUSED_VARS(C); #endif /* WITH_PYTHON */ if (n->val_flag[idx] & NUM_NEGATE) { diff --git a/source/blender/editors/uvedit/uvedit_buttons.c b/source/blender/editors/uvedit/uvedit_buttons.c index 6b4dd0f0210..f037783bd5e 100644 --- a/source/blender/editors/uvedit/uvedit_buttons.c +++ b/source/blender/editors/uvedit/uvedit_buttons.c @@ -61,7 +61,7 @@ /* UV Utilities */ -static int uvedit_center(Scene *scene, BMEditMesh *em, Image *ima, float center[2]) +static int uvedit_center(Scene *scene, Object *obedit, BMEditMesh *em, Image *ima, float center[2]) { BMFace *f; BMLoop *l; @@ -73,7 +73,7 @@ static int uvedit_center(Scene *scene, BMEditMesh *em, Image *ima, float center[ zero_v2(center); BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, ima, f)) + if (!uvedit_face_visible_test(scene, obedit, ima, f)) continue; BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { @@ -93,7 +93,7 @@ static int uvedit_center(Scene *scene, BMEditMesh *em, Image *ima, float center[ return tot; } -static void uvedit_translate(Scene *scene, BMEditMesh *em, Image *ima, float delta[2]) +static void uvedit_translate(Scene *scene, Object *obedit, BMEditMesh *em, Image *ima, float delta[2]) { BMFace *f; BMLoop *l; @@ -103,7 +103,7 @@ static void uvedit_translate(Scene *scene, BMEditMesh *em, Image *ima, float del const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, ima, f)) + if (!uvedit_face_visible_test(scene, obedit, ima, f)) continue; BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { @@ -134,7 +134,7 @@ static void uvedit_vertex_buttons(const bContext *C, uiBlock *block) em = BKE_editmesh_from_object(obedit); - if (uvedit_center(scene, em, ima, center)) { + if (uvedit_center(scene, obedit, em, ima, center)) { float range_xy[2][2] = { {-10.0f, 10.0f}, {-10.0f, 10.0f}, @@ -190,7 +190,7 @@ static void do_uvedit_vertex(bContext *C, void *UNUSED(arg), int event) em = BKE_editmesh_from_object(obedit); ED_space_image_get_size(sima, &imx, &imy); - uvedit_center(scene, em, ima, center); + uvedit_center(scene, obedit, em, ima, center); if (sima->flag & SI_COORDFLOATS) { delta[0] = uvedit_old_center[0] - center[0]; @@ -201,7 +201,7 @@ static void do_uvedit_vertex(bContext *C, void *UNUSED(arg), int event) delta[1] = uvedit_old_center[1] / imy - center[1]; } - uvedit_translate(scene, em, ima, delta); + uvedit_translate(scene, obedit, em, ima, delta); WM_event_add_notifier(C, NC_IMAGE, sima->image); } diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index f882f3ecd65..3fcc89d0973 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -59,6 +59,7 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" +#include "GPU_batch.h" #include "GPU_immediate.h" #include "GPU_immediate_util.h" #include "GPU_matrix.h" @@ -73,7 +74,7 @@ #include "uvedit_intern.h" -static void draw_uvs_lineloop_bmface(BMFace *efa, const int cd_loop_uv_offset, const uint shdr_pos); +static void draw_uvs_lineloop_bmfaces(BMesh *bm, const int cd_loop_uv_offset, const uint shdr_pos); void ED_image_draw_cursor(ARegion *ar, const float cursor[2]) { @@ -160,8 +161,6 @@ static void draw_uvs_shadow(Object *obedit) { BMEditMesh *em = BKE_editmesh_from_object(obedit); BMesh *bm = em->bm; - BMFace *efa; - BMIter iter; const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); @@ -172,14 +171,12 @@ static void draw_uvs_shadow(Object *obedit) /* draws the mesh when painting */ immUniformThemeColor(TH_UV_SHADOW); - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset, pos); - } + draw_uvs_lineloop_bmfaces(bm, cd_loop_uv_offset, pos); immUnbindProgram(); } -static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, const BMFace *efa_act) +static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, Object *obedit, BMEditMesh *em, const BMFace *efa_act) { BMesh *bm = em->bm; BMFace *efa; @@ -217,7 +214,7 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, con totarea += BM_face_calc_area(efa); totuvarea += area_poly_v2(tf_uv, efa->len); - if (uvedit_face_visible_test(scene, ima, efa)) { + if (uvedit_face_visible_test(scene, obedit, ima, efa)) { BM_elem_flag_enable(efa, BM_ELEM_TAG); } else { @@ -314,7 +311,7 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, con immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - if (uvedit_face_visible_test(scene, ima, efa)) { + if (uvedit_face_visible_test(scene, obedit, ima, efa)) { const int efa_len = efa->len; float (*tf_uv)[2] = (float (*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa_len); float (*tf_uvorig)[2] = (float (*)[2])BLI_buffer_reinit_data(&tf_uvorig_buf, vec2f, efa_len); @@ -384,18 +381,43 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, con BLI_buffer_free(&tf_uvorig_buf); } -static void draw_uvs_lineloop_bmface(BMFace *efa, const int cd_loop_uv_offset, const uint shdr_pos) +static void draw_uvs_lineloop_bmfaces(BMesh *bm, const int cd_loop_uv_offset, const uint shdr_pos) { - BMIter liter; + BMIter iter, liter; + BMFace *efa; BMLoop *l; MLoopUV *luv; - immBegin(GWN_PRIM_LINE_LOOP, efa->len); + /* For more efficiency first transfer the entire buffer to vram. */ + Gwn_Batch *uv_batch = immBeginBatchAtMost(GWN_PRIM_LINE_LOOP, bm->totloop); + + BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) + continue; + + BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + immVertex2fv(shdr_pos, luv->uv); + } + } + immEnd(); - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - immVertex2fv(shdr_pos, luv->uv); + /* Then draw each face contour separately. */ + GWN_batch_program_use_begin(uv_batch); + unsigned int index = 0; + BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) + continue; + + GWN_batch_draw_range_ex(uv_batch, index, efa->len, false); + index += efa->len; } + GWN_batch_program_use_end(uv_batch); + + GWN_vertbuf_discard(uv_batch->verts[0]); + GWN_batch_discard(uv_batch); + + immUnbindProgram(); immEnd(); } @@ -615,7 +637,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje BMLoop *l; BMIter iter, liter; MLoopUV *luv; - unsigned char col1[4], col2[4]; + float col1[4], col2[4]; float pointsize; int drawfaces, interpedges; Image *ima = sima->image; @@ -669,12 +691,12 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje /* 2. draw colored faces */ if (sima->flag & SI_DRAW_STRETCH) { - draw_uvs_stretch(sima, scene, em, efa_act); + draw_uvs_stretch(sima, scene, obedit, em, efa_act); } else { unsigned int tri_count = 0; BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { - if (uvedit_face_visible_test(scene, ima, efa)) { + if (uvedit_face_visible_test(scene, obedit, ima, efa)) { BM_elem_flag_enable(efa, BM_ELEM_TAG); tri_count += efa->len - 2; } @@ -683,16 +705,16 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje } } - if (!(sima->flag & SI_NO_DRAWFACES)) { + if (tri_count && !(sima->flag & SI_NO_DRAWFACES)) { /* draw transparent faces */ - UI_GetThemeColor4ubv(TH_FACE, col1); - UI_GetThemeColor4ubv(TH_FACE_SELECT, col2); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + UI_GetThemeColor4fv(TH_FACE, col1); + UI_GetThemeColor4fv(TH_FACE_SELECT, col2); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); Gwn_VertFormat *format = immVertexFormat(); pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT); + color = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 4, GWN_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); @@ -704,12 +726,12 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje if (efa == efa_act) { /* only once */ - unsigned char tmp_col[4]; - UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, tmp_col); - immAttrib4ubv(color, tmp_col); + float tmp_col[4]; + UI_GetThemeColor4fv(TH_EDITMESH_ACTIVE, tmp_col); + immAttrib4fv(color, tmp_col); } else { - immAttrib4ubv(color, is_select ? col2 : col1); + immAttrib4fv(color, is_select ? col2 : col1); } draw_uvs_looptri(em, &i, cd_loop_uv_offset, pos); @@ -722,7 +744,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje glDisable(GL_BLEND); } else { - if (efa_act && !uvedit_face_visible_test(scene, ima, efa_act)) { + if (efa_act && !uvedit_face_visible_test(scene, obedit, ima, efa_act)) { efa_act = NULL; } } @@ -736,16 +758,14 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje if (sima->flag & SI_SMOOTH_UV) { glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } - glLineWidth(1); + pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); switch (sima->dt_uv) { case SI_UVDT_DASH: { - const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); float viewport_size[4]; @@ -755,141 +775,160 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje immUniform1i("num_colors", 2); /* "advanced" mode */ immUniformArray4fv("colors", (float *)(float[][4]){{0.56f, 0.56f, 0.56f, 1.0f}, {0.07f, 0.07f, 0.07f, 1.0f}}, 2); immUniform1f("dash_width", 4.0f); - - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) - continue; - - draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset, shdr_pos); - } - - immUnbindProgram(); + glLineWidth(1.0f); break; } case SI_UVDT_BLACK: /* black/white */ case SI_UVDT_WHITE: - pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - if (sima->dt_uv == SI_UVDT_WHITE) { immUniformColor3f(1.0f, 1.0f, 1.0f); } else { immUniformColor3f(0.0f, 0.0f, 0.0f); } - - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) - continue; - - draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset, pos); - } - - immUnbindProgram(); + glLineWidth(1.0f); break; case SI_UVDT_OUTLINE: - pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - - glLineWidth(3); imm_cpack(0x0); + glLineWidth(3.0f); - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) - continue; + break; + } - draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset, pos); - } + /* For more efficiency first transfer the entire buffer to vram. */ + Gwn_Batch *uv_batch = immBeginBatchAtMost(GWN_PRIM_LINE_LOOP, bm->totloop); + Gwn_VertBuf* uv_vbo = uv_batch->verts[0]; + BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) + continue; - immUnbindProgram(); + BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + immVertex2fv(pos, luv->uv); + } + } + immEnd(); - glLineWidth(1); - UI_GetThemeColor4ubv(TH_WIRE_EDIT, col2); + /* Then draw each face contour separately. */ + GWN_batch_program_use_begin(uv_batch); + unsigned int index = 0, vbo_len_used; + BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) + continue; - if (me->drawflag & ME_DRAWEDGES) { - int sel; - UI_GetThemeColor4ubv(TH_EDGE_SELECT, col1); + GWN_batch_draw_range_ex(uv_batch, index, efa->len, false); + index += efa->len; + } + vbo_len_used = index; + GWN_batch_program_use_end(uv_batch); + immUnbindProgram(); - Gwn_VertFormat *format = immVertexFormat(); - pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT); - if (interpedges) { - immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); + if (sima->dt_uv == SI_UVDT_OUTLINE) { + glLineWidth(1.0f); + UI_GetThemeColor4fv(TH_WIRE_EDIT, col2); - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) - continue; + if (me->drawflag & ME_DRAWEDGES) { + int sel; + UI_GetThemeColor4fv(TH_EDGE_SELECT, col1); - immBegin(GWN_PRIM_LINE_LOOP, efa->len); + if (interpedges) { + /* Create a color buffer. */ + static Gwn_VertFormat format = {0}; + static uint shdr_col; + if (format.attrib_ct == 0) { + shdr_col = GWN_vertformat_attr_add(&format, "color", GWN_COMP_F32, 4, GWN_FETCH_FLOAT); + } - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - sel = uvedit_uv_select_test(scene, l, cd_loop_uv_offset); - immAttrib4ubv(color, sel ? (GLubyte *)col1 : (GLubyte *)col2); + Gwn_VertBuf *vbo_col = GWN_vertbuf_create_with_format(&format); + GWN_vertbuf_data_alloc(vbo_col, vbo_len_used); - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - immVertex2fv(pos, luv->uv); - } + index = 0; + BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) + continue; - immEnd(); + BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) { + sel = uvedit_uv_select_test(scene, l, cd_loop_uv_offset); + GWN_vertbuf_attr_set(vbo_col, shdr_col, index++, sel ? col1 : col2); } - - immUnbindProgram(); } - else { - immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + /* Reuse the UV buffer and add the color buffer. */ + GWN_batch_vertbuf_add_ex(uv_batch, vbo_col, true); - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - int lastsel = -1; + /* Now draw each face contour separately with another builtin program. */ + GWN_batch_program_set_builtin(uv_batch, GPU_SHADER_2D_SMOOTH_COLOR); + gpuBindMatrices(uv_batch->interface); - if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) - continue; - - immBegin(GWN_PRIM_LINES, efa->len * 2); - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - sel = uvedit_edge_select_test(scene, l, cd_loop_uv_offset); - if (sel != lastsel) { - immAttrib4ubv(color, sel ? (GLubyte *)col1 : (GLubyte *)col2); - lastsel = sel; - } - - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - immVertex2fv(pos, luv->uv); - luv = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); - immVertex2fv(pos, luv->uv); - } - - immEnd(); - } + GWN_batch_program_use_begin(uv_batch); + index = 0; + BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) + continue; - immUnbindProgram(); + GWN_batch_draw_range_ex(uv_batch, index, efa->len, false); + index += efa->len; } + GWN_batch_program_use_end(uv_batch); } else { - pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + Gwn_VertFormat *format = immVertexFormat(); + pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + color = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 4, GWN_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformColor4ubv(col2); + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); - /* no nice edges */ + /* Use batch here to avoid problems with `IMM_BUFFER_SIZE`. */ + Gwn_Batch *flat_edges_batch = immBeginBatchAtMost(GWN_PRIM_LINES, vbo_len_used * 2); BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) continue; - - draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset, pos); + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + sel = uvedit_edge_select_test(scene, l, cd_loop_uv_offset); + immAttrib4fv(color, sel ? col1 : col2); + + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + immVertex2fv(pos, luv->uv); + luv = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); + immVertex2fv(pos, luv->uv); + } } + immEnd(); + + GWN_batch_draw(flat_edges_batch); + GWN_vertbuf_discard(flat_edges_batch->verts[0]); + GWN_batch_discard(flat_edges_batch); immUnbindProgram(); } + } + else { + GWN_batch_uniform_4fv(uv_batch, "color", col2); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - break; + /* no nice edges */ + GWN_batch_program_use_begin(uv_batch); + index = 0; + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) + continue; + + GWN_batch_draw_range_ex(uv_batch, index, efa->len, false); + index += efa->len; + } + GWN_batch_program_use_end(uv_batch); + immUnbindProgram(); + } } + GWN_vertbuf_discard(uv_vbo); + GWN_batch_discard(uv_batch); + if (sima->flag & SI_SMOOTH_UV) { glDisable(GL_LINE_SMOOTH); glDisable(GL_BLEND); @@ -903,7 +942,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje Gwn_VertFormat *format = immVertexFormat(); pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT); + color = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); @@ -921,8 +960,8 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje if (!uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { /* Only set color for the first face */ if (!col_set) { - UI_GetThemeColor3ubv(TH_WIRE, col1); - immAttrib3ubv(color, col1); + UI_GetThemeColor3fv(TH_WIRE, col1); + immAttrib3fv(color, col1); col_set = true; } @@ -943,8 +982,8 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje if (uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { /* Only set color for the first face */ if (!col_set) { - UI_GetThemeColor3ubv(TH_FACE_DOT, col1); - immAttrib3ubv(color, col1); + UI_GetThemeColor3fv(TH_FACE_DOT, col1); + immAttrib3fv(color, col1); col_set = true; } @@ -1032,7 +1071,9 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje } -static void draw_uv_shadows_get(SpaceImage *sima, Object *ob, Object *obedit, bool *show_shadow, bool *show_texpaint) +static void draw_uv_shadows_get( + SpaceImage *sima, Object *ob, Object *obedit, + bool *show_shadow, bool *show_texpaint) { *show_shadow = *show_texpaint = false; @@ -1048,7 +1089,9 @@ static void draw_uv_shadows_get(SpaceImage *sima, Object *ob, Object *obedit, bo *show_texpaint = (ob && ob->type == OB_MESH && ob->mode == OB_MODE_TEXTURE_PAINT); } -void ED_uvedit_draw_main(SpaceImage *sima, ARegion *ar, Scene *scene, ViewLayer *view_layer, Object *obedit, Object *obact, Depsgraph *depsgraph) +void ED_uvedit_draw_main( + SpaceImage *sima, + ARegion *ar, Scene *scene, ViewLayer *view_layer, Object *obedit, Object *obact, Depsgraph *depsgraph) { ToolSettings *toolsettings = scene->toolsettings; bool show_uvedit, show_uvshadow, show_texpaint_uvshadow; diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h index 6ca46941404..c5f16d6fb14 100644 --- a/source/blender/editors/uvedit/uvedit_intern.h +++ b/source/blender/editors/uvedit/uvedit_intern.h @@ -50,17 +50,30 @@ void uv_poly_center(struct BMFace *f, float r_cent[2], const int cd_loop_uv_off /* find nearest */ -typedef struct NearestHit { +typedef struct UvNearestHit { + /** Always set if we have a hit. */ struct BMFace *efa; struct BMLoop *l; struct MLoopUV *luv, *luv_next; - int lindex; /* index of loop within face */ -} NearestHit; + /** Index of loop within face. */ + int lindex; + /** Needs to be set before calling nearest functions. */ + float dist_sq; +} UvNearestHit; -void uv_find_nearest_vert(struct Scene *scene, struct Image *ima, struct BMEditMesh *em, - const float co[2], const float penalty[2], struct NearestHit *hit); -void uv_find_nearest_edge(struct Scene *scene, struct Image *ima, struct BMEditMesh *em, - const float co[2], struct NearestHit *hit); +#define UV_NEAREST_HIT_INIT { .dist_sq = FLT_MAX, } + +bool uv_find_nearest_vert( + struct Scene *scene, struct Image *ima, struct Object *obedit, + const float co[2], const float penalty_dist, struct UvNearestHit *hit_final); + +bool uv_find_nearest_edge( + struct Scene *scene, struct Image *ima, struct Object *obedit, + const float co[2], struct UvNearestHit *hit_final); + +bool uv_find_nearest_face( + struct Scene *scene, struct Image *ima, struct Object *obedit, + const float co[2], struct UvNearestHit *hit_final); /* utility tool functions */ diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 03a5f4dddc8..9df0c7c89ed 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -49,7 +49,7 @@ #include "BLI_utildefines.h" #include "BLI_alloca.h" #include "BLI_math.h" -#include "BLI_lasso.h" +#include "BLI_lasso_2d.h" #include "BLI_blenlib.h" #include "BLI_array.h" @@ -89,11 +89,13 @@ #include "uvedit_intern.h" -static void uv_select_all_perform(Scene *scene, Image *ima, BMEditMesh *em, int action); +static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, int action); static void uv_select_flush_from_tag_face(SpaceImage *sima, Scene *scene, Object *obedit, const bool select); static void uv_select_flush_from_tag_loop(SpaceImage *sima, Scene *scene, Object *obedit, const bool select); -/************************* state testing ************************/ +/* -------------------------------------------------------------------- */ +/** \name State Testing + * \{ */ bool ED_uvedit_test(Object *obedit) { @@ -134,15 +136,21 @@ static int UNUSED_FUNCTION(ED_operator_uvmap_mesh) (bContext *C) return 0; } -/**************************** object active image *****************************/ + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Object Active Image + * \{ */ static bool is_image_texture_node(bNode *node) { return ELEM(node->type, SH_NODE_TEX_IMAGE, SH_NODE_TEX_ENVIRONMENT); } -bool ED_object_get_active_image(Object *ob, int mat_nr, - Image **r_ima, ImageUser **r_iuser, bNode **r_node, bNodeTree **r_ntree) +bool ED_object_get_active_image( + Object *ob, int mat_nr, + Image **r_ima, ImageUser **r_iuser, bNode **r_node, bNodeTree **r_ntree) { Material *ma = give_current_material(ob, mat_nr); bNodeTree *ntree = (ma && ma->use_nodes) ? ma->nodetree : NULL; @@ -175,7 +183,11 @@ void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *i } } -/************************* assign image ************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Assign Image + * \{ */ //#define USE_SWITCH_ASPECT @@ -230,7 +242,7 @@ void ED_uvedit_assign_image(Main *UNUSED(bmain), Scene *scene, Object *obedit, I /* now assign to all visible faces */ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (uvedit_face_visible_test(scene, previma, efa) && + if (uvedit_face_visible_test(scene, obedit, previma, efa) && (selected == true || uvedit_face_select_test(scene, efa, cd_loop_uv_offset))) { #ifdef USE_SWITCH_ASPECT @@ -266,7 +278,11 @@ void ED_uvedit_assign_image(Main *UNUSED(bmain), Scene *scene, Object *obedit, I } -/*********************** space conversion *********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Space Conversion + * \{ */ static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist) { @@ -284,7 +300,26 @@ static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist dist[1] = pixeldist / height; } -/*************** visibility and selection utilities **************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Visibility and Selection Utilities + * \{ */ + +static void uvedit_vertex_select_tagged(BMEditMesh *em, Scene *scene, bool select, int cd_loop_uv_offset) +{ + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + } + } + } +} bool uvedit_face_visible_nolocal(Scene *scene, BMFace *efa) { @@ -296,12 +331,12 @@ bool uvedit_face_visible_nolocal(Scene *scene, BMFace *efa) return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0 && BM_elem_flag_test(efa, BM_ELEM_SELECT)); } -bool uvedit_face_visible_test(Scene *scene, Image *ima, BMFace *efa) +bool uvedit_face_visible_test(Scene *scene, Object *obedit, Image *ima, BMFace *efa) { ToolSettings *ts = scene->toolsettings; if (ts->uv_flag & UV_SHOW_SAME_IMAGE) { - const Image *face_image = BKE_object_material_edit_image_get(scene->obedit, efa->mat_nr); + const Image *face_image = BKE_object_material_edit_image_get(obedit, efa->mat_nr); return (face_image == ima) ? uvedit_face_visible_nolocal(scene, efa) : false; } else { @@ -309,8 +344,9 @@ bool uvedit_face_visible_test(Scene *scene, Image *ima, BMFace *efa) } } -bool uvedit_face_select_test(Scene *scene, BMFace *efa, - const int cd_loop_uv_offset) +bool uvedit_face_select_test( + Scene *scene, BMFace *efa, + const int cd_loop_uv_offset) { ToolSettings *ts = scene->toolsettings; if (ts->uv_flag & UV_SYNC_SELECTION) { @@ -331,8 +367,9 @@ bool uvedit_face_select_test(Scene *scene, BMFace *efa, } } -bool uvedit_face_select_set(struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa, const bool select, - const bool do_history, const int cd_loop_uv_offset) +bool uvedit_face_select_set( + struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa, const bool select, + const bool do_history, const int cd_loop_uv_offset) { if (select) { return uvedit_face_select_enable(scene, em, efa, do_history, cd_loop_uv_offset); @@ -342,8 +379,9 @@ bool uvedit_face_select_set(struct Scene *scene, struct BMEditMesh *em, struct B } } -bool uvedit_face_select_enable(Scene *scene, BMEditMesh *em, BMFace *efa, const bool do_history, - const int cd_loop_uv_offset) +bool uvedit_face_select_enable( + Scene *scene, BMEditMesh *em, BMFace *efa, const bool do_history, + const int cd_loop_uv_offset) { ToolSettings *ts = scene->toolsettings; @@ -369,8 +407,9 @@ bool uvedit_face_select_enable(Scene *scene, BMEditMesh *em, BMFace *efa, const return false; } -bool uvedit_face_select_disable(Scene *scene, BMEditMesh *em, BMFace *efa, - const int cd_loop_uv_offset) +bool uvedit_face_select_disable( + Scene *scene, BMEditMesh *em, BMFace *efa, + const int cd_loop_uv_offset) { ToolSettings *ts = scene->toolsettings; @@ -393,8 +432,9 @@ bool uvedit_face_select_disable(Scene *scene, BMEditMesh *em, BMFace *efa, return false; } -bool uvedit_edge_select_test(Scene *scene, BMLoop *l, - const int cd_loop_uv_offset) +bool uvedit_edge_select_test( + Scene *scene, BMLoop *l, + const int cd_loop_uv_offset) { ToolSettings *ts = scene->toolsettings; @@ -420,8 +460,9 @@ bool uvedit_edge_select_test(Scene *scene, BMLoop *l, } } -void uvedit_edge_select_set(BMEditMesh *em, Scene *scene, BMLoop *l, const bool select, - const bool do_history, const int cd_loop_uv_offset) +void uvedit_edge_select_set( + BMEditMesh *em, Scene *scene, BMLoop *l, const bool select, + const bool do_history, const int cd_loop_uv_offset) { if (select) { @@ -432,8 +473,9 @@ void uvedit_edge_select_set(BMEditMesh *em, Scene *scene, BMLoop *l, const bool } } -void uvedit_edge_select_enable(BMEditMesh *em, Scene *scene, BMLoop *l, const bool do_history, - const int cd_loop_uv_offset) +void uvedit_edge_select_enable( + BMEditMesh *em, Scene *scene, BMLoop *l, const bool do_history, + const int cd_loop_uv_offset) { ToolSettings *ts = scene->toolsettings; @@ -463,8 +505,9 @@ void uvedit_edge_select_enable(BMEditMesh *em, Scene *scene, BMLoop *l, const bo } } -void uvedit_edge_select_disable(BMEditMesh *em, Scene *scene, BMLoop *l, - const int cd_loop_uv_offset) +void uvedit_edge_select_disable( + BMEditMesh *em, Scene *scene, BMLoop *l, + const int cd_loop_uv_offset) { ToolSettings *ts = scene->toolsettings; @@ -490,8 +533,9 @@ void uvedit_edge_select_disable(BMEditMesh *em, Scene *scene, BMLoop *l, } } -bool uvedit_uv_select_test(Scene *scene, BMLoop *l, - const int cd_loop_uv_offset) +bool uvedit_uv_select_test( + Scene *scene, BMLoop *l, + const int cd_loop_uv_offset) { ToolSettings *ts = scene->toolsettings; @@ -507,8 +551,9 @@ bool uvedit_uv_select_test(Scene *scene, BMLoop *l, } } -void uvedit_uv_select_set(BMEditMesh *em, Scene *scene, BMLoop *l, const bool select, - const bool do_history, const int cd_loop_uv_offset) +void uvedit_uv_select_set( + BMEditMesh *em, Scene *scene, BMLoop *l, const bool select, + const bool do_history, const int cd_loop_uv_offset) { if (select) { uvedit_uv_select_enable(em, scene, l, do_history, cd_loop_uv_offset); @@ -518,8 +563,9 @@ void uvedit_uv_select_set(BMEditMesh *em, Scene *scene, BMLoop *l, const bool se } } -void uvedit_uv_select_enable(BMEditMesh *em, Scene *scene, BMLoop *l, - const bool do_history, const int cd_loop_uv_offset) +void uvedit_uv_select_enable( + BMEditMesh *em, Scene *scene, BMLoop *l, + const bool do_history, const int cd_loop_uv_offset) { ToolSettings *ts = scene->toolsettings; @@ -539,8 +585,9 @@ void uvedit_uv_select_enable(BMEditMesh *em, Scene *scene, BMLoop *l, } } -void uvedit_uv_select_disable(BMEditMesh *em, Scene *scene, BMLoop *l, - const int cd_loop_uv_offset) +void uvedit_uv_select_disable( + BMEditMesh *em, Scene *scene, BMLoop *l, + const int cd_loop_uv_offset) { ToolSettings *ts = scene->toolsettings; @@ -556,7 +603,11 @@ void uvedit_uv_select_disable(BMEditMesh *em, Scene *scene, BMLoop *l, } } -/*********************** live unwrap utilities ***********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Live Unwrap Utilities + * \{ */ void uvedit_live_unwrap_update(SpaceImage *sima, Scene *scene, Object *obedit) { @@ -567,7 +618,12 @@ void uvedit_live_unwrap_update(SpaceImage *sima, Scene *scene, Object *obedit) } } -/*********************** geometric utilities ***********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Geometric Utilities + * \{ */ + void uv_poly_center(BMFace *f, float r_cent[2], const int cd_loop_uv_offset) { BMLoop *l; @@ -607,7 +663,7 @@ bool ED_uvedit_minmax(Scene *scene, Image *ima, Object *obedit, float r_min[2], INIT_MINMAX2(r_min, r_max); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, ima, efa)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -653,7 +709,7 @@ static bool ED_uvedit_median(Scene *scene, Image *ima, Object *obedit, float co[ zero_v2(co); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, ima, efa)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -690,81 +746,100 @@ bool ED_uvedit_center(Scene *scene, Image *ima, Object *obedit, float cent[2], c return changed; } -/************************** find nearest ****************************/ +/** \} */ -void uv_find_nearest_edge(Scene *scene, Image *ima, BMEditMesh *em, const float co[2], NearestHit *hit) +/* -------------------------------------------------------------------- */ +/** \name Find Nearest Elements + * \{ */ + +bool uv_find_nearest_edge( + Scene *scene, Image *ima, Object *obedit, const float co[2], + UvNearestHit *hit) { + BMEditMesh *em = BKE_editmesh_from_object(obedit); BMFace *efa; BMLoop *l; BMIter iter, liter; MLoopUV *luv, *luv_next; - float mindist_squared, dist_squared; int i; + bool found = false; const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - mindist_squared = 1e10f; - memset(hit, 0, sizeof(*hit)); - BM_mesh_elem_index_ensure(em->bm, BM_VERT); - + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, ima, efa)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { continue; - + } BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); - dist_squared = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv); + const float dist_test_sq = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv); - if (dist_squared < mindist_squared) { + if (dist_test_sq < hit->dist_sq) { hit->efa = efa; - + hit->l = l; hit->luv = luv; hit->luv_next = luv_next; hit->lindex = i; - mindist_squared = dist_squared; + hit->dist_sq = dist_test_sq; + found = true; } } } + return found; } -static void uv_find_nearest_face(Scene *scene, Image *ima, BMEditMesh *em, const float co[2], NearestHit *hit) +bool uv_find_nearest_face( + Scene *scene, Image *ima, Object *obedit, const float co[2], + UvNearestHit *hit_final) { - BMFace *efa; - BMIter iter; - float mindist, dist, cent[2]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + bool found = false; const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - mindist = 1e10f; - memset(hit, 0, sizeof(*hit)); + /* this will fill in hit.vert1 and hit.vert2 */ + float dist_sq_init = hit_final->dist_sq; + UvNearestHit hit = *hit_final; + if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) { + hit.dist_sq = dist_sq_init; + hit.l = NULL; + hit.luv = hit.luv_next = NULL; - /*this will fill in hit.vert1 and hit.vert2*/ - uv_find_nearest_edge(scene, ima, em, co, hit); - hit->l = NULL; - hit->luv = hit->luv_next = NULL; + BMIter iter; + BMFace *efa; - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, ima, efa)) - continue; + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + continue; + } - uv_poly_center(efa, cent, cd_loop_uv_offset); + float cent[2]; + uv_poly_center(efa, cent, cd_loop_uv_offset); - dist = len_manhattan_v2v2(co, cent); + const float dist_test_sq = len_squared_v2v2(co, cent); - if (dist < mindist) { - hit->efa = efa; - mindist = dist; + if (dist_test_sq < hit.dist_sq) { + hit.efa = efa; + hit.dist_sq = dist_test_sq; + found = true; + } } } + if (found) { + *hit_final = hit; + } + return found; } -static bool uv_nearest_between(const BMLoop *l, const float co[2], - const int cd_loop_uv_offset) +static bool uv_nearest_between( + const BMLoop *l, const float co[2], + const int cd_loop_uv_offset) { const float *uv_prev = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset))->uv; const float *uv_curr = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset))->uv; @@ -774,56 +849,73 @@ static bool uv_nearest_between(const BMLoop *l, const float co[2], (line_point_side_v2(uv_next, uv_curr, co) <= 0.0f)); } -void uv_find_nearest_vert(Scene *scene, Image *ima, BMEditMesh *em, - float const co[2], const float penalty[2], NearestHit *hit) +bool uv_find_nearest_vert( + Scene *scene, Image *ima, Object *obedit, + float const co[2], const float penalty_dist, UvNearestHit *hit_final) { - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - float mindist, dist; - int i; + bool found = false; - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + /* this will fill in hit.vert1 and hit.vert2 */ + float dist_sq_init = hit_final->dist_sq; + UvNearestHit hit = *hit_final; + if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) { + hit.dist_sq = dist_sq_init; - /*this will fill in hit.vert1 and hit.vert2*/ - uv_find_nearest_edge(scene, ima, em, co, hit); - hit->l = NULL; - hit->luv = hit->luv_next = NULL; + hit.l = NULL; + hit.luv = hit.luv_next = NULL; - mindist = 1e10f; - memset(hit, 0, sizeof(*hit)); - - BM_mesh_elem_index_ensure(em->bm, BM_VERT); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMIter iter; - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, ima, efa)) - continue; + BM_mesh_elem_index_ensure(em->bm, BM_VERT); - BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (penalty && uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) - dist = len_manhattan_v2v2(co, luv->uv) + len_manhattan_v2(penalty); - else - dist = len_manhattan_v2v2(co, luv->uv); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - if (dist <= mindist) { - if (dist == mindist) { - if (!uv_nearest_between(l, co, cd_loop_uv_offset)) { - continue; - } + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + continue; + } + + BMIter liter; + BMLoop *l; + int i; + BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { + float dist_test_sq; + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if (penalty_dist != 0.0f && uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + dist_test_sq = len_v2v2(co, luv->uv) + penalty_dist; + dist_test_sq = SQUARE(dist_test_sq); + } + else { + dist_test_sq = len_squared_v2v2(co, luv->uv); } - mindist = dist; + if (dist_test_sq <= hit.dist_sq) { + if (dist_test_sq == hit.dist_sq) { + if (!uv_nearest_between(l, co, cd_loop_uv_offset)) { + continue; + } + } - hit->l = l; - hit->luv = luv; - hit->luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); - hit->efa = efa; - hit->lindex = i; + hit.dist_sq = dist_test_sq; + + hit.l = l; + hit.luv = luv; + hit.luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); + hit.efa = efa; + hit.lindex = i; + found = true; + } } } } + + if (found) { + *hit_final = hit; + } + + return found; } bool ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, const float co[2], float r_uv[2]) @@ -842,7 +934,7 @@ bool ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, const float copy_v2_v2(r_uv, co); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, ima, efa)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -861,7 +953,11 @@ bool ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, const float return found; } -/*********************** loop select ***********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Loop Select + * \{ */ static void uv_select_edgeloop_vertex_loop_flag(UvMapVert *first) { @@ -946,8 +1042,9 @@ static bool uv_select_edgeloop_edge_tag_faces(BMEditMesh *em, UvMapVert *first1, return true; } -static int uv_select_edgeloop(Scene *scene, Image *ima, BMEditMesh *em, NearestHit *hit, - const float limit[2], const bool extend) +static int uv_select_edgeloop( + Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, UvNearestHit *hit, + const float limit[2], const bool extend) { BMFace *efa; BMIter iter, liter; @@ -967,7 +1064,7 @@ static int uv_select_edgeloop(Scene *scene, Image *ima, BMEditMesh *em, NearestH BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE); if (!extend) { - uv_select_all_perform(scene, ima, em, SEL_DESELECT); + uv_select_all_perform(scene, ima, obedit, em, SEL_DESELECT); } BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); @@ -991,7 +1088,7 @@ static int uv_select_edgeloop(Scene *scene, Image *ima, BMEditMesh *em, NearestH /* find correct valence edges which are not tagged yet, but connect to tagged one */ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_TAG) && uvedit_face_visible_test(scene, ima, efa)) { + if (!BM_elem_flag_test(efa, BM_ELEM_TAG) && uvedit_face_visible_test(scene, obedit, ima, efa)) { BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { /* check face not hidden and not tagged */ if (!(iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l))) @@ -1044,9 +1141,15 @@ static int uv_select_edgeloop(Scene *scene, Image *ima, BMEditMesh *em, NearestH return (select) ? 1 : -1; } -/*********************** linked select ***********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Linked + * \{ */ -static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const float limit[2], NearestHit *hit, bool extend, bool select_faces) +static void uv_select_linked( + Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, const float limit[2], + UvNearestHit *hit_final, bool extend, bool select_faces) { BMFace *efa; BMLoop *l; @@ -1076,9 +1179,10 @@ static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const flo stack = MEM_mallocN(sizeof(*stack) * (em->bm->totface + 1), "UvLinkStack"); flag = MEM_callocN(sizeof(*flag) * em->bm->totface, "UvLinkFlag"); - if (!hit) { + if (hit_final == NULL) { + /* Use existing selection */ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) { - if (uvedit_face_visible_test(scene, ima, efa)) { + if (uvedit_face_visible_test(scene, obedit, ima, efa)) { if (select_faces) { if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { stack[stacksize] = a; @@ -1104,7 +1208,7 @@ static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const flo } else { BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) { - if (efa == hit->efa) { + if (efa == hit_final->efa) { stack[stacksize] = a; stacksize++; flag[a] = 1; @@ -1236,7 +1340,7 @@ static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const flo /* WATCH IT: this returns first selected UV, * not ideal in many cases since there could be multiple */ -static float *uv_sel_co_from_eve(Scene *scene, Image *ima, BMEditMesh *em, BMVert *eve) +static float *uv_sel_co_from_eve(Scene *scene, Object *obedit, Image *ima, BMEditMesh *em, BMVert *eve) { BMIter liter; BMLoop *l; @@ -1244,7 +1348,7 @@ static float *uv_sel_co_from_eve(Scene *scene, Image *ima, BMEditMesh *em, BMVer const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) { - if (!uvedit_face_visible_test(scene, ima, l->f)) + if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) continue; if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { @@ -1256,6 +1360,12 @@ static float *uv_sel_co_from_eve(Scene *scene, Image *ima, BMEditMesh *em, BMVer return NULL; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select More/Less Operator + * \{ */ + static int uv_select_more_less(bContext *C, const bool select) { Scene *scene = CTX_data_scene(C); @@ -1286,13 +1396,11 @@ static int uv_select_more_less(bContext *C, const bool select) if (ts->uv_selectmode == UV_SELECT_FACE) { /* clear tags */ - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - BM_elem_flag_disable(efa, BM_ELEM_TAG); - } + BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); /* mark loops to be selected */ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (uvedit_face_visible_test(scene, ima, efa)) { + if (uvedit_face_visible_test(scene, obedit, ima, efa)) { #define IS_SEL 1 #define IS_UNSEL 2 @@ -1335,7 +1443,7 @@ static int uv_select_more_less(bContext *C, const bool select) /* mark loops to be selected */ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (uvedit_face_visible_test(scene, ima, efa)) { + if (uvedit_face_visible_test(scene, obedit, ima, efa)) { BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); @@ -1393,7 +1501,11 @@ static void UV_OT_select_less(wmOperatorType *ot) ot->poll = ED_operator_uvedit_space_image; } -/* ******************** align operator **************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Weld Align Operator + * \{ */ static void uv_weld_align(bContext *C, int tool) { @@ -1418,7 +1530,7 @@ static void uv_weld_align(bContext *C, int tool) BMLoop *l; BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, ima, efa)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -1440,7 +1552,7 @@ static void uv_weld_align(bContext *C, int tool) BMLoop *l; BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, ima, efa)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -1459,7 +1571,7 @@ static void uv_weld_align(bContext *C, int tool) BMLoop *l; BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, ima, efa)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -1480,14 +1592,12 @@ static void uv_weld_align(bContext *C, int tool) BMIter iter, liter, eiter; /* clear tag */ - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - BM_elem_flag_disable(eve, BM_ELEM_TAG); - } + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); /* tag verts with a selected UV */ BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) { - if (!uvedit_face_visible_test(scene, ima, l->f)) + if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) continue; if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { @@ -1499,8 +1609,10 @@ static void uv_weld_align(bContext *C, int tool) /* flush vertex tags to edges */ BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { - BM_elem_flag_set(eed, BM_ELEM_TAG, (BM_elem_flag_test(eed->v1, BM_ELEM_TAG) && - BM_elem_flag_test(eed->v2, BM_ELEM_TAG))); + BM_elem_flag_set( + eed, BM_ELEM_TAG, + (BM_elem_flag_test(eed->v1, BM_ELEM_TAG) && + BM_elem_flag_test(eed->v2, BM_ELEM_TAG))); } /* find a vertex with only one tagged edge */ @@ -1551,11 +1663,13 @@ static void uv_weld_align(bContext *C, int tool) } /* now we have all verts, make into a line */ - if (BLI_array_count(eve_line) > 2) { + if (BLI_array_len(eve_line) > 2) { /* we know the returns from these must be valid */ - const float *uv_start = uv_sel_co_from_eve(scene, ima, em, eve_line[0]); - const float *uv_end = uv_sel_co_from_eve(scene, ima, em, eve_line[BLI_array_count(eve_line) - 1]); + const float *uv_start = uv_sel_co_from_eve( + scene, obedit, ima, em, eve_line[0]); + const float *uv_end = uv_sel_co_from_eve( + scene, obedit, ima, em, eve_line[BLI_array_len(eve_line) - 1]); /* For t & u modes */ float a = 0.0f; @@ -1573,9 +1687,9 @@ static void uv_weld_align(bContext *C, int tool) } /* go over all verts except for endpoints */ - for (i = 0; i < BLI_array_count(eve_line); i++) { + for (i = 0; i < BLI_array_len(eve_line); i++) { BM_ITER_ELEM (l, &liter, eve_line[i], BM_LOOPS_OF_VERT) { - if (!uvedit_face_visible_test(scene, ima, l->f)) + if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) continue; if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { @@ -1644,7 +1758,12 @@ static void UV_OT_align(wmOperatorType *ot) /* properties */ RNA_def_enum(ot->srna, "axis", axis_items, 'a', "Axis", "Axis to align UV locations on"); } -/* ******************** weld near operator **************** */ + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Remove Doubles Operator + * \{ */ typedef struct UVvert { MLoopUV *uv_loop; @@ -1682,9 +1801,9 @@ static int uv_remove_doubles_exec(bContext *C, wmOperator *op) MLoopUV **loop_arr = NULL; BLI_array_declare(loop_arr); - /* TODO, use qsort as with MESH_OT_remove_doubles, this isn't optimal */ + /* TODO, use kd-tree as with MESH_OT_remove_doubles, this isn't optimal */ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, ima, efa)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -1699,12 +1818,12 @@ static int uv_remove_doubles_exec(bContext *C, wmOperator *op) } } - for (uv_a_index = 0; uv_a_index < BLI_array_count(vert_arr); uv_a_index++) { + for (uv_a_index = 0; uv_a_index < BLI_array_len(vert_arr); uv_a_index++) { if (vert_arr[uv_a_index].weld == false) { float uv_min[2]; float uv_max[2]; - BLI_array_empty(loop_arr); + BLI_array_clear(loop_arr); BLI_array_append(loop_arr, vert_arr[uv_a_index].uv_loop); uv_a = vert_arr[uv_a_index].uv_loop->uv; @@ -1713,7 +1832,7 @@ static int uv_remove_doubles_exec(bContext *C, wmOperator *op) copy_v2_v2(uv_min, uv_a); vert_arr[uv_a_index].weld = true; - for (uv_b_index = uv_a_index + 1; uv_b_index < BLI_array_count(vert_arr); uv_b_index++) { + for (uv_b_index = uv_a_index + 1; uv_b_index < BLI_array_len(vert_arr); uv_b_index++) { uv_b = vert_arr[uv_b_index].uv_loop->uv; if ((vert_arr[uv_b_index].weld == false) && (len_manhattan_v2v2(uv_a, uv_b) < threshold)) @@ -1723,10 +1842,10 @@ static int uv_remove_doubles_exec(bContext *C, wmOperator *op) vert_arr[uv_b_index].weld = true; } } - if (BLI_array_count(loop_arr)) { + if (BLI_array_len(loop_arr)) { float uv_mid[2]; mid_v2_v2v2(uv_mid, uv_min, uv_max); - for (uv_b_index = 0; uv_b_index < BLI_array_count(loop_arr); uv_b_index++) { + for (uv_b_index = 0; uv_b_index < BLI_array_len(loop_arr); uv_b_index++) { copy_v2_v2(loop_arr[uv_b_index]->uv, uv_mid); } } @@ -1746,7 +1865,7 @@ static int uv_remove_doubles_exec(bContext *C, wmOperator *op) BLI_array_declare(loop_arr_unselected); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, ima, efa)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -1760,12 +1879,12 @@ static int uv_remove_doubles_exec(bContext *C, wmOperator *op) } } - for (uv_a_index = 0; uv_a_index < BLI_array_count(loop_arr); uv_a_index++) { + for (uv_a_index = 0; uv_a_index < BLI_array_len(loop_arr); uv_a_index++) { float dist_best = FLT_MAX, dist; const float *uv_best = NULL; uv_a = loop_arr[uv_a_index]->uv; - for (uv_b_index = 0; uv_b_index < BLI_array_count(loop_arr_unselected); uv_b_index++) { + for (uv_b_index = 0; uv_b_index < BLI_array_len(loop_arr_unselected); uv_b_index++) { uv_b = loop_arr_unselected[uv_b_index]->uv; dist = len_manhattan_v2v2(uv_a, uv_b); if ((dist < threshold) && (dist < dist_best)) { @@ -1805,7 +1924,12 @@ static void UV_OT_remove_doubles(wmOperatorType *ot) "Merge Distance", "Maximum distance between welded vertices", 0.0f, 1.0f); RNA_def_boolean(ot->srna, "use_unselected", 0, "Unselected", "Merge selected to other unselected vertices"); } -/* ******************** weld operator **************** */ + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Weld Near Operator + * \{ */ static int uv_weld_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -1827,10 +1951,13 @@ static void UV_OT_weld(wmOperatorType *ot) ot->poll = ED_operator_uvedit; } +/** \} */ -/* ******************** (de)select all operator **************** */ +/* -------------------------------------------------------------------- */ +/** \name (De)Select All Operator + * \{ */ -static void uv_select_all_perform(Scene *scene, Image *ima, BMEditMesh *em, int action) +static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, int action) { ToolSettings *ts = scene->toolsettings; BMFace *efa; @@ -1862,7 +1989,7 @@ static void uv_select_all_perform(Scene *scene, Image *ima, BMEditMesh *em, int if (action == SEL_TOGGLE) { action = SEL_SELECT; BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, ima, efa)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -1878,7 +2005,7 @@ static void uv_select_all_perform(Scene *scene, Image *ima, BMEditMesh *em, int BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, ima, efa)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -1909,7 +2036,7 @@ static int uv_select_all_exec(bContext *C, wmOperator *op) int action = RNA_enum_get(op->ptr, "action"); - uv_select_all_perform(scene, ima, em, action); + uv_select_all_perform(scene, ima, obedit, em, action); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); @@ -1931,9 +2058,13 @@ static void UV_OT_select_all(wmOperatorType *ot) WM_operator_properties_select_all(ot); } -/* ******************** mouse select operator **************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mouse Select Operator + * \{ */ -static bool uv_sticky_select(float *limit, int hitv[4], int v, float *hituv[4], float *uv, int sticky, int hitlen) +static bool uv_sticky_select(float *limit, int hitv[], int v, float *hituv[], float *uv, int sticky, int hitlen) { int i; @@ -1968,12 +2099,11 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo BMLoop *l; BMIter iter, liter; MLoopUV *luv; - NearestHit hit; + UvNearestHit hit = UV_NEAREST_HIT_INIT; int i, selectmode, sticky, sync, *hitv = NULL; bool select = true; int flush = 0, hitlen = 0; /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */ float limit[2], **hituv = NULL; - float penalty[2]; const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); @@ -1983,8 +2113,13 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo * shift-selecting can consider an adjacent point close enough to add to * the selection rather than de-selecting the closest. */ - uvedit_pixel_to_float(sima, limit, 0.05f); - uvedit_pixel_to_float(sima, penalty, 5.0f / (sima ? sima->zoom : 1.0f)); + float penalty_dist; + { + float penalty[2]; + uvedit_pixel_to_float(sima, limit, 0.05f); + uvedit_pixel_to_float(sima, penalty, 5.0f / (sima ? sima->zoom : 1.0f)); + penalty_dist = len_v2(penalty); + } /* retrieve operation mode */ if (ts->uv_flag & UV_SYNC_SELECTION) { @@ -2008,8 +2143,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo /* find nearest element */ if (loop) { /* find edge */ - uv_find_nearest_edge(scene, ima, em, co, &hit); - if (hit.efa == NULL) { + if (!uv_find_nearest_edge(scene, ima, obedit, co, &hit)) { return OPERATOR_CANCELLED; } @@ -2017,8 +2151,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo } else if (selectmode == UV_SELECT_VERTEX) { /* find vertex */ - uv_find_nearest_vert(scene, ima, em, co, penalty, &hit); - if (hit.efa == NULL) { + if (!uv_find_nearest_vert(scene, ima, obedit, co, penalty_dist, &hit)) { return OPERATOR_CANCELLED; } @@ -2034,8 +2167,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo } else if (selectmode == UV_SELECT_EDGE) { /* find edge */ - uv_find_nearest_edge(scene, ima, em, co, &hit); - if (hit.efa == NULL) { + if (!uv_find_nearest_edge(scene, ima, obedit, co, &hit)) { return OPERATOR_CANCELLED; } @@ -2053,11 +2185,10 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo } else if (selectmode == UV_SELECT_FACE) { /* find face */ - uv_find_nearest_face(scene, ima, em, co, &hit); - if (hit.efa == NULL) { + if (!uv_find_nearest_face(scene, ima, obedit, co, &hit)) { return OPERATOR_CANCELLED; } - + /* make active */ BM_mesh_active_face_set(em->bm, hit.efa); @@ -2074,9 +2205,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo hitlen = hit.efa->len; } else if (selectmode == UV_SELECT_ISLAND) { - uv_find_nearest_edge(scene, ima, em, co, &hit); - - if (hit.efa == NULL) { + if (!uv_find_nearest_edge(scene, ima, obedit, co, &hit)) { return OPERATOR_CANCELLED; } @@ -2089,10 +2218,10 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo /* do selection */ if (loop) { - flush = uv_select_edgeloop(scene, ima, em, &hit, limit, extend); + flush = uv_select_edgeloop(scene, ima, obedit, em, &hit, limit, extend); } else if (selectmode == UV_SELECT_ISLAND) { - uv_select_linked(scene, ima, em, limit, &hit, extend, false); + uv_select_linked(scene, ima, obedit, em, limit, &hit, extend, false); } else if (extend) { if (selectmode == UV_SELECT_VERTEX) { @@ -2127,7 +2256,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo BM_mesh_elem_index_ensure(em->bm, BM_VERT); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, ima, efa)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -2142,7 +2271,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo } else { /* deselect all */ - uv_select_all_perform(scene, ima, em, SEL_DESELECT); + uv_select_all_perform(scene, ima, obedit, em, SEL_DESELECT); if (selectmode == UV_SELECT_VERTEX) { /* select vertex */ @@ -2162,7 +2291,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo /* select sticky uvs */ if (sticky != SI_STICKY_DISABLE) { BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, ima, efa)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -2254,7 +2383,11 @@ static void UV_OT_select(wmOperatorType *ot) "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f); } -/* ******************** loop select operator **************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Loop Select Operator + * \{ */ static int uv_select_loop_exec(bContext *C, wmOperator *op) { @@ -2299,7 +2432,11 @@ static void UV_OT_select_loop(wmOperatorType *ot) "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f); } -/* ******************** linked select operator **************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Linked Operator + * \{ */ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent *event, int pick) { @@ -2313,7 +2450,7 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent int extend; bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE); - NearestHit hit, *hit_p = NULL; + UvNearestHit hit = UV_NEAREST_HIT_INIT; if ((ts->uv_flag & UV_SYNC_SELECTION) && !(ts->selectmode & SCE_SELECT_FACE)) { BKE_report(op->reports, RPT_ERROR, "Select linked only works in face select mode when sync selection is enabled"); @@ -2338,11 +2475,12 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent RNA_float_get_array(op->ptr, "location", co); } - uv_find_nearest_edge(scene, ima, em, co, &hit); - hit_p = &hit; + if (!uv_find_nearest_edge(scene, ima, obedit, co, &hit)) { + return OPERATOR_CANCELLED; + } } - uv_select_linked(scene, ima, em, limit, hit_p, extend, select_faces); + uv_select_linked(scene, ima, obedit, em, limit, pick ? &hit : NULL, extend, select_faces); DEG_id_tag_update(obedit->data, 0); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); @@ -2434,7 +2572,7 @@ static int uv_select_split_exec(bContext *C, wmOperator *op) bool is_sel = false; bool is_unsel = false; - if (!uvedit_face_visible_test(scene, ima, efa)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; /* are we all selected? */ @@ -2506,17 +2644,21 @@ static void uv_select_sync_flush(ToolSettings *ts, BMEditMesh *em, const short s } } - +/** \} */ /* -------------------------------------------------------------------- */ -/* Utility functions to flush the uv-selection from tags */ +/** \name Select/Tag Flushing Utils + * + * Utility functions to flush the uv-selection from tags. + * \{ */ /** * helper function for #uv_select_flush_from_tag_loop and uv_select_flush_from_tag_face */ -static void uv_select_flush_from_tag_sticky_loc_internal(Scene *scene, BMEditMesh *em, UvVertMap *vmap, - const unsigned int efa_index, BMLoop *l, - const bool select, const int cd_loop_uv_offset) +static void uv_select_flush_from_tag_sticky_loc_internal( + Scene *scene, BMEditMesh *em, UvVertMap *vmap, + const unsigned int efa_index, BMLoop *l, + const bool select, const int cd_loop_uv_offset) { UvMapVert *start_vlist = NULL, *vlist_iter; BMFace *efa_vlist; @@ -2580,12 +2722,8 @@ static void uv_select_flush_from_tag_face(SpaceImage *sima, Scene *scene, Object if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) { /* Tag all verts as untouched, then touch the ones that have a face center * in the loop and select all MLoopUV's that use a touched vert. */ - BMVert *eve; - - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - BM_elem_flag_disable(eve, BM_ELEM_TAG); - } - + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -2623,8 +2761,9 @@ static void uv_select_flush_from_tag_face(SpaceImage *sima, Scene *scene, Object /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - uv_select_flush_from_tag_sticky_loc_internal(scene, em, vmap, efa_index, l, - select, cd_loop_uv_offset); + uv_select_flush_from_tag_sticky_loc_internal( + scene, em, vmap, efa_index, l, + select, cd_loop_uv_offset); } } } @@ -2670,11 +2809,7 @@ static void uv_select_flush_from_tag_loop(SpaceImage *sima, Scene *scene, Object if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) { /* Tag all verts as untouched, then touch the ones that have a face center * in the loop and select all MLoopUV's that use a touched vert. */ - BMVert *eve; - - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - BM_elem_flag_disable(eve, BM_ELEM_TAG); - } + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -2713,8 +2848,9 @@ static void uv_select_flush_from_tag_loop(SpaceImage *sima, Scene *scene, Object BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { if (BM_elem_flag_test(l, BM_ELEM_TAG)) { - uv_select_flush_from_tag_sticky_loc_internal(scene, em, vmap, efa_index, l, - select, cd_loop_uv_offset); + uv_select_flush_from_tag_sticky_loc_internal( + scene, em, vmap, efa_index, l, + select, cd_loop_uv_offset); } } } @@ -2732,7 +2868,11 @@ static void uv_select_flush_from_tag_loop(SpaceImage *sima, Scene *scene, Object } } -/* ******************** border select operator **************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Border Select Operator + * \{ */ static int uv_border_select_exec(bContext *C, wmOperator *op) { @@ -2749,9 +2889,10 @@ static int uv_border_select_exec(bContext *C, wmOperator *op) MLoopUV *luv; rctf rectf; bool changed, pinned, select, extend; - const bool use_face_center = (ts->uv_flag & UV_SYNC_SELECTION) ? - (ts->selectmode == SCE_SELECT_FACE) : - (ts->uv_selectmode == UV_SELECT_FACE); + const bool use_face_center = ( + (ts->uv_flag & UV_SYNC_SELECTION) ? + (ts->selectmode == SCE_SELECT_FACE) : + (ts->uv_selectmode == UV_SELECT_FACE)); const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); @@ -2765,7 +2906,7 @@ static int uv_border_select_exec(bContext *C, wmOperator *op) pinned = RNA_boolean_get(op->ptr, "pinned"); if (!extend) - uv_select_all_perform(scene, ima, em, SEL_DESELECT); + uv_select_all_perform(scene, ima, obedit, em, SEL_DESELECT); /* do actual selection */ if (use_face_center && !pinned) { @@ -2778,7 +2919,7 @@ static int uv_border_select_exec(bContext *C, wmOperator *op) /* assume not touched */ BM_elem_flag_disable(efa, BM_ELEM_TAG); - if (uvedit_face_visible_test(scene, ima, efa)) { + if (uvedit_face_visible_test(scene, obedit, ima, efa)) { uv_poly_center(efa, cent, cd_loop_uv_offset); if (BLI_rctf_isect_pt_v(&rectf, cent)) { BM_elem_flag_enable(efa, BM_ELEM_TAG); @@ -2795,9 +2936,10 @@ static int uv_border_select_exec(bContext *C, wmOperator *op) else { /* other selection modes */ changed = true; - + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, ima, efa)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); @@ -2807,15 +2949,21 @@ static int uv_border_select_exec(bContext *C, wmOperator *op) /* UV_SYNC_SELECTION - can't do pinned selection */ if (BLI_rctf_isect_pt_v(&rectf, luv->uv)) { uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + BM_elem_flag_enable(l->v, BM_ELEM_TAG); } } else if (pinned) { if ((luv->flag & MLOOPUV_PINNED) && BLI_rctf_isect_pt_v(&rectf, luv->uv)) { uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + BM_elem_flag_enable(l->v, BM_ELEM_TAG); } } } } + + if (sima->sticky == SI_STICKY_VERTEX) { + uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset); + } } if (changed) { @@ -2854,7 +3002,11 @@ static void UV_OT_select_border(wmOperatorType *ot) WM_operator_properties_gesture_border_select(ot); } -/* ******************** circle select operator **************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Circle Select Operator + * \{ */ static int uv_inside_circle(const float uv[2], const float offset[2], const float ellipse[2]) { @@ -2865,19 +3017,6 @@ static int uv_inside_circle(const float uv[2], const float offset[2], const floa return ((x * x + y * y) < 1.0f); } -static bool uv_select_inside_ellipse(BMEditMesh *em, Scene *scene, const bool select, - const float offset[2], const float ellipse[2], BMLoop *l, MLoopUV *luv, - const int cd_loop_uv_offset) -{ - if (uv_inside_circle(luv->uv, offset, ellipse)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - return true; - } - else { - return false; - } -} - static int uv_circle_select_exec(bContext *C, wmOperator *op) { SpaceImage *sima = CTX_wm_space_image(C); @@ -2894,9 +3033,10 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op) float zoomx, zoomy, offset[2], ellipse[2]; const bool select = !RNA_boolean_get(op->ptr, "deselect"); bool changed = false; - const bool use_face_center = (ts->uv_flag & UV_SYNC_SELECTION) ? - (ts->selectmode == SCE_SELECT_FACE) : - (ts->uv_selectmode == UV_SELECT_FACE); + const bool use_face_center = ( + (ts->uv_flag & UV_SYNC_SELECTION) ? + (ts->selectmode == SCE_SELECT_FACE) : + (ts->uv_selectmode == UV_SELECT_FACE)); const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); @@ -2937,12 +3077,22 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op) } } else { + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - changed |= uv_select_inside_ellipse(em, scene, select, offset, ellipse, l, luv, cd_loop_uv_offset); + if (uv_inside_circle(luv->uv, offset, ellipse)) { + changed = true; + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + BM_elem_flag_enable(l->v, BM_ELEM_TAG); + } } } + + if (sima->sticky == SI_STICKY_VERTEX) { + uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset); + } } if (changed) { @@ -2975,11 +3125,15 @@ static void UV_OT_circle_select(wmOperatorType *ot) WM_operator_properties_gesture_circle_select(ot); } +/** \} */ -/* ******************** lasso select operator **************** */ +/* -------------------------------------------------------------------- */ +/** \name Lasso Select Operator + * \{ */ -static bool do_lasso_select_mesh_uv(bContext *C, const int mcords[][2], short moves, - const bool select, const bool extend) +static bool do_lasso_select_mesh_uv( + bContext *C, const int mcords[][2], short moves, + const bool select, const bool extend) { SpaceImage *sima = CTX_wm_space_image(C); Image *ima = CTX_data_edit_image(C); @@ -3006,7 +3160,7 @@ static bool do_lasso_select_mesh_uv(bContext *C, const int mcords[][2], short mo BLI_lasso_boundbox(&rect, mcords, moves); if (!extend && select) { - uv_select_all_perform(scene, ima, em, SEL_DESELECT); + uv_select_all_perform(scene, ima, obedit, em, SEL_DESELECT); } if (use_face_center) { /* Face Center Sel */ @@ -3033,24 +3187,32 @@ static bool do_lasso_select_mesh_uv(bContext *C, const int mcords[][2], short mo } } else { /* Vert Sel */ + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (uvedit_face_visible_test(scene, ima, efa)) { + if (uvedit_face_visible_test(scene, obedit, ima, efa)) { BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) { MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (UI_view2d_view_to_region_clip(&ar->v2d, - luv->uv[0], luv->uv[1], - &screen_uv[0], &screen_uv[1]) && + if (UI_view2d_view_to_region_clip( + &ar->v2d, + luv->uv[0], luv->uv[1], + &screen_uv[0], &screen_uv[1]) && BLI_rcti_isect_pt_v(&rect, screen_uv) && BLI_lasso_is_point_inside(mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED)) { uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); changed = true; + BM_elem_flag_enable(l->v, BM_ELEM_TAG); } } } } } + + if (sima->sticky == SI_STICKY_VERTEX) { + uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset); + } } if (changed) { @@ -3104,9 +3266,11 @@ static void UV_OT_select_lasso(wmOperatorType *ot) WM_operator_properties_gesture_lasso_select(ot); } +/** \} */ - -/* ******************** snap cursor operator **************** */ +/* -------------------------------------------------------------------- */ +/** \name Snap Cursor Operator + * \{ */ static void uv_snap_to_pixel(float uvco[2], float w, float h) { @@ -3174,7 +3338,11 @@ static void UV_OT_snap_cursor(wmOperatorType *ot) RNA_def_enum(ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UVs to"); } -/* ******************** snap selection operator **************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Snap Selection Operator + * \{ */ static bool uv_snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, const float cursor[2]) { @@ -3188,7 +3356,7 @@ static bool uv_snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, cons const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, ima, efa)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -3215,7 +3383,7 @@ static bool uv_snap_uvs_offset(Scene *scene, Image *ima, Object *obedit, const f const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, ima, efa)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -3244,7 +3412,7 @@ static bool uv_snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object /* index every vert that has a selected UV using it, but only once so as to * get unique indices and to count how much to malloc */ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (uvedit_face_visible_test(scene, ima, f)) { + if (uvedit_face_visible_test(scene, obedit, ima, f)) { BM_elem_flag_enable(f, BM_ELEM_TAG); BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { BM_elem_flag_set(l, BM_ELEM_TAG, uvedit_uv_select_test(scene, l, cd_loop_uv_offset)); @@ -3304,7 +3472,7 @@ static bool uv_snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit h = (float)height; BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, ima, efa)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -3383,7 +3551,11 @@ static void UV_OT_snap_selected(wmOperatorType *ot) RNA_def_enum(ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UVs to"); } -/* ******************** pin operator **************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Pin UV's Operator + * \{ */ static int uv_pin_exec(bContext *C, wmOperator *op) { @@ -3400,7 +3572,7 @@ static int uv_pin_exec(bContext *C, wmOperator *op) const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, ima, efa)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -3438,7 +3610,11 @@ static void UV_OT_pin(wmOperatorType *ot) RNA_def_boolean(ot->srna, "clear", 0, "Clear", "Clear pinning for the selection instead of setting it"); } -/******************* select pinned operator ***************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Pinned UV's Operator + * \{ */ static int uv_select_pinned_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -3454,7 +3630,7 @@ static int uv_select_pinned_exec(bContext *C, wmOperator *UNUSED(op)) const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, ima, efa)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -3483,15 +3659,20 @@ static void UV_OT_select_pinned(wmOperatorType *ot) ot->poll = ED_operator_uvedit; } -/********************** hide operator *********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Hide Operator + * \{ */ /* check if we are selected or unselected based on 'bool_test' arg, * needed for select swap support */ #define UV_SEL_TEST(luv, bool_test) ((((luv)->flag & MLOOPUV_VERTSEL) == MLOOPUV_VERTSEL) == bool_test) /* is every UV vert selected or unselected depending on bool_test */ -static bool bm_face_is_all_uv_sel(BMFace *f, bool select_test, - const int cd_loop_uv_offset) +static bool bm_face_is_all_uv_sel( + BMFace *f, bool select_test, + const int cd_loop_uv_offset) { BMLoop *l_iter; BMLoop *l_first; @@ -3534,7 +3715,7 @@ static int uv_hide_exec(bContext *C, wmOperator *op) BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { int hide = 0; - if (!uvedit_face_visible_test(scene, ima, efa)) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { continue; } @@ -3617,7 +3798,11 @@ static void UV_OT_hide(wmOperatorType *ot) RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected"); } -/****************** reveal operator ******************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Reveal Operator + * \{ */ static int uv_reveal_exec(bContext *C, wmOperator *op) { @@ -3752,7 +3937,11 @@ static void UV_OT_reveal(wmOperatorType *ot) RNA_def_boolean(ot->srna, "select", true, "Select", ""); } -/******************** set 3d cursor operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Set 2D Cursor Operator + * \{ */ static int uv_set_2d_cursor_poll(bContext *C) { @@ -3815,6 +4004,12 @@ static void UV_OT_cursor_set(wmOperatorType *ot) "Cursor location in normalized (0.0-1.0) coordinates", -10.0f, 10.0f); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Seam from UV Islands Operator + * \{ */ + static int uv_seams_from_islands_exec(bContext *C, wmOperator *op) { UvVertMap *vmap; @@ -3949,6 +4144,12 @@ static void UV_OT_seams_from_islands(wmOperatorType *ot) RNA_def_boolean(ot->srna, "mark_sharp", 0, "Mark Sharp", "Mark boundary edges as sharp"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mark Seam Operator + * \{ */ + static int uv_mark_seam_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_edit_object(C); @@ -3959,17 +4160,14 @@ static int uv_mark_seam_exec(bContext *C, wmOperator *op) BMFace *efa; BMLoop *loop; BMIter iter, liter; - bool clear = RNA_boolean_get(op->ptr, "clear"); + bool flag_set = !RNA_boolean_get(op->ptr, "clear"); const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) { if (uvedit_edge_select_test(scene, loop, cd_loop_uv_offset)) { - if (clear) - BM_elem_flag_disable(loop->e, BM_ELEM_SEAM); - else - BM_elem_flag_enable(loop->e, BM_ELEM_SEAM); + BM_elem_flag_set(loop->e, BM_ELEM_SEAM, flag_set); } } } @@ -4024,8 +4222,11 @@ static void UV_OT_mark_seam(wmOperatorType *ot) RNA_def_boolean(ot->srna, "clear", false, "Clear Seams", "Clear instead of marking seams"); } +/** \} */ -/* ************************** registration **********************************/ +/* -------------------------------------------------------------------- */ +/** \name Operator Registration & Keymap + * \{ */ void ED_operatortypes_uvedit(void) { @@ -4159,3 +4360,4 @@ void ED_keymap_uvedit(wmKeyConfig *keyconf) transform_keymap_for_space(keyconf, keymap, SPACE_IMAGE); } +/** \} */ diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c index 29c908ff900..c510c12ae53 100644 --- a/source/blender/editors/uvedit/uvedit_parametrizer.c +++ b/source/blender/editors/uvedit/uvedit_parametrizer.c @@ -32,8 +32,8 @@ #include "BLI_math.h" #include "BLI_rand.h" #include "BLI_heap.h" -#include "BLI_boxpack2d.h" -#include "BLI_convexhull2d.h" +#include "BLI_boxpack_2d.h" +#include "BLI_convexhull_2d.h" #include "uvedit_parametrizer.h" @@ -1291,7 +1291,7 @@ static void p_chart_fill_boundary(PChart *chart, PEdge *be, int nedges) while (nedges > 2) { PEdge *ne, *ne1, *ne2; - e = (PEdge *)BLI_heap_popmin(heap); + e = (PEdge *)BLI_heap_pop_min(heap); e1 = p_boundary_edge_prev(e); e2 = p_boundary_edge_next(e); @@ -2185,12 +2185,12 @@ static void p_chart_simplify_compute(PChart *chart) e->u.nextcollapse = NULL; /* pop edge collapse out of heap one by one */ - while (!BLI_heap_empty(heap)) { + while (!BLI_heap_is_empty(heap)) { if (ncollapsed == NCOLLAPSE) break; HeapNode *link = BLI_heap_top(heap); - PEdge *edge = (PEdge *)BLI_heap_popmin(heap), *pair = edge->pair; + PEdge *edge = (PEdge *)BLI_heap_pop_min(heap), *pair = edge->pair; PVert *oldv, *keepv; PEdge *wheele, *nexte; diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c index fa936e998fa..4c205818329 100644 --- a/source/blender/editors/uvedit/uvedit_smart_stitch.c +++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c @@ -157,6 +157,8 @@ typedef struct StitchState { bool snap_islands; /* stitch at midpoints or at islands */ bool midpoints; + /* object for editmesh */ + Object *obedit; /* editmesh, cached for use in modal handler */ BMEditMesh *em; /* clear seams of stitched edges after stitch */ @@ -1719,6 +1721,7 @@ static int stitch_init(bContext *C, wmOperator *op) /* initialize state */ state->use_limit = RNA_boolean_get(op->ptr, "use_limit"); state->limit_dist = RNA_float_get(op->ptr, "limit"); + state->obedit = obedit; state->em = em; state->snap_islands = RNA_boolean_get(op->ptr, "snap_islands"); state->static_island = RNA_int_get(op->ptr, "static_island"); @@ -1848,7 +1851,7 @@ static int stitch_init(bContext *C, wmOperator *op) } } - total_edges = BLI_ghash_size(edge_hash); + total_edges = BLI_ghash_len(edge_hash); state->edges = edges = MEM_mallocN(sizeof(*edges) * total_edges, "stitch_edges"); /* I assume any system will be able to at least allocate an iterator :p */ @@ -2124,16 +2127,16 @@ static void stitch_select(bContext *C, Scene *scene, const wmEvent *event, Stitc { /* add uv under mouse to processed uv's */ float co[2]; - NearestHit hit; + UvNearestHit hit = UV_NEAREST_HIT_INIT; ARegion *ar = CTX_wm_region(C); Image *ima = CTX_data_edit_image(C); UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); if (state->mode == STITCH_VERT) { - uv_find_nearest_vert(scene, ima, state->em, co, NULL, &hit); - - if (hit.efa) { + if (uv_find_nearest_vert( + scene, ima, state->obedit, co, 0.0f, &hit)) + { /* Add vertex to selection, deselect all common uv's of vert other * than selected and update the preview. This behavior was decided so that * you can do stuff like deselect the opposite stitchable vertex and the initial still gets deselected */ @@ -2145,9 +2148,9 @@ static void stitch_select(bContext *C, Scene *scene, const wmEvent *event, Stitc } } else { - uv_find_nearest_edge(scene, ima, state->em, co, &hit); - - if (hit.efa) { + if (uv_find_nearest_edge( + scene, ima, state->obedit, co, &hit)) + { UvEdge *edge = uv_edge_get(hit.l, state); stitch_select_edge(edge, state, false); } |