Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Montagne <montagne29@wanadoo.fr>2016-05-24 17:48:10 +0300
committerBastien Montagne <montagne29@wanadoo.fr>2016-05-24 17:48:10 +0300
commitfaec4309147988fbab7b7d7ec661f5130358d169 (patch)
tree0c839f8f88fe80f4a3762980adb5efe729ce1b44 /source/blender/editors
parentf85745b17bfe68673bf5f799e98c617d9471ddf1 (diff)
parente1dd83b399d46d81ea51f6c41725eec5c1a1db7a (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')
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c3
-rw-r--r--source/blender/editors/animation/anim_markers.c10
-rw-r--r--source/blender/editors/armature/armature_add.c40
-rw-r--r--source/blender/editors/armature/armature_edit.c5
-rw-r--r--source/blender/editors/armature/armature_intern.h5
-rw-r--r--source/blender/editors/armature/armature_utils.c24
-rw-r--r--source/blender/editors/armature/editarmature_retarget.c9
-rw-r--r--source/blender/editors/armature/editarmature_sketch.c128
-rw-r--r--source/blender/editors/armature/pose_lib.c14
-rw-r--r--source/blender/editors/armature/pose_slide.c27
-rw-r--r--source/blender/editors/armature/pose_transform.c28
-rw-r--r--source/blender/editors/armature/pose_utils.c25
-rw-r--r--source/blender/editors/curve/curve_intern.h1
-rw-r--r--source/blender/editors/curve/curve_ops.c9
-rw-r--r--source/blender/editors/curve/editcurve.c113
-rw-r--r--source/blender/editors/curve/editcurve_paint.c30
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c219
-rw-r--r--source/blender/editors/gpencil/editaction_gpencil.c3
-rw-r--r--source/blender/editors/gpencil/gpencil_brush.c21
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c51
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h2
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c79
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c27
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c120
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c18
-rw-r--r--source/blender/editors/include/BIF_glutil.h18
-rw-r--r--source/blender/editors/include/ED_armature.h5
-rw-r--r--source/blender/editors/include/ED_gpencil.h4
-rw-r--r--source/blender/editors/include/ED_transform.h92
-rw-r--r--source/blender/editors/include/ED_transform_snap_object_context.h140
-rw-r--r--source/blender/editors/include/UI_icons.h22
-rw-r--r--source/blender/editors/interface/interface_anim.c14
-rw-r--r--source/blender/editors/interface/interface_handlers.c46
-rw-r--r--source/blender/editors/interface/interface_icons.c78
-rw-r--r--source/blender/editors/interface/interface_templates.c6
-rw-r--r--source/blender/editors/interface/interface_widgets.c15
-rw-r--r--source/blender/editors/interface/resources.c18
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c31
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c2
-rw-r--r--source/blender/editors/mesh/editmesh_inset.c8
-rw-r--r--source/blender/editors/mesh/editmesh_loopcut.c99
-rw-r--r--source/blender/editors/mesh/editmesh_path.c15
-rw-r--r--source/blender/editors/mesh/editmesh_rip.c4
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c23
-rw-r--r--source/blender/editors/mesh/meshtools.c10
-rw-r--r--source/blender/editors/object/object_vgroup.c55
-rw-r--r--source/blender/editors/physics/dynamicpaint_ops.c8
-rw-r--r--source/blender/editors/screen/area.c4
-rw-r--r--source/blender/editors/screen/glutil.c104
-rw-r--r--source/blender/editors/screen/screen_ops.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c25
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c128
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c13
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c2
-rw-r--r--source/blender/editors/space_action/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_action/action_buttons.c132
-rw-r--r--source/blender/editors/space_action/action_intern.h10
-rw-r--r--source/blender/editors/space_action/action_ops.c10
-rw-r--r--source/blender/editors/space_action/space_action.c99
-rw-r--r--source/blender/editors/space_console/space_console.c4
-rw-r--r--source/blender/editors/space_file/filelist.c2
-rw-r--r--source/blender/editors/space_file/filesel.c2
-rw-r--r--source/blender/editors/space_graph/graph_edit.c10
-rw-r--r--source/blender/editors/space_graph/graph_intern.h2
-rw-r--r--source/blender/editors/space_graph/graph_ops.c6
-rw-r--r--source/blender/editors/space_graph/graph_select.c2
-rw-r--r--source/blender/editors/space_image/image_draw.c20
-rw-r--r--source/blender/editors/space_image/image_intern.h1
-rw-r--r--source/blender/editors/space_image/image_ops.c92
-rw-r--r--source/blender/editors/space_image/space_image.c2
-rw-r--r--source/blender/editors/space_node/drawnode.c1
-rw-r--r--source/blender/editors/space_node/node_relationships.c6
-rw-r--r--source/blender/editors/space_node/node_templates.c6
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c9
-rw-r--r--source/blender/editors/space_sequencer/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c9
-rw-r--r--source/blender/editors/space_sequencer/sequencer_scopes.c117
-rw-r--r--source/blender/editors/space_view3d/drawarmature.c102
-rw-r--r--source/blender/editors/space_view3d/drawmesh.c16
-rw-r--r--source/blender/editors/space_view3d/drawobject.c22
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c20
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c81
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h7
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c9
-rw-r--r--source/blender/editors/space_view3d/view3d_project.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_ruler.c17
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c53
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c2
-rw-r--r--source/blender/editors/transform/transform.c237
-rw-r--r--source/blender/editors/transform/transform.h3
-rw-r--r--source/blender/editors/transform/transform_constraints.c6
-rw-r--r--source/blender/editors/transform/transform_conversions.c10
-rw-r--r--source/blender/editors/transform/transform_generics.c13
-rw-r--r--source/blender/editors/transform/transform_snap.c440
-rw-r--r--source/blender/editors/transform/transform_snap_object.c799
-rw-r--r--source/blender/editors/util/CMakeLists.txt1
-rw-r--r--source/blender/editors/util/undo.c13
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c2
-rw-r--r--source/blender/editors/uvedit/uvedit_smart_stitch.c17
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c9
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, &region[a], curveb, texmaskb, frombuf,
+ mask_max, blend, tilex, tiley, tilew, tileh);
}
+ else {
+ Paint2DForeachData data;
+ data.s = s;
+ data.region = &region[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,
&params_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);
}