diff options
author | Bastien Montagne <montagne29@wanadoo.fr> | 2016-05-24 17:48:10 +0300 |
---|---|---|
committer | Bastien Montagne <montagne29@wanadoo.fr> | 2016-05-24 17:48:10 +0300 |
commit | faec4309147988fbab7b7d7ec661f5130358d169 (patch) | |
tree | 0c839f8f88fe80f4a3762980adb5efe729ce1b44 /source/blender/editors | |
parent | f85745b17bfe68673bf5f799e98c617d9471ddf1 (diff) | |
parent | e1dd83b399d46d81ea51f6c41725eec5c1a1db7a (diff) |
Merge branch 'master' into blender2.8
Conflicts:
intern/cycles/blender/blender_curves.cpp
source/blender/blenkernel/intern/dynamicpaint.c
source/blender/blenkernel/intern/particle.c
source/blender/blenloader/intern/versioning_270.c
source/blender/editors/physics/particle_edit.c
source/blender/editors/transform/transform_snap_object.c
source/blender/editors/util/undo.c
source/blender/makesrna/intern/rna_object_force.c
Diffstat (limited to 'source/blender/editors')
100 files changed, 3158 insertions, 1271 deletions
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index 157aa4cf368..486b2bcd979 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -3813,6 +3813,9 @@ static void achannel_setting_flush_widget_cb(bContext *C, void *ale_npoin, void /* send notifiers before doing anything else... */ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); + if (ale_setting->type == ANIMTYPE_GPLAYER) + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL); + /* verify animation context */ if (ANIM_animdata_get_context(C, &ac) == 0) return; diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c index 40376c38c3b..823cde75334 100644 --- a/source/blender/editors/animation/anim_markers.c +++ b/source/blender/editors/animation/anim_markers.c @@ -39,6 +39,8 @@ #include "BLI_math_base.h" #include "BLI_utildefines.h" +#include "BLT_translation.h" + #include "BKE_context.h" #include "BKE_fcurve.h" #include "BKE_main.h" @@ -685,7 +687,7 @@ static void ed_marker_move_update_header(bContext *C, wmOperator *op) MarkerMove *mm = op->customdata; TimeMarker *marker, *selmarker = NULL; const int offs = RNA_int_get(op->ptr, "frames"); - char str[256]; + char str[UI_MAX_DRAW_STR]; char str_offs[NUM_STR_REP_LEN]; int totmark; const bool use_time = ed_marker_move_use_time(mm); @@ -710,14 +712,14 @@ static void ed_marker_move_update_header(bContext *C, wmOperator *op) if (totmark == 1 && selmarker) { /* we print current marker value */ if (use_time) { - BLI_snprintf(str, sizeof(str), "Marker %.2f offset %s", FRA2TIME(selmarker->frame), str_offs); + BLI_snprintf(str, sizeof(str), IFACE_("Marker %.2f offset %s"), FRA2TIME(selmarker->frame), str_offs); } else { - BLI_snprintf(str, sizeof(str), "Marker %d offset %s", selmarker->frame, str_offs); + BLI_snprintf(str, sizeof(str), IFACE_("Marker %d offset %s"), selmarker->frame, str_offs); } } else { - BLI_snprintf(str, sizeof(str), "Marker offset %s", str_offs); + BLI_snprintf(str, sizeof(str), IFACE_("Marker offset %s"), str_offs); } ED_area_headerprint(CTX_wm_area(C), str); diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c index 218f215a350..559d93c7eb1 100644 --- a/source/blender/editors/armature/armature_add.c +++ b/source/blender/editors/armature/armature_add.c @@ -83,6 +83,15 @@ EditBone *ED_armature_edit_bone_add(bArmature *arm, const char *name) bone->segments = 1; bone->layer = arm->layer; + bone->roll1 = 0.0f; + bone->roll2 = 0.0f; + bone->curveInX = 0.0f; + bone->curveInY = 0.0f; + bone->curveOutX = 0.0f; + bone->curveOutY = 0.0f; + bone->scaleIn = 1.0f; + bone->scaleOut = 1.0f; + return bone; } @@ -291,12 +300,8 @@ void preEditBoneDuplicate(ListBase *editbones) /** * Helper function for #postEditBoneDuplicate, * return the destination pchan from the original. - * - * \param use_orig_fallback: return the input value if no new channel is found. */ -static bPoseChannel *pchan_duplicate_map( - const bPose *pose, GHash *name_map, - bPoseChannel *pchan_src, bool use_orig_fallback) +static bPoseChannel *pchan_duplicate_map(const bPose *pose, GHash *name_map, bPoseChannel *pchan_src) { bPoseChannel *pchan_dst = NULL; const char *name_src = pchan_src->name; @@ -305,7 +310,7 @@ static bPoseChannel *pchan_duplicate_map( pchan_dst = BKE_pose_channel_find_name(pose, name_dst); } - if ((pchan_dst == NULL) && use_orig_fallback) { + if (pchan_dst == NULL) { pchan_dst = pchan_src; } @@ -325,6 +330,9 @@ void postEditBoneDuplicate(struct ListBase *editbones, Object *ob) for (EditBone *ebone_src = editbones->first; ebone_src; ebone_src = ebone_src->next) { EditBone *ebone_dst = ebone_src->temp.ebone; + if (!ebone_dst) { + ebone_dst = ED_armature_bone_get_mirrored(editbones, ebone_src); + } if (ebone_dst) { BLI_ghash_insert(name_map, ebone_src->name, ebone_dst->name); } @@ -338,7 +346,13 @@ void postEditBoneDuplicate(struct ListBase *editbones, Object *ob) bPoseChannel *pchan_dst = BKE_pose_channel_find_name(ob->pose, ebone_dst->name); if (pchan_dst) { if (pchan_src->custom_tx) { - pchan_dst->custom_tx = pchan_duplicate_map(ob->pose, name_map, pchan_src->custom_tx, true); + pchan_dst->custom_tx = pchan_duplicate_map(ob->pose, name_map, pchan_src->custom_tx); + } + if (pchan_src->bbone_prev) { + pchan_dst->bbone_prev = pchan_duplicate_map(ob->pose, name_map, pchan_src->bbone_prev); + } + if (pchan_src->bbone_next) { + pchan_dst->bbone_next = pchan_duplicate_map(ob->pose, name_map, pchan_src->bbone_next); } } } @@ -682,7 +696,7 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op) } } - /* Run though the list and fix the pointers */ + /* Run through the list and fix the pointers */ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) { if (ebone_iter->temp.ebone) { /* copy all flags except for ... */ @@ -891,6 +905,16 @@ static int armature_extrude_exec(bContext *C, wmOperator *op) newbone->segments = 1; newbone->layer = ebone->layer; + newbone->roll1 = ebone->roll1; + newbone->roll2 = ebone->roll2; + newbone->curveInX = ebone->curveInX; + newbone->curveInY = ebone->curveInY; + newbone->curveOutX = ebone->curveOutX; + newbone->curveOutY = ebone->curveOutY; + newbone->scaleIn = ebone->scaleIn; + newbone->scaleOut = ebone->scaleOut; + + BLI_strncpy(newbone->name, ebone->name, sizeof(newbone->name)); if (flipbone && forked) { // only set if mirror edit diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c index b1c23fb4cac..354b748e129 100644 --- a/source/blender/editors/armature/armature_edit.c +++ b/source/blender/editors/armature/armature_edit.c @@ -317,9 +317,10 @@ static int armature_calc_roll_exec(bContext *C, wmOperator *op) float cursor_local[3]; const float *cursor = ED_view3d_cursor3d_get(scene, v3d); - + invert_m4_m4(ob->imat, ob->obmat); copy_v3_v3(cursor_local, cursor); - mul_m3_v3(imat, cursor_local); + mul_m4_v3(ob->imat, cursor_local); + /* cursor */ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h index ac150b9af74..02aefce3464 100644 --- a/source/blender/editors/armature/armature_intern.h +++ b/source/blender/editors/armature/armature_intern.h @@ -170,6 +170,11 @@ typedef struct tPChanFCurveLink { float oldangle; float oldaxis[3]; + float roll1, roll2; /* old bbone values (to be restored along with the transform properties) */ + float curveInX, curveInY; /* (NOTE: we haven't renamed these this time, as their names are already long enough) */ + float curveOutX, curveOutY; + float scaleIn, scaleOut; + struct IDProperty *oldprops; /* copy of custom properties at start of operator (to be restored before each modal step) */ } tPChanFCurveLink; diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c index 61ed7fdc41b..d73536e5ba7 100644 --- a/source/blender/editors/armature/armature_utils.c +++ b/source/blender/editors/armature/armature_utils.c @@ -179,7 +179,6 @@ EditBone *ED_armature_bone_find_shared_parent(EditBone *ebone_child[], const uns /* accumulate */ for (i = 0; i < ebone_child_tot; i++) { - ebone_iter = ebone_child[i]; for (ebone_iter = ebone_child[i]->parent; ebone_iter; ebone_iter = ebone_iter->parent) { EBONE_TEMP_UINT(ebone_iter) += 1; } @@ -457,7 +456,16 @@ EditBone *make_boneList(ListBase *edbo, ListBase *bones, EditBone *parent, Bone eBone->rad_tail = curBone->rad_tail; eBone->segments = curBone->segments; eBone->layer = curBone->layer; - + + eBone->roll1 = curBone->roll1; + eBone->roll2 = curBone->roll2; + eBone->curveInX = curBone->curveInX; + eBone->curveInY = curBone->curveInY; + eBone->curveOutX = curBone->curveOutX; + eBone->curveOutY = curBone->curveOutY; + eBone->scaleIn = curBone->scaleIn; + eBone->scaleOut = curBone->scaleOut; + if (curBone->prop) eBone->prop = IDP_CopyProperty(curBone->prop); @@ -612,7 +620,17 @@ void ED_armature_from_edit(bArmature *arm) newBone->rad_tail = eBone->rad_tail; newBone->segments = eBone->segments; newBone->layer = eBone->layer; - + + newBone->roll1 = eBone->roll1; + newBone->roll2 = eBone->roll2; + newBone->curveInX = eBone->curveInX; + newBone->curveInY = eBone->curveInY; + newBone->curveOutX = eBone->curveOutX; + newBone->curveOutY = eBone->curveOutY; + newBone->scaleIn = eBone->scaleIn; + newBone->scaleOut = eBone->scaleOut; + + if (eBone->prop) newBone->prop = IDP_CopyProperty(eBone->prop); } diff --git a/source/blender/editors/armature/editarmature_retarget.c b/source/blender/editors/armature/editarmature_retarget.c index 7c09ad49f35..fa7bf6e7ad4 100644 --- a/source/blender/editors/armature/editarmature_retarget.c +++ b/source/blender/editors/armature/editarmature_retarget.c @@ -1451,6 +1451,15 @@ static EditBone *add_editbonetolist(char *name, ListBase *list) bone->segments = 1; bone->layer = 1; //arm->layer; + bone->roll1 = 0.0f; + bone->roll2 = 0.0f; + bone->curveInX = 0.0f; + bone->curveInY = 0.0f; + bone->curveOutX = 0.0f; + bone->curveOutY = 0.0f; + bone->scaleIn = 1.0f; + bone->scaleOut = 1.0f; + return bone; } #endif diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c index b62714700fa..5530e293edd 100644 --- a/source/blender/editors/armature/editarmature_sketch.c +++ b/source/blender/editors/armature/editarmature_sketch.c @@ -47,6 +47,7 @@ #include "BIF_generate.h" #include "ED_transform.h" +#include "ED_transform_snap_object_context.h" #include "WM_api.h" #include "WM_types.h" @@ -969,100 +970,30 @@ static int sk_getStrokeSnapPoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, S ToolSettings *ts = CTX_data_tool_settings(C); int point_added = 0; - if (ts->snap_mode == SCE_SNAP_MODE_VOLUME) { - DepthPeel *p1, *p2; - float *last_p = NULL; - float dist = FLT_MAX; - float p[3] = {0}; - float size = 0; - float mvalf[2]; - - BLI_freelistN(&sketch->depth_peels); - BLI_listbase_clear(&sketch->depth_peels); - - mvalf[0] = dd->mval[0]; - mvalf[1] = dd->mval[1]; - peelObjectsContext(C, mvalf, SNAP_ALL, &sketch->depth_peels); - - if (stk->nb_points > 0 && stk->points[stk->nb_points - 1].type == PT_CONTINUOUS) { - last_p = stk->points[stk->nb_points - 1].p; - } - else if (LAST_SNAP_POINT_VALID) { - last_p = LAST_SNAP_POINT; - } - - - for (p1 = sketch->depth_peels.first; p1; p1 = p1->next) { - if (p1->flag == 0) { - float vec[3]; - float new_dist; - float new_size = 0; - - p2 = NULL; - p1->flag = 1; - - /* if peeling objects, take the first and last from each object */ - if (ts->snap_flag & SCE_SNAP_PEEL_OBJECT) { - DepthPeel *peel; - for (peel = p1->next; peel; peel = peel->next) { - if (peel->ob == p1->ob) { - peel->flag = 1; - p2 = peel; - } - } - } - /* otherwise, pair first with second and so on */ - else { - for (p2 = p1->next; p2 && p2->ob != p1->ob; p2 = p2->next) { - /* nothing to do here */ - } - } - - if (p2) { - p2->flag = 1; - - add_v3_v3v3(vec, p1->p, p2->p); - mul_v3_fl(vec, 0.5f); - new_size = len_v3v3(p1->p, p2->p); - } - else { - copy_v3_v3(vec, p1->p); - } - - if (last_p == NULL) { - copy_v3_v3(p, vec); - size = new_size; - dist = 0; - break; - } - - new_dist = len_v3v3(last_p, vec); + struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d( + CTX_data_main(C), CTX_data_scene(C), 0, + CTX_wm_region(C), CTX_wm_view3d(C)); - if (new_dist < dist) { - copy_v3_v3(p, vec); - dist = new_dist; - size = new_size; - } - } - } + float mvalf[2] = {UNPACK2(dd->mval)}; + float loc[3], dummy_no[3]; - if (dist != FLT_MAX) { + if (ts->snap_mode == SCE_SNAP_MODE_VOLUME) { + float size; + if (peelObjectsSnapContext( + snap_context, mvalf, SNAP_ALL, + (ts->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0, + loc, dummy_no, &size)) + { pt->type = dd->type; pt->mode = PT_SNAP; pt->size = size / 2; - copy_v3_v3(pt->p, p); + copy_v3_v3(pt->p, loc); point_added = 1; } - - //BLI_freelistN(&depth_peels); } else { SK_Stroke *snap_stk; - float vec[3]; - float no[3]; - float mval[2]; - int found = 0; float dist_px = SNAP_MIN_DISTANCE; // Use a user defined value here /* snap to strokes */ @@ -1081,37 +1012,28 @@ static int sk_getStrokeSnapPoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, S point_added = 1; } } - - mval[0] = dd->mval[0]; - mval[1] = dd->mval[1]; /* try to snap to closer object */ { - struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d( - CTX_data_main(C), CTX_data_scene(C), 0, - CTX_wm_region(C), CTX_wm_view3d(C)); - - found = ED_transform_snap_object_project_view3d_mixed( + if (ED_transform_snap_object_project_view3d( snap_context, &(const struct SnapObjectParams){ .snap_select = SNAP_NOT_SELECTED, - .snap_to_flag = SCE_SELECT_FACE, + .snap_to = ts->snap_mode, }, - mval, &dist_px, true, - vec, no); - - ED_transform_snap_object_context_destroy(snap_context); - } - - if (found == 1) { - pt->type = dd->type; - pt->mode = PT_SNAP; - copy_v3_v3(pt->p, vec); + mvalf, &dist_px, NULL, + loc, dummy_no)) + { + pt->type = dd->type; + pt->mode = PT_SNAP; + copy_v3_v3(pt->p, loc); - point_added = 1; + point_added = 1; + } } } + ED_transform_snap_object_context_destroy(snap_context); return point_added; } diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c index a984e5d1ccd..dca9aa3e446 100644 --- a/source/blender/editors/armature/pose_lib.c +++ b/source/blender/editors/armature/pose_lib.c @@ -762,7 +762,7 @@ typedef struct tPoseLib_PreviewData { char searchstr[64]; /* (Part of) Name to search for to filter poses that get shown */ char searchold[64]; /* Previously set searchstr (from last loop run), so that we can detected when to rebuild searchp */ - char headerstr[200]; /* Info-text to print in header */ + char headerstr[UI_MAX_DRAW_STR]; /* Info-text to print in header */ } tPoseLib_PreviewData; /* defines for tPoseLib_PreviewData->state values */ @@ -1016,7 +1016,7 @@ static void poselib_preview_apply(bContext *C, wmOperator *op) if (pld->state == PL_PREVIEW_RUNNING) { if (pld->flag & PL_PREVIEW_SHOWORIGINAL) { BLI_strncpy(pld->headerstr, - "PoseLib Previewing Pose: [Showing Original Pose] | Use Tab to start previewing poses again", + IFACE_("PoseLib Previewing Pose: [Showing Original Pose] | Use Tab to start previewing poses again"), sizeof(pld->headerstr)); ED_area_headerprint(pld->sa, pld->headerstr); } @@ -1041,16 +1041,16 @@ static void poselib_preview_apply(bContext *C, wmOperator *op) BLI_strncpy(markern, pld->marker ? pld->marker->name : "No Matches", sizeof(markern)); BLI_snprintf(pld->headerstr, sizeof(pld->headerstr), - "PoseLib Previewing Pose: Filter - [%s] | " - "Current Pose - \"%s\" | " - "Use ScrollWheel or PageUp/Down to change", + IFACE_("PoseLib Previewing Pose: Filter - [%s] | " + "Current Pose - \"%s\" | " + "Use ScrollWheel or PageUp/Down to change"), tempstr, markern); ED_area_headerprint(pld->sa, pld->headerstr); } else { BLI_snprintf(pld->headerstr, sizeof(pld->headerstr), - "PoseLib Previewing Pose: \"%s\" | " - "Use ScrollWheel or PageUp/Down to change", + IFACE_("PoseLib Previewing Pose: \"%s\" | " + "Use ScrollWheel or PageUp/Down to change"), pld->marker->name); ED_area_headerprint(pld->sa, pld->headerstr); } diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c index 16ba1483e38..cd0ea23e2d3 100644 --- a/source/blender/editors/armature/pose_slide.c +++ b/source/blender/editors/armature/pose_slide.c @@ -51,6 +51,8 @@ #include "WM_api.h" #include "WM_types.h" +#include "UI_interface.h" + #include "ED_armature.h" #include "ED_keyframes_draw.h" #include "ED_markers.h" @@ -301,8 +303,8 @@ static void pose_slide_apply_vec3(tPoseSlideOp *pso, tPChanFCurveLink *pfl, floa MEM_freeN(path); } -/* helper for apply() - perform sliding for custom properties */ -static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl) +/* helper for apply() - perform sliding for custom properties or bbone properties */ +static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl, const char prop_prefix[]) { PointerRNA ptr = {{NULL}}; LinkData *ld; @@ -311,8 +313,10 @@ static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl) /* setup pointer RNA for resolving paths */ RNA_pointer_create(NULL, &RNA_PoseBone, pfl->pchan, &ptr); - /* custom properties are just denoted using ["..."][etc.] after the end of the base path, - * so just check for opening pair after the end of the path + /* - custom properties are just denoted using ["..."][etc.] after the end of the base path, + * so just check for opening pair after the end of the path + * - bbone properties are similar, but they always start with a prefix "bbone_*", + * so a similar method should work here for those too */ for (ld = pfl->fcurves.first; ld; ld = ld->next) { FCurve *fcu = (FCurve *)ld->data; @@ -326,7 +330,7 @@ static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl) * - pPtr is the chunk of the path which is left over */ bPtr = strstr(fcu->rna_path, pfl->pchan_path) + len; - pPtr = strstr(bPtr, "[\""); /* dummy " for texteditor bugs */ + pPtr = strstr(bPtr, prop_prefix); if (pPtr) { /* use RNA to try and get a handle on this property, then, assuming that it is just @@ -515,9 +519,16 @@ static void pose_slide_apply(bContext *C, tPoseSlideOp *pso) } } + if (pchan->flag & POSE_BBONE_SHAPE) { + /* bbone properties - they all start a "bbone_" prefix */ + pose_slide_apply_props(pso, pfl, "bbone_"); + } + if (pfl->oldprops) { - /* not strictly a transform, but contributes to the pose produced in many rigs */ - pose_slide_apply_props(pso, pfl); + /* not strictly a transform, but custom properties contribute to the pose produced in many rigs + * (e.g. the facial rigs used in Sintel) + */ + pose_slide_apply_props(pso, pfl, "[\""); /* dummy " for texteditor bugs */ } } @@ -544,7 +555,7 @@ static void pose_slide_reset(tPoseSlideOp *pso) /* draw percentage indicator in header */ static void pose_slide_draw_status(tPoseSlideOp *pso) { - char status_str[256]; + char status_str[UI_MAX_DRAW_STR]; char mode_str[32]; switch (pso->mode) { diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c index 01e16df9f08..df906a3638a 100644 --- a/source/blender/editors/armature/pose_transform.c +++ b/source/blender/editors/armature/pose_transform.c @@ -367,10 +367,26 @@ static bPoseChannel *pose_bone_do_paste(Object *ob, bPoseChannel *chan, const bo axis_angle_to_quat(pchan->quat, chan->rotAxis, pchan->rotAngle); } + /* B-Bone posing options should also be included... */ + pchan->curveInX = chan->curveInX; + pchan->curveInY = chan->curveInY; + pchan->curveOutX = chan->curveOutX; + pchan->curveOutY = chan->curveOutY; + + pchan->roll1 = chan->roll1; + pchan->roll2 = chan->roll2; + pchan->scaleIn = chan->scaleIn; + pchan->scaleOut = chan->scaleOut; + /* paste flipped pose? */ if (flip) { pchan->loc[0] *= -1; + pchan->curveInX *= -1; + pchan->curveOutX *= -1; + pchan->roll1 *= -1; // XXX? + pchan->roll2 *= -1; // XXX? + /* has to be done as eulers... */ if (pchan->rotmode > 0) { pchan->eul[1] *= -1; @@ -540,6 +556,9 @@ static void pchan_clear_scale(bPoseChannel *pchan) pchan->size[1] = 1.0f; if ((pchan->protectflag & OB_LOCK_SCALEZ) == 0) pchan->size[2] = 1.0f; + + pchan->scaleIn = 1.0f; + pchan->scaleOut = 1.0f; } /* clear location of pose-channel */ @@ -650,6 +669,15 @@ static void pchan_clear_rot(bPoseChannel *pchan) zero_v3(pchan->eul); } } + + /* Clear also Bendy Bone stuff - Roll is obvious, but Curve X/Y stuff is also kindof rotational in nature... */ + pchan->roll1 = 0.0f; + pchan->roll2 = 0.0f; + + pchan->curveInX = 0.0f; + pchan->curveInY = 0.0f; + pchan->curveOutX = 0.0f; + pchan->curveOutY = 0.0f; } /* clear loc/rot/scale of pose-channel */ diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c index 2ba1eedd33b..b960bec3603 100644 --- a/source/blender/editors/armature/pose_utils.c +++ b/source/blender/editors/armature/pose_utils.c @@ -71,7 +71,7 @@ static void fcurves_to_pchan_links_get(ListBase *pfLinks, Object *ob, bAction *a ListBase curves = {NULL, NULL}; int transFlags = action_get_item_transforms(act, ob, pchan, &curves); - pchan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE); + pchan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE | POSE_BBONE_SHAPE); /* check if any transforms found... */ if (transFlags) { @@ -96,6 +96,8 @@ static void fcurves_to_pchan_links_get(ListBase *pfLinks, Object *ob, bAction *a pchan->flag |= POSE_ROT; if (transFlags & ACT_TRANS_SCALE) pchan->flag |= POSE_SIZE; + if (transFlags & ACT_TRANS_BBONE) + pchan->flag |= POSE_BBONE_SHAPE; /* store current transforms */ copy_v3_v3(pfl->oldloc, pchan->loc); @@ -105,6 +107,16 @@ static void fcurves_to_pchan_links_get(ListBase *pfLinks, Object *ob, bAction *a copy_v3_v3(pfl->oldaxis, pchan->rotAxis); pfl->oldangle = pchan->rotAngle; + /* store current bbone values */ + pfl->roll1 = pchan->roll1; + pfl->roll2 = pchan->roll2; + pfl->curveInX = pchan->curveInX; + pfl->curveInY = pchan->curveInY; + pfl->curveOutX = pchan->curveOutX; + pfl->curveOutY = pchan->curveOutY; + pfl->scaleIn = pchan->scaleIn; + pfl->scaleOut = pchan->scaleOut; + /* make copy of custom properties */ if (pchan->prop && (transFlags & ACT_TRANS_PROP)) pfl->oldprops = IDP_CopyProperty(pchan->prop); @@ -133,6 +145,7 @@ void poseAnim_mapping_get(bContext *C, ListBase *pfLinks, Object *ob, bAction *a fcurves_to_pchan_links_get(pfLinks, ob, act, pchan); } CTX_DATA_END; + } } @@ -199,6 +212,16 @@ void poseAnim_mapping_reset(ListBase *pfLinks) copy_v3_v3(pchan->rotAxis, pfl->oldaxis); pchan->rotAngle = pfl->oldangle; + /* store current bbone values */ + pchan->roll1 = pfl->roll1; + pchan->roll2 = pfl->roll2; + pchan->curveInX = pfl->curveInX; + pchan->curveInY = pfl->curveInY; + pchan->curveOutX = pfl->curveOutX; + pchan->curveOutY = pfl->curveOutY; + pchan->scaleIn = pfl->scaleIn; + pchan->scaleOut = pfl->scaleOut; + /* just overwrite values of properties from the stored copies (there should be some) */ if (pfl->oldprops) IDP_SyncGroupValues(pfl->pchan->prop, pfl->oldprops); diff --git a/source/blender/editors/curve/curve_intern.h b/source/blender/editors/curve/curve_intern.h index d63616e4f43..856573ffab0 100644 --- a/source/blender/editors/curve/curve_intern.h +++ b/source/blender/editors/curve/curve_intern.h @@ -102,6 +102,7 @@ void CURVE_OT_separate(struct wmOperatorType *ot); void CURVE_OT_split(struct wmOperatorType *ot); void CURVE_OT_duplicate(struct wmOperatorType *ot); void CURVE_OT_delete(struct wmOperatorType *ot); +void CURVE_OT_dissolve_verts(struct wmOperatorType *ot); void CURVE_OT_spline_type_set(struct wmOperatorType *ot); void CURVE_OT_radius_set(struct wmOperatorType *ot); diff --git a/source/blender/editors/curve/curve_ops.c b/source/blender/editors/curve/curve_ops.c index d1994c8fc15..fce6425b9be 100644 --- a/source/blender/editors/curve/curve_ops.c +++ b/source/blender/editors/curve/curve_ops.c @@ -87,6 +87,7 @@ void ED_operatortypes_curve(void) WM_operatortype_append(CURVE_OT_split); WM_operatortype_append(CURVE_OT_duplicate); WM_operatortype_append(CURVE_OT_delete); + WM_operatortype_append(CURVE_OT_dissolve_verts); WM_operatortype_append(CURVE_OT_spline_type_set); WM_operatortype_append(CURVE_OT_radius_set); @@ -262,8 +263,12 @@ void ED_keymap_curve(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "CURVE_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0); WM_keymap_add_item(keymap, "CURVE_OT_make_segment", FKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "CURVE_OT_cyclic_toggle", CKEY, KM_PRESS, KM_ALT, 0); - WM_keymap_add_item(keymap, "CURVE_OT_delete", XKEY, KM_PRESS, 0, 0); - WM_keymap_add_item(keymap, "CURVE_OT_delete", DELKEY, KM_PRESS, 0, 0); + + WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_curve_delete", XKEY, KM_PRESS, 0, 0); + WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_curve_delete", DELKEY, KM_PRESS, 0, 0); + + WM_keymap_add_item(keymap, "CURVE_OT_dissolve_verts", XKEY, KM_PRESS, KM_CTRL, 0); + WM_keymap_add_item(keymap, "CURVE_OT_dissolve_verts", DELKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "CURVE_OT_tilt_clear", TKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "TRANSFORM_OT_tilt", TKEY, KM_PRESS, KM_CTRL, 0); diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 395da2cd2f1..18fdcb546b0 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -36,6 +36,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_array_utils.h" #include "BLI_blenlib.h" #include "BLI_math.h" #include "BLI_ghash.h" @@ -63,6 +64,7 @@ #include "ED_object.h" #include "ED_screen.h" #include "ED_transform.h" +#include "ED_transform_snap_object_context.h" #include "ED_types.h" #include "ED_util.h" #include "ED_view3d.h" @@ -70,6 +72,8 @@ #include "curve_intern.h" +#include "curve_fit_nd.h" + #include "UI_interface.h" #include "UI_resources.h" @@ -5776,6 +5780,115 @@ void CURVE_OT_delete(wmOperatorType *ot) ot->prop = prop; } +static bool test_bezt_is_sel_any(const void *bezt_v, void *user_data) +{ + Curve *cu = user_data; + const BezTriple *bezt = bezt_v; + return BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt); +} + +static int curve_dissolve_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obedit = CTX_data_edit_object(C); + Curve *cu = (Curve *)obedit->data; + + { + ListBase *editnurb = object_editcurve_get(obedit); + Nurb *nu; + + for (nu = editnurb->first; nu; nu = nu->next) { + if ((nu->type == CU_BEZIER) && (nu->pntsu > 2)) { + unsigned int span_step[2] = {nu->pntsu, nu->pntsu}; + unsigned int span_len; + + while (BLI_array_iter_span( + nu->bezt, nu->pntsu, + (nu->flagu & CU_NURB_CYCLIC) != 0, false, + test_bezt_is_sel_any, cu, + span_step, &span_len)) + { + BezTriple *bezt_prev = &nu->bezt[mod_i(span_step[0] - 1, nu->pntsu)]; + BezTriple *bezt_next = &nu->bezt[mod_i(span_step[1] + 1, nu->pntsu)]; + + int i_span_edge_len = span_len + 1; + const unsigned int dims = 3; + + const unsigned int points_len = ((cu->resolu - 1) * i_span_edge_len) + 1; + float *points = MEM_mallocN(points_len * dims * sizeof(float), __func__); + float *points_stride = points; + const int points_stride_len = (cu->resolu - 1); + + for (int segment = 0; segment < i_span_edge_len; segment++) { + BezTriple *bezt_a = &nu->bezt[mod_i((span_step[0] + segment) - 1, nu->pntsu)]; + BezTriple *bezt_b = &nu->bezt[mod_i((span_step[0] + segment), nu->pntsu)]; + + for (int axis = 0; axis < dims; axis++) { + BKE_curve_forward_diff_bezier( + bezt_a->vec[1][axis], bezt_a->vec[2][axis], + bezt_b->vec[0][axis], bezt_b->vec[1][axis], + points_stride + axis, points_stride_len, dims * sizeof(float)); + } + + points_stride += dims * points_stride_len; + } + + BLI_assert(points_stride + dims == points + (points_len * dims)); + + float tan_l[3], tan_r[3], error_sq_dummy; + + sub_v3_v3v3(tan_l, bezt_prev->vec[1], bezt_prev->vec[2]); + normalize_v3(tan_l); + sub_v3_v3v3(tan_r, bezt_next->vec[0], bezt_next->vec[1]); + normalize_v3(tan_r); + + curve_fit_cubic_to_points_single_fl( + points, points_len, dims, FLT_EPSILON, + tan_l, tan_r, + bezt_prev->vec[2], bezt_next->vec[0], + &error_sq_dummy); + + if (!ELEM(bezt_prev->h2, HD_FREE, HD_ALIGN)) { + bezt_prev->h2 = (bezt_prev->h2 == HD_VECT) ? HD_FREE : HD_ALIGN; + } + if (!ELEM(bezt_next->h1, HD_FREE, HD_ALIGN)) { + bezt_next->h1 = (bezt_next->h1 == HD_VECT) ? HD_FREE : HD_ALIGN; + } + + MEM_freeN(points); + } + } + } + } + + ed_curve_delete_selected(obedit); + + { + cu->actnu = cu->actvert = CU_ACT_NONE; + + if (ED_curve_updateAnimPaths(obedit->data)) WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit); + + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + DAG_id_tag_update(obedit->data, 0); + } + + return OPERATOR_FINISHED; +} + +void CURVE_OT_dissolve_verts(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Dissolve Vertices"; + ot->description = "Delete selected control points, correcting surrounding handles"; + ot->idname = "CURVE_OT_dissolve_verts"; + + /* api callbacks */ + ot->exec = curve_dissolve_exec; + ot->poll = ED_operator_editcurve; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + /********************** shade smooth/flat operator *********************/ static int shade_smooth_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c index f17349822c9..bb7cc61f580 100644 --- a/source/blender/editors/curve/editcurve_paint.c +++ b/source/blender/editors/curve/editcurve_paint.c @@ -194,6 +194,8 @@ struct CurveDrawData { /* offset projection by this value */ bool use_offset; float offset[3]; /* worldspace */ + float surface_offset; + bool use_surface_offset_absolute; } project; /* cursor sampling */ @@ -204,7 +206,6 @@ struct CurveDrawData { struct { float min, max, range; - float offset; } radius; struct { @@ -243,7 +244,10 @@ static float stroke_elem_radius(const struct CurveDrawData *cdd, const struct St static void stroke_elem_pressure_set(const struct CurveDrawData *cdd, struct StrokeElem *selem, float pressure) { - if ((cdd->radius.offset != 0.0f) && !is_zero_v3(selem->normal_local)) { + if ((cdd->project.surface_offset != 0.0f) && + !cdd->project.use_surface_offset_absolute && + !is_zero_v3(selem->normal_local)) + { const float adjust = stroke_elem_radius_from_pressure(cdd, pressure) - stroke_elem_radius_from_pressure(cdd, selem->pressure); madd_v3_v3fl(selem->location_local, selem->normal_local, adjust); @@ -269,7 +273,7 @@ static void stroke_elem_interp( static bool stroke_elem_project( const struct CurveDrawData *cdd, const int mval_i[2], const float mval_fl[2], - const float radius_offset, const float radius, + float surface_offset, const float radius, float r_location_world[3], float r_normal_world[3]) { View3D *v3d = cdd->vc.v3d; @@ -307,10 +311,11 @@ static bool stroke_elem_project( zero_v3(r_normal_world); } - if (radius_offset != 0.0f) { + if (surface_offset != 0.0f) { + const float offset = cdd->project.use_surface_offset_absolute ? 1.0f : radius; float normal[3]; if (depth_read_normal(&cdd->vc, &cdd->mats, mval_i, normal)) { - madd_v3_v3fl(r_location_world, normal, radius_offset * radius); + madd_v3_v3fl(r_location_world, normal, offset * surface_offset); if (r_normal_world) { copy_v3_v3(r_normal_world, normal); } @@ -333,14 +338,14 @@ static bool stroke_elem_project( static bool stroke_elem_project_fallback( const struct CurveDrawData *cdd, const int mval_i[2], const float mval_fl[2], - const float radius_offset, const float radius, + const float surface_offset, const float radius, const float location_fallback_depth[3], float r_location_world[3], float r_location_local[3], float r_normal_world[3], float r_normal_local[3]) { bool is_depth_found = stroke_elem_project( cdd, mval_i, mval_fl, - radius_offset, radius, + surface_offset, radius, r_location_world, r_normal_world); if (is_depth_found == false) { ED_view3d_win_to_3d(cdd->vc.ar, location_fallback_depth, mval_fl, r_location_world); @@ -372,7 +377,7 @@ static bool stroke_elem_project_fallback_elem( const float radius = stroke_elem_radius(cdd, selem); return stroke_elem_project_fallback( cdd, mval_i, selem->mval, - cdd->radius.offset, radius, + cdd->project.surface_offset, radius, location_fallback_depth, selem->location_world, selem->location_local, selem->normal_world, selem->normal_local); @@ -480,7 +485,7 @@ static void curve_draw_stroke_3d(const struct bContext *UNUSED(C), ARegion *UNUS selem->location_local[2] - location_prev[2]); location_prev = selem->location_local; const float radius = stroke_elem_radius(cdd, selem); - gluSphere(qobj, radius , 12, 8); + gluSphere(qobj, radius, 12, 8); location_prev = selem->location_local; } @@ -637,7 +642,7 @@ static void curve_draw_event_add_first(wmOperator *op, const wmEvent *event) /* Special case for when we only have offset applied on the first-hit, * the remaining stroke must be offset too. */ - if (cdd->radius.offset != 0.0f) { + if (cdd->project.surface_offset != 0.0f) { const float mval_fl[2] = {UNPACK2(event->mval)}; float location_no_offset[3]; @@ -688,7 +693,8 @@ static bool curve_draw_init(bContext *C, wmOperator *op, bool is_invoke) cdd->radius.min = cps->radius_min; cdd->radius.max = cps->radius_max; cdd->radius.range = cps->radius_max - cps->radius_min; - cdd->radius.offset = cps->radius_offset; + cdd->project.surface_offset = cps->surface_offset; + cdd->project.use_surface_offset_absolute = (cps->flag & CURVE_PAINT_FLAG_DEPTH_STROKE_OFFSET_ABS) != 0; cdd->stroke_elem_pool = BLI_mempool_create( sizeof(struct StrokeElem), 0, 512, BLI_MEMPOOL_ALLOW_ITER); @@ -1113,7 +1119,7 @@ static int curve_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event) /* use view plane (when set or as fallback when surface can't be found) */ if (cdd->project.use_depth == false) { - plane_co = ED_view3d_cursor3d_get(cdd->vc.scene, v3d);; + plane_co = ED_view3d_cursor3d_get(cdd->vc.scene, v3d); plane_no = rv3d->viewinv[2]; cdd->project.use_plane = true; } diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index 43c82732451..79a2c494239 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -35,10 +35,13 @@ #include <math.h> #include <float.h> +#include "MEM_guardedalloc.h" + #include "BLI_sys_types.h" #include "BLI_math.h" #include "BLI_utildefines.h" +#include "BLI_polyfill2d.h" #include "BLF_api.h" #include "BLT_translation.h" @@ -82,6 +85,7 @@ typedef enum eDrawStrokeFlags { GP_DRAWDATA_NO_ONIONS = (1 << 6), /* no onionskins should be drawn (for animation playback) */ GP_DRAWDATA_VOLUMETRIC = (1 << 7), /* draw strokes as "volumetric" circular billboards */ GP_DRAWDATA_FILL = (1 << 8), /* fill insides/bounded-regions of strokes */ + GP_DRAWDATA_HQ_FILL = (1 << 9) /* Use high quality fill */ } eDrawStrokeFlags; @@ -325,36 +329,186 @@ static void gp_draw_stroke_volumetric_3d(bGPDspoint *points, int totpoints, shor /* --------------- Stroke Fills ----------------- */ -/* draw fills for shapes */ -static void gp_draw_stroke_fill(bGPDspoint *points, int totpoints, short UNUSED(thickness), - short UNUSED(dflag), short sflag, - int offsx, int offsy, int winx, int winy) +/* Get points of stroke always flat to view not affected by camera view or view position */ +static void gp_stroke_2d_flat(bGPDspoint *points, int totpoints, float(*points2d)[2], int *r_direction) { - bGPDspoint *pt; - int i; + bGPDspoint *pt0 = &points[0]; + bGPDspoint *pt1 = &points[1]; + bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)]; - BLI_assert(totpoints >= 3); + float locx[3]; + float locy[3]; + float loc3[3]; + float normal[3]; - /* As an initial implementation, we use the OpenGL filled polygon drawing - * here since it's the easiest option to implement for this case. It does - * come with limitations (notably for concave shapes), though it shouldn't - * be much of an issue in most cases. - */ - glBegin(GL_POLYGON); + /* local X axis (p0 -> p1) */ + sub_v3_v3v3(locx, &pt1->x, &pt0->x); - for (i = 0, pt = points; i < totpoints; i++, pt++) { - if (sflag & GP_STROKE_3DSPACE) { - glVertex3fv(&pt->x); + /* point vector at 3/4 */ + sub_v3_v3v3(loc3, &pt3->x, &pt0->x); + + /* vector orthogonal to polygon plane */ + cross_v3_v3v3(normal, locx, loc3); + + /* local Y axis (cross to normal/x axis) */ + cross_v3_v3v3(locy, normal, locx); + + /* Normalize vectors */ + normalize_v3(locx); + normalize_v3(locy); + + /* Get all points in local space */ + for (int i = 0; i < totpoints; i++) { + bGPDspoint *pt = &points[i]; + float loc[3]; + + /* Get local space using first point as origin */ + sub_v3_v3v3(loc, &pt->x, &pt0->x); + + points2d[i][0] = dot_v3v3(loc, locx); + points2d[i][1] = dot_v3v3(loc, locy); + } + + /* Concave (-1), Convex (1), or Autodetect (0)? */ + *r_direction = (int)locy[2]; +} + + +/* Triangulate stroke for high quality fill (this is done only if cache is null or stroke was modified) */ +static void gp_triangulate_stroke_fill(bGPDstroke *gps) +{ + BLI_assert(gps->totpoints >= 3); + gps->tot_triangles = gps->totpoints - 2; + + /* allocate memory for temporary areas */ + unsigned int (*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * gps->tot_triangles, "GP Stroke temp triangulation"); + float (*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints, "GP Stroke temp 2d points"); + + int direction = 0; + + /* convert to 2d and triangulate */ + gp_stroke_2d_flat(gps->points, gps->totpoints, points2d, &direction); + BLI_polyfill_calc((const float(*)[2])points2d, (unsigned int)gps->totpoints, direction, (unsigned int(*)[3])tmp_triangles); + + /* save triangulation data in stroke cache */ + if (gps->tot_triangles > 0) { + if (gps->triangles == NULL) { + gps->triangles = MEM_callocN(sizeof(*gps->triangles) * gps->tot_triangles, "GP Stroke triangulation"); } else { - float co[2]; - - gp_calc_2d_stroke_xy(pt, sflag, offsx, offsy, winx, winy, co); - glVertex2fv(co); + gps->triangles = MEM_recallocN(gps->triangles, sizeof(*gps->triangles) * gps->tot_triangles); + } + + int i; + + for (i = 0; i < gps->tot_triangles; i++) { + bGPDtriangle *stroke_triangle = &gps->triangles[i]; + stroke_triangle->v1 = tmp_triangles[i][0]; + stroke_triangle->v2 = tmp_triangles[i][1]; + stroke_triangle->v3 = tmp_triangles[i][2]; } } + else { + /* No triangles needed - Free anything allocated previously */ + if (gps->triangles) + MEM_freeN(gps->triangles); + + gps->triangles = NULL; + } - glEnd(); + /* disable recalculation flag */ + if (gps->flag & GP_STROKE_RECALC_CACHES) { + gps->flag &= ~GP_STROKE_RECALC_CACHES; + } + + /* clear memory */ + if (tmp_triangles) MEM_freeN(tmp_triangles); + if (points2d) MEM_freeN(points2d); +} + + +/* draw fills for shapes */ +static void gp_draw_stroke_fill(bGPDstroke *gps, short UNUSED(thickness), short dflag, int offsx, int offsy, int winx, int winy) +{ + BLI_assert(gps->totpoints >= 3); + + /* Triangulation fill if high quality flag is enabled */ + if (dflag & GP_DRAWDATA_HQ_FILL) { + bGPDtriangle *stroke_triangle; + bGPDspoint *pt; + int i; + + /* Calculate triangles cache for filling area (must be done only after changes) */ + if ((gps->flag & GP_STROKE_RECALC_CACHES) || (gps->tot_triangles == 0) || (gps->triangles == NULL)) { + gp_triangulate_stroke_fill(gps); + } + + /* Draw all triangles for filling the polygon (cache must be calculated before) */ + BLI_assert(gps->tot_triangles >= 1); + glBegin(GL_TRIANGLES); + for (i = 0, stroke_triangle = gps->triangles; i < gps->tot_triangles; i++, stroke_triangle++) { + if (gps->flag & GP_STROKE_3DSPACE) { + /* vertex 1 */ + pt = &gps->points[stroke_triangle->v1]; + glVertex3fv(&pt->x); + + /* vertex 2 */ + pt = &gps->points[stroke_triangle->v2]; + glVertex3fv(&pt->x); + + /* vertex 3 */ + pt = &gps->points[stroke_triangle->v3]; + glVertex3fv(&pt->x); + } + else { + float co[2]; + + /* vertex 1 */ + pt = &gps->points[stroke_triangle->v1]; + gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co); + glVertex2fv(co); + + /* vertex 2 */ + pt = &gps->points[stroke_triangle->v2]; + gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co); + glVertex2fv(co); + + /* vertex 3 */ + pt = &gps->points[stroke_triangle->v3]; + gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co); + glVertex2fv(co); + } + } + glEnd(); + } + else { + /* As an initial implementation, we use the OpenGL filled polygon drawing + * here since it's the easiest option to implement for this case. It does + * come with limitations (notably for concave shapes), though it works well + * enough for many simple situations. + * + * We keep this legacy implementation around despite now having the high quality + * fills, as this is necessary for keeping everything working nicely for files + * created using old versions of Blender which may have depended on the artifacts + * the old fills created. + */ + bGPDspoint *pt; + int i; + + glBegin(GL_POLYGON); + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + if (gps->flag & GP_STROKE_3DSPACE) { + glVertex3fv(&pt->x); + } + else { + float co[2]; + + gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co); + glVertex2fv(co); + } + } + glEnd(); + } } /* ----- Existing Strokes Drawing (3D and Point) ------ */ @@ -696,7 +850,7 @@ static void gp_draw_strokes(bGPDframe *gpf, int offsx, int offsy, int winx, int /* 3D Fill */ if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) { glColor4fv(fill_color); - gp_draw_stroke_fill(gps->points, gps->totpoints, lthick, dflag, gps->flag, offsx, offsy, winx, winy); + gp_draw_stroke_fill(gps, lthick, dflag, offsx, offsy, winx, winy); } /* 3D Stroke */ @@ -731,7 +885,7 @@ static void gp_draw_strokes(bGPDframe *gpf, int offsx, int offsy, int winx, int /* 2D - Fill */ if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) { glColor4fv(fill_color); - gp_draw_stroke_fill(gps->points, gps->totpoints, lthick, dflag, gps->flag, offsx, offsy, winx, winy); + gp_draw_stroke_fill(gps, lthick, dflag, offsx, offsy, winx, winy); } /* 2D Strokes... */ @@ -891,7 +1045,7 @@ static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int of copy_v3_v3(color, gpl->color); } - if (gpl->gstep) { + if (gpl->gstep > 0) { bGPDframe *gf; float fac; @@ -908,13 +1062,16 @@ static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int of break; } } - else { + else if (gpl->gstep == 0) { /* draw the strokes for the ghost frames (at half of the alpha set by user) */ if (gpf->prev) { color[3] = (alpha / 7); gp_draw_strokes(gpf->prev, offsx, offsy, winx, winy, dflag, debug, lthick, color, color); } } + else { + /* don't draw - disabled */ + } /* 2) Now draw next frames */ @@ -925,7 +1082,7 @@ static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int of copy_v3_v3(color, gpl->color); } - if (gpl->gstep_next) { + if (gpl->gstep_next > 0) { bGPDframe *gf; float fac; @@ -942,13 +1099,16 @@ static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int of break; } } - else { + else if (gpl->gstep_next == 0) { /* draw the strokes for the ghost frames (at half of the alpha set by user) */ if (gpf->next) { color[3] = (alpha / 4); gp_draw_strokes(gpf->next, offsx, offsy, winx, winy, dflag, debug, lthick, color, color); } } + else { + /* don't draw - disabled */ + } /* 3) restore alpha */ glColor4fv(gpl->color); @@ -991,7 +1151,10 @@ static void gp_draw_data_layers(bGPdata *gpd, int offsx, int offsy, int winx, in /* volumetric strokes... */ GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_VOLUMETRIC), GP_DRAWDATA_VOLUMETRIC); - + + /* HQ fills... */ + GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_HQ_FILL), GP_DRAWDATA_HQ_FILL); + /* fill strokes... */ // XXX: this is not a very good limit GP_DRAWFLAG_APPLY((gpl->fill[3] > GPENCIL_ALPHA_OPACITY_THRESH), GP_DRAWDATA_FILL); diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c index 09a72c10457..a49b3362155 100644 --- a/source/blender/editors/gpencil/editaction_gpencil.c +++ b/source/blender/editors/gpencil/editaction_gpencil.c @@ -460,7 +460,8 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode) /* make a copy of stroke, then of its points array */ gpsn = MEM_dupallocN(gps); gpsn->points = MEM_dupallocN(gps->points); - + /* duplicate triangle information */ + gpsn->triangles = MEM_dupallocN(gps->triangles); /* append stroke to frame */ BLI_addtail(&gpf->strokes, gpsn); } diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c index 43751dbadb9..0271afd6827 100644 --- a/source/blender/editors/gpencil/gpencil_brush.c +++ b/source/blender/editors/gpencil/gpencil_brush.c @@ -766,8 +766,9 @@ static void gp_brush_clone_add(bContext *C, tGP_BrushEditData *gso) new_stroke = MEM_dupallocN(gps); new_stroke->points = MEM_dupallocN(gps->points); - new_stroke->next = new_stroke->prev = NULL; + new_stroke->triangles = MEM_dupallocN(gps->triangles); + new_stroke->next = new_stroke->prev = NULL; BLI_addtail(&gpf->strokes, new_stroke); /* Adjust all the stroke's points, so that the strokes @@ -865,14 +866,18 @@ static void gp_brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customda glTranslatef((float)x, (float)y, 0.0f); - /* TODO: toggle between add and remove? */ - glColor4ub(255, 255, 255, 128); - glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); + /* Inner Ring: Light color for action of the brush */ + /* TODO: toggle between add and remove? */ + glColor4ub(255, 255, 255, 200); glutil_draw_lined_arc(0.0, M_PI * 2.0, brush->size, 40); + /* Outer Ring: Dark color for contrast on light backgrounds (e.g. gray on white) */ + glColor3ub(30, 30, 30); + glutil_draw_lined_arc(0.0, M_PI * 2.0, brush->size + 1, 40); + glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); @@ -905,7 +910,7 @@ static void gpencil_toggle_brush_cursor(bContext *C, bool enable) static void gpsculpt_brush_header_set(bContext *C, tGP_BrushEditData *gso) { const char *brush_name = NULL; - char str[256] = ""; + char str[UI_MAX_DRAW_STR] = ""; RNA_enum_name(rna_enum_gpencil_sculpt_brush_items, gso->brush_type, &brush_name); @@ -1284,6 +1289,12 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso) printf("ERROR: Unknown type of GPencil Sculpt brush - %u\n", gso->brush_type); break; } + + /* Triangulation must be calculated if changed */ + if (changed) { + gps->flag |= GP_STROKE_RECALC_CACHES; + gps->tot_triangles = 0; + } } CTX_DATA_END; diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 03d5ed3e24f..bd1697b9a54 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -170,6 +170,11 @@ static void gp_duplicate_points(const bGPDstroke *gps, ListBase *new_strokes) /* make a stupid copy first of the entire stroke (to get the flags too) */ gpsd = MEM_dupallocN(gps); + /* initialize triangle memory - will be calculated on next redraw */ + gpsd->triangles = NULL; + gpsd->flag |= GP_STROKE_RECALC_CACHES; + gpsd->tot_triangles = 0; + /* now, make a new points array, and copy of the relevant parts */ gpsd->points = MEM_callocN(sizeof(bGPDspoint) * len, "gps stroke points copy"); memcpy(gpsd->points, gps->points + start_idx, sizeof(bGPDspoint) * len); @@ -223,6 +228,10 @@ static int gp_duplicate_exec(bContext *C, wmOperator *op) gpsd = MEM_dupallocN(gps); gpsd->points = MEM_dupallocN(gps->points); + /* triangle information - will be calculated on next redraw */ + gpsd->flag |= GP_STROKE_RECALC_CACHES; + gpsd->triangles = NULL; + /* add to temp buffer */ gpsd->next = gpsd->prev = NULL; BLI_addtail(&new_strokes, gpsd); @@ -287,11 +296,13 @@ void ED_gpencil_strokes_copybuf_free(void) for (gps = gp_strokes_copypastebuf.first; gps; gps = gpsn) { gpsn = gps->next; - MEM_freeN(gps->points); + if (gps->points) MEM_freeN(gps->points); + if (gps->triangles) MEM_freeN(gps->triangles); + BLI_freelinkN(&gp_strokes_copypastebuf, gps); } - BLI_listbase_clear(&gp_strokes_copypastebuf); + gp_strokes_copypastebuf.first = gp_strokes_copypastebuf.last = NULL; } /* --------------------- */ @@ -336,6 +347,11 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op) gpsd = MEM_dupallocN(gps); gpsd->points = MEM_dupallocN(gps->points); + /* triangles cache - will be recalculated on next redraw */ + gpsd->flag |= GP_STROKE_RECALC_CACHES; + gpsd->tot_triangles = 0; + gpsd->triangles = NULL; + /* add to temp buffer */ gpsd->next = gpsd->prev = NULL; BLI_addtail(&gp_strokes_copypastebuf, gpsd); @@ -371,6 +387,14 @@ void GPENCIL_OT_copy(wmOperatorType *ot) /* --------------------- */ /* Paste selected strokes */ +static int gp_strokes_paste_poll(bContext *C) +{ + /* 1) Must have GP layer to paste to... + * 2) Copy buffer must at least have something (though it may be the wrong sort...) + */ + return (CTX_data_active_gpencil_layer(C) != NULL) && (!BLI_listbase_is_empty(&gp_strokes_copypastebuf)); +} + static int gp_strokes_paste_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); @@ -450,8 +474,11 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op) bGPDstroke *new_stroke = MEM_dupallocN(gps); new_stroke->points = MEM_dupallocN(gps->points); - new_stroke->next = new_stroke->prev = NULL; + new_stroke->flag |= GP_STROKE_RECALC_CACHES; + new_stroke->triangles = NULL; + + new_stroke->next = new_stroke->prev = NULL; BLI_addtail(&gpf->strokes, new_stroke); } } @@ -472,7 +499,7 @@ void GPENCIL_OT_paste(wmOperatorType *ot) /* callbacks */ ot->exec = gp_strokes_paste_exec; - ot->poll = gp_stroke_edit_poll; + ot->poll = gp_strokes_paste_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -672,6 +699,7 @@ static int gp_delete_selected_strokes(bContext *C) if (gps->flag & GP_STROKE_SELECT) { /* free stroke memory arrays, then stroke itself */ if (gps->points) MEM_freeN(gps->points); + if (gps->triangles) MEM_freeN(gps->triangles); BLI_freelinkN(&gpf->strokes, gps); changed = true; @@ -732,6 +760,9 @@ static int gp_dissolve_selected_points(bContext *C) if (tot <= 0) { /* remove the entire stroke */ MEM_freeN(gps->points); + if (gps->triangles) { + MEM_freeN(gps->triangles); + } BLI_freelinkN(&gpf->strokes, gps); } else { @@ -753,6 +784,10 @@ static int gp_dissolve_selected_points(bContext *C) gps->points = new_points; gps->totpoints = tot; + /* triangles cache needs to be recalculated */ + gps->flag |= GP_STROKE_RECALC_CACHES; + gps->tot_triangles = 0; + /* deselect the stroke, since none of its selected points will still be selected */ gps->flag &= ~GP_STROKE_SELECT; } @@ -842,6 +877,11 @@ void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke tGPDeleteIsland *island = &islands[idx]; bGPDstroke *new_stroke = MEM_dupallocN(gps); + /* initialize triangle memory - to be calculated on next redraw */ + new_stroke->triangles = NULL; + new_stroke->flag |= GP_STROKE_RECALC_CACHES; + new_stroke->tot_triangles = 0; + /* Compute new buffer size (+ 1 needed as the endpoint index is "inclusive") */ new_stroke->totpoints = island->end_idx - island->start_idx + 1; new_stroke->points = MEM_callocN(sizeof(bGPDspoint) * new_stroke->totpoints, "gp delete stroke fragment"); @@ -886,6 +926,9 @@ void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke /* Delete the old stroke */ MEM_freeN(gps->points); + if (gps->triangles) { + MEM_freeN(gps->triangles); + } BLI_freelinkN(&gpf->strokes, gps); } diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index 368da618a1d..dd28f6ac531 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -177,6 +177,8 @@ void GPENCIL_OT_select_linked(struct wmOperatorType *ot); void GPENCIL_OT_select_grouped(struct wmOperatorType *ot); void GPENCIL_OT_select_more(struct wmOperatorType *ot); void GPENCIL_OT_select_less(struct wmOperatorType *ot); +void GPENCIL_OT_select_first(struct wmOperatorType *ot); +void GPENCIL_OT_select_last(struct wmOperatorType *ot); void GPENCIL_OT_duplicate(struct wmOperatorType *ot); void GPENCIL_OT_delete(struct wmOperatorType *ot); diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index 9f5633ae668..405b673c42b 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -102,6 +102,10 @@ static void ed_keymap_gpencil_general(wmKeyConfig *keyconf) /* Pie Menu - For standard tools */ WM_keymap_add_menu_pie(keymap, "GPENCIL_PIE_tool_palette", QKEY, KM_PRESS, 0, DKEY); WM_keymap_add_menu_pie(keymap, "GPENCIL_PIE_settings_palette", WKEY, KM_PRESS, 0, DKEY); + + /* Delete Active Frame - For easier video tutorials/review sessions */ + /* NOTE: This works even when not in EditMode */ + WM_keymap_add_item(keymap, "GPENCIL_OT_active_frame_delete", XKEY, KM_PRESS, 0, DKEY); } /* ==================== */ @@ -140,6 +144,36 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf) kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, 0, 0); RNA_string_set(kmi->ptr, "data_path_primary", "user_preferences.edit.grease_pencil_eraser_radius"); + + /* Sculpting ------------------------------------- */ + + /* Brush-Based Editing: + * EKEY + LMB = Single stroke, draw immediately + * + Other Modifiers (Ctrl/Shift) = Invert, Smooth, etc. + * + * For the modal version, use D+E -> Sculpt + */ + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, 0, EKEY); + RNA_boolean_set(kmi->ptr, "wait_for_input", false); + + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, KM_CTRL, EKEY); + RNA_boolean_set(kmi->ptr, "wait_for_input", false); + /*RNA_boolean_set(kmi->ptr, "use_invert", true);*/ + + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, KM_SHIFT, EKEY); + RNA_boolean_set(kmi->ptr, "wait_for_input", false); + /*RNA_boolean_set(kmi->ptr, "use_smooth", true);*/ + + + /* Shift-FKEY = Sculpt Strength */ + kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0); + RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.brush.strength"); + + /* Ctrl-FKEY = Sculpt Brush Size */ + kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_CTRL, 0); + RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.brush.size"); + + /* Selection ------------------------------------- */ /* select all */ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_all", AKEY, KM_PRESS, 0, 0); @@ -160,6 +194,15 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf) kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_SHIFT | KM_CTRL, 0); RNA_boolean_set(kmi->ptr, "deselect", true); + /* In the Node Editor, lasso select needs ALT modifier too (as somehow CTRL+LMB drag gets taken for "cut" quite early) + * There probably isn't too much harm adding this for other editors too as part of standard GP editing keymap. This hotkey + * combo doesn't seem to see much use under standard scenarios? + */ + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_ALT, 0); + RNA_boolean_set(kmi->ptr, "deselect", false); + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_SHIFT | KM_CTRL | KM_ALT, 0); + RNA_boolean_set(kmi->ptr, "deselect", true); + /* normal select */ WM_keymap_add_item(keymap, "GPENCIL_OT_select", SELECTMOUSE, KM_PRESS, 0, 0); @@ -191,10 +234,12 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf) /* delete */ WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_gpencil_delete", XKEY, KM_PRESS, 0, 0); WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_gpencil_delete", DELKEY, KM_PRESS, 0, 0); - + WM_keymap_add_item(keymap, "GPENCIL_OT_dissolve", XKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "GPENCIL_OT_dissolve", DELKEY, KM_PRESS, KM_CTRL, 0); + WM_keymap_add_item(keymap, "GPENCIL_OT_active_frame_delete", XKEY, KM_PRESS, KM_SHIFT, 0); + /* copy + paste */ WM_keymap_add_item(keymap, "GPENCIL_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "GPENCIL_OT_paste", VKEY, KM_PRESS, KM_CTRL, 0); @@ -229,36 +274,6 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "GPENCIL_OT_move_to_layer", MKEY, KM_PRESS, 0, 0); - - /* Brush-Based Editing: - * EKEY + LMB = Single stroke, draw immediately - * + Other Modifiers (Ctrl/Shift) = Invert, Smooth, etc. - * - * For the modal version, use D+E -> Sculpt - */ - kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, 0, EKEY); - RNA_boolean_set(kmi->ptr, "wait_for_input", false); - - kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, KM_CTRL, EKEY); - RNA_boolean_set(kmi->ptr, "wait_for_input", false); - /*RNA_boolean_set(kmi->ptr, "use_invert", true);*/ - - kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, KM_SHIFT, EKEY); - RNA_boolean_set(kmi->ptr, "wait_for_input", false); - /*RNA_boolean_set(kmi->ptr, "use_smooth", true);*/ - - - /* Shift-FKEY = Sculpt Strength */ - kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0); - RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.brush.strength"); - - /* Ctrl-FKEY = Sculpt Brush Size */ - kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_CTRL, 0); - RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.brush.size"); - - - - /* Transform Tools */ kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", GKEY, KM_PRESS, 0, 0); @@ -314,6 +329,8 @@ void ED_operatortypes_gpencil(void) WM_operatortype_append(GPENCIL_OT_select_grouped); WM_operatortype_append(GPENCIL_OT_select_more); WM_operatortype_append(GPENCIL_OT_select_less); + WM_operatortype_append(GPENCIL_OT_select_first); + WM_operatortype_append(GPENCIL_OT_select_last); WM_operatortype_append(GPENCIL_OT_duplicate); WM_operatortype_append(GPENCIL_OT_delete); diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 2a81b481ed1..fba2f30e715 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -572,6 +572,9 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) gps->flag = gpd->sbuffer_sflag; gps->inittime = p->inittime; + /* enable recalculation flag by default (only used if hq fill) */ + gps->flag |= GP_STROKE_RECALC_CACHES; + /* allocate enough memory for a continuous array for storage points */ int sublevel = gpl->sublevel; int new_totpoints = gps->totpoints; @@ -580,7 +583,10 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) new_totpoints += new_totpoints - 1; } gps->points = MEM_callocN(sizeof(bGPDspoint) * new_totpoints, "gp_stroke_points"); - + /* initialize triangle memory to dummy data */ + gps->triangles = MEM_callocN(sizeof(bGPDtriangle), "GP Stroke triangulation"); + gps->flag |= GP_STROKE_RECALC_CACHES; + gps->tot_triangles = 0; /* set pointer to first non-initialized point */ pt = gps->points + (gps->totpoints - totelem); @@ -710,11 +716,18 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) } } - /* smooth stroke - only if there's something to do */ - /* NOTE: No pressure smoothing, or else we get annoying thickness changes while drawing... */ + /* smooth stroke after subdiv - only if there's something to do + * for each iteration, the factor is reduced to get a better smoothing without changing too much + * the original stroke + */ if (gpl->draw_smoothfac > 0.0f) { - for (i = 0; i < gps->totpoints; i++) { - gp_smooth_stroke(gps, i, gpl->draw_smoothfac, false); + float reduce = 0.0f; + for (int r = 0; r < gpl->draw_smoothlvl; ++r) { + for (i = 0; i < gps->totpoints; i++) { + /* NOTE: No pressure smoothing, or else we get annoying thickness changes while drawing... */ + gp_smooth_stroke(gps, i, gpl->draw_smoothfac - reduce, false); + } + reduce += 0.25f; // reduce the factor } } @@ -795,6 +808,8 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, /* just free stroke */ if (gps->points) MEM_freeN(gps->points); + if (gps->triangles) + MEM_freeN(gps->triangles); BLI_freelinkN(&gpf->strokes, gps); } else if (gps->totpoints == 1) { @@ -807,6 +822,8 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, /* free stroke */ // XXX: pressure sensitive eraser should apply here too? MEM_freeN(gps->points); + if (gps->triangles) + MEM_freeN(gps->triangles); BLI_freelinkN(&gpf->strokes, gps); } } diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c index 0a36df471f1..b6482786b4f 100644 --- a/source/blender/editors/gpencil/gpencil_select.c +++ b/source/blender/editors/gpencil/gpencil_select.c @@ -349,6 +349,126 @@ void GPENCIL_OT_select_grouped(wmOperatorType *ot) } /* ********************************************** */ +/* Select First */ + +static int gpencil_select_first_exec(bContext *C, wmOperator *op) +{ + const bool only_selected = RNA_boolean_get(op->ptr, "only_selected_strokes"); + const bool extend = RNA_boolean_get(op->ptr, "extend"); + + CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) + { + /* skip stroke if we're only manipulating selected strokes */ + if (only_selected && !(gps->flag & GP_STROKE_SELECT)) { + continue; + } + + /* select first point */ + BLI_assert(gps->totpoints >= 1); + + gps->points->flag |= GP_SPOINT_SELECT; + gps->flag |= GP_STROKE_SELECT; + + /* deselect rest? */ + if ((extend == false) && (gps->totpoints > 1)) { + /* start from index 1, to skip the first point that we'd just selected... */ + bGPDspoint *pt = &gps->points[1]; + int i = 1; + + for (; i < gps->totpoints; i++, pt++) { + pt->flag &= ~GP_SPOINT_SELECT; + } + } + } + CTX_DATA_END; + + /* updates */ + WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_select_first(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select First"; + ot->idname = "GPENCIL_OT_select_first"; + ot->description = "Select first point in Grease Pencil strokes"; + + /* callbacks */ + ot->exec = gpencil_select_first_exec; + ot->poll = gpencil_select_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, "only_selected_strokes", false, "Selected Strokes Only", + "Only select the first point of strokes that already have points selected"); + + RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting all other selected points"); +} + +/* ********************************************** */ +/* Select First */ + +static int gpencil_select_last_exec(bContext *C, wmOperator *op) +{ + const bool only_selected = RNA_boolean_get(op->ptr, "only_selected_strokes"); + const bool extend = RNA_boolean_get(op->ptr, "extend"); + + CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) + { + /* skip stroke if we're only manipulating selected strokes */ + if (only_selected && !(gps->flag & GP_STROKE_SELECT)) { + continue; + } + + /* select last point */ + BLI_assert(gps->totpoints >= 1); + + gps->points[gps->totpoints - 1].flag |= GP_SPOINT_SELECT; + gps->flag |= GP_STROKE_SELECT; + + /* deselect rest? */ + if ((extend == false) && (gps->totpoints > 1)) { + /* don't include the last point... */ + bGPDspoint *pt = gps->points; + int i = 1; + + for (; i < gps->totpoints - 1; i++, pt++) { + pt->flag &= ~GP_SPOINT_SELECT; + } + } + } + CTX_DATA_END; + + /* updates */ + WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_select_last(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Last"; + ot->idname = "GPENCIL_OT_select_last"; + ot->description = "Select last point in Grease Pencil strokes"; + + /* callbacks */ + ot->exec = gpencil_select_last_exec; + ot->poll = gpencil_select_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, "only_selected_strokes", false, "Selected Strokes Only", + "Only select the last point of strokes that already have points selected"); + + RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting all other selected points"); +} + +/* ********************************************** */ /* Select More */ static int gpencil_select_more_exec(bContext *C, wmOperator *UNUSED(op)) diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index f54da91af71..b2c6107ab61 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -641,3 +641,21 @@ void gp_subdivide_stroke(bGPDstroke *gps, const int new_totpoints) } /* ******************************************************** */ + + +bool ED_gpencil_stroke_minmax( + const bGPDstroke *gps, const bool use_select, + float r_min[3], float r_max[3]) +{ + const bGPDspoint *pt; + int i; + bool changed = false; + + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + if ((use_select == false) || (pt->flag & GP_SPOINT_SELECT)) {; + minmax_v3v3_v3(r_min, r_max, &pt->x); + changed = true; + } + } + return changed; +} diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h index e45e5f5e7ab..0ac5c17a552 100644 --- a/source/blender/editors/include/BIF_glutil.h +++ b/source/blender/editors/include/BIF_glutil.h @@ -143,6 +143,8 @@ void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int fo */ void glaDrawPixelsTex(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect); +void glaDrawPixelsTex_clipping(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect, + float clip_min_x, float clip_min_y, float clip_max_x, float clip_max_y); /** * glaDrawPixelsAuto - Switches between texture or pixel drawing using UserDef. @@ -150,9 +152,13 @@ void glaDrawPixelsTex(float x, float y, int img_w, int img_h, int format, int ty * needs glaDefine2DArea to be set. */ void glaDrawPixelsAuto(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect); +void glaDrawPixelsAuto_clipping(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect, + float clip_min_x, float clip_min_y, float clip_max_x, float clip_max_y); void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect, float scaleX, float scaleY); +void glaDrawPixelsTexScaled_clipping(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); /* 2D Drawing Assistance */ @@ -205,9 +211,21 @@ void bgl_get_mats(bglMats *mats); void glaDrawImBuf_glsl(struct ImBuf *ibuf, float x, float y, int zoomfilter, struct ColorManagedViewSettings *view_settings, struct ColorManagedDisplaySettings *display_settings); +void glaDrawImBuf_glsl_clipping(struct ImBuf *ibuf, float x, float y, int zoomfilter, + struct ColorManagedViewSettings *view_settings, + struct ColorManagedDisplaySettings *display_settings, + float clip_min_x, float clip_min_y, + float clip_max_x, float clip_max_y); + /* Draw imbuf on a screen, preferably using GLSL display transform */ void glaDrawImBuf_glsl_ctx(const struct bContext *C, struct ImBuf *ibuf, float x, float y, int zoomfilter); +void glaDrawImBuf_glsl_ctx_clipping(const struct bContext *C, + struct ImBuf *ibuf, + float x, float y, + int zoomfilter, + float clip_min_x, float clip_min_y, + float clip_max_x, float clip_max_y); void glaDrawBorderCorners(const struct rcti *border, float zoomx, float zoomy); diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index 15c68378b9a..904132b8876 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -74,7 +74,10 @@ typedef struct EditBone { float xwidth, length, zwidth; /* put them in order! transform uses this as scale */ float ease1, ease2; float rad_head, rad_tail; - + float roll1, roll2; + float curveOutX, curveOutY; + float curveInX, curveInY; + float scaleIn, scaleOut; float oldlength; /* for envelope scaling */ short segments; diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index 0f638c449ad..255827db373 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -86,6 +86,10 @@ bool ED_gpencil_has_keyframe_v3d(struct Scene *scene, struct Object *ob, int cfr bool ED_gpencil_stroke_can_use_direct(const struct ScrArea *sa, const struct bGPDstroke *gps); bool ED_gpencil_stroke_can_use(const struct bContext *C, const struct bGPDstroke *gps); +bool ED_gpencil_stroke_minmax( + const struct bGPDstroke *gps, const bool use_select, + float r_min[3], float r_max[3]); + /* ----------- Grease Pencil Operators ----------------- */ void ED_keymap_gpencil(struct wmKeyConfig *keyconf); diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h index 39df52e5f68..933f480a554 100644 --- a/source/blender/editors/include/ED_transform.h +++ b/source/blender/editors/include/ED_transform.h @@ -158,19 +158,6 @@ void BIF_draw_manipulator(const struct bContext *C); /* Snapping */ - -typedef struct DepthPeel { - struct DepthPeel *next, *prev; - - float depth; - float p[3]; - float no[3]; - struct Object *ob; - int flag; -} DepthPeel; - -struct ListBase; - typedef enum SnapSelect { SNAP_ALL = 0, SNAP_NOT_SELECTED = 1, @@ -179,14 +166,18 @@ typedef enum SnapSelect { #define SNAP_MIN_DISTANCE 30 -bool peelObjectsTransForm( - struct TransInfo *t, const float mval[2], SnapSelect snap_select, +bool peelObjectsTransform( + struct TransInfo *t, const float mval[2], + SnapSelect snap_select, bool use_peel_object, /* return args */ - struct ListBase *r_depth_peels); -bool peelObjectsContext( - struct bContext *C, const float mval[2], SnapSelect snap_select, + float r_loc[3], float r_no[3], float *r_thickness); +bool peelObjectsSnapContext( + struct SnapObjectContext *sctx, + const float mval[2], + SnapSelect snap_select, bool use_peel_object, /* return args */ - struct ListBase *r_depth_peels); + float r_loc[3], float r_no[3], float *r_thickness); + bool snapObjectsTransform( struct TransInfo *t, const float mval[2], SnapSelect snap_select, float *dist_px, @@ -201,67 +192,4 @@ bool snapNodesContext( /* return args */ float r_loc[2], float *r_dist_px, char *r_node_border); - -/* transform_snap_object.c */ - -/* ED_transform_snap_object_*** API */ -struct SnapObjectParams { - SnapSelect snap_select; - union { - unsigned int snap_to : 4; - /* snap_target_flag: Snap to vert/edge/face. */ - unsigned int snap_to_flag : 4; - }; - /* use editmode cage */ - unsigned int use_object_edit : 1; - /* special context sensitive handling for the active object */ - unsigned int use_object_active : 1; -}; - -enum { - SNAP_OBJECT_USE_CACHE = (1 << 0), -}; - -typedef struct SnapObjectContext SnapObjectContext; -SnapObjectContext *ED_transform_snap_object_context_create( - struct Main *bmain, struct Scene *scene, int flag); -SnapObjectContext *ED_transform_snap_object_context_create_view3d( - struct Main *bmain, struct Scene *scene, int flag, - /* extra args for view3d */ - struct ARegion *ar, struct View3D *v3d); -void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx); - -bool ED_transform_snap_object_project_ray_ex( - struct SnapObjectContext *sctx, - const struct SnapObjectParams *params, - const float ray_start[3], const float ray_normal[3], float *ray_depth, - /* return args */ - float r_loc[3], float r_no[3], int *r_index, - struct Object **r_ob, float r_obmat[4][4]); -bool ED_transform_snap_object_project_ray( - SnapObjectContext *sctx, - const float ray_origin[3], const float ray_direction[3], float *ray_dist, - float r_co[3], float r_no[3]); - -bool ED_transform_snap_object_project_view3d_ex( - struct SnapObjectContext *sctx, - const struct SnapObjectParams *params, - const float mval[2], float *dist_px, - float *ray_depth, - float r_loc[3], float r_no[3], int *r_index); -bool ED_transform_snap_object_project_view3d( - struct SnapObjectContext *sctx, - const struct SnapObjectParams *params, - const float mval[2], float *dist_px, - float *ray_depth, - /* return args */ - float r_loc[3], float r_no[3]); -bool ED_transform_snap_object_project_view3d_mixed( - SnapObjectContext *sctx, - const struct SnapObjectParams *params, - const float mval_fl[2], float *dist_px, - bool use_depth, - float r_co[3], float r_no[3]); - - #endif /* __ED_TRANSFORM_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 new file mode 100644 index 00000000000..900b7593f2e --- /dev/null +++ b/source/blender/editors/include/ED_transform_snap_object_context.h @@ -0,0 +1,140 @@ +/* + * ***** 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_transform_snap_object_context.h + * \ingroup editors + */ + +#ifndef __ED_TRANSFORM_SNAP_OBJECT_CONTEXT_H__ +#define __ED_TRANSFORM_SNAP_OBJECT_CONTEXT_H__ + +struct BMVert; +struct BMEdge; +struct BMFace; + +struct ListBase; +struct Scene; +struct Main; +struct Object; +struct ARegion; +struct View3D; + +/* transform_snap_object.c */ + +/* ED_transform_snap_object_*** API */ + +/** used for storing multiple hits */ +struct SnapObjectHitDepth { + struct SnapObjectHitDepth *next, *prev; + + float depth; + float co[3]; + float no[3]; + int index; + + struct Object *ob; + float obmat[4][4]; + + /* needed to tell which ray-cast this was part of, + * the same object may be part of many ray-casts when dupli's are used. */ + unsigned int ob_uuid; +}; + +struct SnapObjectParams { + int snap_select; /* SnapSelect */ + union { + unsigned int snap_to : 4; + /* snap_target_flag: Snap to vert/edge/face. */ + unsigned int snap_to_flag : 4; + }; + /* use editmode cage */ + unsigned int use_object_edit : 1; + /* special context sensitive handling for the active object */ + unsigned int use_object_active : 1; +}; + +enum { + SNAP_OBJECT_USE_CACHE = (1 << 0), +}; + +typedef struct SnapObjectContext SnapObjectContext; +SnapObjectContext *ED_transform_snap_object_context_create( + struct Main *bmain, struct Scene *scene, int flag); +SnapObjectContext *ED_transform_snap_object_context_create_view3d( + struct Main *bmain, struct Scene *scene, int flag, + /* extra args for view3d */ + struct ARegion *ar, struct View3D *v3d); +void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx); + +/* callbacks to filter how snap works */ +void ED_transform_snap_object_context_set_editmesh_callbacks( + SnapObjectContext *sctx, + bool (*test_vert_fn)(struct BMVert *, void *user_data), + bool (*test_edge_fn)(struct BMEdge *, void *user_data), + bool (*test_face_fn)(struct BMFace *, void *user_data), + void *user_data); + +bool ED_transform_snap_object_project_ray_ex( + struct SnapObjectContext *sctx, + const struct SnapObjectParams *params, + const float ray_start[3], const float ray_normal[3], float *ray_depth, + /* return args */ + float r_loc[3], float r_no[3], int *r_index, + struct Object **r_ob, float r_obmat[4][4]); +bool ED_transform_snap_object_project_ray( + SnapObjectContext *sctx, + const float ray_origin[3], const float ray_direction[3], float *ray_depth, + float r_co[3], float r_no[3]); + +bool ED_transform_snap_object_project_ray_all( + SnapObjectContext *sctx, + const struct SnapObjectParams *params, + const float ray_start[3], const float ray_normal[3], + float ray_depth, bool sort, + struct ListBase *r_hit_list); + +bool ED_transform_snap_object_project_view3d_ex( + struct SnapObjectContext *sctx, + const struct SnapObjectParams *params, + const float mval[2], float *dist_px, + float *ray_depth, + float r_loc[3], float r_no[3], int *r_index); +bool ED_transform_snap_object_project_view3d( + struct SnapObjectContext *sctx, + const struct SnapObjectParams *params, + const float mval[2], float *dist_px, + float *ray_depth, + /* return args */ + float r_loc[3], float r_no[3]); +bool ED_transform_snap_object_project_view3d_mixed( + SnapObjectContext *sctx, + const struct SnapObjectParams *params, + const float mval_fl[2], float *dist_px, + bool use_depth, + float r_co[3], float r_no[3]); + +bool ED_transform_snap_object_project_all_view3d_ex( + SnapObjectContext *sctx, + const struct SnapObjectParams *params, + const float mval[2], + float ray_depth, bool sort, + ListBase *r_hit_list); + +#endif /* __ED_TRANSFORM_SNAP_OBJECT_CONTEXT_H__ */ diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index 76ff9e0fbd8..2c80701bf69 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -1020,3 +1020,25 @@ DEF_VICO(KEYTYPE_KEYFRAME_VEC) DEF_VICO(KEYTYPE_BREAKDOWN_VEC) DEF_VICO(KEYTYPE_EXTREME_VEC) DEF_VICO(KEYTYPE_JITTER_VEC) + +DEF_VICO(COLORSET_01_VEC) +DEF_VICO(COLORSET_02_VEC) +DEF_VICO(COLORSET_03_VEC) +DEF_VICO(COLORSET_04_VEC) +DEF_VICO(COLORSET_05_VEC) +DEF_VICO(COLORSET_06_VEC) +DEF_VICO(COLORSET_07_VEC) +DEF_VICO(COLORSET_08_VEC) +DEF_VICO(COLORSET_09_VEC) +DEF_VICO(COLORSET_10_VEC) +DEF_VICO(COLORSET_11_VEC) +DEF_VICO(COLORSET_12_VEC) +DEF_VICO(COLORSET_13_VEC) +DEF_VICO(COLORSET_14_VEC) +DEF_VICO(COLORSET_15_VEC) +DEF_VICO(COLORSET_16_VEC) +DEF_VICO(COLORSET_17_VEC) +DEF_VICO(COLORSET_18_VEC) +DEF_VICO(COLORSET_19_VEC) +DEF_VICO(COLORSET_20_VEC) + diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c index 06831576507..88924495ae5 100644 --- a/source/blender/editors/interface/interface_anim.c +++ b/source/blender/editors/interface/interface_anim.c @@ -232,13 +232,8 @@ void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra) if (IS_AUTOKEY_ON(scene)) { ReportList *reports = CTX_wm_reports(C); ToolSettings *ts = scene->toolsettings; - PointerRNA ptr = {{NULL}}; - PropertyRNA *prop = NULL; - int index; - UI_context_active_but_prop_get(C, &ptr, &prop, &index); - - insert_keyframe_direct(reports, ptr, prop, fcu, cfra, ts->keyframe_type, 0); + insert_keyframe_direct(reports, but->rnapoin, but->rnaprop, fcu, cfra, ts->keyframe_type, 0); WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); } } @@ -249,13 +244,8 @@ void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra) if (IS_AUTOKEY_ON(scene)) { ReportList *reports = CTX_wm_reports(C); ToolSettings *ts = scene->toolsettings; - PointerRNA ptr = {{NULL}}; - PropertyRNA *prop = NULL; - int index; - - UI_context_active_but_prop_get(C, &ptr, &prop, &index); - insert_keyframe_direct(reports, ptr, prop, fcu, cfra, ts->keyframe_type, INSERTKEY_DRIVER); + insert_keyframe_direct(reports, but->rnapoin, but->rnaprop, fcu, cfra, ts->keyframe_type, INSERTKEY_DRIVER); WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); } } diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index dd686f18a78..10ab85a6142 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -2945,18 +2945,6 @@ static bool ui_textedit_copypaste(uiBut *but, uiHandleButtonData *data, const in } #ifdef WITH_INPUT_IME -/* test if the translation context allows IME input - used to - * avoid weird character drawing if IME inputs non-ascii chars */ -static bool ui_ime_is_lang_supported(void) -{ - const char *uilng = BLT_lang_get(); - const bool is_lang_supported = STREQ(uilng, "zh_CN") || - STREQ(uilng, "zh_TW") || - STREQ(uilng, "ja_JP"); - - return ((U.transopts & USER_DOTRANSLATE) && is_lang_supported); -} - /* enable ime, and set up uibut ime data */ static void ui_textedit_ime_begin(wmWindow *win, uiBut *UNUSED(but)) { @@ -3078,7 +3066,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data) WM_cursor_modal_set(win, BC_TEXTEDITCURSOR); #ifdef WITH_INPUT_IME - if (is_num_but == false && ui_ime_is_lang_supported()) { + if (is_num_but == false && BLT_lang_is_ime_supported()) { ui_textedit_ime_begin(win, but); } #endif @@ -3405,7 +3393,7 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle #ifdef WITH_INPUT_IME && !is_ime_composing && - !WM_event_is_ime_switch(event) + (!WM_event_is_ime_switch(event) || !BLT_lang_is_ime_supported()) #endif ) { @@ -7383,7 +7371,6 @@ static void ui_blocks_set_tooltips(ARegion *ar, const bool enable) static bool ui_region_contains_point_px(ARegion *ar, int x, int y) { - uiBlock *block = ar->uiblocks.first; rcti winrct; /* scale down area rect to exclude shadow */ @@ -7391,7 +7378,7 @@ static bool ui_region_contains_point_px(ARegion *ar, int x, int y) /* check if the mouse is in the region */ if (!BLI_rcti_isect_pt(&winrct, x, y)) { - for (block = ar->uiblocks.first; block; block = block->next) + for (uiBlock *block = ar->uiblocks.first; block; block = block->next) block->auto_open = false; return false; @@ -7885,6 +7872,19 @@ static void button_activate_exit( ui_apply_but_undo(but); ui_apply_but_autokey(C, but); +#ifdef USE_ALLSELECT + { + /* only RNA from this button is used */ + uiBut but_temp = *but; + uiSelectContextStore *selctx_data = &data->select_others; + for (int i = 0; i < selctx_data->elems_len; i++) { + uiSelectContextElem *other = &selctx_data->elems[i]; + but_temp.rnapoin = other->ptr; + ui_apply_but_autokey(C, &but_temp); + } + } +#endif + /* popup menu memory */ if (block->flag & UI_BLOCK_POPUP_MEMORY) ui_popup_menu_memory_set(block, but); @@ -8451,8 +8451,8 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar, } if (val == KM_PRESS) { - if (ELEM(type, UPARROWKEY, DOWNARROWKEY) || - ((ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->ctrl))) + if ((ELEM(type, UPARROWKEY, DOWNARROWKEY) && !IS_EVENT_MOD(event, shift, ctrl, alt, oskey)) || + ((ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->ctrl && !IS_EVENT_MOD(event, shift, alt, oskey)))) { const int value_orig = RNA_property_int_get(&listbox->rnapoin, listbox->rnaprop); int value, min, max, inc; @@ -9823,9 +9823,17 @@ static int ui_region_handler(bContext *C, const wmEvent *event, void *UNUSED(use retval = ui_handler_panel_region(C, event, ar, listbox ? listbox : but); - if (retval == WM_UI_HANDLER_CONTINUE && listbox) + if (retval == WM_UI_HANDLER_CONTINUE && listbox) { retval = ui_handle_list_event(C, event, ar, listbox); + /* interactions with the listbox should disable tips */ + if (retval == WM_UI_HANDLER_BREAK) { + if (but) { + UI_but_tooltip_timer_remove(C, but); + } + } + } + if (retval == WM_UI_HANDLER_CONTINUE) { if (but) retval = ui_handle_button_event(C, event, but); diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index b39ddad5140..0874979e080 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -505,6 +505,63 @@ static void vicon_keytype_jitter_draw(int x, int y, int w, int h, float alpha) vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_JITTER); } +static void vicon_colorset_draw(int index, int x, int y, int w, int h, float UNUSED(alpha)) +{ + bTheme *btheme = UI_GetTheme(); + ThemeWireColor *cs = &btheme->tarm[index]; + + /* Draw three bands of color: One per color + * x-----a-----b-----c + * | N | S | A | + * x-----a-----b-----c + */ + const int a = x + w / 3; + const int b = x + w / 3 * 2; + const int c = x + w; + + /* XXX: Include alpha into this... */ + /* normal */ + glColor3ubv((unsigned char *)cs->solid); + glRecti(x, y, a, y + h); + + /* selected */ + glColor3ubv((unsigned char *)cs->select); + glRecti(a, y, b, y + h); + + /* active */ + glColor3ubv((unsigned char *)cs->active); + glRecti(b, y, c, y + h); +} + +#define DEF_VICON_COLORSET_DRAW_NTH(prefix, index) \ + static void vicon_colorset_draw_##prefix(int x, int y, int w, int h, float alpha) \ + { \ + vicon_colorset_draw(index, x, y, w, h, alpha); \ + } + +DEF_VICON_COLORSET_DRAW_NTH(01, 0) +DEF_VICON_COLORSET_DRAW_NTH(02, 1) +DEF_VICON_COLORSET_DRAW_NTH(03, 2) +DEF_VICON_COLORSET_DRAW_NTH(04, 3) +DEF_VICON_COLORSET_DRAW_NTH(05, 4) +DEF_VICON_COLORSET_DRAW_NTH(06, 5) +DEF_VICON_COLORSET_DRAW_NTH(07, 6) +DEF_VICON_COLORSET_DRAW_NTH(08, 7) +DEF_VICON_COLORSET_DRAW_NTH(09, 8) +DEF_VICON_COLORSET_DRAW_NTH(10, 9) +DEF_VICON_COLORSET_DRAW_NTH(11, 10) +DEF_VICON_COLORSET_DRAW_NTH(12, 11) +DEF_VICON_COLORSET_DRAW_NTH(13, 12) +DEF_VICON_COLORSET_DRAW_NTH(14, 13) +DEF_VICON_COLORSET_DRAW_NTH(15, 14) +DEF_VICON_COLORSET_DRAW_NTH(16, 15) +DEF_VICON_COLORSET_DRAW_NTH(17, 16) +DEF_VICON_COLORSET_DRAW_NTH(18, 17) +DEF_VICON_COLORSET_DRAW_NTH(19, 18) +DEF_VICON_COLORSET_DRAW_NTH(20, 19) + +#undef DEF_VICON_COLORSET_DRAW_NTH + #ifndef WITH_HEADLESS static void init_brush_icons(void) @@ -735,6 +792,27 @@ static void init_internal_icons(void) def_internal_vicon(VICO_KEYTYPE_BREAKDOWN_VEC, vicon_keytype_breakdown_draw); def_internal_vicon(VICO_KEYTYPE_EXTREME_VEC, vicon_keytype_extreme_draw); def_internal_vicon(VICO_KEYTYPE_JITTER_VEC, vicon_keytype_jitter_draw); + + def_internal_vicon(VICO_COLORSET_01_VEC, vicon_colorset_draw_01); + def_internal_vicon(VICO_COLORSET_02_VEC, vicon_colorset_draw_02); + def_internal_vicon(VICO_COLORSET_03_VEC, vicon_colorset_draw_03); + def_internal_vicon(VICO_COLORSET_04_VEC, vicon_colorset_draw_04); + def_internal_vicon(VICO_COLORSET_05_VEC, vicon_colorset_draw_05); + def_internal_vicon(VICO_COLORSET_06_VEC, vicon_colorset_draw_06); + def_internal_vicon(VICO_COLORSET_07_VEC, vicon_colorset_draw_07); + def_internal_vicon(VICO_COLORSET_08_VEC, vicon_colorset_draw_08); + def_internal_vicon(VICO_COLORSET_09_VEC, vicon_colorset_draw_09); + def_internal_vicon(VICO_COLORSET_10_VEC, vicon_colorset_draw_10); + def_internal_vicon(VICO_COLORSET_11_VEC, vicon_colorset_draw_11); + def_internal_vicon(VICO_COLORSET_12_VEC, vicon_colorset_draw_12); + def_internal_vicon(VICO_COLORSET_13_VEC, vicon_colorset_draw_13); + def_internal_vicon(VICO_COLORSET_14_VEC, vicon_colorset_draw_14); + def_internal_vicon(VICO_COLORSET_15_VEC, vicon_colorset_draw_15); + def_internal_vicon(VICO_COLORSET_16_VEC, vicon_colorset_draw_16); + def_internal_vicon(VICO_COLORSET_17_VEC, vicon_colorset_draw_17); + def_internal_vicon(VICO_COLORSET_18_VEC, vicon_colorset_draw_18); + def_internal_vicon(VICO_COLORSET_19_VEC, vicon_colorset_draw_19); + def_internal_vicon(VICO_COLORSET_20_VEC, vicon_colorset_draw_20); IMB_freeImBuf(b16buf); IMB_freeImBuf(b32buf); diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index e8c1d3df7bf..b7096583376 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -2912,7 +2912,11 @@ void uiTemplateList( /* We tag the list id with the list type... */ BLI_snprintf(ui_list_id, sizeof(ui_list_id), "%s_%s", ui_list_type->idname, list_id ? list_id : ""); - ar = CTX_wm_region(C); + /* Allows to work in popups. */ + ar = CTX_wm_menu(C); + if (ar == NULL) { + ar = CTX_wm_region(C); + } ui_list = BLI_findstring(&ar->ui_lists, ui_list_id, offsetof(uiList, list_id)); if (!ui_list) { diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 7d74ad14b61..5098e701638 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -856,10 +856,17 @@ static void widget_draw_icon( else if (but->flag & UI_ACTIVE) {} else alpha = 0.5f; } - - /* extra feature allows more alpha blending */ - if ((but->type == UI_BTYPE_LABEL) && but->a1 == 1.0f) - alpha *= but->a2; + else if ((but->type == UI_BTYPE_LABEL)) { + /* extra feature allows more alpha blending */ + if (but->a1 == 1.0f) { + alpha *= but->a2; + } + } + else if (ELEM(but->type, UI_BTYPE_BUT)) { + if (but->flag & UI_BUT_DISABLED) { + alpha *= 0.5f; + } + } glEnable(GL_BLEND); diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index 3c862666aa6..e2e2413c717 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -786,9 +786,14 @@ static void ui_theme_init_new_do(ThemeSpace *ts) rgba_char_args_set(ts->panel_text_hi, 255, 255, 255, 255); #endif + ts->panelcolors.show_back = false; + ts->panelcolors.show_header = false; + rgba_char_args_set(ts->panelcolors.back, 114, 114, 114, 128); + rgba_char_args_set(ts->panelcolors.header, 0, 0, 0, 25); + rgba_char_args_set(ts->button, 145, 145, 145, 245); rgba_char_args_set(ts->button_title, 0, 0, 0, 255); - rgba_char_args_set(ts->button_text, 0, 0, 0, 255); + rgba_char_args_set(ts->button_text, 0, 0, 0, 255); rgba_char_args_set(ts->button_text_hi, 255, 255, 255, 255); rgba_char_args_set(ts->list, 165, 165, 165, 255); @@ -848,14 +853,9 @@ void ui_theme_init_default(void) /* UI buttons */ ui_widget_color_init(&btheme->tui); - + btheme->tui.iconfile[0] = 0; - btheme->tui.panel.show_back = false; - btheme->tui.panel.show_header = false; - rgba_char_args_set(btheme->tui.panel.header, 0, 0, 0, 25); - rgba_char_args_set(btheme->tui.wcol_tooltip.text, 255, 255, 255, 255); - rgba_char_args_set_fl(btheme->tui.widget_emboss, 1.0f, 1.0f, 1.0f, 0.02f); rgba_char_args_set(btheme->tui.xaxis, 220, 0, 0, 255); @@ -872,10 +872,6 @@ void ui_theme_init_default(void) ui_theme_init_new(btheme); /* space view3d */ - btheme->tv3d.panelcolors.show_back = false; - btheme->tv3d.panelcolors.show_header = false; - rgba_char_args_set_fl(btheme->tv3d.panelcolors.back, 0.45, 0.45, 0.45, 0.5); - rgba_char_args_set_fl(btheme->tv3d.panelcolors.header, 0, 0, 0, 0.01); rgba_char_args_set_fl(btheme->tv3d.back, 0.225, 0.225, 0.225, 1.0); rgba_char_args_set(btheme->tv3d.text, 0, 0, 0, 255); rgba_char_args_set(btheme->tv3d.text_hi, 255, 255, 255, 255); diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index 5eaac72590b..242cbf79a83 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -44,6 +44,8 @@ #include "WM_api.h" #include "WM_types.h" +#include "UI_interface.h" + #include "ED_mesh.h" #include "ED_numinput.h" #include "ED_screen.h" @@ -69,16 +71,15 @@ typedef struct { BMBackup mesh_backup; void *draw_handle_pixel; short twtype; + float segments; /* Segments as float so smooth mouse pan works in small increments */ } BevelData; -#define HEADER_LENGTH 180 - static void edbm_bevel_update_header(bContext *C, wmOperator *op) { const char *str = IFACE_("Confirm: (Enter/LMB), Cancel: (Esc/RMB), Mode: %s (M), Clamp Overlap: %s (C), " "Vertex Only: %s (V), Offset: %s, Segments: %d"); - char msg[HEADER_LENGTH]; + char msg[UI_MAX_DRAW_STR]; ScrArea *sa = CTX_wm_area(C); Scene *sce = CTX_data_scene(C); @@ -97,7 +98,7 @@ static void edbm_bevel_update_header(bContext *C, wmOperator *op) RNA_property_enum_name_gettexted(C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &type_str); - BLI_snprintf(msg, HEADER_LENGTH, str, type_str, + BLI_snprintf(msg, sizeof(msg), str, type_str, WM_bool_as_string(RNA_boolean_get(op->ptr, "clamp_overlap")), WM_bool_as_string(RNA_boolean_get(op->ptr, "vertex_only")), offset_str, RNA_int_get(op->ptr, "segments")); @@ -332,7 +333,6 @@ static float edbm_bevel_mval_factor(wmOperator *op, const wmEvent *event) static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event) { BevelData *opdata = op->customdata; - int segments = RNA_int_get(op->ptr, "segments"); const bool has_numinput = hasNumInput(&opdata->num_input); /* Modal numinput active, try to handle numeric inputs first... */ @@ -373,6 +373,19 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event) } break; + case MOUSEPAN: { + float delta = 0.02f * (event->y - event->prevy); + if (opdata->segments >= 1 && opdata->segments + delta < 1) + opdata->segments = 1; + else + opdata->segments += delta; + RNA_int_set(op->ptr, "segments", (int)opdata->segments); + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + handled = true; + break; + } + /* Note this will prevent padplus and padminus to ever activate modal numinput. * This is not really an issue though, as we only expect positive values here... * Else we could force them to only modify segments number when shift is pressed, or so. @@ -383,8 +396,8 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event) if (event->val == KM_RELEASE) break; - segments++; - RNA_int_set(op->ptr, "segments", segments); + opdata->segments = opdata->segments + 1; + RNA_int_set(op->ptr, "segments", (int)opdata->segments); edbm_bevel_calc(op); edbm_bevel_update_header(C, op); handled = true; @@ -395,8 +408,8 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event) if (event->val == KM_RELEASE) break; - segments = max_ii(segments - 1, 1); - RNA_int_set(op->ptr, "segments", segments); + opdata->segments = max_ff(opdata->segments - 1, 1); + RNA_int_set(op->ptr, "segments", (int)opdata->segments); edbm_bevel_calc(op); edbm_bevel_update_header(C, op); handled = true; diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c index 2401b749ab2..1dfb1cddd2c 100644 --- a/source/blender/editors/mesh/editmesh_extrude.c +++ b/source/blender/editors/mesh/editmesh_extrude.c @@ -740,7 +740,7 @@ static int edbm_spin_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e if (rv3d) { prop = RNA_struct_find_property(op->ptr, "axis"); if (!RNA_property_is_set(op->ptr, prop)) { - RNA_property_float_set_array(op->ptr, prop, rv3d->viewinv[1]); + RNA_property_float_set_array(op->ptr, prop, rv3d->viewinv[2]); } } diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c index 097117cce6b..3e0747f055f 100644 --- a/source/blender/editors/mesh/editmesh_inset.c +++ b/source/blender/editors/mesh/editmesh_inset.c @@ -44,6 +44,8 @@ #include "WM_api.h" #include "WM_types.h" +#include "UI_interface.h" + #include "ED_mesh.h" #include "ED_numinput.h" #include "ED_screen.h" @@ -54,8 +56,6 @@ #include "mesh_intern.h" /* own include */ -#define HEADER_LENGTH 180 - typedef struct { float old_thickness; float old_depth; @@ -83,7 +83,7 @@ static void edbm_inset_update_header(wmOperator *op, bContext *C) const char *str = IFACE_("Confirm: Enter/LClick, Cancel: (Esc/RClick), Thickness: %s, " "Depth (Ctrl to tweak): %s (%s), Outset (O): (%s), Boundary (B): (%s), Individual (I): (%s)"); - char msg[HEADER_LENGTH]; + char msg[UI_MAX_DRAW_STR]; ScrArea *sa = CTX_wm_area(C); Scene *sce = CTX_data_scene(C); @@ -95,7 +95,7 @@ static void edbm_inset_update_header(wmOperator *op, bContext *C) BLI_snprintf(flts_str, NUM_STR_REP_LEN, "%f", RNA_float_get(op->ptr, "thickness")); BLI_snprintf(flts_str + NUM_STR_REP_LEN, NUM_STR_REP_LEN, "%f", RNA_float_get(op->ptr, "depth")); } - BLI_snprintf(msg, HEADER_LENGTH, str, + BLI_snprintf(msg, sizeof(msg), str, flts_str, flts_str + NUM_STR_REP_LEN, WM_bool_as_string(opdata->modify_depth), diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c index c35a36069a7..f1c1e4105d0 100644 --- a/source/blender/editors/mesh/editmesh_loopcut.c +++ b/source/blender/editors/mesh/editmesh_loopcut.c @@ -47,6 +47,8 @@ #include "BIF_gl.h" +#include "UI_interface.h" + #include "ED_screen.h" #include "ED_space_api.h" #include "ED_view3d.h" @@ -87,6 +89,9 @@ typedef struct RingSelOpData { bool extend; bool do_cut; + + float cuts; /* cuts as float so smooth mouse pan works in small increments */ + float smoothness; } RingSelOpData; /* modal loop selection drawing callback */ @@ -501,6 +506,8 @@ static int ringsel_init(bContext *C, wmOperator *op, bool do_cut) lcd->em = BKE_editmesh_from_object(lcd->ob); lcd->extend = do_cut ? false : RNA_boolean_get(op->ptr, "extend"); lcd->do_cut = do_cut; + lcd->cuts = RNA_int_get(op->ptr, "number_cuts"); + lcd->smoothness = RNA_float_get(op->ptr, "smoothness"); initNumInput(&lcd->num); lcd->num.idx_max = 1; @@ -648,9 +655,9 @@ static int loopcut_finish(RingSelOpData *lcd, bContext *C, wmOperator *op) static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event) { - float smoothness = RNA_float_get(op->ptr, "smoothness"); - int cuts = RNA_int_get(op->ptr, "number_cuts"); RingSelOpData *lcd = op->customdata; + float cuts = lcd->cuts; + float smoothness = lcd->smoothness; bool show_cuts = false; const bool has_numinput = hasNumInput(&lcd->num); @@ -662,20 +669,10 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event) /* using the keyboard to input the number of cuts */ /* Modal numinput active, try to handle numeric inputs first... */ if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &lcd->num, event)) { - float values[2] = {(float)cuts, smoothness}; + float values[2] = {cuts, smoothness}; applyNumInput(&lcd->num, values); - - /* allow zero so you can backspace and type in a value - * otherwise 1 as minimum would make more sense */ - cuts = CLAMPIS(values[0], 0, SUBD_CUTS_MAX); - smoothness = CLAMPIS(values[1], -SUBD_SMOOTH_MAX, SUBD_SMOOTH_MAX); - - RNA_int_set(op->ptr, "number_cuts", cuts); - ringsel_find_edge(lcd, cuts); - show_cuts = true; - RNA_float_set(op->ptr, "smoothness", smoothness); - - ED_region_tag_redraw(lcd->ar); + cuts = values[0]; + smoothness = values[1]; } else { bool handled = false; @@ -708,25 +705,28 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event) ED_region_tag_redraw(lcd->ar); handled = true; break; + case MOUSEPAN: + if (event->alt == 0) { + cuts += 0.02f * (event->y - event->prevy); + if (cuts < 1 && lcd->cuts >= 1) + cuts = 1; + } + else { + smoothness += 0.002f * (event->y - event->prevy); + } + handled = true; + break; case PADPLUSKEY: case PAGEUPKEY: case WHEELUPMOUSE: /* change number of cuts */ if (event->val == KM_RELEASE) break; if (event->alt == 0) { - cuts++; - cuts = CLAMPIS(cuts, 0, SUBD_CUTS_MAX); - RNA_int_set(op->ptr, "number_cuts", cuts); - ringsel_find_edge(lcd, cuts); - show_cuts = true; + cuts += 1; } else { - smoothness = min_ff(smoothness + 0.05f, SUBD_SMOOTH_MAX); - RNA_float_set(op->ptr, "smoothness", smoothness); - show_cuts = true; + smoothness += 0.05f; } - - ED_region_tag_redraw(lcd->ar); handled = true; break; case PADMINUS: @@ -734,27 +734,19 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event) case WHEELDOWNMOUSE: /* change number of cuts */ if (event->val == KM_RELEASE) break; - if (event->alt == 0) { - cuts = max_ii(cuts - 1, 1); - RNA_int_set(op->ptr, "number_cuts", cuts); - ringsel_find_edge(lcd, cuts); - show_cuts = true; + cuts = max_ff(cuts - 1, 1); } else { - smoothness = max_ff(smoothness - 0.05f, -SUBD_SMOOTH_MAX); - RNA_float_set(op->ptr, "smoothness", smoothness); - show_cuts = true; + smoothness -= 0.05f; } - - ED_region_tag_redraw(lcd->ar); handled = true; break; case MOUSEMOVE: /* mouse moved somewhere to select another loop */ if (!has_numinput) { lcd->vc.mval[0] = event->mval[0]; lcd->vc.mval[1] = event->mval[1]; - loopcut_mouse_move(lcd, cuts); + loopcut_mouse_move(lcd, (int)lcd->cuts); ED_region_tag_redraw(lcd->ar); handled = true; @@ -764,32 +756,39 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event) /* Modal numinput inactive, try to handle numeric inputs last... */ if (!handled && event->val == KM_PRESS && handleNumInput(C, &lcd->num, event)) { - float values[2] = {(float)cuts, smoothness}; + float values[2] = {cuts, smoothness}; applyNumInput(&lcd->num, values); + cuts = values[0]; + smoothness = values[1]; + } + } - /* allow zero so you can backspace and type in a value - * otherwise 1 as minimum would make more sense */ - cuts = CLAMPIS(values[0], 0, SUBD_CUTS_MAX); - smoothness = CLAMPIS(values[1], -SUBD_SMOOTH_MAX, SUBD_SMOOTH_MAX); - - RNA_int_set(op->ptr, "number_cuts", cuts); - ringsel_find_edge(lcd, cuts); - show_cuts = true; - RNA_float_set(op->ptr, "smoothness", smoothness); + if (cuts != lcd->cuts) { + /* allow zero so you can backspace and type in a value + * otherwise 1 as minimum would make more sense */ + lcd->cuts = CLAMPIS(cuts, 0, SUBD_CUTS_MAX); + RNA_int_set(op->ptr, "number_cuts", (int)lcd->cuts); + ringsel_find_edge(lcd, (int)lcd->cuts); + show_cuts = true; + ED_region_tag_redraw(lcd->ar); + } - ED_region_tag_redraw(lcd->ar); - } + if (smoothness != lcd->smoothness) { + lcd->smoothness = CLAMPIS(smoothness, -SUBD_SMOOTH_MAX, SUBD_SMOOTH_MAX); + RNA_float_set(op->ptr, "smoothness", lcd->smoothness); + show_cuts = true; + ED_region_tag_redraw(lcd->ar); } if (show_cuts) { Scene *sce = CTX_data_scene(C); - char buf[64 + NUM_STR_REP_LEN * 2]; + char buf[UI_MAX_DRAW_STR]; char str_rep[NUM_STR_REP_LEN * 2]; if (hasNumInput(&lcd->num)) { outputNumInput(&lcd->num, str_rep, &sce->unit); } else { - BLI_snprintf(str_rep, NUM_STR_REP_LEN, "%d", cuts); + BLI_snprintf(str_rep, NUM_STR_REP_LEN, "%d", (int)lcd->cuts); BLI_snprintf(str_rep + NUM_STR_REP_LEN, NUM_STR_REP_LEN, "%.2f", smoothness); } BLI_snprintf(buf, sizeof(buf), IFACE_("Number of Cuts: %s, Smooth: %s (Alt)"), diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c index 55ed0e521ea..4431712e720 100644 --- a/source/blender/editors/mesh/editmesh_path.c +++ b/source/blender/editors/mesh/editmesh_path.c @@ -588,6 +588,17 @@ static BMElem *edbm_elem_find_nearest(ViewContext *vc, const char htype) return NULL; } +static BMElem *edbm_elem_active_elem_or_face_get(BMesh *bm) +{ + BMElem *ele = BM_mesh_active_elem_get(bm); + + if ((ele == NULL) && bm->act_face && BM_elem_flag_test(bm->act_face, BM_ELEM_SELECT)) { + ele = (BMElem *)bm->act_face; + } + + return ele; +} + static int edbm_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) { if (RNA_struct_property_is_set(op->ptr, "index")) { @@ -605,7 +616,7 @@ static int edbm_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmE view3d_operator_needs_opengl(C); BMElem *ele_src, *ele_dst; - if (!(ele_src = BM_mesh_active_elem_get(em->bm)) || + if (!(ele_src = edbm_elem_active_elem_or_face_get(em->bm)) || !(ele_dst = edbm_elem_find_nearest(&vc, ele_src->head.htype))) { /* special case, toggle edge tags even when we don't have a path */ @@ -655,7 +666,7 @@ static int edbm_shortest_path_pick_exec(bContext *C, wmOperator *op) } BMElem *ele_src, *ele_dst; - if (!(ele_src = BM_mesh_active_elem_get(em->bm)) || + if (!(ele_src = edbm_elem_active_elem_or_face_get(em->bm)) || !(ele_dst = EDBM_elem_from_index_any(em, index))) { return OPERATOR_CANCELLED; diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c index c7a7828f3b2..9e71e646b1a 100644 --- a/source/blender/editors/mesh/editmesh_rip.c +++ b/source/blender/editors/mesh/editmesh_rip.c @@ -77,14 +77,14 @@ static float edbm_rip_edgedist_squared( const float dist_2d = len_v2v2(vec1, vec2); if (dist_2d > FLT_EPSILON) { const float dist = inset / dist_2d; - BLI_assert(finite(dist)); + BLI_assert(isfinite(dist)); interp_v2_v2v2(vec1, vec1, vec2, dist); interp_v2_v2v2(vec2, vec2, vec1, dist); } } dist_sq = dist_squared_to_line_segment_v2(mvalf, vec1, vec2); - BLI_assert(finite(dist_sq)); + BLI_assert(isfinite(dist_sq)); return dist_sq; } diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 49794d2e5cd..ba17684dd39 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -68,6 +68,7 @@ #include "ED_object.h" #include "ED_screen.h" #include "ED_transform.h" +#include "ED_transform_snap_object_context.h" #include "ED_uvedit.h" #include "ED_view3d.h" @@ -5124,6 +5125,17 @@ static int edbm_bridge_edge_loops_exec(bContext *C, wmOperator *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; + BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); + 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_exec(em->bm, &bmop); if (!BMO_error_occurred(em->bm)) { @@ -5133,17 +5145,6 @@ static int edbm_bridge_edge_loops_exec(bContext *C, wmOperator *op) BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); } - if (use_faces && totface_del) { - int i; - BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); - 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); - } - if (use_merge == false) { struct EdgeRingOpSubdProps op_props; mesh_operator_edgering_props_get(op, &op_props); diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index 90676d2b951..1b2d4b7c130 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -811,9 +811,9 @@ static BMVert *editbmesh_get_x_mirror_vert_spatial(Object *ob, BMEditMesh *em, c int i; /* ignore nan verts */ - if ((finite(co[0]) == false) || - (finite(co[1]) == false) || - (finite(co[2]) == false)) + if ((isfinite(co[0]) == false) || + (isfinite(co[1]) == false) || + (isfinite(co[2]) == false)) { return NULL; } @@ -902,8 +902,8 @@ static float *editmesh_get_mirror_uv(BMEditMesh *em, int axis, float *uv, float float cent[2]; /* ignore nan verts */ - if (isnan(uv[0]) || !finite(uv[0]) || - isnan(uv[1]) || !finite(uv[1]) + if (isnan(uv[0]) || !isfinite(uv[0]) || + isnan(uv[1]) || !isfinite(uv[1]) ) { return NULL; diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index 4619f998a11..414cc476be5 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -2096,14 +2096,19 @@ static void dvert_mirror_op(MDeformVert *dvert, MDeformVert *dvert_mirr, MDeformWeight *dw = defvert_find_index(dvert, act_vgroup); MDeformWeight *dw_mirr = defvert_find_index(dvert_mirr, act_vgroup); - if (dw || dw_mirr) { - if (dw_mirr == NULL) - dw_mirr = defvert_verify_index(dvert_mirr, act_vgroup); - if (dw == NULL) - dw = defvert_verify_index(dvert, act_vgroup); - + if (dw && dw_mirr) { SWAP(float, dw->weight, dw_mirr->weight); } + else if (dw) { + dw_mirr = defvert_verify_index(dvert_mirr, act_vgroup); + dw_mirr->weight = dw->weight; + defvert_remove_group(dvert, dw); + } + else if (dw_mirr) { + dw = defvert_verify_index(dvert, act_vgroup); + dw->weight = dw_mirr->weight; + defvert_remove_group(dvert_mirr, dw_mirr); + } } } @@ -2197,28 +2202,34 @@ void ED_vgroup_mirror(Object *ob, EDBM_verts_mirror_cache_begin(em, 0, true, false, use_topology); + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); + /* Go through the list of editverts and assign them */ BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - if ((eve_mirr = EDBM_verts_mirror_get(em, eve))) { - if (eve_mirr != eve) { - sel = BM_elem_flag_test(eve, BM_ELEM_SELECT); - sel_mirr = BM_elem_flag_test(eve_mirr, BM_ELEM_SELECT); + if (!BM_elem_flag_test(eve, BM_ELEM_TAG)) { + if ((eve_mirr = EDBM_verts_mirror_get(em, eve))) { + if (eve_mirr != eve) { + if (!BM_elem_flag_test(eve_mirr, BM_ELEM_TAG)) { + sel = BM_elem_flag_test(eve, BM_ELEM_SELECT); + sel_mirr = BM_elem_flag_test(eve_mirr, BM_ELEM_SELECT); - if ((sel || sel_mirr) && (eve != eve_mirr)) { - dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); - dvert_mirr = BM_ELEM_CD_GET_VOID_P(eve_mirr, cd_dvert_offset); + if ((sel || sel_mirr) && (eve != eve_mirr)) { + dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); + dvert_mirr = BM_ELEM_CD_GET_VOID_P(eve_mirr, cd_dvert_offset); - VGROUP_MIRR_OP; - totmirr++; + VGROUP_MIRR_OP; + totmirr++; + } + + /* don't use these again */ + BM_elem_flag_enable(eve, BM_ELEM_TAG); + BM_elem_flag_enable(eve_mirr, BM_ELEM_TAG); + } } } - - /* don't use these again */ - EDBM_verts_mirror_cache_clear(em, eve); - EDBM_verts_mirror_cache_clear(em, eve_mirr); - } - else { - totfail++; + else { + totfail++; + } } } EDBM_verts_mirror_cache_end(em); diff --git a/source/blender/editors/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c index a5d2d2c8be7..3d7a45843cc 100644 --- a/source/blender/editors/physics/dynamicpaint_ops.c +++ b/source/blender/editors/physics/dynamicpaint_ops.c @@ -350,6 +350,9 @@ static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job) return; } + /* Show progress bar. */ + *(job->do_update) = true; + /* Set frame to start point (also inits modifier data) */ frame = surface->start_frame; orig_frame = scene->r.cfra; @@ -357,14 +360,15 @@ static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job) ED_update_for_newframe(job->bmain, scene, 1); /* Init surface */ - if (!dynamicPaint_createUVSurface(scene, surface)) { + if (!dynamicPaint_createUVSurface(scene, surface, job->progress, job->do_update)) { job->success = 0; return; } /* Loop through selected frames */ for (frame = surface->start_frame; frame <= surface->end_frame; frame++) { - float progress = (frame - surface->start_frame) / (float)frames; + /* The first 10% are for createUVSurface... */ + const float progress = 0.1f + 0.9f * (frame - surface->start_frame) / (float)frames; surface->current_frame = frame; /* If user requested stop, quit baking */ diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 3511480821a..ab8b7d4e138 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -635,8 +635,8 @@ void ED_area_headerprint(ScrArea *sa, const char *str) if (ar->regiontype == RGN_TYPE_HEADER) { if (str) { if (ar->headerstr == NULL) - ar->headerstr = MEM_mallocN(256, "headerprint"); - BLI_strncpy(ar->headerstr, str, 256); + ar->headerstr = MEM_mallocN(UI_MAX_DRAW_STR, "headerprint"); + BLI_strncpy(ar->headerstr, str, UI_MAX_DRAW_STR); } else if (ar->headerstr) { MEM_freeN(ar->headerstr); diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c index a1c330d9dff..cbf87062955 100644 --- a/source/blender/editors/screen/glutil.c +++ b/source/blender/editors/screen/glutil.c @@ -368,7 +368,11 @@ static int get_cached_work_texture(int *r_w, int *r_h) return texid; } -void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect, float scaleX, float scaleY) +void glaDrawPixelsTexScaled_clipping(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) { unsigned char *uc_rect = (unsigned char *) rect; const float *f_rect = (float *)rect; @@ -377,6 +381,7 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, int seamless, offset_x, offset_y, nsubparts_x, nsubparts_y; int texid = get_cached_work_texture(&tex_w, &tex_h); int components; + const bool use_clipping = ((clip_min_x < clip_max_x) && (clip_min_y < clip_max_y)); /* Specify the color outside this function, and tex will modulate it. * This is useful for changing alpha without using glPixelTransferf() @@ -443,11 +448,23 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, int offset_top = (seamless && remainder_y > tex_h) ? 1 : 0; float rast_x = x + subpart_x * offset_x * xzoom; float rast_y = y + subpart_y * offset_y * yzoom; - /* check if we already got these because we always get 2 more when doing seamless */ if (subpart_w <= seamless || subpart_h <= seamless) continue; - + + if (use_clipping) { + if (rast_x + (float)(subpart_w - offset_right) * xzoom * scaleX < clip_min_x || + rast_y + (float)(subpart_h - offset_top) * yzoom * scaleY < clip_min_y) + { + continue; + } + if (rast_x + (float)offset_left * xzoom > clip_max_x || + rast_y + (float)offset_bot * yzoom > clip_max_y) + { + continue; + } + } + if (type == GL_FLOAT) { glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subpart_w, subpart_h, format, GL_FLOAT, &f_rect[((size_t)subpart_y) * offset_y * img_w * components + subpart_x * offset_x * components]); @@ -497,9 +514,26 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, #endif } +void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, + int format, int type, int zoomfilter, void *rect, + float scaleX, float scaleY) +{ + glaDrawPixelsTexScaled_clipping(x, y, img_w, img_h, format, type, zoomfilter, rect, + scaleX, scaleY, 0.0f, 0.0f, 0.0f, 0.0f); +} + void glaDrawPixelsTex(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect) { - glaDrawPixelsTexScaled(x, y, img_w, img_h, format, type, zoomfilter, rect, 1.0f, 1.0f); + glaDrawPixelsTexScaled_clipping(x, y, img_w, img_h, format, type, zoomfilter, rect, 1.0f, 1.0f, + 0.0f, 0.0f, 0.0f, 0.0f); +} + +void glaDrawPixelsTex_clipping(float x, float y, int img_w, int img_h, + int format, int type, int zoomfilter, void *rect, + float clip_min_x, float clip_min_y, float clip_max_x, float clip_max_y) +{ + glaDrawPixelsTexScaled_clipping(x, y, img_w, img_h, format, type, zoomfilter, rect, 1.0f, 1.0f, + clip_min_x, clip_min_y, clip_max_x, clip_max_y); } void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int format, int type, void *rect) @@ -580,17 +614,27 @@ void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int fo } /* uses either DrawPixelsSafe or DrawPixelsTex, based on user defined maximum */ -void glaDrawPixelsAuto(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect) +void glaDrawPixelsAuto_clipping(float x, float y, int img_w, int img_h, + int format, int type, int zoomfilter, void *rect, + float clip_min_x, float clip_min_y, + float clip_max_x, float clip_max_y) { if (U.image_draw_method != IMAGE_DRAW_METHOD_DRAWPIXELS) { glColor4f(1.0, 1.0, 1.0, 1.0); - glaDrawPixelsTex(x, y, img_w, img_h, format, type, zoomfilter, rect); + glaDrawPixelsTex_clipping(x, y, img_w, img_h, format, type, zoomfilter, rect, + clip_min_x, clip_min_y, clip_max_x, clip_max_y); } else { glaDrawPixelsSafe(x, y, img_w, img_h, img_w, format, type, rect); } } +void glaDrawPixelsAuto(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect) +{ + glaDrawPixelsAuto_clipping(x, y, img_w, img_h, format, type, zoomfilter, rect, + 0.0f, 0.0f, 0.0f, 0.0f); +} + /* 2D Drawing Assistance */ void glaDefine2DArea(rcti *screen_rect) @@ -822,9 +866,11 @@ void bglPolygonOffset(float viewdist, float dist) /* **** Color management helper functions for GLSL display/transform ***** */ /* Draw given image buffer on a screen using GLSL for display transform */ -void glaDrawImBuf_glsl(ImBuf *ibuf, float x, float y, int zoomfilter, - ColorManagedViewSettings *view_settings, - ColorManagedDisplaySettings *display_settings) +void glaDrawImBuf_glsl_clipping(ImBuf *ibuf, float x, float y, int zoomfilter, + ColorManagedViewSettings *view_settings, + ColorManagedDisplaySettings *display_settings, + float clip_min_x, float clip_min_y, + float clip_max_x, float clip_max_y) { bool force_fallback = false; bool need_fallback = true; @@ -874,14 +920,16 @@ void glaDrawImBuf_glsl(ImBuf *ibuf, float x, float y, int zoomfilter, BLI_assert(!"Incompatible number of channels for GLSL display"); if (format != 0) { - glaDrawPixelsTex(x, y, ibuf->x, ibuf->y, format, GL_FLOAT, - zoomfilter, ibuf->rect_float); + glaDrawPixelsTex_clipping(x, y, ibuf->x, ibuf->y, format, GL_FLOAT, + zoomfilter, ibuf->rect_float, + clip_min_x, clip_min_y, clip_max_x, clip_max_y); } } else if (ibuf->rect) { /* ibuf->rect is always RGBA */ - glaDrawPixelsTex(x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, - zoomfilter, ibuf->rect); + glaDrawPixelsTex_clipping(x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, + zoomfilter, ibuf->rect, + clip_min_x, clip_min_y, clip_max_x, clip_max_y); } IMB_colormanagement_finish_glsl_draw(); @@ -897,21 +945,43 @@ void glaDrawImBuf_glsl(ImBuf *ibuf, float x, float y, int zoomfilter, display_buffer = IMB_display_buffer_acquire(ibuf, view_settings, display_settings, &cache_handle); - if (display_buffer) - glaDrawPixelsAuto(x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, zoomfilter, display_buffer); + if (display_buffer) { + glaDrawPixelsAuto_clipping(x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, + zoomfilter, display_buffer, + clip_min_x, clip_min_y, clip_max_x, clip_max_y); + } IMB_display_buffer_release(cache_handle); } } -void glaDrawImBuf_glsl_ctx(const bContext *C, ImBuf *ibuf, float x, float y, int zoomfilter) +void glaDrawImBuf_glsl(ImBuf *ibuf, float x, float y, int zoomfilter, + ColorManagedViewSettings *view_settings, + ColorManagedDisplaySettings *display_settings) +{ + glaDrawImBuf_glsl_clipping(ibuf, x, y, zoomfilter, view_settings, display_settings, + 0.0f, 0.0f, 0.0f, 0.0f); +} + +void glaDrawImBuf_glsl_ctx_clipping(const bContext *C, + ImBuf *ibuf, + float x, float y, + int zoomfilter, + float clip_min_x, float clip_min_y, + float clip_max_x, float clip_max_y) { ColorManagedViewSettings *view_settings; ColorManagedDisplaySettings *display_settings; IMB_colormanagement_display_settings_from_ctx(C, &view_settings, &display_settings); - glaDrawImBuf_glsl(ibuf, x, y, zoomfilter, view_settings, display_settings); + glaDrawImBuf_glsl_clipping(ibuf, x, y, zoomfilter, view_settings, display_settings, + clip_min_x, clip_min_y, clip_max_x, clip_max_y); +} + +void glaDrawImBuf_glsl_ctx(const bContext *C, ImBuf *ibuf, float x, float y, int zoomfilter) +{ + glaDrawImBuf_glsl_ctx_clipping(C, ibuf, x, y, zoomfilter, 0.0f, 0.0f, 0.0f, 0.0f); } void cpack(unsigned int x) diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index be421d779eb..4111f67553a 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -3467,7 +3467,7 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv if ((scene->audio.flag & AUDIO_SYNC) && (sad->flag & ANIMPLAY_FLAG_REVERSE) == false && - finite(time = BKE_sound_sync_scene(scene))) + isfinite(time = BKE_sound_sync_scene(scene))) { double newfra = (double)time * FPS; diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index a9cd601c9b0..88b3bc5d8fd 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -36,15 +36,12 @@ #include "MEM_guardedalloc.h" -#ifdef WIN32 -# include "BLI_winstuff.h" -#endif - #include "BLI_math.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" #include "BLI_threads.h" +#include "BLT_translation.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" @@ -64,6 +61,7 @@ #include "BKE_paint.h" #include "BKE_texture.h" +#include "UI_interface.h" #include "UI_view2d.h" #include "ED_image.h" @@ -498,8 +496,10 @@ void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short te if (texpaint || (sima && sima->lock)) { int w = imapaintpartial.x2 - imapaintpartial.x1; int h = imapaintpartial.y2 - imapaintpartial.y1; - /* Testing with partial update in uv editor too */ - GPU_paint_update_image(image, (sima ? &sima->iuser : NULL), imapaintpartial.x1, imapaintpartial.y1, w, h); //!texpaint); + if (w && h) { + /* Testing with partial update in uv editor too */ + GPU_paint_update_image(image, (sima ? &sima->iuser : NULL), imapaintpartial.x1, imapaintpartial.y1, w, h); + } } } @@ -1169,20 +1169,17 @@ typedef struct { static void sample_color_update_header(SampleColorData *data, bContext *C) { -#define HEADER_LENGTH 150 - char msg[HEADER_LENGTH]; + char msg[UI_MAX_DRAW_STR]; ScrArea *sa = CTX_wm_area(C); if (sa) { - BLI_snprintf(msg, HEADER_LENGTH, - "Sample color for %s", + BLI_snprintf(msg, sizeof(msg), + IFACE_("Sample color for %s"), !data->sample_palette ? - "Brush. Use Left Click to sample for palette instead" : - "Palette. Use Left Click to sample more colors"); + IFACE_("Brush. Use Left Click to sample for palette instead") : + IFACE_("Palette. Use Left Click to sample more colors")); ED_area_headerprint(sa, msg); } - -#undef HEADER_LENGTH } static int sample_color_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c index c5a066e9b14..080bd5b73c7 100644 --- a/source/blender/editors/sculpt_paint/paint_image_2d.c +++ b/source/blender/editors/sculpt_paint/paint_image_2d.c @@ -42,6 +42,7 @@ #include "BLI_math_color_blend.h" #include "BLI_stack.h" #include "BLI_bitmap.h" +#include "BLI_task.h" #include "BKE_context.h" #include "BKE_depsgraph.h" @@ -302,8 +303,8 @@ static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter, const srcx = srcy = 0; w = cache->tex_mask_old_w; h = cache->tex_mask_old_h; - destx = (int)painter->lastpaintpos[0] - (int)pos[0] + (diameter / 2 - w / 2); - desty = (int)painter->lastpaintpos[1] - (int)pos[1] + (diameter / 2 - h / 2); + destx = (int)floorf(painter->lastpaintpos[0]) - (int)floorf(pos[0]) + (diameter / 2 - w / 2); + desty = (int)floorf(painter->lastpaintpos[1]) - (int)floorf(pos[1]) + (diameter / 2 - h / 2); /* hack, use temporary rects so that clipping works */ IMB_rectclip(&maskibuf, &maskibuf_old, &destx, &desty, &srcx, &srcy, &w, &h); @@ -570,8 +571,8 @@ static void brush_painter_imbuf_partial_update(BrushPainter *painter, const floa srcx = srcy = 0; w = oldtexibuf->x; h = oldtexibuf->y; - destx = (int)painter->lastpaintpos[0] - (int)pos[0] + (diameter / 2 - w / 2); - desty = (int)painter->lastpaintpos[1] - (int)pos[1] + (diameter / 2 - h / 2); + destx = (int)floorf(painter->lastpaintpos[0]) - (int)floorf(pos[0]) + (diameter / 2 - w / 2); + desty = (int)floorf(painter->lastpaintpos[1]) - (int)floorf(pos[1]) + (diameter / 2 - h / 2); IMB_rectclip(cache->texibuf, oldtexibuf, &destx, &desty, &srcx, &srcy, &w, &h); } @@ -641,8 +642,8 @@ static void brush_painter_2d_tex_mapping(ImagePaintState *s, int diameter, const mapping->ymax = 1.0f; } else /* if (mapmode == MTEX_MAP_MODE_TILED) */ { - mapping->xmin = (int)(-diameter * 0.5) + (int)pos[0] - (int)startpos[0]; - mapping->ymin = (int)(-diameter * 0.5) + (int)pos[1] - (int)startpos[1]; + mapping->xmin = (int)(-diameter * 0.5) + (int)floorf(pos[0]) - (int)floorf(startpos[0]); + mapping->ymin = (int)(-diameter * 0.5) + (int)floorf(pos[1]) - (int)floorf(startpos[1]); mapping->xmax = 1.0f; mapping->ymax = 1.0f; } @@ -758,8 +759,8 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s, BrushPainter *pai } else if (do_partial_update) { /* do only partial update of texture */ - int dx = (int)painter->lastpaintpos[0] - (int)pos[0]; - int dy = (int)painter->lastpaintpos[1] - (int)pos[1]; + int dx = (int)floorf(painter->lastpaintpos[0]) - (int)floorf(pos[0]); + int dy = (int)floorf(painter->lastpaintpos[1]) - (int)floorf(pos[1]); if ((dx != 0) || (dy != 0)) { brush_painter_imbuf_partial_update(painter, pos, diameter); @@ -1019,6 +1020,64 @@ static void paint_2d_convert_brushco(ImBuf *ibufb, const float pos[2], int ipos[ ipos[1] = (int)floorf((pos[1] - ibufb->y / 2)); } +static void paint_2d_do_making_brush(ImagePaintState *s, + ImagePaintRegion *region, + unsigned short *curveb, + unsigned short *texmaskb, + ImBuf *frombuf, + float mask_max, + short blend, + int tilex, int tiley, + int tilew, int tileh) +{ + ImBuf tmpbuf; + IMB_initImBuf(&tmpbuf, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, 0); + + for (int ty = tiley; ty <= tileh; ty++) { + for (int tx = tilex; tx <= tilew; tx++) { + /* retrieve original pixels + mask from undo buffer */ + unsigned short *mask; + int origx = region->destx - tx * IMAPAINT_TILE_SIZE; + 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); + else + tmpbuf.rect = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask, false); + + IMB_rectblend(s->canvas, &tmpbuf, frombuf, mask, + curveb, texmaskb, mask_max, + region->destx, region->desty, + origx, origy, + region->srcx, region->srcy, + region->width, region->height, + blend, ((s->brush->flag & BRUSH_ACCUMULATE) != 0)); + } + } +} + +typedef struct Paint2DForeachData { + ImagePaintState *s; + ImagePaintRegion *region; + unsigned short *curveb; + unsigned short *texmaskb; + ImBuf *frombuf; + float mask_max; + short blend; + int tilex; + int tilew; +} Paint2DForeachData; + +static void paint_2d_op_foreach_do(void *data_v, const int iter) +{ + Paint2DForeachData *data = (Paint2DForeachData *)data_v; + paint_2d_do_making_brush(data->s, data->region, data->curveb, + data->texmaskb, data->frombuf, data->mask_max, + data->blend, + data->tilex, iter, + data->tilew, iter); +} + static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsigned short *texmaskb, const float lastpos[2], const float pos[2]) { ImagePaintState *s = ((ImagePaintState *)state); @@ -1072,45 +1131,40 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsign if (s->do_masking) { /* masking, find original pixels tiles from undo buffer to composite over */ - int tilex, tiley, tilew, tileh, tx, ty; - ImBuf *tmpbuf; + int tilex, tiley, tilew, tileh; imapaint_region_tiles(s->canvas, region[a].destx, region[a].desty, region[a].width, region[a].height, &tilex, &tiley, &tilew, &tileh); - tmpbuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, 0); - - for (ty = tiley; ty <= tileh; ty++) { - for (tx = tilex; tx <= tilew; tx++) { - /* retrieve original pixels + mask from undo buffer */ - unsigned short *mask; - int origx = region[a].destx - tx * IMAPAINT_TILE_SIZE; - int origy = region[a].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); - else - tmpbuf->rect = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask, false); - - IMB_rectblend(s->canvas, tmpbuf, frombuf, mask, - curveb, texmaskb, mask_max, - region[a].destx, region[a].desty, - origx, origy, - region[a].srcx, region[a].srcy, - region[a].width, region[a].height, blend, ((s->brush->flag & BRUSH_ACCUMULATE) != 0)); - } + if (tiley == tileh) { + paint_2d_do_making_brush(s, ®ion[a], curveb, texmaskb, frombuf, + mask_max, blend, tilex, tiley, tilew, tileh); } + else { + Paint2DForeachData data; + data.s = s; + data.region = ®ion[a]; + data.curveb = curveb; + data.texmaskb = texmaskb; + data.frombuf = frombuf; + data.mask_max = mask_max; + data.blend = blend; + data.tilex = tilex; + data.tilew = tilew; + BLI_task_parallel_range(tiley, tileh + 1, &data, + paint_2d_op_foreach_do, + true); - IMB_freeImBuf(tmpbuf); + } } else { /* no masking, composite brush directly onto canvas */ - IMB_rectblend(s->canvas, s->canvas, frombuf, NULL, curveb, texmaskb, mask_max, - region[a].destx, region[a].desty, - region[a].destx, region[a].desty, - region[a].srcx, region[a].srcy, - region[a].width, region[a].height, blend, false); + IMB_rectblend_threaded(s->canvas, s->canvas, frombuf, NULL, curveb, texmaskb, mask_max, + region[a].destx, region[a].desty, + region[a].destx, region[a].desty, + region[a].srcx, region[a].srcy, + region[a].width, region[a].height, blend, false); } } diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index bce3b46010b..d273f8320a1 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -107,6 +107,8 @@ #include "paint_intern.h" +static void partial_redraw_array_init(ImagePaintPartialRedraw *pr); + /* Defines and Structs */ /* FTOCHAR as inline function */ BLI_INLINE unsigned char f_to_char(const float val) @@ -3647,7 +3649,7 @@ static void project_paint_build_proj_ima( projIma->ibuf = BKE_image_acquire_ibuf(projIma->ima, NULL, NULL); size = sizeof(void **) * IMAPAINT_TILE_NUMBER(projIma->ibuf->x) * IMAPAINT_TILE_NUMBER(projIma->ibuf->y); projIma->partRedrawRect = BLI_memarena_alloc(arena, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED); - memset(projIma->partRedrawRect, 0, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED); + partial_redraw_array_init(projIma->partRedrawRect); projIma->undoRect = (volatile void **) BLI_memarena_alloc(arena, size); memset((void *)projIma->undoRect, 0, size); projIma->maskRect = BLI_memarena_alloc(arena, size); @@ -3998,8 +4000,8 @@ static void project_paint_end(ProjPaintState *ps) /* 1 = an undo, -1 is a redo. */ static void partial_redraw_single_init(ImagePaintPartialRedraw *pr) { - pr->x1 = 10000000; - pr->y1 = 10000000; + pr->x1 = INT_MAX; + pr->y1 = INT_MAX; pr->x2 = -1; pr->y2 = -1; @@ -5360,9 +5362,6 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op) float lastpos[2] = {0.0, 0.0}; int a; - for (a = 0; a < ps.image_tot; a++) - partial_redraw_array_init(ps.projImages[a].partRedrawRect); - project_paint_op(&ps, lastpos, pos); project_image_refresh_tagged(&ps); @@ -5867,7 +5866,7 @@ static int add_simple_uvs_exec(bContext *C, wmOperator *UNUSED(op)) ED_mesh_uv_texture_ensure(me, NULL); BM_mesh_bm_from_me( - bm, me,(&(struct BMeshFromMeshParams){ + bm, me, (&(struct BMeshFromMeshParams){ .calc_face_normal = true, })); /* select all uv loops first - pack parameters needs this to make sure charts are registered */ diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 7ebc050978a..c173156de3a 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -2997,7 +2997,7 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t const bool flip = (ss->cache->bstrength < 0); const float radius = flip ? -ss->cache->radius : ss->cache->radius; const float offset = get_offset(sd, ss); - const float displace = radius * (0.25f + offset);; + const float displace = radius * (0.25f + offset); float area_no_sp[3]; /* the sculpt-plane normal (whatever its set to) */ float area_no[3]; /* geometry normal */ diff --git a/source/blender/editors/space_action/CMakeLists.txt b/source/blender/editors/space_action/CMakeLists.txt index 839071d1330..24c3ee9cd3d 100644 --- a/source/blender/editors/space_action/CMakeLists.txt +++ b/source/blender/editors/space_action/CMakeLists.txt @@ -36,6 +36,7 @@ set(INC_SYS ) set(SRC + action_buttons.c action_data.c action_draw.c action_edit.c diff --git a/source/blender/editors/space_action/action_buttons.c b/source/blender/editors/space_action/action_buttons.c new file mode 100644 index 00000000000..063a477d2b6 --- /dev/null +++ b/source/blender/editors/space_action/action_buttons.c @@ -0,0 +1,132 @@ +/* + * ***** 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) 2016 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Blender Foundation, Joshua Leung + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/space_action/action_buttons.c + * \ingroup spaction + */ + + +#include <string.h> +#include <stdio.h> +#include <math.h> +#include <float.h> + +#include "DNA_anim_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" + +#include "BLT_translation.h" + +#include "BKE_context.h" +#include "BKE_curve.h" +#include "BKE_depsgraph.h" +#include "BKE_fcurve.h" +#include "BKE_main.h" +#include "BKE_global.h" +#include "BKE_screen.h" +#include "BKE_unit.h" + + +#include "WM_api.h" +#include "WM_types.h" + +#include "RNA_access.h" + +#include "ED_anim_api.h" +#include "ED_keyframing.h" +#include "ED_screen.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "action_intern.h" // own include + +/* ******************* action editor space & buttons ************** */ + +/* ******************* general ******************************** */ + +void action_buttons_register(ARegionType *UNUSED(art)) +{ +#if 0 + PanelType *pt; + + // TODO: AnimData / Actions List + + pt = MEM_callocN(sizeof(PanelType), "spacetype action panel properties"); + strcpy(pt->idname, "ACTION_PT_properties"); + strcpy(pt->label, N_("Active F-Curve")); + strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); + pt->draw = action_anim_panel_properties; + pt->poll = action_anim_panel_poll; + BLI_addtail(&art->paneltypes, pt); + + pt = MEM_callocN(sizeof(PanelType), "spacetype action panel properties"); + strcpy(pt->idname, "ACTION_PT_key_properties"); + strcpy(pt->label, N_("Active Keyframe")); + strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); + pt->draw = action_anim_panel_key_properties; + pt->poll = action_anim_panel_poll; + BLI_addtail(&art->paneltypes, pt); + + pt = MEM_callocN(sizeof(PanelType), "spacetype action panel modifiers"); + strcpy(pt->idname, "ACTION_PT_modifiers"); + strcpy(pt->label, N_("Modifiers")); + strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); + pt->draw = action_anim_panel_modifiers; + pt->poll = action_anim_panel_poll; + BLI_addtail(&art->paneltypes, pt); +#endif +} + +static int action_properties_toggle_exec(bContext *C, wmOperator *UNUSED(op)) +{ + ScrArea *sa = CTX_wm_area(C); + ARegion *ar = action_has_buttons_region(sa); + + if (ar) + ED_region_toggle_hidden(C, ar); + + return OPERATOR_FINISHED; +} + +void ACTION_OT_properties(wmOperatorType *ot) +{ + ot->name = "Properties"; + ot->idname = "ACTION_OT_properties"; + ot->description = "Toggle display properties panel"; + + ot->exec = action_properties_toggle_exec; + ot->poll = ED_operator_action_active; + + /* flags */ + ot->flag = 0; +} diff --git a/source/blender/editors/space_action/action_intern.h b/source/blender/editors/space_action/action_intern.h index 17f1f404225..50e10e7e154 100644 --- a/source/blender/editors/space_action/action_intern.h +++ b/source/blender/editors/space_action/action_intern.h @@ -34,11 +34,21 @@ struct bContext; struct bAnimContext; struct SpaceAction; +struct ScrArea; struct ARegion; +struct ARegionType; struct wmOperatorType; /* internal exports only */ +/* **************************************** */ +/* space_action.c / action_buttons.c */ + +struct ARegion *action_has_buttons_region(struct ScrArea *sa); + +void action_buttons_register(struct ARegionType *art); +void ACTION_OT_properties(struct wmOperatorType *ot); + /* ***************************************** */ /* action_draw.c */ void draw_channel_names(struct bContext *C, struct bAnimContext *ac, struct ARegion *ar); diff --git a/source/blender/editors/space_action/action_ops.c b/source/blender/editors/space_action/action_ops.c index 59b147c6f6c..f69f9944f8a 100644 --- a/source/blender/editors/space_action/action_ops.c +++ b/source/blender/editors/space_action/action_ops.c @@ -51,6 +51,9 @@ void action_operatortypes(void) { + /* view */ + WM_operatortype_append(ACTION_OT_properties); + /* keyframes */ /* selection */ WM_operatortype_append(ACTION_OT_clickselect); @@ -257,6 +260,13 @@ void action_keymap(wmKeyConfig *keyconf) { wmKeyMap *keymap; + /* keymap for all regions */ + keymap = WM_keymap_find(keyconf, "Dopesheet Generic", SPACE_ACTION, 0); + + /* region management... */ + WM_keymap_add_item(keymap, "ACTION_OT_properties", NKEY, KM_PRESS, 0, 0); + + /* channels */ /* Channels are not directly handled by the Action Editor module, but are inherited from the Animation module. * All the relevant operations, keymaps, drawing, etc. can therefore all be found in that module instead, as these diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c index 53c5a008af8..60240109432 100644 --- a/source/blender/editors/space_action/space_action.c +++ b/source/blender/editors/space_action/space_action.c @@ -59,6 +59,32 @@ #include "action_intern.h" /* own include */ +/* ******************** manage regions ********************* */ + +ARegion *action_has_buttons_region(ScrArea *sa) +{ + ARegion *ar, *arnew; + + ar = BKE_area_find_region_type(sa, RGN_TYPE_UI); + if (ar) return ar; + + /* add subdiv level; after main */ + ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); + + /* is error! */ + if (ar == NULL) return NULL; + + arnew = MEM_callocN(sizeof(ARegion), "buttons for action"); + + BLI_insertlinkafter(&sa->regionbase, ar, arnew); + arnew->regiontype = RGN_TYPE_UI; + arnew->alignment = RGN_ALIGN_RIGHT; + + arnew->flag = RGN_FLAG_HIDDEN; + + return arnew; +} + /* ******************** default callbacks for action space ***************** */ static SpaceLink *action_new(const bContext *C) @@ -93,6 +119,14 @@ static SpaceLink *action_new(const bContext *C) ar->v2d.scroll = V2D_SCROLL_BOTTOM; ar->v2d.flag = V2D_VIEWSYNC_AREA_VERTICAL; + /* ui buttons */ + ar = MEM_callocN(sizeof(ARegion), "buttons region for action"); + + BLI_addtail(&saction->regionbase, ar); + ar->regiontype = RGN_TYPE_UI; + ar->alignment = RGN_ALIGN_RIGHT; + ar->flag = RGN_FLAG_HIDDEN; + /* main region */ ar = MEM_callocN(sizeof(ARegion), "main region for action"); @@ -159,6 +193,8 @@ static void action_main_region_init(wmWindowManager *wm, ARegion *ar) /* own keymap */ keymap = WM_keymap_find(wm->defaultconf, "Dopesheet", SPACE_ACTION, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); + keymap = WM_keymap_find(wm->defaultconf, "Dopesheet Generic", SPACE_ACTION, 0); + WM_event_add_keymap_handler(&ar->handlers, keymap); } static void action_main_region_draw(const bContext *C, ARegion *ar) @@ -231,6 +267,9 @@ static void action_channel_region_init(wmWindowManager *wm, ARegion *ar) /* own keymap */ keymap = WM_keymap_find(wm->defaultconf, "Animation Channels", 0, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); + + keymap = WM_keymap_find(wm->defaultconf, "Dopesheet Generic", SPACE_ACTION, 0); + WM_event_add_keymap_handler(&ar->handlers, keymap); } static void action_channel_region_draw(const bContext *C, ARegion *ar) @@ -498,6 +537,54 @@ static void action_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(s } +/* add handlers, stuff you only do once or on area/region changes */ +static void action_buttons_area_init(wmWindowManager *wm, ARegion *ar) +{ + wmKeyMap *keymap; + + ED_region_panels_init(wm, ar); + + keymap = WM_keymap_find(wm->defaultconf, "Dopesheet Generic", SPACE_ACTION, 0); + WM_event_add_keymap_handler(&ar->handlers, keymap); +} + +static void action_buttons_area_draw(const bContext *C, ARegion *ar) +{ + ED_region_panels(C, ar, NULL, -1, true); +} + +static void action_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) +{ + /* context changes */ + switch (wmn->category) { + case NC_ANIMATION: + ED_region_tag_redraw(ar); + break; + case NC_SCENE: + switch (wmn->data) { + case ND_OB_ACTIVE: + case ND_FRAME: + case ND_MARKERS: + ED_region_tag_redraw(ar); + break; + } + break; + case NC_OBJECT: + switch (wmn->data) { + case ND_BONE_ACTIVE: + case ND_BONE_SELECT: + case ND_KEYS: + ED_region_tag_redraw(ar); + break; + } + break; + default: + if (wmn->data == ND_KEYS) + ED_region_tag_redraw(ar); + break; + } +} + static void action_refresh(const bContext *C, ScrArea *sa) { SpaceAction *saction = (SpaceAction *)sa->spacedata.first; @@ -579,6 +666,18 @@ void ED_spacetype_action(void) BLI_addhead(&st->regiontypes, art); + /* regions: UI buttons */ + art = MEM_callocN(sizeof(ARegionType), "spacetype action region"); + art->regionid = RGN_TYPE_UI; + art->prefsizex = 200; + art->keymapflag = ED_KEYMAP_UI; + art->listener = action_region_listener; + art->init = action_buttons_area_init; + art->draw = action_buttons_area_draw; + + BLI_addhead(&st->regiontypes, art); + + action_buttons_register(art); BKE_spacetype_register(st); } diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c index 182f2bd2e80..97a85bce006 100644 --- a/source/blender/editors/space_console/space_console.c +++ b/source/blender/editors/space_console/space_console.c @@ -27,10 +27,6 @@ #include <string.h> #include <stdio.h> -#ifdef WIN32 -# include "BLI_winstuff.h" -#endif - #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 207879c2809..8e1f781827a 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -1426,7 +1426,7 @@ int filelist_files_ensure(FileList *filelist) filelist_filter(filelist); } - return filelist->filelist.nbr_entries_filtered;; + return filelist->filelist.nbr_entries_filtered; } static FileDirEntry *filelist_file_create_entry(FileList *filelist, const int index) diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index 7f4cd03c2fa..2a3f964f477 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -477,7 +477,7 @@ static void column_widths(FileSelectParams *params, struct FileLayout *layout) layout->column_widths[i] = 0; } - layout->column_widths[COLUMN_NAME] = ((float)params->thumbnail_size / 8.0f) * UI_UNIT_X;; + layout->column_widths[COLUMN_NAME] = ((float)params->thumbnail_size / 8.0f) * UI_UNIT_X; /* Biggest possible reasonable values... */ layout->column_widths[COLUMN_DATE] = file_string_width(small_size ? "23/08/89" : "23-Dec-89"); layout->column_widths[COLUMN_TIME] = file_string_width("23:59"); diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index effcd80e1f0..f1063996ca3 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -693,6 +693,14 @@ static int graphkeys_click_insert_exec(bContext *C, wmOperator *op) short mapping_flag = ANIM_get_normalization_flags(&ac); float scale, offset; + /* preserve selection? */ + if (RNA_boolean_get(op->ptr, "extend") == false) { + /* deselect all keyframes first, so that we can immediately start manipulating the newly added one(s) + * - only affect the keyframes themselves, as we don't want channels popping in and out... + */ + deselect_graph_keys(&ac, false, SELECT_SUBTRACT, false); + } + /* get frame and value from props */ frame = RNA_float_get(op->ptr, "frame"); val = RNA_float_get(op->ptr, "value"); @@ -782,6 +790,8 @@ void GRAPH_OT_click_insert(wmOperatorType *ot) /* properties */ RNA_def_float(ot->srna, "frame", 1.0f, -FLT_MAX, FLT_MAX, "Frame Number", "Frame to insert keyframe on", 0, 100); RNA_def_float(ot->srna, "value", 1.0f, -FLT_MAX, FLT_MAX, "Value", "Value for keyframe on", 0, 100); + + RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting everything first"); } /* ******************** Copy/Paste Keyframes Operator ************************* */ diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h index b6b711e129f..534b712fd5e 100644 --- a/source/blender/editors/space_graph/graph_intern.h +++ b/source/blender/editors/space_graph/graph_intern.h @@ -56,6 +56,8 @@ void graph_draw_ghost_curves(struct bAnimContext *ac, struct SpaceIpo *sipo, str /* ***************************************** */ /* graph_select.c */ +void deselect_graph_keys(struct bAnimContext *ac, bool test, short sel, bool do_channels); + void GRAPH_OT_select_all_toggle(struct wmOperatorType *ot); void GRAPH_OT_select_border(struct wmOperatorType *ot); void GRAPH_OT_select_lasso(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c index 7ffa8250067..6b860990c10 100644 --- a/source/blender/editors/space_graph/graph_ops.c +++ b/source/blender/editors/space_graph/graph_ops.c @@ -610,7 +610,11 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap) /* insertkey */ WM_keymap_add_item(keymap, "GRAPH_OT_keyframe_insert", IKEY, KM_PRESS, 0, 0); - WM_keymap_add_item(keymap, "GRAPH_OT_click_insert", ACTIONMOUSE, KM_CLICK, KM_CTRL, 0); + + kmi = WM_keymap_add_item(keymap, "GRAPH_OT_click_insert", ACTIONMOUSE, KM_CLICK, KM_CTRL, 0); + RNA_boolean_set(kmi->ptr, "extend", false); + kmi = WM_keymap_add_item(keymap, "GRAPH_OT_click_insert", ACTIONMOUSE, KM_CLICK, KM_CTRL | KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "extend", true); /* copy/paste */ WM_keymap_add_item(keymap, "GRAPH_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0); diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index 67274100312..eb786d872ec 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -83,7 +83,7 @@ * 2 = invert * - do_channels: whether to affect selection status of channels */ -static void deselect_graph_keys(bAnimContext *ac, short test, short sel, short do_channels) +void deselect_graph_keys(bAnimContext *ac, bool test, short sel, bool do_channels) { ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c index 0ddbb1153c0..e810f4db7dd 100644 --- a/source/blender/editors/space_image/image_draw.c +++ b/source/blender/editors/space_image/image_draw.c @@ -197,6 +197,19 @@ void ED_image_draw_info(Scene *scene, ARegion *ar, bool color_manage, bool use_d dx += BLF_width(blf_mono_font, str, sizeof(str)); } + if (channels == 1 && (cp != NULL || fp != NULL)) { + if (fp != NULL) { + BLI_snprintf(str, sizeof(str), " Val:%-.3f |", fp[0]); + } + else if (cp != NULL) { + BLI_snprintf(str, sizeof(str), " Val:%-.3f |", cp[0] / 255.0f); + } + glColor3ub(255, 255, 255); + BLF_position(blf_mono_font, dx, dy, 0); + BLF_draw_ascii(blf_mono_font, str, sizeof(str)); + dx += BLF_width(blf_mono_font, str, sizeof(str)); + } + if (channels >= 3) { glColor3ubv(red); if (fp) @@ -526,7 +539,12 @@ static void draw_image_buffer(const bContext *C, SpaceImage *sima, ARegion *ar, } if ((sima->flag & (SI_SHOW_R | SI_SHOW_G | SI_SHOW_B)) == 0) { - glaDrawImBuf_glsl_ctx(C, ibuf, x, y, GL_NEAREST); + int clip_max_x, clip_max_y; + UI_view2d_view_to_region(&ar->v2d, + ar->v2d.cur.xmax, ar->v2d.cur.ymax, + &clip_max_x, &clip_max_y); + glaDrawImBuf_glsl_ctx_clipping(C, ibuf, x, y, GL_NEAREST, + 0, 0, clip_max_x, clip_max_y); } else { unsigned char *display_buffer; diff --git a/source/blender/editors/space_image/image_intern.h b/source/blender/editors/space_image/image_intern.h index 3b57d17f9f3..69993c3be65 100644 --- a/source/blender/editors/space_image/image_intern.h +++ b/source/blender/editors/space_image/image_intern.h @@ -63,6 +63,7 @@ void IMAGE_OT_view_zoom(struct wmOperatorType *ot); void IMAGE_OT_view_zoom_in(struct wmOperatorType *ot); void IMAGE_OT_view_zoom_out(struct wmOperatorType *ot); void IMAGE_OT_view_zoom_ratio(struct wmOperatorType *ot); +void IMAGE_OT_view_zoom_border(struct wmOperatorType *ot); void IMAGE_OT_view_ndof(struct wmOperatorType *ot); void IMAGE_OT_new(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index ae5dcc4c73f..8db5a8f9bd3 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -990,6 +990,62 @@ void IMAGE_OT_view_zoom_ratio(wmOperatorType *ot) "Ratio", "Zoom ratio, 1.0 is 1:1, higher is zoomed in, lower is zoomed out", -FLT_MAX, FLT_MAX); } +/********************** view border-zoom operator *********************/ + +static int image_view_zoom_border_exec(bContext *C, wmOperator *op) +{ + SpaceImage *sima = CTX_wm_space_image(C); + ARegion *ar = CTX_wm_region(C); + rctf bounds; + const int gesture_mode = RNA_int_get(op->ptr, "gesture_mode"); + + WM_operator_properties_border_to_rctf(op, &bounds); + + UI_view2d_region_to_view_rctf(&ar->v2d, &bounds, &bounds); + + const struct { + float xof; + float yof; + float zoom; + } sima_view_prev = { + .xof = sima->xof, + .yof = sima->yof, + .zoom = sima->zoom, + }; + + sima_zoom_set_from_bounds(sima, ar, &bounds); + + /* zoom out */ + if (gesture_mode == GESTURE_MODAL_OUT) { + sima->xof = sima_view_prev.xof + (sima->xof - sima_view_prev.xof); + sima->yof = sima_view_prev.yof + (sima->yof - sima_view_prev.yof); + sima->zoom = sima_view_prev.zoom * (sima_view_prev.zoom / sima->zoom); + } + + ED_region_tag_redraw(ar); + + return OPERATOR_FINISHED; +} + +void IMAGE_OT_view_zoom_border(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Zoom to Border"; + ot->description = "Zoom in the view to the nearest item contained in the border"; + ot->idname = "IMAGE_OT_view_zoom_border"; + + /* api callbacks */ + ot->invoke = WM_border_select_invoke; + ot->exec = image_view_zoom_border_exec; + ot->modal = WM_border_select_modal; + ot->cancel = WM_border_select_cancel; + + ot->poll = space_image_main_region_poll; + + /* rna */ + WM_operator_properties_gesture_border(ot, false); +} + /**************** load/replace/save callbacks ******************/ static void image_filesel(bContext *C, wmOperator *op, const char *path) { @@ -2770,8 +2826,8 @@ typedef struct ImageSampleInfo { int *zp; float *zfp; - int draw; - int color_manage; + bool draw; + bool color_manage; int use_default_view; } ImageSampleInfo; @@ -2845,7 +2901,7 @@ static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event if (ibuf == NULL) { ED_space_image_release_buffer(sima, ibuf, lock); - info->draw = 0; + info->draw = false; return; } @@ -2862,7 +2918,7 @@ static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event info->x = x; info->y = y; - info->draw = 1; + info->draw = true; info->channels = ibuf->channels; info->colp = NULL; @@ -2895,10 +2951,24 @@ static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event if (ibuf->rect_float) { fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x)); - info->colf[0] = fp[0]; - info->colf[1] = fp[1]; - info->colf[2] = fp[2]; - info->colf[3] = fp[3]; + if (ibuf->channels == 4) { + info->colf[0] = fp[0]; + info->colf[1] = fp[1]; + info->colf[2] = fp[2]; + info->colf[3] = fp[3]; + } + else if (ibuf->channels == 3) { + info->colf[0] = fp[0]; + info->colf[1] = fp[1]; + info->colf[2] = fp[2]; + info->colf[3] = 1.0f; + } + else { + info->colf[0] = fp[0]; + info->colf[1] = fp[0]; + info->colf[2] = fp[0]; + info->colf[3] = 1.0f; + } info->colfp = info->colf; copy_v4_v4(info->linearcol, info->colf); @@ -2909,10 +2979,16 @@ static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event if (ibuf->zbuf) { info->z = ibuf->zbuf[y * ibuf->x + x]; info->zp = &info->z; + if (ibuf->zbuf == (int*)ibuf->rect) { + info->colp = NULL; + } } if (ibuf->zbuf_float) { info->zf = ibuf->zbuf_float[y * ibuf->x + x]; info->zfp = &info->zf; + if (ibuf->zbuf_float == ibuf->rect_float) { + info->colfp = NULL; + } } if (curve_mapping && ibuf->channels == 4) { diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index ccf9e825e1b..168f9c0dfdf 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -232,6 +232,7 @@ static void image_operatortypes(void) WM_operatortype_append(IMAGE_OT_view_zoom_in); WM_operatortype_append(IMAGE_OT_view_zoom_out); WM_operatortype_append(IMAGE_OT_view_zoom_ratio); + WM_operatortype_append(IMAGE_OT_view_zoom_border); WM_operatortype_append(IMAGE_OT_view_ndof); WM_operatortype_append(IMAGE_OT_new); @@ -303,6 +304,7 @@ static void image_keymap(struct wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom", MIDDLEMOUSE, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom", MOUSEZOOM, 0, 0, 0); WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom", MOUSEPAN, 0, KM_CTRL, 0); + WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_border", BKEY, KM_PRESS, KM_SHIFT, 0); /* ctrl now works as well, shift + numpad works as arrow keys on Windows */ RNA_float_set(WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_ratio", PAD8, KM_PRESS, KM_CTRL, 0)->ptr, "ratio", 8.0f); diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index b2f3306fb62..ddbd07616bc 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -1953,6 +1953,7 @@ static void node_composit_buts_colorbalance(uiLayout *layout, bContext *UNUSED(C uiTemplateColorPicker(col, ptr, "offset", 1, 1, 0, 1); row = uiLayoutRow(col, false); uiItemR(row, ptr, "offset", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "offset_basis", 0, NULL, ICON_NONE); col = uiLayoutColumn(split, false); uiTemplateColorPicker(col, ptr, "power", 1, 1, 0, 1); diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c index 4abc7f5e71b..d7249897723 100644 --- a/source/blender/editors/space_node/node_relationships.c +++ b/source/blender/editors/space_node/node_relationships.c @@ -514,12 +514,10 @@ void NODE_OT_link_viewer(wmOperatorType *ot) static void node_link_update_header(bContext *C, bNodeLinkDrag *UNUSED(nldrag)) { -#define HEADER_LENGTH 256 - char header[HEADER_LENGTH]; + char header[UI_MAX_DRAW_STR]; - BLI_strncpy(header, IFACE_("LMB: drag node link, RMB: cancel"), HEADER_LENGTH); + BLI_strncpy(header, IFACE_("LMB: drag node link, RMB: cancel"), sizeof(header)); ED_area_headerprint(CTX_wm_area(C), header); -#undef HEADER_LENGTH } static int node_count_links(bNodeTree *ntree, bNodeSocket *sock) diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c index 9d1cf65b8ac..09594ab543c 100644 --- a/source/blender/editors/space_node/node_templates.c +++ b/source/blender/editors/space_node/node_templates.c @@ -423,8 +423,8 @@ static int ui_compatible_sockets(int typeA, int typeB) static int ui_node_item_name_compare(const void *a, const void *b) { - const bNodeType* type_a = *(const bNodeType**)a; - const bNodeType* type_b = *(const bNodeType**)b; + const bNodeType *type_a = *(const bNodeType **)a; + const bNodeType *type_b = *(const bNodeType **)b; return BLI_natstrcmp(type_a->ui_name, type_b->ui_name); } @@ -462,7 +462,7 @@ 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_count(sorted_ntypes), sizeof(bNodeType *), ui_node_item_name_compare); /* generate UI */ for (int j = 0; j < BLI_array_count(sorted_ntypes); j++) { diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index cda9de92a82..17b6930e2d9 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -612,6 +612,8 @@ static void tree_element_active_ebone__sel(bContext *C, Scene *scene, bArmature static eOLDrawState tree_element_active_ebone( bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tselem), const eOLSetState set, bool recursive) { + BLI_assert(scene->obedit != NULL); + bArmature *arm = scene->obedit->data; EditBone *ebone = te->directdata; eOLDrawState status = OL_DRAWSEL_NONE; @@ -899,11 +901,14 @@ static bool do_outliner_item_activate(bContext *C, Scene *scene, ARegion *ar, Sp /* name and first icon */ else if (mval[0] > te->xs + UI_UNIT_X && mval[0] < te->xend) { - /* always makes active object */ - if (tselem->type != TSE_SEQUENCE && tselem->type != TSE_SEQ_STRIP && tselem->type != TSE_SEQUENCE_DUP) + /* always makes active object, except for some specific types. + * Note about TSE_EBONE: In case of a same ID_AR datablock shared among several objects, we do not want + * to switch out of edit mode (see T48328 for details). */ + if (!ELEM(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP, TSE_EBONE)) { tree_element_set_active_object(C, scene, soops, te, (extend && tselem->type == 0) ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL, recursive && tselem->type == 0); + } if (tselem->type == 0) { // the lib blocks /* editmode? */ diff --git a/source/blender/editors/space_sequencer/CMakeLists.txt b/source/blender/editors/space_sequencer/CMakeLists.txt index 778ccf902d1..6dce962ee02 100644 --- a/source/blender/editors/space_sequencer/CMakeLists.txt +++ b/source/blender/editors/space_sequencer/CMakeLists.txt @@ -28,6 +28,7 @@ set(INC ../../makesdna ../../makesrna ../../windowmanager + ../../../../intern/atomic ../../../../intern/guardedalloc ../../../../intern/glew-mx ) diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index e3cdedf042b..8ae89941bdb 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -1506,23 +1506,20 @@ static int sequencer_slip_exec(bContext *C, wmOperator *op) static void sequencer_slip_update_header(Scene *scene, ScrArea *sa, SlipData *data, int offset) { -#define HEADER_LENGTH 40 - char msg[HEADER_LENGTH]; + char msg[UI_MAX_DRAW_STR]; if (sa) { if (hasNumInput(&data->num_input)) { char num_str[NUM_STR_REP_LEN]; outputNumInput(&data->num_input, num_str, &scene->unit); - BLI_snprintf(msg, HEADER_LENGTH, "Trim offset: %s", num_str); + BLI_snprintf(msg, sizeof(msg), IFACE_("Trim offset: %s"), num_str); } else { - BLI_snprintf(msg, HEADER_LENGTH, "Trim offset: %d", offset); + BLI_snprintf(msg, sizeof(msg), IFACE_("Trim offset: %d"), offset); } } ED_area_headerprint(sa, msg); - -#undef HEADER_LENGTH } static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *event) diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.c b/source/blender/editors/space_sequencer/sequencer_scopes.c index c197aabedfd..80cb42c0b3d 100644 --- a/source/blender/editors/space_sequencer/sequencer_scopes.c +++ b/source/blender/editors/space_sequencer/sequencer_scopes.c @@ -30,11 +30,14 @@ #include <string.h> #include "BLI_utildefines.h" +#include "BLI_task.h" #include "IMB_colormanagement.h" #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" +#include "atomic_ops.h" + #include "sequencer_intern.h" /* XXX, why is this function better then BLI_math version? @@ -450,41 +453,57 @@ static void draw_histogram_bar(ImBuf *ibuf, int x, float val, int col) #define HIS_STEPS 512 -static ImBuf *make_histogram_view_from_ibuf_byte(ImBuf *ibuf) +typedef struct MakeHistogramViewData { + const ImBuf *ibuf; + uint32_t (*bins)[HIS_STEPS]; +} MakeHistogramViewData; + +static void make_histogram_view_from_ibuf_byte_cb_ex( + void *userdata, void *userdata_chunk, const int y, const int UNUSED(threadid)) { - ImBuf *rval = IMB_allocImBuf(515, 128, 32, IB_rect); - int x, y; - unsigned int nr, ng, nb; + MakeHistogramViewData *data = userdata; + const ImBuf *ibuf = data->ibuf; const unsigned char *src = (unsigned char *)ibuf->rect; - unsigned int bins[3][HIS_STEPS]; - - memset(bins, 0, sizeof(bins)); + uint32_t (*cur_bins)[HIS_STEPS] = userdata_chunk; -#pragma omp parallel for shared(bins, src, ibuf) private(x, y) if (ibuf->y >= 256) - for (y = 0; y < ibuf->y; y++) { - unsigned int cur_bins[3][HIS_STEPS]; + for (int x = 0; x < ibuf->x; x++) { + const unsigned char *pixel = src + (y * ibuf->x + x) * 4; - memset(cur_bins, 0, sizeof(cur_bins)); + for (int j = 3; j--;) { + cur_bins[j][pixel[j]]++; + } + } +} - for (x = 0; x < ibuf->x; x++) { - const unsigned char *pixel = src + (y * ibuf->x + x) * 4; +static void make_histogram_view_from_ibuf_finalize(void *userdata, void *userdata_chunk) +{ + MakeHistogramViewData *data = userdata; + uint32_t (*bins)[HIS_STEPS] = data->bins; - cur_bins[0][pixel[0]]++; - cur_bins[1][pixel[1]]++; - cur_bins[2][pixel[2]]++; - } + uint32_t (*cur_bins)[HIS_STEPS] = userdata_chunk; -#pragma omp critical - { - int i; - for (i = 0; i < HIS_STEPS; i++) { - bins[0][i] += cur_bins[0][i]; - bins[1][i] += cur_bins[1][i]; - bins[2][i] += cur_bins[2][i]; - } + for (int j = 3; j--;) { + for (int i = 0; i < HIS_STEPS; i++) { + bins[j][i] += cur_bins[j][i]; } } +} + +static ImBuf *make_histogram_view_from_ibuf_byte(ImBuf *ibuf) +{ + ImBuf *rval = IMB_allocImBuf(515, 128, 32, IB_rect); + int x; + unsigned int nr, ng, nb; + + unsigned int bins[3][HIS_STEPS]; + + memset(bins, 0, sizeof(bins)); + + MakeHistogramViewData data = {.ibuf = ibuf, .bins = bins}; + BLI_task_parallel_range_finalize( + 0, ibuf->y, &data, bins, sizeof(bins), make_histogram_view_from_ibuf_byte_cb_ex, + make_histogram_view_from_ibuf_finalize, ibuf->y >= 256, false); nr = nb = ng = 0; for (x = 0; x < HIS_STEPS; x++) { @@ -528,40 +547,38 @@ BLI_INLINE int get_bin_float(float f) return (int) (((f + 0.25f) / 1.5f) * 512); } -static ImBuf *make_histogram_view_from_ibuf_float(ImBuf *ibuf) +static void make_histogram_view_from_ibuf_float_cb_ex( + void *userdata, void *userdata_chunk, const int y, const int UNUSED(threadid)) { - ImBuf *rval = IMB_allocImBuf(515, 128, 32, IB_rect); - int nr, ng, nb, x, y; + const MakeHistogramViewData *data = userdata; + const ImBuf *ibuf = data->ibuf; const float *src = ibuf->rect_float; - unsigned int bins[3][HIS_STEPS]; + uint32_t (*cur_bins)[HIS_STEPS] = userdata_chunk; - memset(bins, 0, sizeof(bins)); + for (int x = 0; x < ibuf->x; x++) { + const float *pixel = src + (y * ibuf->x + x) * 4; -#pragma omp parallel for shared(bins, src, ibuf) private(x, y) if (ibuf->y >= 256) - for (y = 0; y < ibuf->y; y++) { - unsigned int cur_bins[3][HIS_STEPS]; + for (int j = 3; j--;) { + cur_bins[j][get_bin_float(pixel[j])]++; + } + } +} - memset(cur_bins, 0, sizeof(cur_bins)); +static ImBuf *make_histogram_view_from_ibuf_float(ImBuf *ibuf) +{ + ImBuf *rval = IMB_allocImBuf(515, 128, 32, IB_rect); + int nr, ng, nb; + int x; - for (x = 0; x < ibuf->x; x++) { - const float *pixel = src + (y * ibuf->x + x) * 4; + unsigned int bins[3][HIS_STEPS]; - cur_bins[0][get_bin_float(pixel[0])]++; - cur_bins[1][get_bin_float(pixel[1])]++; - cur_bins[2][get_bin_float(pixel[2])]++; - } + memset(bins, 0, sizeof(bins)); -#pragma omp critical - { - int i; - for (i = 0; i < HIS_STEPS; i++) { - bins[0][i] += cur_bins[0][i]; - bins[1][i] += cur_bins[1][i]; - bins[2][i] += cur_bins[2][i]; - } - } - } + MakeHistogramViewData data = {.ibuf = ibuf, .bins = bins}; + BLI_task_parallel_range_finalize( + 0, ibuf->y, &data, bins, sizeof(bins), make_histogram_view_from_ibuf_float_cb_ex, + make_histogram_view_from_ibuf_finalize, ibuf->y >= 256, false); nr = nb = ng = 0; for (x = 0; x < HIS_STEPS; x++) { diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c index 9917486d549..f4171221816 100644 --- a/source/blender/editors/space_view3d/drawarmature.c +++ b/source/blender/editors/space_view3d/drawarmature.c @@ -53,6 +53,7 @@ #include "BKE_global.h" #include "BKE_modifier.h" #include "BKE_nla.h" +#include "BKE_curve.h" #include "BIF_gl.h" @@ -1090,20 +1091,101 @@ static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned glPopMatrix(); } -static void draw_b_bone_boxes(const short dt, bPoseChannel *pchan, float xwidth, float length, float zwidth) +/* A partial copy of b_bone_spline_setup(), with just the parts for previewing editmode curve settings + * + * This assumes that prev/next bones don't have any impact (since they should all still be in the "straight" + * position here anyway), and that we can simply apply the bbone settings to get the desired effect... + */ +static void ebone_spline_preview(EditBone *ebone, Mat4 result_array[MAX_BBONE_SUBDIV]) +{ + float h1[3], h2[3], length, hlength1, hlength2, roll1 = 0.0f, roll2 = 0.0f; + float mat3[3][3]; + float data[MAX_BBONE_SUBDIV + 1][4], *fp; + int a; + + length = ebone->length; + + hlength1 = ebone->ease1 * length * 0.390464f; /* 0.5f * sqrt(2) * kappa, the handle length for near-perfect circles */ + hlength2 = ebone->ease2 * length * 0.390464f; + + /* find the handle points, since this is inside bone space, the + * first point = (0, 0, 0) + * last point = (0, length, 0) + * + * we also just apply all the "extra effects", since they're the whole reason we're doing this... + */ + h1[0] = ebone->curveInX; + h1[1] = hlength1; + h1[2] = ebone->curveInY; + roll1 = ebone->roll1; + + h2[0] = ebone->curveOutX; + h2[1] = -hlength2; + h2[2] = ebone->curveOutY; + roll2 = ebone->roll2; + + /* make curve */ + if (ebone->segments > MAX_BBONE_SUBDIV) + ebone->segments = MAX_BBONE_SUBDIV; + + BKE_curve_forward_diff_bezier(0.0f, h1[0], h2[0], 0.0f, data[0], MAX_BBONE_SUBDIV, 4 * sizeof(float)); + BKE_curve_forward_diff_bezier(0.0f, h1[1], length + h2[1], length, data[0] + 1, MAX_BBONE_SUBDIV, 4 * sizeof(float)); + BKE_curve_forward_diff_bezier(0.0f, h1[2], h2[2], 0.0f, data[0] + 2, MAX_BBONE_SUBDIV, 4 * sizeof(float)); + BKE_curve_forward_diff_bezier(roll1, roll1 + 0.390464f * (roll2 - roll1), roll2 - 0.390464f * (roll2 - roll1), roll2, data[0] + 3, MAX_BBONE_SUBDIV, 4 * sizeof(float)); + + equalize_bbone_bezier(data[0], ebone->segments); /* note: does stride 4! */ + + /* make transformation matrices for the segments for drawing */ + for (a = 0, fp = data[0]; a < ebone->segments; a++, fp += 4) { + sub_v3_v3v3(h1, fp + 4, fp); + vec_roll_to_mat3(h1, fp[3], mat3); /* fp[3] is roll */ + + copy_m4_m3(result_array[a].mat, mat3); + copy_v3_v3(result_array[a].mat[3], fp); + + /* "extra" scale facs... */ + { + const int num_segments = ebone->segments; + + const float scaleFactorIn = 1.0f + (ebone->scaleIn - 1.0f) * ((float)(num_segments - a) / (float)num_segments); + const float scaleFactorOut = 1.0f + (ebone->scaleOut - 1.0f) * ((float)(a + 1) / (float)num_segments); + + const float scalefac = scaleFactorIn * scaleFactorOut; + float bscalemat[4][4], bscale[3]; + + bscale[0] = scalefac; + bscale[1] = 1.0f; + bscale[2] = scalefac; + + size_to_mat4(bscalemat, bscale); + + /* Note: don't multiply by inverse scale mat here, as it causes problems with scaling shearing and breaking segment chains */ + mul_m4_series(result_array[a].mat, result_array[a].mat, bscalemat); + } + } +} + +static void draw_b_bone_boxes(const short dt, bPoseChannel *pchan, EditBone *ebone, float xwidth, float length, float zwidth) { int segments = 0; if (pchan) segments = pchan->bone->segments; + else if (ebone) + segments = ebone->segments; - if ((segments > 1) && (pchan)) { + if (segments > 1) { float dlen = length / (float)segments; Mat4 bbone[MAX_BBONE_SUBDIV]; int a; - - b_bone_spline_setup(pchan, 0, bbone); - + + if (pchan) { + b_bone_spline_setup(pchan, 0, bbone); + } + else if (ebone) { + ebone_spline_preview(ebone, bbone); + } + for (a = 0; a < segments; a++) { glPushMatrix(); glMultMatrixf(bbone[a].mat); @@ -1174,7 +1256,7 @@ static void draw_b_bone(const short dt, int armflag, int boneflag, short constfl else UI_ThemeColor(TH_BONE_SOLID); - draw_b_bone_boxes(OB_SOLID, pchan, xwidth, length, zwidth); + draw_b_bone_boxes(OB_SOLID, pchan, ebone, xwidth, length, zwidth); /* disable solid drawing */ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); @@ -1187,7 +1269,7 @@ static void draw_b_bone(const short dt, int armflag, int boneflag, short constfl if (set_pchan_glColor(PCHAN_COLOR_CONSTS, boneflag, constflag)) { glEnable(GL_BLEND); - draw_b_bone_boxes(OB_SOLID, pchan, xwidth, length, zwidth); + draw_b_bone_boxes(OB_SOLID, pchan, ebone, xwidth, length, zwidth); glDisable(GL_BLEND); } @@ -1197,7 +1279,7 @@ static void draw_b_bone(const short dt, int armflag, int boneflag, short constfl } } - draw_b_bone_boxes(OB_WIRE, pchan, xwidth, length, zwidth); + draw_b_bone_boxes(OB_WIRE, pchan, ebone, xwidth, length, zwidth); } } @@ -1887,7 +1969,9 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, } /* custom bone may draw outline double-width */ - glLineWidth(1.0f); + if (arm->flag & ARM_POSEMODE) { + glLineWidth(1.0f); + } /* wire draw over solid only in posemode */ if ((dt <= OB_WIRE) || (arm->flag & ARM_POSEMODE) || ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) { diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c index 53d4ac088e5..1c1068eff78 100644 --- a/source/blender/editors/space_view3d/drawmesh.c +++ b/source/blender/editors/space_view3d/drawmesh.c @@ -711,6 +711,8 @@ static void update_tface_color_layer(DerivedMesh *dm, bool use_mcol) } } } + + dm->dirty |= DM_DIRTY_MCOL_UPDATE_DRAW; } static DMDrawOption draw_tface_mapped__set_draw(void *userData, int origindex, int UNUSED(mat_nr)) @@ -997,7 +999,16 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d else { userData.me = NULL; - update_tface_color_layer(dm, !(ob->mode & OB_MODE_TEXTURE_PAINT)); + if ((ob->mode & OB_MODE_ALL_PAINT) == 0) { + + /* Note: this isn't efficient and runs on every redraw, + * its needed so material colors are used for vertex colors. + * In the future we will likely remove 'texface' so, just avoid running this where possible, + * (when vertex paint or weight paint are used). */ + + update_tface_color_layer(dm, !(ob->mode & OB_MODE_TEXTURE_PAINT)); + } + dm->drawFacesTex( dm, draw_tface__set_draw, compareDrawOptions, &userData, dm_draw_flag); @@ -1181,7 +1192,8 @@ void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d, set_face_cb = NULL; /* test if we can use glsl */ - bool glsl = (v3d->drawtype == OB_MATERIAL) && !picking; + const int drawtype = view3d_effective_drawtype(v3d); + bool glsl = (drawtype == OB_MATERIAL) && !picking; GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL); diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index cdee56dd6d8..109a4952e52 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -225,16 +225,25 @@ static void ob_wire_color_blend_theme_id(const unsigned char ob_wire_col[4], con glColor3fv(col); } +int view3d_effective_drawtype(const struct View3D *v3d) +{ + if (v3d->drawtype == OB_RENDER) { + return v3d->prev_drawtype; + } + return v3d->drawtype; +} + /* this condition has been made more complex since editmode can draw textures */ bool check_object_draw_texture(Scene *scene, View3D *v3d, const char drawtype) { + const int v3d_drawtype = view3d_effective_drawtype(v3d); /* texture and material draw modes */ - if (ELEM(v3d->drawtype, OB_TEXTURE, OB_MATERIAL) && drawtype > OB_SOLID) { + if (ELEM(v3d_drawtype, OB_TEXTURE, OB_MATERIAL) && drawtype > OB_SOLID) { return true; } /* textured solid */ - if ((v3d->drawtype == OB_SOLID) && + if ((v3d_drawtype == OB_SOLID) && (v3d->flag2 & V3D_SOLID_TEX) && (BKE_scene_use_new_shading_nodes(scene) == false)) { @@ -296,7 +305,7 @@ bool draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, const char dt) if (v3d->flag2 & V3D_SHOW_SOLID_MATCAP) return true; - + if (v3d->drawtype == OB_TEXTURE) return (scene->gm.matmode == GAME_MAT_GLSL && !BKE_scene_use_new_shading_nodes(scene)); else if (v3d->drawtype == OB_MATERIAL && dt > OB_SOLID) @@ -1656,7 +1665,8 @@ static void draw_viewport_object_reconstruction( v3d->bundle_size / 0.05f / camera_size[1], v3d->bundle_size / 0.05f / camera_size[2]); - if (v3d->drawtype == OB_WIRE) { + const int v3d_drawtype = view3d_effective_drawtype(v3d); + if (v3d_drawtype == OB_WIRE) { if ((dflag & DRAW_CONSTCOLOR) == 0) { if (selected && (track->flag & TRACK_CUSTOMCOLOR) == 0) { glColor3ubv(ob_wire_col); @@ -1668,7 +1678,7 @@ static void draw_viewport_object_reconstruction( drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype); } - else if (v3d->drawtype > OB_WIRE) { + else if (v3d_drawtype > OB_WIRE) { if (v3d->bundle_drawtype == OB_EMPTY_SPHERE) { /* selection outline */ if (selected) { @@ -6436,7 +6446,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short /* maximum drawtype */ char dt = v3d->drawtype; - if (dt == OB_RENDER) dt = OB_SOLID; + if (dt == OB_RENDER) dt = v3d->prev_drawtype; dt = MIN2(dt, ob->dt); if (v3d->zbuf == 0 && dt > OB_WIRE) dt = OB_WIRE; short dtx = 0; diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 027d90ef039..d060a4a4b4c 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -315,12 +315,12 @@ static void drawgrid(UnitSettings *unit, ARegion *ar, View3D *v3d, const char ** if (unit->system) { /* Use GRID_MIN_PX * 2 for units because very very small grid * items are less useful when dealing with units */ - void *usys; + const void *usys; int len, i; double dx_scalar; float blend_fac; - bUnit_GetSystem(&usys, &len, unit->system, B_UNIT_LENGTH); + bUnit_GetSystem(unit->system, B_UNIT_LENGTH, &usys, &len); if (usys) { i = len; @@ -455,10 +455,10 @@ float ED_scene_grid_scale(Scene *scene, const char **grid_unit) { /* apply units */ if (scene->unit.system) { - void *usys; + const void *usys; int len; - bUnit_GetSystem(&usys, &len, scene->unit.system, B_UNIT_LENGTH); + bUnit_GetSystem(scene->unit.system, B_UNIT_LENGTH, &usys, &len); if (usys) { int i = bUnit_GetBaseUnit(usys); @@ -2602,19 +2602,20 @@ static void gpu_update_lamps_shadows_world(Scene *scene, View3D *v3d) CustomDataMask ED_view3d_datamask(const Scene *scene, const View3D *v3d) { CustomDataMask mask = 0; + const int drawtype = view3d_effective_drawtype(v3d); - if (ELEM(v3d->drawtype, OB_TEXTURE, OB_MATERIAL) || - ((v3d->drawtype == OB_SOLID) && (v3d->flag2 & V3D_SOLID_TEX))) + if (ELEM(drawtype, OB_TEXTURE, OB_MATERIAL) || + ((drawtype == OB_SOLID) && (v3d->flag2 & V3D_SOLID_TEX))) { mask |= CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL; if (BKE_scene_use_new_shading_nodes(scene)) { - if (v3d->drawtype == OB_MATERIAL) + if (drawtype == OB_MATERIAL) mask |= CD_MASK_ORCO; } else { - if ((scene->gm.matmode == GAME_MAT_GLSL && v3d->drawtype == OB_TEXTURE) || - (v3d->drawtype == OB_MATERIAL)) + if ((scene->gm.matmode == GAME_MAT_GLSL && drawtype == OB_TEXTURE) || + (drawtype == OB_MATERIAL)) { mask |= CD_MASK_ORCO; } @@ -3961,6 +3962,7 @@ static void view3d_main_region_draw_info(const bContext *C, Scene *scene, drawviewborder(scene, ar, v3d); } else if (v3d->flag2 & V3D_RENDER_BORDER) { + glLineWidth(1.0f); setlinestyle(3); cpack(0x4040FF); diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index f636a07b064..48701ed1db6 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -37,6 +37,7 @@ #include "DNA_curve_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_gpencil_types.h" #include "MEM_guardedalloc.h" @@ -73,6 +74,7 @@ #include "ED_screen.h" #include "ED_transform.h" #include "ED_mesh.h" +#include "ED_gpencil.h" #include "ED_view3d.h" #include "UI_resources.h" @@ -1228,6 +1230,8 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_PASS_THROUGH; } + ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar); + /* switch from camera view when: */ if (view3d_ensure_persp(vod->v3d, vod->ar)) { /* If we're switching from camera view to the perspective one, @@ -1646,8 +1650,10 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event) viewops_data_alloc(C, op); viewops_data_create_ex(C, op, event, (U.uiflag & USER_ORBIT_SELECTION) != 0, false); - vod = op->customdata; + + ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar); + v3d = vod->v3d; rv3d = vod->rv3d; @@ -1714,6 +1720,9 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev (U.uiflag & USER_ORBIT_SELECTION) != 0, false); vod = op->customdata; + + ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar); + v3d = vod->v3d; rv3d = vod->rv3d; @@ -2023,6 +2032,8 @@ static int viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *event) viewops_data_create(C, op, event); vod = op->customdata; + ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar); + if (event->type == MOUSEPAN) { /* 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); @@ -2502,6 +2513,8 @@ static int viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event) viewops_data_create(C, op, event); vod = op->customdata; + ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar); + /* if one or the other zoom position aren't set, set from event */ if (!RNA_struct_property_is_set(op->ptr, "mx") || !RNA_struct_property_is_set(op->ptr, "my")) { RNA_int_set(op->ptr, "mx", event->x); @@ -2742,6 +2755,8 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_PASS_THROUGH; } + ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar); + /* needs to run before 'viewops_data_create' so the backup 'rv3d->ofs' is correct */ /* switch from camera view when: */ if (vod->rv3d->persp != RV3D_PERSP) { @@ -2837,6 +2852,8 @@ static void view3d_from_minmax(bContext *C, View3D *v3d, ARegion *ar, float afm[3]; float size; + ED_view3d_smooth_view_force_finish(C, v3d, ar); + /* SMOOTHVIEW */ float new_ofs[3]; float new_dist; @@ -3003,6 +3020,8 @@ static int viewselected_exec(bContext *C, wmOperator *op) ARegion *ar = CTX_wm_region(C); View3D *v3d = CTX_wm_view3d(C); Scene *scene = CTX_data_scene(C); + bGPdata *gpd = CTX_data_gpencil_data(C); + const bool is_gp_edit = ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE)); Object *ob = OBACT; Object *obedit = CTX_data_edit_object(C); float min[3], max[3]; @@ -3015,6 +3034,10 @@ static int viewselected_exec(bContext *C, wmOperator *op) INIT_MINMAX(min, max); + if (is_gp_edit) { + ob = NULL; + } + if (ob && (ob->mode & OB_MODE_WEIGHT_PAINT)) { /* hard-coded exception, we look for the one selected armature */ /* this is weak code this way, we should make a generic active/selection callback interface once... */ @@ -3031,7 +3054,19 @@ static int viewselected_exec(bContext *C, wmOperator *op) } - if (obedit) { + if (is_gp_edit) { + CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) + { + /* we're only interested in selected points here... */ + if ((gps->flag & GP_STROKE_SELECT) && (gps->flag & GP_STROKE_3DSPACE)) { + if (ED_gpencil_stroke_minmax(gps, true, min, max)) { + ok = true; + } + } + } + CTX_DATA_END; + } + else if (obedit) { ok = ED_view3d_minmax_verts(obedit, min, max); /* only selected */ } else if (ob && (ob->mode & OB_MODE_POSE)) { @@ -3192,6 +3227,8 @@ static int viewcenter_cursor_exec(bContext *C, wmOperator *op) ARegion *ar = CTX_wm_region(C); const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); + ED_view3d_smooth_view_force_finish(C, v3d, ar); + /* non camera center */ float new_ofs[3]; negate_v3_v3(new_ofs, ED_view3d_cursor3d_get(scene, v3d)); @@ -3231,6 +3268,8 @@ static int viewcenter_pick_invoke(bContext *C, wmOperator *op, const wmEvent *ev float new_ofs[3]; const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); + ED_view3d_smooth_view_force_finish(C, v3d, ar); + view3d_operator_needs_opengl(C); if (ED_view3d_autodist(scene, ar, v3d, event->mval, new_ofs, false, NULL)) { @@ -3836,6 +3875,8 @@ static int viewnumpad_exec(bContext *C, wmOperator *op) ED_view3d_context_user_region(C, &v3d, &ar); rv3d = ar->regiondata; + ED_view3d_smooth_view_force_finish(C, v3d, ar); + viewnum = RNA_enum_get(op->ptr, "type"); align_active = RNA_boolean_get(op->ptr, "align_active"); @@ -3986,6 +4027,8 @@ static int vieworbit_exec(bContext *C, wmOperator *op) rv3d = ar->regiondata; } + ED_view3d_smooth_view_force_finish(C, v3d, ar); + if ((rv3d->viewlock & RV3D_LOCKED) == 0 || (view_opposite != RV3D_VIEW_USER)) { if ((rv3d->persp != RV3D_CAMOB) || ED_view3d_camera_lock_check(v3d, rv3d)) { int smooth_viewtx = WM_operator_smooth_viewtx_get(op); @@ -4191,6 +4234,9 @@ static int viewroll_exec(bContext *C, wmOperator *op) rv3d = ar->regiondata; if ((rv3d->persp != RV3D_CAMOB) || ED_view3d_camera_lock_check(v3d, rv3d)) { + + ED_view3d_smooth_view_force_finish(C, v3d, ar); + int type = RNA_enum_get(op->ptr, "type"); float angle = (type == 0) ? RNA_float_get(op->ptr, "angle") : DEG2RADF(U.pad_rot_angle); float mousevec[3]; @@ -4243,6 +4289,8 @@ static int viewroll_invoke(bContext *C, wmOperator *op, const wmEvent *event) viewops_data_create(C, op, event); 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); @@ -4796,6 +4844,35 @@ void VIEW3D_OT_enable_manipulator(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } +/* ************************* Toggle rendered shading *********************** */ + +static int toggle_render_exec(bContext *C, wmOperator *UNUSED(op)) +{ + View3D *v3d = CTX_wm_view3d(C); + if (v3d->drawtype == OB_RENDER) { + v3d->drawtype = v3d->prev_drawtype; + } + else { + 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)); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); + return OPERATOR_FINISHED; +} + +void VIEW3D_OT_toggle_render(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Toggle Rendered Shading"; + ot->description = "Toggle rendered shading mode of the viewport"; + ot->idname = "VIEW3D_OT_toggle_render"; + + /* api callbacks */ + ot->exec = toggle_render_exec; + ot->poll = ED_operator_view3d_active; +} + /* ************************* below the line! *********************** */ diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index 4da3ba352b6..2d050c4fa95 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -103,6 +103,7 @@ void VIEW3D_OT_enable_manipulator(struct wmOperatorType *ot); void VIEW3D_OT_render_border(struct wmOperatorType *ot); void VIEW3D_OT_clear_render_border(struct wmOperatorType *ot); void VIEW3D_OT_zoom_border(struct wmOperatorType *ot); +void VIEW3D_OT_toggle_render(struct wmOperatorType *ot); void view3d_boxview_copy(ScrArea *sa, ARegion *ar); @@ -158,6 +159,8 @@ enum { V3D_CACHE_TEXT_LOCALCLIP = (1 << 4) }; +int view3d_effective_drawtype(const struct View3D *v3d); + /* drawarmature.c */ bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base, const short dt, const short dflag, const unsigned char ob_wire_col[4], @@ -229,6 +232,10 @@ void ED_view3d_smooth_view( struct View3D *v3d, struct ARegion *ar, const int smooth_viewtx, const V3D_SmoothParams *sview); +void ED_view3d_smooth_view_force_finish( + struct bContext *C, + struct View3D *v3d, struct ARegion *ar); + void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rctf *rect); void view3d_viewmatrix_set(Scene *scene, const View3D *v3d, RegionView3D *rv3d); diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index c30e688f1e7..1c84ce3c985 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -218,7 +218,9 @@ void view3d_operatortypes(void) WM_operatortype_append(VIEW3D_OT_snap_cursor_to_center); WM_operatortype_append(VIEW3D_OT_snap_cursor_to_selected); WM_operatortype_append(VIEW3D_OT_snap_cursor_to_active); - + + WM_operatortype_append(VIEW3D_OT_toggle_render); + transform_operatortypes(); } @@ -417,10 +419,7 @@ void view3d_keymap(wmKeyConfig *keyconf) RNA_string_set(kmi->ptr, "value_1", "SOLID"); RNA_string_set(kmi->ptr, "value_2", "TEXTURED"); - kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle_enum", ZKEY, KM_PRESS, KM_SHIFT, 0); - RNA_string_set(kmi->ptr, "data_path", "space_data.viewport_shade"); - RNA_string_set(kmi->ptr, "value_1", "SOLID"); - RNA_string_set(kmi->ptr, "value_2", "RENDERED"); + WM_keymap_add_item(keymap, "VIEW3D_OT_toggle_render", ZKEY, KM_PRESS, KM_SHIFT, 0); /* selection*/ kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, 0, 0); diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c index cbabc8e56de..797d97586c7 100644 --- a/source/blender/editors/space_view3d/view3d_project.c +++ b/source/blender/editors/space_view3d/view3d_project.c @@ -217,8 +217,8 @@ eV3DProjStatus ED_view3d_project_float_ex(const ARegion *ar, float perspmat[4][4 float tvec[2]; eV3DProjStatus ret = ed_view3d_project__internal(ar, perspmat, is_local, co, tvec, flag); if (ret == V3D_PROJ_RET_OK) { - if (finite(tvec[0]) && - finite(tvec[1])) + if (isfinite(tvec[0]) && + isfinite(tvec[1])) { copy_v2_v2(r_co, tvec); } diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c index 26eb707624a..dfa76753f64 100644 --- a/source/blender/editors/space_view3d/view3d_ruler.c +++ b/source/blender/editors/space_view3d/view3d_ruler.c @@ -35,6 +35,8 @@ #include "BLI_math.h" #include "BLI_blenlib.h" +#include "BLT_translation.h" + #include "BKE_context.h" #include "BKE_unit.h" #include "BKE_gpencil.h" @@ -47,6 +49,7 @@ #include "ED_screen.h" #include "ED_view3d.h" #include "ED_transform.h" +#include "ED_transform_snap_object_context.h" #include "ED_space_api.h" #include "BLF_api.h" @@ -719,13 +722,13 @@ static bool view3d_ruler_item_mousemove( static void view3d_ruler_header_update(ScrArea *sa) { - const char *text = "Ctrl+LMB: Add, " - "Del: Remove, " - "Ctrl+Drag: Snap, " - "Shift+Drag: Thickness, " - "Ctrl+C: Copy Value, " - "Enter: Store, " - "Esc: Cancel"; + const char *text = IFACE_("Ctrl+LMB: Add, " + "Del: Remove, " + "Ctrl+Drag: Snap, " + "Shift+Drag: Thickness, " + "Ctrl+C: Copy Value, " + "Enter: Store, " + "Esc: Cancel"); ED_area_headerprint(sa, text); } diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 305b4a3785e..c35646b9e92 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -337,17 +337,12 @@ void ED_view3d_smooth_view( } /* only meant for timer usage */ -static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) +static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *ar, bool sync_boxview) { - View3D *v3d = CTX_wm_view3d(C); - RegionView3D *rv3d = CTX_wm_region_view3d(C); + RegionView3D *rv3d = ar->regiondata; struct SmoothView3DStore *sms = rv3d->sms; float step, step_inv; - /* escape if not our timer */ - if (rv3d->smooth_timer == NULL || rv3d->smooth_timer != event->customdata) - return OPERATOR_PASS_THROUGH; - if (sms->time_allowed != 0.0) step = (float)((rv3d->smooth_timer->duration) / sms->time_allowed); else @@ -404,8 +399,9 @@ static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const w } - if (rv3d->viewlock & RV3D_BOXVIEW) - view3d_boxview_copy(CTX_wm_area(C), CTX_wm_region(C)); + if (sync_boxview && (rv3d->viewlock & RV3D_BOXVIEW)) { + view3d_boxview_copy(CTX_wm_area(C), ar); + } /* note: this doesn't work right because the v3d->lens is now used in ortho mode r51636, * when switching camera in quad-view the other ortho views would zoom & reset. @@ -416,12 +412,47 @@ static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const w WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); } else { - ED_region_tag_redraw(CTX_wm_region(C)); + ED_region_tag_redraw(ar); } - +} + +static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) +{ + View3D *v3d = CTX_wm_view3d(C); + ARegion *ar = CTX_wm_region(C); + RegionView3D *rv3d = ar->regiondata; + + /* escape if not our timer */ + if (rv3d->smooth_timer == NULL || rv3d->smooth_timer != event->customdata) { + return OPERATOR_PASS_THROUGH; + } + + view3d_smoothview_apply(C, v3d, ar, true); + return OPERATOR_FINISHED; } +/** + * Apply the smoothview immediately, use when we need to start a new view operation. + * (so we don't end up half-applying a view operation when pressing keys quickly). + */ +void ED_view3d_smooth_view_force_finish( + bContext *C, + View3D *v3d, ARegion *ar) +{ + RegionView3D *rv3d = ar->regiondata; + + if (rv3d && rv3d->sms) { + rv3d->sms->time_allowed = 0.0; /* force finishing */ + view3d_smoothview_apply(C, v3d, ar, false); + + /* force update of view matrix so tools that run immediately after + * can use them without redrawing first */ + Scene *scene = CTX_data_scene(C); + ED_view3d_update_viewmat(scene, v3d, ar, NULL, NULL); + } +} + void VIEW3D_OT_smoothview(wmOperatorType *ot) { diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c index 73ec0f664da..47f81678699 100644 --- a/source/blender/editors/space_view3d/view3d_walk.c +++ b/source/blender/editors/space_view3d/view3d_walk.c @@ -49,7 +49,7 @@ #include "ED_screen.h" #include "ED_space_api.h" -#include "ED_transform.h" +#include "ED_transform_snap_object_context.h" #include "PIL_time.h" /* smoothview */ diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 9c718285ada..b6c026ebd37 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -80,6 +80,7 @@ #include "WM_api.h" #include "UI_view2d.h" +#include "UI_interface.h" #include "UI_interface_icons.h" #include "UI_resources.h" @@ -93,8 +94,6 @@ /* Disabling, since when you type you know what you are doing, and being able to set it to zero is handy. */ // #define USE_NUM_NO_ZERO -#define MAX_INFO_LEN 256 - static void drawTransformApply(const struct bContext *C, ARegion *ar, void *arg); static void doEdgeSlide(TransInfo *t, float perc); static void doVertSlide(TransInfo *t, float perc); @@ -2910,7 +2909,7 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2])) float pivot[3]; float warp_end_radius[3]; int i; - char str[MAX_INFO_LEN]; + char str[UI_MAX_DRAW_STR]; const struct BendCustomData *data = t->custom.mode.data; const bool is_clamp = (t->flag & T_ALT_TRANSFORM) == 0; @@ -2948,13 +2947,13 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2])) outputNumInput(&(t->num), c, &t->scene->unit); - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bend Angle: %s Radius: %s Alt, Clamp %s"), + BLI_snprintf(str, sizeof(str), IFACE_("Bend Angle: %s Radius: %s Alt, Clamp %s"), &c[0], &c[NUM_STR_REP_LEN], WM_bool_as_string(is_clamp)); } else { /* default header print */ - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bend Angle: %.3f Radius: %.4f, Alt, Clamp %s"), + BLI_snprintf(str, sizeof(str), IFACE_("Bend Angle: %.3f Radius: %.4f, Alt, Clamp %s"), RAD2DEGF(values.angle), values.scale * data->warp_init_dist, WM_bool_as_string(is_clamp)); } @@ -3104,7 +3103,7 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2])) float smat[3][3], tmat[3][3], totmat[3][3], persmat[3][3], persinv[3][3]; float value; int i; - char str[MAX_INFO_LEN]; + char str[UI_MAX_DRAW_STR]; const bool is_local_center = transdata_check_local_center(t, t->around); copy_m3_m4(persmat, t->viewmat); @@ -3124,11 +3123,11 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2])) outputNumInput(&(t->num), c, &t->scene->unit); - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shear: %s %s"), c, t->proptext); + BLI_snprintf(str, sizeof(str), IFACE_("Shear: %s %s"), c, t->proptext); } else { /* default header print */ - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shear: %.3f %s (Press X or Y to set shear axis)"), value, t->proptext); + BLI_snprintf(str, sizeof(str), IFACE_("Shear: %.3f %s (Press X or Y to set shear axis)"), value, t->proptext); } unit_m3(smat); @@ -3228,7 +3227,7 @@ static void initResize(TransInfo *t) t->num.unit_type[2] = B_UNIT_NONE; } -static void headerResize(TransInfo *t, const float vec[3], char str[MAX_INFO_LEN]) +static void headerResize(TransInfo *t, const float vec[3], char str[UI_MAX_DRAW_STR]) { char tvec[NUM_STR_REP_LEN * 3]; size_t ofs = 0; @@ -3244,32 +3243,32 @@ static void headerResize(TransInfo *t, const float vec[3], char str[MAX_INFO_LEN if (t->con.mode & CON_APPLY) { switch (t->num.idx_max) { case 0: - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Scale: %s%s %s"), + ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_("Scale: %s%s %s"), &tvec[0], t->con.text, t->proptext); break; case 1: - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Scale: %s : %s%s %s"), + ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_("Scale: %s : %s%s %s"), &tvec[0], &tvec[NUM_STR_REP_LEN], t->con.text, t->proptext); break; case 2: - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Scale: %s : %s : %s%s %s"), &tvec[0], + ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_("Scale: %s : %s : %s%s %s"), &tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext); break; } } else { if (t->flag & T_2D_EDIT) { - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Scale X: %s Y: %s%s %s"), + ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_("Scale X: %s Y: %s%s %s"), &tvec[0], &tvec[NUM_STR_REP_LEN], t->con.text, t->proptext); } else { - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Scale X: %s Y: %s Z: %s%s %s"), + ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_("Scale X: %s Y: %s Z: %s%s %s"), &tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext); } } if (t->flag & T_PROP_EDIT_ALL) { - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size); + ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size); } } @@ -3394,7 +3393,7 @@ static void applyResize(TransInfo *t, const int mval[2]) TransData *td; float mat[3][3]; int i; - char str[MAX_INFO_LEN]; + char str[UI_MAX_DRAW_STR]; if (t->flag & T_AUTOVALUES) { copy_v3_v3(t->values, t->auto_values); @@ -3512,7 +3511,7 @@ static void applySkinResize(TransInfo *t, const int UNUSED(mval[2])) TransData *td; float size[3], mat[3][3]; int i; - char str[MAX_INFO_LEN]; + char str[UI_MAX_DRAW_STR]; copy_v3_fl(size, t->values[0]); @@ -3610,7 +3609,7 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2])) float vec[3]; float ratio, radius; int i; - char str[MAX_INFO_LEN]; + char str[UI_MAX_DRAW_STR]; TransData *td = t->data; ratio = t->values[0]; @@ -3629,11 +3628,11 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2])) outputNumInput(&(t->num), c, &t->scene->unit); - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("To Sphere: %s %s"), c, t->proptext); + BLI_snprintf(str, sizeof(str), IFACE_("To Sphere: %s %s"), c, t->proptext); } else { /* default header print */ - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("To Sphere: %.4f %s"), ratio, t->proptext); + BLI_snprintf(str, sizeof(str), IFACE_("To Sphere: %.4f %s"), ratio, t->proptext); } @@ -3964,7 +3963,7 @@ static void applyRotationValue(TransInfo *t, float angle, float axis[3]) static void applyRotation(TransInfo *t, const int UNUSED(mval[2])) { - char str[MAX_INFO_LEN]; + char str[UI_MAX_DRAW_STR]; size_t ofs = 0; float final; @@ -3995,15 +3994,15 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2])) outputNumInput(&(t->num), c, &t->scene->unit); - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Rot: %s %s %s"), &c[0], t->con.text, t->proptext); + ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("Rot: %s %s %s"), &c[0], t->con.text, t->proptext); } else { - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Rot: %.2f%s %s"), + ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("Rot: %.2f%s %s"), RAD2DEGF(final), t->con.text, t->proptext); } if (t->flag & T_PROP_EDIT_ALL) { - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size); + ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size); } applyRotationValue(t, final, t->axis); @@ -4074,7 +4073,7 @@ static void applyTrackballValue(TransInfo *t, const float axis1[3], const float static void applyTrackball(TransInfo *t, const int UNUSED(mval[2])) { - char str[MAX_INFO_LEN]; + char str[UI_MAX_DRAW_STR]; size_t ofs = 0; float axis1[3], axis2[3]; #if 0 /* UNUSED */ @@ -4100,16 +4099,16 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2])) outputNumInput(&(t->num), c, &t->scene->unit); - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Trackball: %s %s %s"), + ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("Trackball: %s %s %s"), &c[0], &c[NUM_STR_REP_LEN], t->proptext); } else { - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Trackball: %.2f %.2f %s"), + ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("Trackball: %.2f %.2f %s"), RAD2DEGF(phi[0]), RAD2DEGF(phi[1]), t->proptext); } if (t->flag & T_PROP_EDIT_ALL) { - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size); + ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size); } #if 0 /* UNUSED */ @@ -4206,7 +4205,7 @@ static void initTranslation(TransInfo *t) } } -static void headerTranslation(TransInfo *t, const float vec[3], char str[MAX_INFO_LEN]) +static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_DRAW_STR]) { size_t ofs = 0; char tvec[NUM_STR_REP_LEN * 3]; @@ -4268,15 +4267,15 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[MAX_INF if (t->con.mode & CON_APPLY) { switch (t->num.idx_max) { case 0: - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "D: %s (%s)%s %s %s", + ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, "D: %s (%s)%s %s %s", &tvec[0], distvec, t->con.text, t->proptext, autoik); break; case 1: - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "D: %s D: %s (%s)%s %s %s", + ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, "D: %s D: %s (%s)%s %s %s", &tvec[0], &tvec[NUM_STR_REP_LEN], distvec, t->con.text, t->proptext, autoik); break; case 2: - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "D: %s D: %s D: %s (%s)%s %s %s", + ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, "D: %s D: %s D: %s (%s)%s %s %s", &tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], distvec, t->con.text, t->proptext, autoik); break; @@ -4284,18 +4283,18 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[MAX_INF } else { if (t->flag & T_2D_EDIT) { - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "Dx: %s Dy: %s (%s)%s %s", + ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, "Dx: %s Dy: %s (%s)%s %s", &tvec[0], &tvec[NUM_STR_REP_LEN], distvec, t->con.text, t->proptext); } else { - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "Dx: %s Dy: %s Dz: %s (%s)%s %s %s", + ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, "Dx: %s Dy: %s Dz: %s (%s)%s %s %s", &tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], distvec, t->con.text, t->proptext, autoik); } } if (t->flag & T_PROP_EDIT_ALL) { - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size); + ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size); } if (t->spacetype == SPACE_NODE) { @@ -4304,11 +4303,11 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[MAX_INF if ((snode->flag & SNODE_SKIP_INSOFFSET) == 0) { const char *str_old = BLI_strdup(str); const char *str_dir = (snode->insert_ofs_dir == SNODE_INSERTOFS_DIR_RIGHT) ? IFACE_("right") : IFACE_("left"); - char str_km[MAX_INFO_LEN]; + char str_km[64]; WM_modalkeymap_items_to_string(t->keymap, TFM_MODAL_INSERTOFS_TOGGLE_DIR, true, sizeof(str_km), str_km); - ofs += BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Auto-offset set to %s - press %s to toggle direction | %s"), + ofs += BLI_snprintf(str, UI_MAX_DRAW_STR, IFACE_("Auto-offset set to %s - press %s to toggle direction | %s"), str_dir, str_km, str_old); MEM_freeN((void *)str_old); @@ -4376,7 +4375,7 @@ static void applyTranslationValue(TransInfo *t, const float vec[3]) static void applyTranslation(TransInfo *t, const int UNUSED(mval[2])) { - char str[MAX_INFO_LEN]; + char str[UI_MAX_DRAW_STR]; float value_final[3]; if (t->flag & T_AUTOVALUES) { @@ -4468,7 +4467,7 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) { float distance; int i; - char str[MAX_INFO_LEN]; + char str[UI_MAX_DRAW_STR]; size_t ofs = 0; TransData *td = t->data; @@ -4481,29 +4480,29 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) t->values[0] = -distance; /* header print for NumInput */ - ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Shrink/Fatten:"), MAX_INFO_LEN - ofs); + ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Shrink/Fatten:"), sizeof(str) - ofs); if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; outputNumInput(&(t->num), c, &t->scene->unit); - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, " %s", c); + ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, " %s", c); } else { /* default header print */ - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, " %.4f", distance); + ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, " %.4f", distance); } if (t->proptext[0]) { - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, " %s", t->proptext); + ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, " %s", t->proptext); } - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, ", ("); + ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, ", ("); if (t->keymap) { wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_RESIZE); if (kmi) { - ofs += WM_keymap_item_to_string(kmi, false, MAX_INFO_LEN - ofs, str + ofs); + ofs += WM_keymap_item_to_string(kmi, false, sizeof(str) - ofs, str + ofs); } } - BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" or Alt) Even Thickness %s"), + BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_(" or Alt) Even Thickness %s"), WM_bool_as_string((t->flag & T_ALT_TRANSFORM) != 0)); /* done with header string */ @@ -4563,7 +4562,7 @@ static void applyTilt(TransInfo *t, const int UNUSED(mval[2])) { TransData *td = t->data; int i; - char str[MAX_INFO_LEN]; + char str[UI_MAX_DRAW_STR]; float final; @@ -4580,13 +4579,13 @@ static void applyTilt(TransInfo *t, const int UNUSED(mval[2])) outputNumInput(&(t->num), c, &t->scene->unit); - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Tilt: %s° %s"), &c[0], t->proptext); + BLI_snprintf(str, sizeof(str), IFACE_("Tilt: %s° %s"), &c[0], t->proptext); /* XXX For some reason, this seems needed for this op, else RNA prop is not updated... :/ */ t->values[0] = final; } else { - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Tilt: %.2f° %s"), RAD2DEGF(final), t->proptext); + BLI_snprintf(str, sizeof(str), IFACE_("Tilt: %.2f° %s"), RAD2DEGF(final), t->proptext); } for (i = 0; i < t->total; i++, td++) { @@ -4644,7 +4643,7 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) TransData *td = t->data; float ratio; int i; - char str[MAX_INFO_LEN]; + char str[UI_MAX_DRAW_STR]; ratio = t->values[0]; @@ -4659,10 +4658,10 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) char c[NUM_STR_REP_LEN]; outputNumInput(&(t->num), c, &t->scene->unit); - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shrink/Fatten: %s"), c); + BLI_snprintf(str, sizeof(str), IFACE_("Shrink/Fatten: %s"), c); } else { - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shrink/Fatten: %3f"), ratio); + BLI_snprintf(str, sizeof(str), IFACE_("Shrink/Fatten: %3f"), ratio); } for (i = 0; i < t->total; i++, td++) { @@ -4724,7 +4723,7 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) float ratio; int i; bool initial_feather = false; - char str[MAX_INFO_LEN]; + char str[UI_MAX_DRAW_STR]; ratio = t->values[0]; @@ -4739,10 +4738,10 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) char c[NUM_STR_REP_LEN]; outputNumInput(&(t->num), c, &t->scene->unit); - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Feather Shrink/Fatten: %s"), c); + BLI_snprintf(str, sizeof(str), IFACE_("Feather Shrink/Fatten: %s"), c); } else { - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Feather Shrink/Fatten: %3f"), ratio); + BLI_snprintf(str, sizeof(str), IFACE_("Feather Shrink/Fatten: %3f"), ratio); } /* detect if no points have feather yet */ @@ -4824,7 +4823,7 @@ static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) TransData *td = t->data; float ratio; int i; - char str[MAX_INFO_LEN]; + char str[UI_MAX_DRAW_STR]; ratio = t->values[0]; @@ -4839,10 +4838,10 @@ static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) char c[NUM_STR_REP_LEN]; outputNumInput(&(t->num), c, &t->scene->unit); - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shrink/Fatten: %s"), c); + BLI_snprintf(str, sizeof(str), IFACE_("Shrink/Fatten: %s"), c); } else { - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shrink/Fatten: %3f"), ratio); + BLI_snprintf(str, sizeof(str), IFACE_("Shrink/Fatten: %3f"), ratio); } for (i = 0; i < t->total; i++, td++) { @@ -4897,7 +4896,7 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2])) float vec[3], axis[3]; float distance; int i; - char str[MAX_INFO_LEN]; + char str[UI_MAX_DRAW_STR]; TransData *td = t->data; distance = t->values[0]; @@ -4914,11 +4913,11 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2])) outputNumInput(&(t->num), c, &t->scene->unit); - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Push/Pull: %s%s %s"), c, t->con.text, t->proptext); + BLI_snprintf(str, sizeof(str), IFACE_("Push/Pull: %s%s %s"), c, t->con.text, t->proptext); } else { /* default header print */ - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Push/Pull: %.4f%s %s"), distance, t->con.text, t->proptext); + BLI_snprintf(str, sizeof(str), IFACE_("Push/Pull: %.4f%s %s"), distance, t->con.text, t->proptext); } if (t->con.applyRot && t->con.mode & CON_APPLY) { @@ -4989,7 +4988,7 @@ static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2])) TransData *td = t->data; float weight; int i; - char str[MAX_INFO_LEN]; + char str[UI_MAX_DRAW_STR]; weight = t->values[0]; @@ -5008,16 +5007,16 @@ static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2])) outputNumInput(&(t->num), c, &t->scene->unit); if (weight >= 0.0f) - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bevel Weight: +%s %s"), c, t->proptext); + BLI_snprintf(str, sizeof(str), IFACE_("Bevel Weight: +%s %s"), c, t->proptext); else - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bevel Weight: %s %s"), c, t->proptext); + BLI_snprintf(str, sizeof(str), IFACE_("Bevel Weight: %s %s"), c, t->proptext); } else { /* default header print */ if (weight >= 0.0f) - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bevel Weight: +%.3f %s"), weight, t->proptext); + BLI_snprintf(str, sizeof(str), IFACE_("Bevel Weight: +%.3f %s"), weight, t->proptext); else - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bevel Weight: %.3f %s"), weight, t->proptext); + BLI_snprintf(str, sizeof(str), IFACE_("Bevel Weight: %.3f %s"), weight, t->proptext); } for (i = 0; i < t->total; i++, td++) { @@ -5069,7 +5068,7 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2])) TransData *td = t->data; float crease; int i; - char str[MAX_INFO_LEN]; + char str[UI_MAX_DRAW_STR]; crease = t->values[0]; @@ -5088,16 +5087,16 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2])) outputNumInput(&(t->num), c, &t->scene->unit); if (crease >= 0.0f) - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Crease: +%s %s"), c, t->proptext); + BLI_snprintf(str, sizeof(str), IFACE_("Crease: +%s %s"), c, t->proptext); else - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Crease: %s %s"), c, t->proptext); + BLI_snprintf(str, sizeof(str), IFACE_("Crease: %s %s"), c, t->proptext); } else { /* default header print */ if (crease >= 0.0f) - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Crease: +%.3f %s"), crease, t->proptext); + BLI_snprintf(str, sizeof(str), IFACE_("Crease: +%.3f %s"), crease, t->proptext); else - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Crease: %.3f %s"), crease, t->proptext); + BLI_snprintf(str, sizeof(str), IFACE_("Crease: %.3f %s"), crease, t->proptext); } for (i = 0; i < t->total; i++, td++) { @@ -5151,7 +5150,7 @@ static void initBoneSize(TransInfo *t) t->num.unit_type[2] = B_UNIT_NONE; } -static void headerBoneSize(TransInfo *t, const float vec[3], char str[MAX_INFO_LEN]) +static void headerBoneSize(TransInfo *t, const float vec[3], char str[UI_MAX_DRAW_STR]) { char tvec[NUM_STR_REP_LEN * 3]; if (hasNumInput(&t->num)) { @@ -5166,13 +5165,13 @@ static void headerBoneSize(TransInfo *t, const float vec[3], char str[MAX_INFO_L /* hmm... perhaps the y-axis values don't need to be shown? */ if (t->con.mode & CON_APPLY) { if (t->num.idx_max == 0) - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("ScaleB: %s%s %s"), &tvec[0], t->con.text, t->proptext); + BLI_snprintf(str, UI_MAX_DRAW_STR, IFACE_("ScaleB: %s%s %s"), &tvec[0], t->con.text, t->proptext); else - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("ScaleB: %s : %s : %s%s %s"), + BLI_snprintf(str, UI_MAX_DRAW_STR, IFACE_("ScaleB: %s : %s : %s%s %s"), &tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext); } else { - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("ScaleB X: %s Y: %s Z: %s%s %s"), + BLI_snprintf(str, UI_MAX_DRAW_STR, IFACE_("ScaleB X: %s Y: %s Z: %s%s %s"), &tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext); } } @@ -5203,7 +5202,7 @@ static void applyBoneSize(TransInfo *t, const int mval[2]) float size[3], mat[3][3]; float ratio; int i; - char str[MAX_INFO_LEN]; + char str[UI_MAX_DRAW_STR]; // TRANSFORM_FIX_ME MOVE TO MOUSE INPUT /* for manipulator, center handle, the scaling can't be done relative to center */ @@ -5282,7 +5281,7 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2])) TransData *td = t->data; float ratio; int i; - char str[MAX_INFO_LEN]; + char str[UI_MAX_DRAW_STR]; ratio = t->values[0]; @@ -5297,10 +5296,10 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2])) char c[NUM_STR_REP_LEN]; outputNumInput(&(t->num), c, &t->scene->unit); - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Envelope: %s"), c); + BLI_snprintf(str, sizeof(str), IFACE_("Envelope: %s"), c); } else { - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Envelope: %3f"), ratio); + BLI_snprintf(str, sizeof(str), IFACE_("Envelope: %3f"), ratio); } for (i = 0; i < t->total; i++, td++) { @@ -6959,7 +6958,7 @@ static void doEdgeSlide(TransInfo *t, float perc) static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2])) { - char str[MAX_INFO_LEN]; + char str[UI_MAX_DRAW_STR]; size_t ofs = 0; float final; EdgeSlideData *sld = t->custom.mode.data; @@ -6982,20 +6981,20 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2])) t->values[0] = final; /* header string */ - ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Edge Slide: "), MAX_INFO_LEN - ofs); + ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Edge Slide: "), sizeof(str) - ofs); if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; outputNumInput(&(t->num), c, &t->scene->unit); - ofs += BLI_strncpy_rlen(str + ofs, &c[0], MAX_INFO_LEN - ofs); + ofs += BLI_strncpy_rlen(str + ofs, &c[0], sizeof(str) - ofs); } else { - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "%.4f ", final); + ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, "%.4f ", final); } - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(E)ven: %s, "), WM_bool_as_string(use_even)); + ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("(E)ven: %s, "), WM_bool_as_string(use_even)); if (use_even) { - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(F)lipped: %s, "), WM_bool_as_string(flipped)); + ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("(F)lipped: %s, "), WM_bool_as_string(flipped)); } - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp)); + ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp)); /* done with header string */ /* do stuff here */ @@ -7527,7 +7526,7 @@ static void doVertSlide(TransInfo *t, float perc) static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2])) { - char str[MAX_INFO_LEN]; + char str[UI_MAX_DRAW_STR]; size_t ofs = 0; float final; VertSlideData *sld = t->custom.mode.data; @@ -7550,20 +7549,20 @@ static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2])) t->values[0] = final; /* header string */ - ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Vert Slide: "), MAX_INFO_LEN - ofs); + ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Vert Slide: "), sizeof(str) - ofs); if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; outputNumInput(&(t->num), c, &t->scene->unit); - ofs += BLI_strncpy_rlen(str + ofs, &c[0], MAX_INFO_LEN - ofs); + ofs += BLI_strncpy_rlen(str + ofs, &c[0], sizeof(str) - ofs); } else { - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "%.4f ", final); + ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, "%.4f ", final); } - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(E)ven: %s, "), WM_bool_as_string(use_even)); + ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("(E)ven: %s, "), WM_bool_as_string(use_even)); if (use_even) { - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(F)lipped: %s, "), WM_bool_as_string(flipped)); + ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("(F)lipped: %s, "), WM_bool_as_string(flipped)); } - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp)); + ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp)); /* done with header string */ /* do stuff here */ @@ -7607,7 +7606,7 @@ static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2])) { TransData *td = t->data; int i; - char str[MAX_INFO_LEN]; + char str[UI_MAX_DRAW_STR]; float final; @@ -7624,10 +7623,10 @@ static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2])) outputNumInput(&(t->num), c, &t->scene->unit); - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Roll: %s"), &c[0]); + BLI_snprintf(str, sizeof(str), IFACE_("Roll: %s"), &c[0]); } else { - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Roll: %.2f"), RAD2DEGF(final)); + BLI_snprintf(str, sizeof(str), IFACE_("Roll: %.2f"), RAD2DEGF(final)); } /* set roll values */ @@ -7675,7 +7674,7 @@ static void applyBakeTime(TransInfo *t, const int mval[2]) TransData *td = t->data; float time; int i; - char str[MAX_INFO_LEN]; + char str[UI_MAX_DRAW_STR]; float fac = 0.1f; @@ -7704,16 +7703,16 @@ static void applyBakeTime(TransInfo *t, const int mval[2]) outputNumInput(&(t->num), c, &t->scene->unit); if (time >= 0.0f) - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Time: +%s %s"), c, t->proptext); + BLI_snprintf(str, sizeof(str), IFACE_("Time: +%s %s"), c, t->proptext); else - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Time: %s %s"), c, t->proptext); + BLI_snprintf(str, sizeof(str), IFACE_("Time: %s %s"), c, t->proptext); } else { /* default header print */ if (time >= 0.0f) - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Time: +%.3f %s"), time, t->proptext); + BLI_snprintf(str, sizeof(str), IFACE_("Time: +%.3f %s"), time, t->proptext); else - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Time: %.3f %s"), time, t->proptext); + BLI_snprintf(str, sizeof(str), IFACE_("Time: %.3f %s"), time, t->proptext); } for (i = 0; i < t->total; i++, td++) { @@ -7759,7 +7758,7 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2])) TransData *td; float size[3], mat[3][3]; int i; - char str[MAX_INFO_LEN]; + char str[UI_MAX_DRAW_STR]; /* * OPTIMIZATION: @@ -7777,7 +7776,7 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2])) t->con.applySize(t, NULL, mat); } - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Mirror%s"), t->con.text); + BLI_snprintf(str, sizeof(str), IFACE_("Mirror%s"), t->con.text); for (i = 0, td = t->data; i < t->total; i++, td++) { if (td->flag & TD_NOACTION) @@ -7906,7 +7905,7 @@ static void initSeqSlide(TransInfo *t) t->num.unit_type[1] = B_UNIT_NONE; } -static void headerSeqSlide(TransInfo *t, const float val[2], char str[MAX_INFO_LEN]) +static void headerSeqSlide(TransInfo *t, const float val[2], char str[UI_MAX_DRAW_STR]) { char tvec[NUM_STR_REP_LEN * 3]; size_t ofs = 0; @@ -7918,15 +7917,15 @@ static void headerSeqSlide(TransInfo *t, const float val[2], char str[MAX_INFO_L BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.0f, %.0f", val[0], val[1]); } - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Sequence Slide: %s%s, ("), &tvec[0], t->con.text); + ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_("Sequence Slide: %s%s, ("), &tvec[0], t->con.text); if (t->keymap) { wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_TRANSLATE); if (kmi) { - ofs += WM_keymap_item_to_string(kmi, false, MAX_INFO_LEN - ofs, str + ofs); + ofs += WM_keymap_item_to_string(kmi, false, UI_MAX_DRAW_STR - ofs, str + ofs); } } - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" or Alt) Expand to fit %s"), + ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_(" or Alt) Expand to fit %s"), WM_bool_as_string((t->flag & T_ALT_TRANSFORM) != 0)); } @@ -7948,7 +7947,7 @@ static void applySeqSlideValue(TransInfo *t, const float val[2]) static void applySeqSlide(TransInfo *t, const int mval[2]) { - char str[MAX_INFO_LEN]; + char str[UI_MAX_DRAW_STR]; snapSequenceBounds(t, mval); @@ -8127,7 +8126,7 @@ static void initTimeTranslate(TransInfo *t) t->num.unit_type[0] = B_UNIT_NONE; } -static void headerTimeTranslate(TransInfo *t, char str[MAX_INFO_LEN]) +static void headerTimeTranslate(TransInfo *t, char str[UI_MAX_DRAW_STR]) { char tvec[NUM_STR_REP_LEN * 3]; int ofs = 0; @@ -8166,10 +8165,10 @@ static void headerTimeTranslate(TransInfo *t, char str[MAX_INFO_LEN]) BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", val); } - ofs += BLI_snprintf(str, MAX_INFO_LEN, IFACE_("DeltaX: %s"), &tvec[0]); + ofs += BLI_snprintf(str, UI_MAX_DRAW_STR, IFACE_("DeltaX: %s"), &tvec[0]); if (t->flag & T_PROP_EDIT_ALL) { - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size); + ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size); } } @@ -8231,7 +8230,7 @@ static void applyTimeTranslateValue(TransInfo *t) static void applyTimeTranslate(TransInfo *t, const int mval[2]) { View2D *v2d = (View2D *)t->view; - char str[MAX_INFO_LEN]; + char str[UI_MAX_DRAW_STR]; /* calculate translation amount from mouse movement - in 'time-grid space' */ if (t->flag & T_MODAL) { @@ -8323,7 +8322,7 @@ static void initTimeSlide(TransInfo *t) t->num.unit_type[0] = B_UNIT_NONE; } -static void headerTimeSlide(TransInfo *t, const float sval, char str[MAX_INFO_LEN]) +static void headerTimeSlide(TransInfo *t, const float sval, char str[UI_MAX_DRAW_STR]) { char tvec[NUM_STR_REP_LEN * 3]; @@ -8343,7 +8342,7 @@ static void headerTimeSlide(TransInfo *t, const float sval, char str[MAX_INFO_LE BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", val); } - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("TimeSlide: %s"), &tvec[0]); + BLI_snprintf(str, UI_MAX_DRAW_STR, IFACE_("TimeSlide: %s"), &tvec[0]); } static void applyTimeSlideValue(TransInfo *t, float sval) @@ -8400,7 +8399,7 @@ static void applyTimeSlide(TransInfo *t, const int mval[2]) const float *range = t->custom.mode.data; float minx = range[0]; float maxx = range[1]; - char str[MAX_INFO_LEN]; + char str[UI_MAX_DRAW_STR]; /* calculate mouse co-ordinates */ UI_view2d_region_to_view(v2d, mval[0], mval[1], &cval[0], &cval[1]); @@ -8473,7 +8472,7 @@ static void initTimeScale(TransInfo *t) t->num.unit_type[0] = B_UNIT_NONE; } -static void headerTimeScale(TransInfo *t, char str[MAX_INFO_LEN]) +static void headerTimeScale(TransInfo *t, char str[UI_MAX_DRAW_STR]) { char tvec[NUM_STR_REP_LEN * 3]; @@ -8482,7 +8481,7 @@ static void headerTimeScale(TransInfo *t, char str[MAX_INFO_LEN]) else BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", t->values[0]); - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("ScaleX: %s"), &tvec[0]); + BLI_snprintf(str, UI_MAX_DRAW_STR, IFACE_("ScaleX: %s"), &tvec[0]); } static void applyTimeScaleValue(TransInfo *t) @@ -8526,7 +8525,7 @@ static void applyTimeScaleValue(TransInfo *t) static void applyTimeScale(TransInfo *t, const int UNUSED(mval[2])) { - char str[MAX_INFO_LEN]; + char str[UI_MAX_DRAW_STR]; /* handle numeric-input stuff */ t->vec[0] = t->values[0]; @@ -8558,5 +8557,3 @@ bool checkUseAxisMatrix(TransInfo *t) return false; } - -#undef MAX_INFO_LEN diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 3c69a1cd6c3..f4d93389776 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -59,6 +59,7 @@ struct wmTimer; struct ARegion; struct ReportList; struct EditBone; +struct SnapObjectContext; /* transinfo->redraw */ typedef enum { @@ -105,7 +106,7 @@ typedef struct TransSnap { /** * Re-usable snap context data. */ - SnapObjectContext *object_context; + struct SnapObjectContext *object_context; } TransSnap; typedef struct TransCon { diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index beeba7cf10f..13cc0c22778 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -267,9 +267,9 @@ static void axisProjection(TransInfo *t, const float axis[3], const float in[3], /* possible some values become nan when * viewpoint and object are both zero */ - if (!finite(out[0])) out[0] = 0.0f; - if (!finite(out[1])) out[1] = 0.0f; - if (!finite(out[2])) out[2] = 0.0f; + if (!isfinite(out[0])) out[0] = 0.0f; + if (!isfinite(out[1])) out[1] = 0.0f; + if (!isfinite(out[2])) out[2] = 0.0f; } } } diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 2139dba8a79..137f7c1656a 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -818,6 +818,7 @@ static void pose_grab_with_ik_clear(Object *ob) bKinematicConstraint *data; bPoseChannel *pchan; bConstraint *con, *next; + bool need_dependency_update = false; for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { /* clear all temporary lock flags */ @@ -832,6 +833,7 @@ static void pose_grab_with_ik_clear(Object *ob) data = con->data; if (data->flag & CONSTRAINT_IK_TEMP) { /* iTaSC needs clear for removed constraints */ + need_dependency_update = true; BIK_clear_data(ob->pose); BLI_remlink(&pchan->constraints, con); @@ -847,10 +849,10 @@ static void pose_grab_with_ik_clear(Object *ob) } #ifdef WITH_LEGACY_DEPSGRAPH - if (!DEG_depsgraph_use_legacy()) + if (!DEG_depsgraph_use_legacy() && need_dependency_update) #endif { - /* TODO(sergey): Consuder doing partial update only. */ + /* TODO(sergey): Consider doing partial update only. */ DAG_relations_tag_update(G.main); } } @@ -7622,7 +7624,9 @@ static void createTransGPencil(bContext *C, TransInfo *t) copy_m3_m3(td->mtx, mtx); unit_m3(td->axismtx); // XXX? } - + /* Triangulation must be calculated again, so save the stroke for recalc function */ + td->extra = gps; + td++; tail++; } diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 537e6e65dce..28202f21c0e 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -960,6 +960,16 @@ static void recalcData_sequencer(TransInfo *t) flushTransSeq(t); } +/* force recalculation of triangles during transformation */ +static void recalcData_gpencil_strokes(TransInfo *t) + { + TransData *td = t->data; + for (int i = 0; i < t->total; i++, td++) { + bGPDstroke *gps = td->extra; + gps->flag |= GP_STROKE_RECALC_CACHES; + } +} + /* called for updating while transform acts, once per redraw */ void recalcData(TransInfo *t) { @@ -974,7 +984,8 @@ void recalcData(TransInfo *t) flushTransPaintCurve(t); } else if (t->options & CTX_GPENCIL_STROKES) { - /* pass? */ + /* set recalc triangle cache flag */ + recalcData_gpencil_strokes(t); } else if (t->spacetype == SPACE_IMAGE) { recalcData_image(t); diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 236a223b5ff..1bb8b768981 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -68,6 +68,7 @@ #include "ED_node.h" #include "ED_uvedit.h" #include "ED_view3d.h" +#include "ED_transform_snap_object_context.h" #include "UI_resources.h" #include "UI_view2d.h" @@ -485,6 +486,35 @@ bool validSnappingNormal(TransInfo *t) return false; } +static bool bm_edge_is_snap_target(BMEdge *e, void *UNUSED(user_data)) +{ + if (BM_elem_flag_test(e, BM_ELEM_SELECT | BM_ELEM_HIDDEN) || + BM_elem_flag_test(e->v1, BM_ELEM_SELECT) || + BM_elem_flag_test(e->v2, BM_ELEM_SELECT)) + { + return false; + } + + return true; +} + +static bool bm_face_is_snap_target(BMFace *f, void *UNUSED(user_data)) +{ + if (BM_elem_flag_test(f, BM_ELEM_SELECT | BM_ELEM_HIDDEN)) { + return false; + } + + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) { + return false; + } + } while ((l_iter = l_iter->next) != l_first); + + return true; +} + static void initSnappingMode(TransInfo *t) { ToolSettings *ts = t->settings; @@ -558,11 +588,18 @@ static void initSnappingMode(TransInfo *t) t->tsnap.mode = SCE_SNAP_MODE_INCREMENT; } - if (t->flag & (T_OBJECT | T_EDIT)) { - if (t->spacetype == SPACE_VIEW3D) { + 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, SNAP_OBJECT_USE_CACHE, - t->ar, t->view); + G.main, t->scene, SNAP_OBJECT_USE_CACHE, + t->ar, t->view); + + ED_transform_snap_object_context_set_editmesh_callbacks( + t->tsnap.object_context, + (bool (*)(BMVert *, void *))BM_elem_cb_check_hflag_disabled, + bm_edge_is_snap_target, + bm_face_is_snap_target, + SET_UINT_IN_POINTER((BM_ELEM_SELECT | BM_ELEM_HIDDEN))); } } } @@ -918,86 +955,10 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec)) mval[1] = t->mval[1]; if (t->tsnap.mode == SCE_SNAP_MODE_VOLUME) { - ListBase depth_peels; - DepthPeel *p1, *p2; - const float *last_p = NULL; - float max_dist = FLT_MAX; - float p[3] = {0.0f, 0.0f, 0.0f}; - - BLI_listbase_clear(&depth_peels); - - peelObjectsTransForm(t, mval, t->tsnap.modeSelect, &depth_peels); - -// if (LAST_SNAP_POINT_VALID) -// { -// last_p = LAST_SNAP_POINT; -// } -// else - { - last_p = t->tsnap.snapPoint; - } - - - for (p1 = depth_peels.first; p1; p1 = p1->next) { - if (p1->flag == 0) { - float vec[3]; - float new_dist; - - p2 = NULL; - p1->flag = 1; - - /* if peeling objects, take the first and last from each object */ - if (t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT) { - DepthPeel *peel; - for (peel = p1->next; peel; peel = peel->next) { - if (peel->ob == p1->ob) { - peel->flag = 1; - p2 = peel; - } - } - } - /* otherwise, pair first with second and so on */ - else { - for (p2 = p1->next; p2 && p2->ob != p1->ob; p2 = p2->next) { - /* nothing to do here */ - } - } - - if (p2) { - p2->flag = 1; - - add_v3_v3v3(vec, p1->p, p2->p); - mul_v3_fl(vec, 0.5f); - } - else { - copy_v3_v3(vec, p1->p); - } - - if (last_p == NULL) { - copy_v3_v3(p, vec); - max_dist = 0; - break; - } - - new_dist = len_squared_v3v3(last_p, vec); - - if (new_dist < max_dist) { - copy_v3_v3(p, vec); - max_dist = new_dist; - } - } - } - - if (max_dist != FLT_MAX) { - copy_v3_v3(loc, p); - /* XXX, is there a correct normal in this case ???, for now just z up */ - no[0] = 0.0; - no[1] = 0.0; - no[2] = 1.0; - found = true; - } - - BLI_freelistN(&depth_peels); + found = peelObjectsTransform( + t, mval, t->tsnap.modeSelect, + (t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0, + loc, no, NULL); } else { zero_v3(no); /* objects won't set this */ @@ -1242,8 +1203,6 @@ bool snapObjectsTransform( float *dist_px, float r_loc[3], float r_no[3]) { - float ray_dist = BVH_RAYCAST_DIST_MAX; - return ED_transform_snap_object_project_view3d_ex( t->tsnap.object_context, &(const struct SnapObjectParams){ @@ -1252,269 +1211,94 @@ bool snapObjectsTransform( .use_object_edit = (t->flag & T_EDIT) != 0, .use_object_active = (t->options & CTX_GPENCIL_STROKES) == 0, }, - mval, dist_px, - &ray_dist, + mval, dist_px, NULL, r_loc, r_no, NULL); } /******************** PEELING *********************************/ - -static int cmpPeel(const void *arg1, const void *arg2) +bool peelObjectsSnapContext( + SnapObjectContext *sctx, + const float mval[2], SnapSelect snap_select, bool use_peel_object, + /* return args */ + float r_loc[3], float r_no[3], float *r_thickness) { - const DepthPeel *p1 = arg1; - const DepthPeel *p2 = arg2; - int val = 0; - - if (p1->depth < p2->depth) { - val = -1; - } - else if (p1->depth > p2->depth) { - val = 1; - } - - return val; -} - -static void removeDoublesPeel(ListBase *depth_peels) -{ - DepthPeel *peel; - - for (peel = depth_peels->first; peel; peel = peel->next) { - DepthPeel *next_peel = peel->next; - - if (next_peel && fabsf(peel->depth - next_peel->depth) < 0.0015f) { - peel->next = next_peel->next; - - if (next_peel->next) { - next_peel->next->prev = peel; + ListBase depths_peel = {0}; + ED_transform_snap_object_project_all_view3d_ex( + sctx, + &(const struct SnapObjectParams){ + .snap_to = SCE_SNAP_MODE_FACE, + .snap_select = snap_select, + .use_object_edit = true, + }, + mval, -1.0f, false, + &depths_peel); + + if (!BLI_listbase_is_empty(&depths_peel)) { + /* At the moment we only use the hits of the first object */ + struct SnapObjectHitDepth *hit_min = depths_peel.first; + for (struct SnapObjectHitDepth *iter = hit_min->next; iter; iter = iter->next) { + if (iter->depth < hit_min->depth) { + hit_min = iter; } - - MEM_freeN(next_peel); } - } -} - -static void addDepthPeel(ListBase *depth_peels, float depth, float p[3], float no[3], Object *ob) -{ - DepthPeel *peel = MEM_callocN(sizeof(DepthPeel), "DepthPeel"); - - peel->depth = depth; - peel->ob = ob; - copy_v3_v3(peel->p, p); - copy_v3_v3(peel->no, no); - - BLI_addtail(depth_peels, peel); - - peel->flag = 0; -} - -struct PeelRayCast_Data { - BVHTreeFromMesh bvhdata; - - /* internal vars for adding peel */ - Object *ob; - const float (*obmat)[4]; - const float (*timat)[3]; - - const float *ray_start; /* globalspace */ - - const MLoopTri *looptri; - const float (*polynors)[3]; /* optional, can be NULL */ - - /* output list */ - ListBase *depth_peels; -}; - -static void peelRayCast_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) -{ - struct PeelRayCast_Data *data = userdata; - - data->bvhdata.raycast_callback(&data->bvhdata, index, ray, hit); - - if (hit->index != -1) { - /* get all values in worldspace */ - float location[3], normal[3]; - float depth; - - /* worldspace location */ - mul_v3_m4v3(location, (float (*)[4])data->obmat, hit->co); - depth = len_v3v3(location, data->ray_start); - - /* worldspace normal */ - copy_v3_v3(normal, data->polynors ? data->polynors[data->looptri[hit->index].poly] : hit->no); - mul_m3_v3((float (*)[3])data->timat, normal); - normalize_v3(normal); - - addDepthPeel(data->depth_peels, depth, location, normal, data->ob); - } -} - -static bool peelDerivedMesh( - Object *ob, DerivedMesh *dm, BMEditMesh *em, float obmat[4][4], - const float ray_start[3], const float ray_normal[3], const float UNUSED(mval[2]), - ListBase *depth_peels) -{ - bool retval = false; - int totvert = dm->getNumVerts(dm); - - if (totvert > 0) { - const MLoopTri *looptri = dm->getLoopTriArray(dm); - const int looptri_num = dm->getNumLoopTri(dm); - float imat[4][4]; - float timat[3][3]; /* transpose inverse matrix for normals */ - float ray_start_local[3], ray_normal_local[3]; - bool test = true; - - invert_m4_m4(imat, obmat); - - transpose_m3_m4(timat, imat); - - mul_v3_m4v3(ray_start_local, imat, ray_start); - mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal); - - /* If number of vert is more than an arbitrary limit, - * test against boundbox first - * */ - if (looptri_num > 16) { - BoundBox *bb = BKE_object_boundbox_get(ob); - - if (bb) { - BoundBox bb_temp; - - /* We cannot aford a bbox with some null dimension, which may happen in some cases... - * Threshold is rather high, but seems to be needed to get good behavior, see T46099. */ - bb = BKE_boundbox_ensure_minimum_dimensions(bb, &bb_temp, 1e-1f); - - test = BKE_boundbox_ray_hit_check(bb, ray_start_local, ray_normal_local, NULL); + struct SnapObjectHitDepth *hit_max = NULL; + + if (use_peel_object) { + /* if peeling objects, take the first and last from each object */ + hit_max = hit_min; + for (struct SnapObjectHitDepth *iter = depths_peel.first; iter; iter = iter->next) { + if ((iter->depth > hit_max->depth) && (iter->ob_uuid == hit_min->ob_uuid)) { + hit_max = iter; + } } } - - if (test == true) { - struct PeelRayCast_Data data; - - data.bvhdata.em_evil = em; - data.bvhdata.em_evil_all = false; - bvhtree_from_mesh_looptri(&data.bvhdata, dm, 0.0f, 4, 6); - - if (data.bvhdata.tree != NULL) { - data.ob = ob; - data.obmat = (const float (*)[4])obmat; - data.timat = (const float (*)[3])timat; - data.ray_start = ray_start; - data.looptri = looptri; - data.polynors = dm->getPolyDataArray(dm, CD_NORMAL); /* can be NULL */ - data.depth_peels = depth_peels; - - BLI_bvhtree_ray_cast_all(data.bvhdata.tree, ray_start_local, ray_normal_local, 0.0f, - peelRayCast_cb, &data); + else { + /* otherwise, pair first with second and so on */ + for (struct SnapObjectHitDepth *iter = depths_peel.first; iter; iter = iter->next) { + if ((iter != hit_min) && (iter->ob_uuid == hit_min->ob_uuid)) { + if (hit_max == NULL) { + hit_max = iter; + } + else if (iter->depth < hit_max->depth) { + hit_max = iter; + } + } + } + /* in this case has only one hit. treat as raycast */ + if (hit_max == NULL) { + hit_max = hit_min; } - - free_bvhtree_from_mesh(&data.bvhdata); } - } - - return retval; -} - -static bool peelObjects( - Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, - const float mval[2], SnapSelect snap_select, - ListBase *r_depth_peels) -{ - Base *base; - bool retval = false; - float ray_start[3], ray_normal[3]; - - if (ED_view3d_win_to_ray(ar, v3d, mval, ray_start, ray_normal, true) == false) { - return false; - } - for (base = scene->base.first; base != NULL; base = base->next) { - if (BASE_SELECTABLE(v3d, base)) { - Object *ob = base->object; + mid_v3_v3v3(r_loc, hit_min->co, hit_max->co); - if (ob->transflag & OB_DUPLI) { - DupliObject *dupli_ob; - ListBase *lb = object_duplilist(G.main->eval_ctx, scene, ob); - - for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) { - Object *dob = dupli_ob->ob; - - if (dob->type == OB_MESH) { - BMEditMesh *em; - DerivedMesh *dm = NULL; - bool val; - - if (dob != obedit) { - dm = mesh_get_derived_final(scene, dob, CD_MASK_BAREMESH); - - val = peelDerivedMesh(dob, dm, NULL, dob->obmat, ray_start, ray_normal, mval, r_depth_peels); - } - else { - em = BKE_editmesh_from_object(dob); - dm = editbmesh_get_derived_cage(scene, obedit, em, CD_MASK_BAREMESH); - - val = peelDerivedMesh(dob, dm, em, dob->obmat, ray_start, ray_normal, mval, r_depth_peels); - } + if (r_thickness) { + *r_thickness = hit_max->depth - hit_min->depth; + } - retval = retval || val; - - dm->release(dm); - } - } - - free_object_duplilist(lb); - } - - if (ob->type == OB_MESH) { - bool val = false; + /* XXX, is there a correct normal in this case ???, for now just z up */ + r_no[0] = 0.0; + r_no[1] = 0.0; + r_no[2] = 1.0; - if (ob != obedit && ((snap_select == SNAP_NOT_SELECTED && (base->flag & (SELECT | BA_WAS_SEL)) == 0) || ELEM(snap_select, SNAP_ALL, SNAP_NOT_OBEDIT))) { - DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); - - val = peelDerivedMesh(ob, dm, NULL, ob->obmat, ray_start, ray_normal, mval, r_depth_peels); - dm->release(dm); - } - else if (ob == obedit && snap_select != SNAP_NOT_OBEDIT) { - BMEditMesh *em = BKE_editmesh_from_object(ob); - DerivedMesh *dm = editbmesh_get_derived_cage(scene, obedit, em, CD_MASK_BAREMESH); - - val = peelDerivedMesh(ob, dm, NULL, ob->obmat, ray_start, ray_normal, mval, r_depth_peels); - dm->release(dm); - } - - retval = retval || val; - - } - } + BLI_freelistN(&depths_peel); + return true; } - - BLI_listbase_sort(r_depth_peels, cmpPeel); - removeDoublesPeel(r_depth_peels); - - return retval; -} - -bool peelObjectsTransForm( - TransInfo *t, const float mval[2], SnapSelect snap_select, - ListBase *r_depth_peels) -{ - return peelObjects(t->scene, t->view, t->ar, t->obedit, mval, snap_select, r_depth_peels); + return false; } -bool peelObjectsContext( - bContext *C, const float mval[2], SnapSelect snap_select, - ListBase *r_depth_peels) +bool peelObjectsTransform( + TransInfo *t, + const float mval[2], SnapSelect snap_select, bool use_peel_object, + /* return args */ + float r_loc[3], float r_no[3], float *r_thickness) { - Scene *scene = CTX_data_scene(C); - ScrArea *sa = CTX_wm_area(C); - View3D *v3d = sa->spacedata.first; - ARegion *ar = CTX_wm_region(C); - Object *obedit = CTX_data_edit_object(C); - - return peelObjects(scene, v3d, ar, obedit, mval, snap_select, r_depth_peels); + return peelObjectsSnapContext( + t->tsnap.object_context, + mval, snap_select, use_peel_object, + r_loc, r_no, r_thickness); } /******************** NODES ***********************************/ diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index e9209eea0e7..bf4a3116eeb 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -33,6 +33,8 @@ #include "BLI_kdopbvh.h" #include "BLI_memarena.h" #include "BLI_ghash.h" +#include "BLI_linklist.h" +#include "BLI_listbase.h" #include "BLI_utildefines.h" #include "DNA_armature_types.h" @@ -51,15 +53,30 @@ #include "BKE_tracking.h" #include "ED_transform.h" +#include "ED_transform_snap_object_context.h" #include "ED_view3d.h" #include "ED_armature.h" #include "transform.h" typedef struct SnapObjectData { - BVHTreeFromMesh *bvh_trees[2]; + enum { + SNAP_MESH = 1, + SNAP_EDIT_MESH, + } type; } SnapObjectData; +typedef struct SnapObjectData_Mesh { + SnapObjectData sd; + BVHTreeFromMesh *bvh_trees[2]; + +} SnapObjectData_Mesh; + +typedef struct SnapObjectData_EditMesh { + SnapObjectData sd; + BVHTreeFromEditMesh *bvh_trees[2]; + +} SnapObjectData_EditMesh; struct SnapObjectContext { Main *bmain; @@ -81,8 +98,124 @@ struct SnapObjectContext { MemArena *mem_arena; } cache; + /* Filter data, returns true to check this value */ + struct { + struct { + bool (*test_vert_fn)(BMVert *, void *user_data); + bool (*test_edge_fn)(BMEdge *, void *user_data); + bool (*test_face_fn)(BMFace *, void *user_data); + void *user_data; + } edit_mesh; + } callbacks; + +}; + +static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt); + + +/* -------------------------------------------------------------------- */ + +/** \name Support for storing all depths, not just the first (raycast 'all') + * + * This uses a list of #SnapObjectHitDepth structs. + * + * \{ */ + +/* Store all ray-hits */ +struct RayCastAll_Data { + void *bvhdata; + + /* internal vars for adding depths */ + BVHTree_RayCastCallback raycast_callback; + + const float(*obmat)[4]; + const float(*timat)[3]; + + float len_diff; + float local_scale; + + Object *ob; + unsigned int ob_uuid; + + /* DerivedMesh only */ + DerivedMesh *dm; + const struct MLoopTri *dm_looptri; + + /* output data */ + ListBase *hit_list; + bool retval; }; +static struct SnapObjectHitDepth *hit_depth_create( + const float depth, const float co[3], const float no[3], int index, + Object *ob, const float obmat[4][4], unsigned int ob_uuid) +{ + struct SnapObjectHitDepth *hit = MEM_mallocN(sizeof(*hit), __func__); + + hit->depth = depth; + copy_v3_v3(hit->co, co); + copy_v3_v3(hit->no, no); + hit->index = index; + + hit->ob = ob; + copy_m4_m4(hit->obmat, (float(*)[4])obmat); + hit->ob_uuid = ob_uuid; + + return hit; +} + +static int hit_depth_cmp(const void *arg1, const void *arg2) +{ + const struct SnapObjectHitDepth *h1 = arg1; + const struct SnapObjectHitDepth *h2 = arg2; + int val = 0; + + if (h1->depth < h2->depth) { + val = -1; + } + else if (h1->depth > h2->depth) { + val = 1; + } + + return val; +} + +static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) +{ + struct RayCastAll_Data *data = userdata; + data->raycast_callback(data->bvhdata, index, ray, hit); + if (hit->index != -1) { + /* get all values in worldspace */ + float location[3], normal[3]; + float depth; + + /* worldspace location */ + mul_v3_m4v3(location, (float(*)[4])data->obmat, hit->co); + depth = (hit->dist + data->len_diff) / data->local_scale; + + /* worldspace normal */ + copy_v3_v3(normal, hit->no); + mul_m3_v3((float(*)[3])data->timat, normal); + normalize_v3(normal); + + /* currently unused, and causes issues when looptri's havn't been calculated. + * since theres some overhead in ensuring this data is valid, it may need to be optional. */ +#if 0 + if (data->dm) { + hit->index = dm_looptri_to_poly_index(data->dm, &data->dm_looptri[hit->index]); + } +#endif + + struct SnapObjectHitDepth *hit_item = hit_depth_create( + depth, location, normal, hit->index, + data->ob, data->obmat, data->ob_uuid); + BLI_addtail(data->hit_list, hit_item); + } +} + +/** \} */ + + /* -------------------------------------------------------------------- */ /** \name Internal Object Snapping API @@ -179,7 +312,7 @@ static bool snapEdge( } static bool snapVertex( - ARegion *ar, const float vco[3], const short vno[3], + ARegion *ar, const float vco[3], const float vno[3], float obmat[4][4], float timat[3][3], const float mval_fl[2], float *dist_px, const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], float *ray_depth, float r_loc[3], float r_no[3]) @@ -216,7 +349,7 @@ static bool snapVertex( copy_v3_v3(r_loc, location); if (r_no) { - normal_short_to_float_v3(r_no, vno); + copy_v3_v3(r_no, vno); mul_m3_v3(timat, r_no); normalize_v3(r_no); } @@ -543,16 +676,33 @@ static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt) static bool snapDerivedMesh( SnapObjectContext *sctx, - Object *ob, DerivedMesh *dm, BMEditMesh *em, float obmat[4][4], + Object *ob, DerivedMesh *dm, float obmat[4][4], const float mval[2], float *dist_px, const short snap_to, bool do_bb, - const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth, - float r_loc[3], float r_no[3], int *r_index) + const float ray_start[3], const float ray_normal[3], const float ray_origin[3], + float *ray_depth, unsigned int ob_index, + float r_loc[3], float r_no[3], int *r_index, + ListBase *r_hit_list) { ARegion *ar = sctx->v3d_data.ar; bool retval = false; - int totvert = dm->getNumVerts(dm); - if (totvert > 0) { + if (snap_to == SCE_SNAP_MODE_FACE) { + if (dm->getNumPolys(dm) == 0) { + return retval; + } + } + if (snap_to == SCE_SNAP_MODE_EDGE) { + if (dm->getNumEdges(dm) == 0) { + return retval; + } + } + else { + if (dm->getNumVerts(dm) == 0) { + return retval; + } + } + + { const bool do_ray_start_correction = ( ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX) && (sctx->use_v3d && !((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp)); @@ -579,19 +729,6 @@ static bool snapDerivedMesh( local_depth *= local_scale; } - SnapObjectData *sod = NULL; - - if (sctx->flag & SNAP_OBJECT_USE_CACHE) { - void **sod_p; - if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) { - sod = *sod_p; - } - else { - sod = *sod_p = BLI_memarena_alloc(sctx->cache.mem_arena, sizeof(*sod)); - memset(sod, 0, sizeof(*sod)); - } - } - if (do_bb) { BoundBox *bb = BKE_object_boundbox_get(ob); @@ -619,9 +756,19 @@ static bool snapDerivedMesh( } } + SnapObjectData_Mesh *sod = NULL; BVHTreeFromMesh *treedata = NULL, treedata_stack; if (sctx->flag & SNAP_OBJECT_USE_CACHE) { + void **sod_p; + if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) { + sod = *sod_p; + } + else { + sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod)); + sod->sd.type = SNAP_MESH; + } + int tree_index = -1; switch (snap_to) { case SCE_SNAP_MODE_FACE: @@ -633,9 +780,16 @@ static bool snapDerivedMesh( } if (tree_index != -1) { if (sod->bvh_trees[tree_index] == NULL) { - sod->bvh_trees[tree_index] = BLI_memarena_alloc(sctx->cache.mem_arena, sizeof(*treedata)); + sod->bvh_trees[tree_index] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*treedata)); } treedata = sod->bvh_trees[tree_index]; + + /* the tree is owned by the DM and may have been freed since we last used! */ + if (treedata && treedata->tree) { + if (treedata->cached && !bvhcache_has_tree(dm->bvhCache, treedata->tree)) { + free_bvhtree_from_mesh(treedata); + } + } } } else { @@ -645,9 +799,7 @@ static bool snapDerivedMesh( } } - if (treedata) { - treedata->em_evil = em; - treedata->em_evil_all = false; + if (treedata && treedata->tree == NULL) { switch (snap_to) { case SCE_SNAP_MODE_FACE: bvhtree_from_mesh_looptri(treedata, dm, 0.0f, 4, 6); @@ -699,31 +851,55 @@ static bool snapDerivedMesh( switch (snap_to) { case SCE_SNAP_MODE_FACE: { - BVHTreeRayHit hit; - - hit.index = -1; - hit.dist = local_depth; - - if (treedata->tree && - BLI_bvhtree_ray_cast(treedata->tree, ray_start_local, ray_normal_local, 0.0f, - &hit, treedata->raycast_callback, treedata) != -1) - { - hit.dist += len_diff; - hit.dist /= local_scale; - if (hit.dist <= *ray_depth) { - *ray_depth = hit.dist; - copy_v3_v3(r_loc, hit.co); - copy_v3_v3(r_no, hit.no); - - /* back to worldspace */ - mul_m4_v3(obmat, r_loc); - mul_m3_v3(timat, r_no); - normalize_v3(r_no); - - retval = true; - - if (r_index) { - *r_index = dm_looptri_to_poly_index(dm, &treedata->looptri[hit.index]); + if (r_hit_list) { + struct RayCastAll_Data data; + + data.bvhdata = treedata; + data.raycast_callback = treedata->raycast_callback; + data.obmat = obmat; + data.timat = timat; + data.len_diff = len_diff; + data.local_scale = local_scale; + data.ob = ob; + data.ob_uuid = ob_index, + data.dm = dm; + data.hit_list = r_hit_list; + data.retval = retval; + + BLI_bvhtree_ray_cast_all( + treedata->tree, ray_start_local, ray_normal_local, 0.0f, + *ray_depth, raycast_all_cb, &data); + + retval = data.retval; + } + else { + BVHTreeRayHit hit; + + hit.index = -1; + hit.dist = local_depth; + + if (treedata->tree && + BLI_bvhtree_ray_cast( + treedata->tree, ray_start_local, ray_normal_local, 0.0f, + &hit, treedata->raycast_callback, treedata) != -1) + { + hit.dist += len_diff; + hit.dist /= local_scale; + if (hit.dist <= *ray_depth) { + *ray_depth = hit.dist; + copy_v3_v3(r_loc, hit.co); + copy_v3_v3(r_no, hit.no); + + /* back to worldspace */ + mul_m4_v3(obmat, r_loc); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); + + retval = true; + + if (r_index) { + *r_index = dm_looptri_to_poly_index(dm, &treedata->looptri[hit.index]); + } } } } @@ -741,8 +917,10 @@ static bool snapDerivedMesh( &nearest, NULL, NULL) != -1) { const MVert *v = &treedata->vert[nearest.index]; + float vno[3]; + normal_short_to_float_v3(vno, v->no); retval = snapVertex( - ar, v->co, v->no, obmat, timat, mval, dist_px, + ar, v->co, vno, obmat, timat, mval, dist_px, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, r_no); } @@ -753,45 +931,288 @@ static bool snapDerivedMesh( MVert *verts = dm->getVertArray(dm); MEdge *edges = dm->getEdgeArray(dm); int totedge = dm->getNumEdges(dm); - const int *index_array = NULL; - int index = 0; - int i; - if (em != NULL) { - index_array = dm->getEdgeDataArray(dm, CD_ORIGINDEX); - BM_mesh_elem_table_ensure(em->bm, BM_EDGE); + for (int i = 0; i < totedge; i++) { + MEdge *e = edges + i; + retval |= snapEdge( + ar, verts[e->v1].co, verts[e->v1].no, verts[e->v2].co, verts[e->v2].no, + obmat, timat, mval, dist_px, + ray_start, ray_start_local, ray_normal_local, ray_depth, + r_loc, r_no); } - for (i = 0; i < totedge; i++) { - MEdge *e = edges + i; - bool test = true; + break; + } + } - if (em != NULL) { - if (index_array) { - index = index_array[i]; - } - else { - index = i; - } + if ((sctx->flag & SNAP_OBJECT_USE_CACHE) == 0) { + if (treedata) { + free_bvhtree_from_mesh(treedata); + } + } + } - if (index == ORIGINDEX_NONE) { - test = false; - } - else { - BMEdge *eed = BM_edge_at_index(em->bm, index); + return retval; +} - if (BM_elem_flag_test(eed, BM_ELEM_HIDDEN) || - BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) || - BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)) - { - test = false; + +static bool snapEditMesh( + SnapObjectContext *sctx, + Object *ob, BMEditMesh *em, float obmat[4][4], + const float mval[2], float *dist_px, const short snap_to, + const float ray_start[3], const float ray_normal[3], const float ray_origin[3], + float *ray_depth, const unsigned int ob_index, + float r_loc[3], float r_no[3], int *r_index, + ListBase *r_hit_list) +{ + ARegion *ar = sctx->v3d_data.ar; + bool retval = false; + + if (snap_to == SCE_SNAP_MODE_FACE) { + if (em->bm->totface == 0) { + return retval; + } + } + if (snap_to == SCE_SNAP_MODE_EDGE) { + if (em->bm->totedge == 0) { + return retval; + } + } + else { + if (em->bm->totvert == 0) { + return retval; + } + } + + { + const bool do_ray_start_correction = ( + ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX) && + (sctx->use_v3d && !((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp)); + + float imat[4][4]; + float timat[3][3]; /* transpose inverse matrix for normals */ + float ray_start_local[3], ray_normal_local[3]; + float local_scale, local_depth, len_diff; + + invert_m4_m4(imat, obmat); + transpose_m3_m4(timat, imat); + + copy_v3_v3(ray_start_local, ray_start); + copy_v3_v3(ray_normal_local, ray_normal); + + mul_m4_v3(imat, ray_start_local); + mul_mat3_m4_v3(imat, ray_normal_local); + + /* local scale in normal direction */ + local_scale = normalize_v3(ray_normal_local); + local_depth = *ray_depth; + if (local_depth != BVH_RAYCAST_DIST_MAX) { + local_depth *= local_scale; + } + + SnapObjectData_EditMesh *sod = NULL; + + BVHTreeFromEditMesh *treedata = NULL, treedata_stack; + + if (sctx->flag & SNAP_OBJECT_USE_CACHE) { + void **sod_p; + if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) { + sod = *sod_p; + } + else { + sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod)); + sod->sd.type = SNAP_EDIT_MESH; + } + + int tree_index = -1; + switch (snap_to) { + case SCE_SNAP_MODE_FACE: + tree_index = 1; + break; + case SCE_SNAP_MODE_VERTEX: + tree_index = 0; + break; + } + if (tree_index != -1) { + if (sod->bvh_trees[tree_index] == NULL) { + sod->bvh_trees[tree_index] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*treedata)); + } + treedata = sod->bvh_trees[tree_index]; + } + } + else { + if (ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX)) { + treedata = &treedata_stack; + memset(treedata, 0, sizeof(*treedata)); + } + } + + if (treedata && treedata->tree == NULL) { + switch (snap_to) { + case SCE_SNAP_MODE_FACE: + { + BLI_bitmap *looptri_mask = NULL; + int looptri_num_active = -1; + if (sctx->callbacks.edit_mesh.test_face_fn) { + looptri_mask = BLI_BITMAP_NEW(em->tottri, __func__); + looptri_num_active = BM_iter_mesh_bitmap_from_filter_tessface( + em->bm, looptri_mask, + sctx->callbacks.edit_mesh.test_face_fn, sctx->callbacks.edit_mesh.user_data); + } + bvhtree_from_editmesh_looptri_ex(treedata, em, looptri_mask, looptri_num_active, 0.0f, 4, 6); + if (looptri_mask) { + MEM_freeN(looptri_mask); + } + break; + } + case SCE_SNAP_MODE_VERTEX: + { + BLI_bitmap *verts_mask = NULL; + int verts_num_active = -1; + if (sctx->callbacks.edit_mesh.test_vert_fn) { + verts_mask = BLI_BITMAP_NEW(em->bm->totvert, __func__); + verts_num_active = BM_iter_mesh_bitmap_from_filter( + BM_VERTS_OF_MESH, em->bm, verts_mask, + (bool (*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_vert_fn, + sctx->callbacks.edit_mesh.user_data); + } + bvhtree_from_editmesh_verts_ex(treedata, em, verts_mask, verts_num_active, 0.0f, 2, 6); + if (verts_mask) { + MEM_freeN(verts_mask); + } + break; + } + } + } + + /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already + * been *inside* boundbox, leading to snap failures (see T38409). + * Note also ar might be null (see T38435), in this case we assume ray_start is ok! + */ + if (do_ray_start_correction) { + /* We *need* a reasonably valid len_diff in this case. + * Use BHVTree to find the closest face from ray_start_local. + */ + if (treedata && treedata->tree != NULL) { + BVHTreeNearest nearest; + nearest.index = -1; + nearest.dist_sq = FLT_MAX; + /* Compute and store result. */ + BLI_bvhtree_find_nearest( + treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata); + if (nearest.index != -1) { + len_diff = sqrtf(nearest.dist_sq); + } + } + float ray_org_local[3]; + + copy_v3_v3(ray_org_local, ray_origin); + mul_m4_v3(imat, ray_org_local); + + /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with very far + * away ray_start values (as returned in case of ortho view3d), see T38358. + */ + len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */ + madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local, + len_diff - len_v3v3(ray_start_local, ray_org_local)); + local_depth -= len_diff; + } + else { + len_diff = 0.0f; + } + + switch (snap_to) { + case SCE_SNAP_MODE_FACE: + { + if (r_hit_list) { + struct RayCastAll_Data data; + + data.bvhdata = treedata; + data.raycast_callback = treedata->raycast_callback; + data.obmat = obmat; + data.timat = timat; + data.len_diff = len_diff; + data.local_scale = local_scale; + data.ob = ob; + data.ob_uuid = ob_index; + data.dm = NULL; + data.hit_list = r_hit_list; + data.retval = retval; + + BLI_bvhtree_ray_cast_all( + treedata->tree, ray_start_local, ray_normal_local, 0.0f, + *ray_depth, raycast_all_cb, &data); + + retval = data.retval; + } + else { + BVHTreeRayHit hit; + + hit.index = -1; + hit.dist = local_depth; + + if (treedata->tree && + BLI_bvhtree_ray_cast( + treedata->tree, ray_start_local, ray_normal_local, 0.0f, + &hit, treedata->raycast_callback, treedata) != -1) + { + hit.dist += len_diff; + hit.dist /= local_scale; + if (hit.dist <= *ray_depth) { + *ray_depth = hit.dist; + copy_v3_v3(r_loc, hit.co); + copy_v3_v3(r_no, hit.no); + + /* back to worldspace */ + mul_m4_v3(obmat, r_loc); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); + + retval = true; + + if (r_index) { + *r_index = hit.index; } } } + } + break; + } + case SCE_SNAP_MODE_VERTEX: + { + BVHTreeNearest nearest; - if (test) { + nearest.index = -1; + nearest.dist_sq = local_depth * local_depth; + if (treedata->tree && + BLI_bvhtree_find_nearest_to_ray( + treedata->tree, ray_start_local, ray_normal_local, + &nearest, NULL, NULL) != -1) + { + const BMVert *v = BM_vert_at_index(em->bm, nearest.index); + retval = snapVertex( + ar, v->co, v->no, obmat, timat, mval, dist_px, + ray_start, ray_start_local, ray_normal_local, ray_depth, + r_loc, r_no); + } + break; + } + case SCE_SNAP_MODE_EDGE: + { + BM_mesh_elem_table_ensure(em->bm, BM_EDGE); + int totedge = em->bm->totedge; + for (int i = 0; i < totedge; i++) { + BMEdge *eed = BM_edge_at_index(em->bm, i); + + if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && + !BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) && + !BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)) + { + short v1no[3], v2no[3]; + normal_float_to_short_v3(v1no, eed->v1->no); + normal_float_to_short_v3(v2no, eed->v2->no); retval |= snapEdge( - ar, verts[e->v1].co, verts[e->v1].no, verts[e->v2].co, verts[e->v2].no, + ar, eed->v1->co, v1no, eed->v2->co, v2no, obmat, timat, mval, dist_px, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, r_no); @@ -804,7 +1225,7 @@ static bool snapDerivedMesh( if ((sctx->flag & SNAP_OBJECT_USE_CACHE) == 0) { if (treedata) { - free_bvhtree_from_mesh(treedata); + free_bvhtree_from_editmesh(treedata); } } } @@ -815,28 +1236,33 @@ static bool snapDerivedMesh( static bool snapObject( SnapObjectContext *sctx, Object *ob, float obmat[4][4], bool use_obedit, const short snap_to, - const float mval[2], float *dist_px, - const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth, + const float mval[2], float *dist_px, const unsigned int ob_index, + const float ray_start[3], const float ray_normal[3], const float ray_origin[3], + float *ray_depth, /* return args */ float r_loc[3], float r_no[3], int *r_index, - Object **r_ob, float r_obmat[4][4]) + Object **r_ob, float r_obmat[4][4], + ListBase *r_hit_list) { ARegion *ar = sctx->v3d_data.ar; bool retval = false; if (ob->type == OB_MESH) { BMEditMesh *em; - DerivedMesh *dm; - bool do_bb = true; if (use_obedit) { em = BKE_editmesh_from_object(ob); - dm = editbmesh_get_derived_cage(sctx->scene, ob, em, CD_MASK_BAREMESH); - do_bb = false; + retval = snapEditMesh( + sctx, ob, em, obmat, mval, dist_px, snap_to, + ray_start, ray_normal, ray_origin, + ray_depth, ob_index, + r_loc, r_no, r_index, + r_hit_list); } else { /* in this case we want the mesh from the editmesh, avoids stale data. see: T45978. * still set the 'em' to NULL, since we only want the 'dm'. */ + DerivedMesh *dm; em = BKE_editmesh_from_object(ob); if (em) { editbmesh_get_derived_cage_and_final(sctx->scene, ob, em, CD_MASK_BAREMESH, &dm); @@ -844,15 +1270,14 @@ static bool snapObject( else { dm = mesh_get_derived_final(sctx->scene, ob, CD_MASK_BAREMESH); } - em = NULL; - } + retval = snapDerivedMesh( + sctx, ob, dm, obmat, mval, dist_px, snap_to, true, + ray_start, ray_normal, ray_origin, + ray_depth, ob_index, + r_loc, r_no, r_index, r_hit_list); - retval = snapDerivedMesh( - sctx, ob, dm, em, obmat, mval, dist_px, snap_to, do_bb, - ray_start, ray_normal, ray_origin, ray_depth, - r_loc, r_no, r_index); - - dm->release(dm); + dm->release(dm); + } } else if (ob->type == OB_ARMATURE) { retval = snapArmature( @@ -898,19 +1323,22 @@ static bool snapObjectsRay( const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth, /* return args */ float r_loc[3], float r_no[3], int *r_index, - Object **r_ob, float r_obmat[4][4]) + Object **r_ob, float r_obmat[4][4], + ListBase *r_hit_list) { Base *base; bool retval = false; + bool snap_obedit_first = snap_select == SNAP_ALL && obedit; + unsigned int ob_index = 0; - if (snap_select == SNAP_ALL && obedit) { + if (snap_obedit_first) { Object *ob = obedit; retval |= snapObject( sctx, ob, ob->obmat, true, snap_to, - mval, dist_px, + mval, dist_px, ob_index++, ray_start, ray_normal, ray_origin, ray_depth, - r_loc, r_no, r_index, r_ob, r_obmat); + r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list); } for (base = sctx->scene->base.first; base != NULL; base = base->next) { @@ -924,12 +1352,6 @@ static bool snapObjectsRay( Object *ob_snap = ob; bool use_obedit = false; - /* for linked objects, use the same object but a different matrix */ - if (obedit && ob->data == obedit->data) { - use_obedit = true; - ob_snap = obedit; - } - if (ob->transflag & OB_DUPLI) { DupliObject *dupli_ob; ListBase *lb = object_duplilist(sctx->bmain->eval_ctx, sctx->scene, ob); @@ -940,19 +1362,33 @@ static bool snapObjectsRay( retval |= snapObject( sctx, dupli_snap, dupli_ob->mat, use_obedit_dupli, snap_to, - mval, dist_px, + mval, dist_px, ob_index++, ray_start, ray_normal, ray_origin, ray_depth, - r_loc, r_no, r_index, r_ob, r_obmat); + r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list); } free_object_duplilist(lb); } + if (obedit) { + if ((ob == obedit) && + (snap_obedit_first || (snap_select == SNAP_NOT_OBEDIT))) + { + continue; + } + + if (ob->data == obedit->data) { + /* for linked objects, use the same object but a different matrix */ + use_obedit = true; + ob_snap = obedit; + } + } + retval |= snapObject( sctx, ob_snap, ob->obmat, use_obedit, snap_to, - mval, dist_px, + mval, dist_px, ob_index++, ray_start, ray_normal, ray_origin, ray_depth, - r_loc, r_no, r_index, r_ob, r_obmat); + r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list); } } @@ -999,12 +1435,28 @@ SnapObjectContext *ED_transform_snap_object_context_create_view3d( return sctx; } -static void snap_object_data_free(void *val) +static void snap_object_data_free(void *sod_v) { - SnapObjectData *sod = val; - for (int i = 0; i < ARRAY_SIZE(sod->bvh_trees); i++) { - if (sod->bvh_trees[i]) { - free_bvhtree_from_mesh(sod->bvh_trees[i]); + switch (((SnapObjectData *)sod_v)->type) { + case SNAP_MESH: + { + SnapObjectData_Mesh *sod = sod_v; + for (int i = 0; i < ARRAY_SIZE(sod->bvh_trees); i++) { + if (sod->bvh_trees[i]) { + free_bvhtree_from_mesh(sod->bvh_trees[i]); + } + } + break; + } + case SNAP_EDIT_MESH: + { + SnapObjectData_EditMesh *sod = sod_v; + for (int i = 0; i < ARRAY_SIZE(sod->bvh_trees); i++) { + if (sod->bvh_trees[i]) { + free_bvhtree_from_editmesh(sod->bvh_trees[i]); + } + } + break; } } } @@ -1019,6 +1471,19 @@ void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx) MEM_freeN(sctx); } +void ED_transform_snap_object_context_set_editmesh_callbacks( + SnapObjectContext *sctx, + bool (*test_vert_fn)(BMVert *, void *user_data), + bool (*test_edge_fn)(BMEdge *, void *user_data), + bool (*test_face_fn)(BMFace *, void *user_data), + void *user_data) +{ + sctx->callbacks.edit_mesh.test_vert_fn = test_vert_fn; + sctx->callbacks.edit_mesh.test_edge_fn = test_edge_fn; + sctx->callbacks.edit_mesh.test_face_fn = test_face_fn; + + sctx->callbacks.edit_mesh.user_data = user_data; +} bool ED_transform_snap_object_project_ray_ex( SnapObjectContext *sctx, @@ -1037,7 +1502,53 @@ bool ED_transform_snap_object_project_ray_ex( base_act, obedit, ray_start, ray_normal, ray_start, ray_depth, r_loc, r_no, r_index, - r_ob, r_obmat); + r_ob, r_obmat, NULL); +} + +/** + * Fill in a list of all hits. + * + * \param ray_depth: Only depths in this range are considered, -1.0 for maximum. + * \param sort: Optionally sort the hits by depth. + * \param r_hit_list: List of #SnapObjectHitDepth (caller must free). + */ +bool ED_transform_snap_object_project_ray_all( + SnapObjectContext *sctx, + const struct SnapObjectParams *params, + const float ray_start[3], const float ray_normal[3], + float ray_depth, bool sort, + ListBase *r_hit_list) +{ + Base *base_act = params->use_object_active ? sctx->scene->basact : NULL; + Object *obedit = params->use_object_edit ? sctx->scene->obedit : NULL; + + if (ray_depth == -1.0f) { + ray_depth = BVH_RAYCAST_DIST_MAX; + } + +#ifdef DEBUG + float ray_depth_prev = ray_depth; +#endif + + bool retval = snapObjectsRay( + sctx, + params->snap_select, params->snap_to, + NULL, NULL, + base_act, obedit, + ray_start, ray_normal, ray_start, &ray_depth, + NULL, NULL, NULL, NULL, NULL, + r_hit_list); + + /* meant to be readonly for 'all' hits, ensure it is */ +#ifdef DEBUG + BLI_assert(ray_depth_prev == ray_depth); +#endif + + if (sort) { + BLI_listbase_sort(r_hit_list, hit_depth_cmp); + } + + return retval; } /** @@ -1049,7 +1560,7 @@ bool ED_transform_snap_object_project_ray_ex( */ static bool transform_snap_context_project_ray_impl( SnapObjectContext *sctx, - const float ray_start[3], const float ray_normal[3], float *ray_dist, + const float ray_start[3], const float ray_normal[3], float *ray_depth, float r_co[3], float r_no[3]) { bool ret; @@ -1062,7 +1573,7 @@ static bool transform_snap_context_project_ray_impl( .snap_to = SCE_SNAP_MODE_FACE, .use_object_edit = (sctx->scene->obedit != NULL), }, - ray_start, ray_normal, ray_dist, + ray_start, ray_normal, ray_depth, r_co, r_no, NULL, NULL, NULL); @@ -1071,13 +1582,13 @@ static bool transform_snap_context_project_ray_impl( bool ED_transform_snap_object_project_ray( SnapObjectContext *sctx, - const float ray_origin[3], const float ray_direction[3], float *ray_dist, + const float ray_origin[3], const float ray_direction[3], float *ray_depth, float r_co[3], float r_no[3]) { - float ray_dist_fallback; - if (ray_dist == NULL) { - ray_dist_fallback = BVH_RAYCAST_DIST_MAX; - ray_dist = &ray_dist_fallback; + float ray_depth_fallback; + if (ray_depth == NULL) { + ray_depth_fallback = BVH_RAYCAST_DIST_MAX; + ray_depth = &ray_depth_fallback; } float no_fallback[3]; @@ -1087,7 +1598,7 @@ bool ED_transform_snap_object_project_ray( return transform_snap_context_project_ray_impl( sctx, - ray_origin, ray_direction, ray_dist, + ray_origin, ray_direction, ray_depth, r_co, r_no); } @@ -1098,7 +1609,7 @@ static bool transform_snap_context_project_view3d_mixed_impl( bool use_depth, float r_co[3], float r_no[3]) { - float ray_dist = BVH_RAYCAST_DIST_MAX; + float ray_depth = BVH_RAYCAST_DIST_MAX; bool is_hit = false; float r_no_dummy[3]; @@ -1116,7 +1627,7 @@ static bool transform_snap_context_project_view3d_mixed_impl( for (int i = 0; i < 3; i++) { if ((params->snap_to_flag & (1 << i)) && (is_hit == false || use_depth)) { if (use_depth == false) { - ray_dist = BVH_RAYCAST_DIST_MAX; + ray_depth = BVH_RAYCAST_DIST_MAX; } params_temp.snap_to = elem_type[i]; @@ -1124,7 +1635,7 @@ static bool transform_snap_context_project_view3d_mixed_impl( if (ED_transform_snap_object_project_view3d( sctx, ¶ms_temp, - mval, dist_px, &ray_dist, + mval, dist_px, &ray_depth, r_co, r_no)) { is_hit = true; @@ -1171,6 +1682,12 @@ bool ED_transform_snap_object_project_view3d_ex( { float ray_start[3], ray_normal[3], ray_orgigin[3]; + float ray_depth_fallback; + if (ray_depth == NULL) { + ray_depth_fallback = BVH_RAYCAST_DIST_MAX; + ray_depth = &ray_depth_fallback; + } + if (!ED_view3d_win_to_ray_ex( sctx->v3d_data.ar, sctx->v3d_data.v3d, mval, ray_orgigin, ray_normal, ray_start, true)) @@ -1186,7 +1703,7 @@ bool ED_transform_snap_object_project_view3d_ex( mval, dist_px, base_act, obedit, ray_start, ray_normal, ray_orgigin, ray_depth, - r_loc, r_no, r_index, NULL, NULL); + r_loc, r_no, r_index, NULL, NULL, NULL); } bool ED_transform_snap_object_project_view3d( @@ -1204,4 +1721,32 @@ bool ED_transform_snap_object_project_view3d( r_loc, r_no, NULL); } +/** + * see: #ED_transform_snap_object_project_ray_all + */ +bool ED_transform_snap_object_project_all_view3d_ex( + SnapObjectContext *sctx, + const struct SnapObjectParams *params, + const float mval[2], + float ray_depth, bool sort, + ListBase *r_hit_list) +{ + float ray_start[3], ray_normal[3]; + + BLI_assert(params->snap_to == SCE_SNAP_MODE_FACE); + + if (!ED_view3d_win_to_ray_ex( + sctx->v3d_data.ar, sctx->v3d_data.v3d, + mval, NULL, ray_normal, ray_start, true)) + { + return false; + } + + return ED_transform_snap_object_project_ray_all( + sctx, + params, + ray_start, ray_normal, ray_depth, sort, + r_hit_list); +} + /** \} */ diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt index e105b6f893d..321b1043595 100644 --- a/source/blender/editors/util/CMakeLists.txt +++ b/source/blender/editors/util/CMakeLists.txt @@ -82,6 +82,7 @@ set(SRC ../include/ED_space_api.h ../include/ED_text.h ../include/ED_transform.h + ../include/ED_transform_snap_object_context.h ../include/ED_transverts.h ../include/ED_types.h ../include/ED_util.h diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c index 2a58b1fd2ec..805238bd2af 100644 --- a/source/blender/editors/util/undo.c +++ b/source/blender/editors/util/undo.c @@ -420,7 +420,8 @@ void ED_undo_operator_repeat_cb_evt(bContext *C, void *arg_op, int UNUSED(arg_ev enum { UNDOSYSTEM_GLOBAL = 1, UNDOSYSTEM_EDITMODE = 2, - UNDOSYSTEM_IMAPAINT = 3 + UNDOSYSTEM_IMAPAINT = 3, + UNDOSYSTEM_SCULPT = 4, }; static int get_undo_system(bContext *C) @@ -450,6 +451,10 @@ static int get_undo_system(bContext *C) 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; @@ -474,6 +479,9 @@ static EnumPropertyItem *rna_undo_itemf(bContext *C, int undosys, int *totitem) 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); } @@ -552,6 +560,9 @@ static int undo_history_exec(bContext *C, wmOperator *op) 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); diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 1071e0f12e8..193b006cf0d 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -4302,7 +4302,7 @@ void ED_keymap_uvedit(wmKeyConfig *keyconf) /* border/circle selection */ kmi = WM_keymap_add_item(keymap, "UV_OT_select_border", BKEY, KM_PRESS, 0, 0); RNA_boolean_set(kmi->ptr, "pinned", false); - kmi = WM_keymap_add_item(keymap, "UV_OT_select_border", BKEY, KM_PRESS, KM_SHIFT, 0); + kmi = WM_keymap_add_item(keymap, "UV_OT_select_border", BKEY, KM_PRESS, KM_CTRL, 0); RNA_boolean_set(kmi->ptr, "pinned", true); WM_keymap_add_item(keymap, "UV_OT_circle_select", CKEY, KM_PRESS, 0, 0); diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c index 20a8ab5c98c..59442e89787 100644 --- a/source/blender/editors/uvedit/uvedit_smart_stitch.c +++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c @@ -46,6 +46,8 @@ #include "BLI_math_vector.h" #include "BLI_string.h" +#include "BLT_translation.h" + #include "BIF_gl.h" #include "BKE_context.h" @@ -54,6 +56,8 @@ #include "BKE_mesh_mapping.h" #include "BKE_editmesh.h" +#include "UI_interface.h" + #include "ED_mesh.h" #include "ED_uvedit.h" #include "ED_screen.h" @@ -259,25 +263,24 @@ static void stitch_preview_delete(StitchPreviewer *stitch_preview) } } -#define HEADER_LENGTH 256 - /* This function updates the header of the UV editor when the stitch tool updates its settings */ static void stitch_update_header(StitchState *state, bContext *C) { - static char str[] = + const char *str = IFACE_( "Mode(TAB) %s, " "(S)nap %s, " "(M)idpoints %s, " "(L)imit %.2f (Alt Wheel adjust) %s, " "Switch (I)sland, " - "shift select vertices"; + "shift select vertices" + ); - char msg[HEADER_LENGTH]; + char msg[UI_MAX_DRAW_STR]; ScrArea *sa = CTX_wm_area(C); if (sa) { - BLI_snprintf(msg, HEADER_LENGTH, str, - state->mode == STITCH_VERT ? "Vertex" : "Edge", + BLI_snprintf(msg, sizeof(msg), str, + state->mode == STITCH_VERT ? IFACE_("Vertex") : IFACE_("Edge"), WM_bool_as_string(state->snap_islands), WM_bool_as_string(state->midpoints), state->limit_dist, diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index 768624b1968..8e4ba4c0afa 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -49,6 +49,8 @@ #include "BLI_uvproject.h" #include "BLI_string.h" +#include "BLT_translation.h" + #include "BKE_cdderivedmesh.h" #include "BKE_subsurf.h" #include "BKE_context.h" @@ -62,6 +64,8 @@ #include "PIL_time.h" +#include "UI_interface.h" + #include "ED_image.h" #include "ED_mesh.h" #include "ED_screen.h" @@ -554,12 +558,13 @@ static void minimize_stretch_iteration(bContext *C, wmOperator *op, bool interac RNA_int_set(op->ptr, "iterations", ms->i); if (interactive && (PIL_check_seconds_timer() - ms->lasttime > 0.5)) { - char str[100]; + char str[UI_MAX_DRAW_STR]; param_flush(ms->handle); if (sa) { - BLI_snprintf(str, sizeof(str), "Minimize Stretch. Blend %.2f (Press + and -, or scroll wheel to set)", ms->blend); + BLI_snprintf(str, sizeof(str), + IFACE_("Minimize Stretch. Blend %.2f (Press + and -, or scroll wheel to set)"), ms->blend); ED_area_headerprint(sa, str); } |