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:
authorDalai Felinto <dfelinto@gmail.com>2016-10-20 19:03:44 +0300
committerDalai Felinto <dfelinto@gmail.com>2016-10-20 20:00:49 +0300
commit418b24551e1b8a4458deceedca945a631f0684ac (patch)
treecfb1f42ff1eb58e36f714132d3ed623c18bfc6f7 /source/blender/editors
parenta84794b39960029a61d7c2c79e4ad7e2fda06bb7 (diff)
parent9269574089a742130f02c0a1184a19d94f0e665d (diff)
Merge commit '9269574089a742130f02c0a1184a19d94f0e665d' into pbr-online
Merge conflicts fixes include fix on ob->reflectionplane for write and read, and a few manual fixes to account for the ID remap changes Conflicts: source/blender/blenkernel/intern/object.c source/blender/blenkernel/intern/world.c source/blender/blenloader/intern/writefile.c source/blender/editors/space_view3d/view3d_draw.c source/blender/gpu/GPU_draw.h source/blender/gpu/intern/gpu_draw.c source/blender/gpu/intern/gpu_material.c source/blender/gpu/intern/gpu_texture.c source/blender/gpu/shaders/gpu_shader_vertex_world.glsl
Diffstat (limited to 'source/blender/editors')
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c2
-rw-r--r--source/blender/editors/animation/anim_ipo_utils.c2
-rw-r--r--source/blender/editors/animation/drivers.c8
-rw-r--r--source/blender/editors/animation/keyframes_edit.c74
-rw-r--r--source/blender/editors/animation/keyframing.c5
-rw-r--r--source/blender/editors/curve/CMakeLists.txt1
-rw-r--r--source/blender/editors/curve/editcurve_paint.c2
-rw-r--r--source/blender/editors/curve/editfont.c58
-rw-r--r--source/blender/editors/curve/editfont_undo.c311
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c1
-rw-r--r--source/blender/editors/gpencil/editaction_gpencil.c30
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c60
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h1
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c5
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c46
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c4
-rw-r--r--source/blender/editors/include/BIF_glutil.h1
-rw-r--r--source/blender/editors/include/ED_anim_api.h2
-rw-r--r--source/blender/editors/include/ED_buttons.h2
-rw-r--r--source/blender/editors/include/ED_curve.h6
-rw-r--r--source/blender/editors/include/ED_fileselect.h5
-rw-r--r--source/blender/editors/include/ED_gpencil.h2
-rw-r--r--source/blender/editors/include/ED_keyframes_edit.h34
-rw-r--r--source/blender/editors/include/ED_mask.h2
-rw-r--r--source/blender/editors/include/ED_node.h2
-rw-r--r--source/blender/editors/include/ED_outliner.h6
-rw-r--r--source/blender/editors/include/ED_physics.h8
-rw-r--r--source/blender/editors/include/ED_transform_snap_object_context.h2
-rw-r--r--source/blender/editors/include/ED_util.h2
-rw-r--r--source/blender/editors/include/ED_view3d.h12
-rw-r--r--source/blender/editors/include/UI_interface.h12
-rw-r--r--source/blender/editors/interface/interface.c10
-rw-r--r--source/blender/editors/interface/interface_draw.c21
-rw-r--r--source/blender/editors/interface/interface_handlers.c132
-rw-r--r--source/blender/editors/interface/interface_icons.c11
-rw-r--r--source/blender/editors/interface/interface_panel.c2
-rw-r--r--source/blender/editors/interface/interface_style.c12
-rw-r--r--source/blender/editors/interface/interface_templates.c17
-rw-r--r--source/blender/editors/interface/interface_widgets.c12
-rw-r--r--source/blender/editors/io/io_collada.c4
-rw-r--r--source/blender/editors/mask/mask_draw.c18
-rw-r--r--source/blender/editors/mask/mask_editaction.c30
-rw-r--r--source/blender/editors/mesh/editface.c3
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c236
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c2
-rw-r--r--source/blender/editors/mesh/editmesh_rip.c2
-rw-r--r--source/blender/editors/mesh/editmesh_select.c6
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c10
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c91
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c25
-rw-r--r--source/blender/editors/object/object_add.c35
-rw-r--r--source/blender/editors/object/object_constraint.c76
-rw-r--r--source/blender/editors/object/object_edit.c1
-rw-r--r--source/blender/editors/object/object_group.c4
-rw-r--r--source/blender/editors/object/object_relations.c2
-rw-r--r--source/blender/editors/physics/particle_edit.c8
-rw-r--r--source/blender/editors/physics/rigidbody_constraint.c15
-rw-r--r--source/blender/editors/physics/rigidbody_object.c21
-rw-r--r--source/blender/editors/render/render_preview.c8
-rw-r--r--source/blender/editors/screen/glutil.c13
-rw-r--r--source/blender/editors/screen/screen_edit.c5
-rw-r--r--source/blender/editors/screen/screen_ops.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c10
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h4
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c240
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c14
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c49
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c138
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c4
-rw-r--r--source/blender/editors/sound/sound_ops.c2
-rw-r--r--source/blender/editors/space_action/action_intern.h2
-rw-r--r--source/blender/editors/space_action/action_ops.c10
-rw-r--r--source/blender/editors/space_action/action_select.c259
-rw-r--r--source/blender/editors/space_action/space_action.c17
-rw-r--r--source/blender/editors/space_buttons/buttons_context.c30
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c58
-rw-r--r--source/blender/editors/space_clip/clip_draw.c52
-rw-r--r--source/blender/editors/space_clip/space_clip.c21
-rw-r--r--source/blender/editors/space_file/file_intern.h1
-rw-r--r--source/blender/editors/space_file/file_ops.c105
-rw-r--r--source/blender/editors/space_file/file_utils.c17
-rw-r--r--source/blender/editors/space_file/filelist.c16
-rw-r--r--source/blender/editors/space_file/filesel.c4
-rw-r--r--source/blender/editors/space_graph/graph_ops.c7
-rw-r--r--source/blender/editors/space_graph/graph_select.c83
-rw-r--r--source/blender/editors/space_graph/space_graph.c62
-rw-r--r--source/blender/editors/space_image/image_ops.c2
-rw-r--r--source/blender/editors/space_image/space_image.c30
-rw-r--r--source/blender/editors/space_logic/space_logic.c21
-rw-r--r--source/blender/editors/space_nla/space_nla.c17
-rw-r--r--source/blender/editors/space_node/node_edit.c28
-rw-r--r--source/blender/editors/space_node/space_node.c37
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c23
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c470
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h66
-rw-r--r--source/blender/editors/space_outliner/outliner_ops.c4
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c278
-rw-r--r--source/blender/editors/space_outliner/space_outliner.c36
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c20
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c111
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c19
-rw-r--r--source/blender/editors/space_text/space_text.c18
-rw-r--r--source/blender/editors/space_text/text_autocomplete.c6
-rw-r--r--source/blender/editors/space_text/text_ops.c3
-rw-r--r--source/blender/editors/space_view3d/drawanimviz.c2
-rw-r--r--source/blender/editors/space_view3d/drawarmature.c25
-rw-r--r--source/blender/editors/space_view3d/drawmesh.c42
-rw-r--r--source/blender/editors/space_view3d/drawobject.c82
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c63
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c20
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_project.c19
-rw-r--r--source/blender/editors/space_view3d/view3d_ruler.c47
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c4
-rw-r--r--source/blender/editors/transform/transform.c26
-rw-r--r--source/blender/editors/transform/transform.h4
-rw-r--r--source/blender/editors/transform/transform_conversions.c62
-rw-r--r--source/blender/editors/transform/transform_ops.c5
-rw-r--r--source/blender/editors/transform/transform_orientations.c4
-rw-r--r--source/blender/editors/transform/transform_snap.c22
-rw-r--r--source/blender/editors/transform/transform_snap_object.c922
-rw-r--r--source/blender/editors/util/ed_util.c19
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c9
-rw-r--r--source/blender/editors/uvedit/uvedit_parametrizer.c14
125 files changed, 3963 insertions, 1370 deletions
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index 8822c8511de..c98470fb194 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -2119,7 +2119,7 @@ static int animchannels_clean_empty_exec(bContext *C, wmOperator *UNUSED(op))
/* remove AnimData? */
if (action_empty && nla_empty && drivers_empty) {
- BKE_animdata_free(id);
+ BKE_animdata_free(id, true);
}
}
diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c
index ae6894ac546..fc6f4036d02 100644
--- a/source/blender/editors/animation/anim_ipo_utils.c
+++ b/source/blender/editors/animation/anim_ipo_utils.c
@@ -192,7 +192,7 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu)
#define HSV_BANDWIDTH 0.3f
/* used to determine the color of F-Curves with FCURVE_COLOR_AUTO_RAINBOW set */
-//void fcurve_rainbow (unsigned int cur, unsigned int tot, float *out)
+// void fcurve_rainbow(unsigned int cur, unsigned int tot, float *out)
void getcolor_fcurve_rainbow(int cur, int tot, float out[3])
{
float hsv[3], fac;
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index a82cca9e52a..21c25f829b1 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -158,7 +158,7 @@ static int add_driver_with_target(
ReportList *UNUSED(reports),
ID *dst_id, const char dst_path[], int dst_index,
ID *src_id, const char src_path[], int src_index,
- PointerRNA *UNUSED(dst_ptr), PropertyRNA *dst_prop,
+ PointerRNA *dst_ptr, PropertyRNA *dst_prop,
PointerRNA *src_ptr, PropertyRNA *src_prop,
short flag, int driver_type)
{
@@ -207,11 +207,15 @@ static int add_driver_with_target(
/* Create a driver variable for the target
* - For transform properties, we want to automatically use "transform channel" instead
* (The only issue is with quat rotations vs euler channels...)
+ * - To avoid problems with transform properties depending on the final transform that they
+ * control (thus creating pseudo-cycles - see T48734), we don't use transform channels
+ * when both the source and destinations are in same places.
*/
dvar = driver_add_new_variable(driver);
if (ELEM(src_ptr->type, &RNA_Object, &RNA_PoseBone) &&
- (STREQ(prop_name, "location") || STREQ(prop_name, "scale") || STRPREFIX(prop_name, "rotation_")))
+ (STREQ(prop_name, "location") || STREQ(prop_name, "scale") || STRPREFIX(prop_name, "rotation_")) &&
+ (src_ptr->data != dst_ptr->data))
{
/* Transform Channel */
DriverTarget *dtar;
diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c
index 08a7355694b..7b35a154fc8 100644
--- a/source/blender/editors/animation/keyframes_edit.c
+++ b/source/blender/editors/animation/keyframes_edit.c
@@ -539,10 +539,10 @@ static short ok_bezier_region(KeyframeEditData *ked, BezTriple *bezt)
}
/**
- * only called from #ok_bezier_region_lasso
+ * Called from #ok_bezier_region_lasso and #ok_bezier_channel_lasso
*/
-static bool bezier_region_lasso_test(
- const struct KeyframeEdit_LassoData *data_lasso,
+bool keyframe_region_lasso_test(
+ const KeyframeEdit_LassoData *data_lasso,
const float xy[2])
{
if (BLI_rctf_isect_pt_v(data_lasso->rectf_scaled, xy)) {
@@ -564,7 +564,7 @@ static short ok_bezier_region_lasso(KeyframeEditData *ked, BezTriple *bezt)
if (ked->data) {
short ok = 0;
-#define KEY_CHECK_OK(_index) bezier_region_lasso_test(ked->data, bezt->vec[_index])
+#define KEY_CHECK_OK(_index) keyframe_region_lasso_test(ked->data, bezt->vec[_index])
KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
#undef KEY_CHECK_OK
@@ -575,11 +575,38 @@ static short ok_bezier_region_lasso(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
+static short ok_bezier_channel_lasso(KeyframeEditData *ked, BezTriple *bezt)
+{
+ /* check for lasso customdata (KeyframeEdit_LassoData) */
+ if (ked->data) {
+ KeyframeEdit_LassoData *data = ked->data;
+ float pt[2];
+
+ /* late-binding remap of the x values (for summary channels) */
+ /* XXX: Ideally we reset, but it should be fine just leaving it as-is
+ * as the next channel will reset it properly, while the next summary-channel
+ * curve will also reset by itself...
+ */
+ if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) {
+ data->rectf_scaled->xmin = ked->f1;
+ data->rectf_scaled->xmax = ked->f2;
+ }
+
+ /* only use the x-coordinate of the point; the y is the channel range... */
+ pt[0] = bezt->vec[1][0];
+ pt[1] = ked->channel_y;
+
+ if (keyframe_region_lasso_test(data, pt))
+ return KEYFRAME_OK_KEY;
+ }
+ return 0;
+}
+
/**
- * only called from #ok_bezier_region_circle
+ * Called from #ok_bezier_region_circle and #ok_bezier_channel_circle
*/
-static bool bezier_region_circle_test(
- const struct KeyframeEdit_CircleData *data_circle,
+bool keyframe_region_circle_test(
+ const KeyframeEdit_CircleData *data_circle,
const float xy[2])
{
if (BLI_rctf_isect_pt_v(data_circle->rectf_scaled, xy)) {
@@ -602,7 +629,7 @@ static short ok_bezier_region_circle(KeyframeEditData *ked, BezTriple *bezt)
if (ked->data) {
short ok = 0;
-#define KEY_CHECK_OK(_index) bezier_region_circle_test(ked->data, bezt->vec[_index])
+#define KEY_CHECK_OK(_index) keyframe_region_circle_test(ked->data, bezt->vec[_index])
KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
#undef KEY_CHECK_OK
@@ -613,6 +640,33 @@ static short ok_bezier_region_circle(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
+static short ok_bezier_channel_circle(KeyframeEditData *ked, BezTriple *bezt)
+{
+ /* check for circle select customdata (KeyframeEdit_CircleData) */
+ if (ked->data) {
+ KeyframeEdit_CircleData *data = ked->data;
+ float pt[2];
+
+ /* late-binding remap of the x values (for summary channels) */
+ /* XXX: Ideally we reset, but it should be fine just leaving it as-is
+ * as the next channel will reset it properly, while the next summary-channel
+ * curve will also reset by itself...
+ */
+ if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) {
+ data->rectf_scaled->xmin = ked->f1;
+ data->rectf_scaled->xmax = ked->f2;
+ }
+
+ /* only use the x-coordinate of the point; the y is the channel range... */
+ pt[0] = bezt->vec[1][0];
+ pt[1] = ked->channel_y;
+
+ if (keyframe_region_circle_test(data, pt))
+ return KEYFRAME_OK_KEY;
+ }
+ return 0;
+}
+
KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
{
@@ -634,6 +688,10 @@ KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
return ok_bezier_region_lasso;
case BEZT_OK_REGION_CIRCLE: /* only if the point falls within KeyframeEdit_CircleData defined data */
return ok_bezier_region_circle;
+ case BEZT_OK_CHANNEL_LASSO: /* same as BEZT_OK_REGION_LASSO, but we're only using the x-value of the points */
+ return ok_bezier_channel_lasso;
+ case BEZT_OK_CHANNEL_CIRCLE: /* same as BEZT_OK_REGION_CIRCLE, but we're only using the x-value of the points */
+ return ok_bezier_channel_circle;
default: /* nothing was ok */
return NULL;
}
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 172f2b9069e..0c0f54f0179 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -1069,6 +1069,9 @@ short insert_keyframe(ReportList *reports, ID *id, bAction *act, const char grou
if (ELEM(RNA_property_subtype(prop), PROP_TRANSLATION, PROP_XYZ, PROP_EULER, PROP_COLOR, PROP_COORDS)) {
fcu->color_mode = FCURVE_COLOR_AUTO_RGB;
}
+ else if (RNA_property_subtype(prop), PROP_QUATERNION) {
+ fcu->color_mode = FCURVE_COLOR_AUTO_YRGB;
+ }
}
/* insert keyframe */
@@ -2035,7 +2038,7 @@ bool autokeyframe_cfra_can_key(Scene *scene, ID *id)
else {
/* Normal Mode (or treat as being normal mode):
*
- * Just in case the flags are't set properly (i.e. only on/off is set, without a mode)
+ * Just in case the flags aren't set properly (i.e. only on/off is set, without a mode)
* let's set the "normal" flag too, so that it will all be sane everywhere...
*/
scene->toolsettings->autokey_mode = AUTOKEY_MODE_NORMAL;
diff --git a/source/blender/editors/curve/CMakeLists.txt b/source/blender/editors/curve/CMakeLists.txt
index ebdf6bb43ff..2f5b2ab6e87 100644
--- a/source/blender/editors/curve/CMakeLists.txt
+++ b/source/blender/editors/curve/CMakeLists.txt
@@ -43,6 +43,7 @@ set(SRC
editcurve_paint.c
editcurve_select.c
editfont.c
+ editfont_undo.c
curve_intern.h
)
diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c
index bb7cc61f580..38018541929 100644
--- a/source/blender/editors/curve/editcurve_paint.c
+++ b/source/blender/editors/curve/editcurve_paint.c
@@ -911,7 +911,7 @@ static int curve_draw_exec(bContext *C, wmOperator *op)
unsigned int corners_index_len = 0;
const int result = curve_fit_cubic_to_points_fl(
- coords, stroke_len, dims, error_threshold,
+ coords, stroke_len, dims, error_threshold, CURVE_FIT_CALC_HIGH_QUALIY,
corners, corners_len,
&cubic_spline, &cubic_spline_len,
NULL,
diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c
index 7c1fe0cadf0..053a7ee5023 100644
--- a/source/blender/editors/curve/editfont.c
+++ b/source/blender/editors/curve/editfont.c
@@ -1794,64 +1794,6 @@ void FONT_OT_unlink(wmOperatorType *ot)
ot->exec = font_unlink_exec;
}
-
-/* **************** undo for font object ************** */
-
-static void undoFont_to_editFont(void *strv, void *ecu, void *UNUSED(obdata))
-{
- Curve *cu = (Curve *)ecu;
- EditFont *ef = cu->editfont;
- const char *str = strv;
-
- ef->pos = *((const short *)str);
- ef->len = *((const short *)(str + 2));
-
- memcpy(ef->textbuf, str + 4, (ef->len + 1) * sizeof(wchar_t));
- memcpy(ef->textbufinfo, str + 4 + (ef->len + 1) * sizeof(wchar_t), ef->len * sizeof(CharInfo));
-
- ef->selstart = ef->selend = 0;
-
-}
-
-static void *editFont_to_undoFont(void *ecu, void *UNUSED(obdata))
-{
- Curve *cu = (Curve *)ecu;
- EditFont *ef = cu->editfont;
- char *str;
-
- /* The undo buffer includes [MAXTEXT+6]=actual string and [MAXTEXT+4]*sizeof(CharInfo)=charinfo */
- str = MEM_callocN((MAXTEXT + 6) * sizeof(wchar_t) + (MAXTEXT + 4) * sizeof(CharInfo), "string undo");
-
- /* Copy the string and string information */
- memcpy(str + 4, ef->textbuf, (ef->len + 1) * sizeof(wchar_t));
- memcpy(str + 4 + (ef->len + 1) * sizeof(wchar_t), ef->textbufinfo, ef->len * sizeof(CharInfo));
-
- *((short *)(str + 0)) = ef->pos;
- *((short *)(str + 2)) = ef->len;
-
- return str;
-}
-
-static void free_undoFont(void *strv)
-{
- MEM_freeN(strv);
-}
-
-static void *get_undoFont(bContext *C)
-{
- Object *obedit = CTX_data_edit_object(C);
- if (obedit && obedit->type == OB_FONT) {
- return obedit->data;
- }
- return NULL;
-}
-
-/* and this is all the undo system needs to know */
-void undo_push_font(bContext *C, const char *name)
-{
- undo_editmode_push(C, name, get_undoFont, free_undoFont, undoFont_to_editFont, editFont_to_undoFont, NULL);
-}
-
/**
* TextBox selection
*/
diff --git a/source/blender/editors/curve/editfont_undo.c b/source/blender/editors/curve/editfont_undo.c
new file mode 100644
index 00000000000..a0453f9694d
--- /dev/null
+++ b/source/blender/editors/curve/editfont_undo.c
@@ -0,0 +1,311 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/curve/editfont_undo.c
+ * \ingroup edcurve
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_context.h"
+#include "BKE_font.h"
+
+#include "ED_curve.h"
+#include "ED_util.h"
+
+#define USE_ARRAY_STORE
+
+#ifdef USE_ARRAY_STORE
+// # define DEBUG_PRINT
+# include "BLI_array_store.h"
+# include "BLI_array_store_utils.h"
+# include "BLI_listbase.h"
+# define ARRAY_CHUNK_SIZE 32
+#endif
+
+typedef struct UndoFont {
+ wchar_t *textbuf;
+ struct CharInfo *textbufinfo;
+
+ int len, pos;
+
+#ifdef USE_ARRAY_STORE
+ struct {
+ BArrayState *textbuf;
+ BArrayState *textbufinfo;
+ } store;
+#endif
+} UndoFont;
+
+
+#ifdef USE_ARRAY_STORE
+
+/** \name Array Store
+ * \{ */
+
+static struct {
+ struct BArrayStore_AtSize bs_stride;
+ int users;
+
+ /* We could have the undo API pass in the previous state, for now store a local list */
+ ListBase local_links;
+
+} uf_arraystore = {NULL};
+
+/**
+ * \param create: When false, only free the arrays.
+ * This is done since when reading from an undo state, they must be temporarily expanded.
+ * then discarded afterwards, having this argument avoids having 2x code paths.
+ */
+static void uf_arraystore_compact_ex(
+ UndoFont *uf, const UndoFont *uf_ref,
+ bool create)
+{
+#define STATE_COMPACT(uf, id, len) \
+ if ((uf)->id) { \
+ BLI_assert(create == ((uf)->store.id == NULL)); \
+ if (create) { \
+ BArrayState *state_reference = uf_ref ? uf_ref->store.id : NULL; \
+ const size_t stride = sizeof(*(uf)->id); \
+ BArrayStore *bs = BLI_array_store_at_size_ensure(&uf_arraystore.bs_stride, stride, ARRAY_CHUNK_SIZE); \
+ (uf)->store.id = BLI_array_store_state_add( \
+ bs, (uf)->id, (size_t)(len) * stride, state_reference); \
+ } \
+ /* keep uf->len for validation */ \
+ MEM_freeN((uf)->id); \
+ (uf)->id = NULL; \
+ } ((void)0)
+
+ STATE_COMPACT(uf, textbuf, uf->len + 1);
+ STATE_COMPACT(uf, textbufinfo, uf->len + 1);
+
+#undef STATE_COMPACT
+
+ if (create) {
+ uf_arraystore.users += 1;
+ }
+}
+
+/**
+ * Move data from allocated arrays to de-duplicated states and clear arrays.
+ */
+static void uf_arraystore_compact(UndoFont *um, const UndoFont *uf_ref)
+{
+ uf_arraystore_compact_ex(um, uf_ref, true);
+}
+
+static void uf_arraystore_compact_with_info(UndoFont *um, const UndoFont *uf_ref)
+{
+#ifdef DEBUG_PRINT
+ size_t size_expanded_prev, size_compacted_prev;
+ BLI_array_store_at_size_calc_memory_usage(&uf_arraystore.bs_stride, &size_expanded_prev, &size_compacted_prev);
+#endif
+
+ uf_arraystore_compact(um, uf_ref);
+
+#ifdef DEBUG_PRINT
+ {
+ size_t size_expanded, size_compacted;
+ BLI_array_store_at_size_calc_memory_usage(&uf_arraystore.bs_stride, &size_expanded, &size_compacted);
+
+ const double percent_total = size_expanded ?
+ (((double)size_compacted / (double)size_expanded) * 100.0) : -1.0;
+
+ size_t size_expanded_step = size_expanded - size_expanded_prev;
+ size_t size_compacted_step = size_compacted - size_compacted_prev;
+ const double percent_step = size_expanded_step ?
+ (((double)size_compacted_step / (double)size_expanded_step) * 100.0) : -1.0;
+
+ printf("overall memory use: %.8f%% of expanded size\n", percent_total);
+ printf("step memory use: %.8f%% of expanded size\n", percent_step);
+ }
+#endif
+}
+
+/**
+ * Remove data we only expanded for temporary use.
+ */
+static void uf_arraystore_expand_clear(UndoFont *um)
+{
+ uf_arraystore_compact_ex(um, NULL, false);
+}
+
+static void uf_arraystore_expand(UndoFont *uf)
+{
+#define STATE_EXPAND(uf, id, len) \
+ if ((uf)->store.id) { \
+ const size_t stride = sizeof(*(uf)->id); \
+ BArrayState *state = (uf)->store.id; \
+ size_t state_len; \
+ (uf)->id = BLI_array_store_state_data_get_alloc(state, &state_len); \
+ BLI_assert((len) == (state_len / stride)); \
+ UNUSED_VARS_NDEBUG(stride); \
+ } ((void)0)
+
+ STATE_EXPAND(uf, textbuf, uf->len + 1);
+ STATE_EXPAND(uf, textbufinfo, uf->len + 1);
+
+#undef STATE_EXPAND
+}
+
+static void uf_arraystore_free(UndoFont *uf)
+{
+#define STATE_FREE(uf, id) \
+ if ((uf)->store.id) { \
+ const size_t stride = sizeof(*(uf)->id); \
+ BArrayStore *bs = BLI_array_store_at_size_get(&uf_arraystore.bs_stride, stride); \
+ BArrayState *state = (uf)->store.id; \
+ BLI_array_store_state_remove(bs, state); \
+ (uf)->store.id = NULL; \
+ } ((void)0)
+
+ STATE_FREE(uf, textbuf);
+ STATE_FREE(uf, textbufinfo);
+
+#undef STATE_FREE
+
+ uf_arraystore.users -= 1;
+
+ BLI_assert(uf_arraystore.users >= 0);
+
+ if (uf_arraystore.users == 0) {
+#ifdef DEBUG_PRINT
+ printf("editfont undo store: freeing all data!\n");
+#endif
+
+ BLI_array_store_at_size_clear(&uf_arraystore.bs_stride);
+ }
+
+}
+
+/** \} */
+
+#endif /* USE_ARRAY_STORE */
+
+static void undoFont_to_editFont(void *uf_v, void *ecu, void *UNUSED(obdata))
+{
+ Curve *cu = (Curve *)ecu;
+ EditFont *ef = cu->editfont;
+ const UndoFont *uf = uf_v;
+
+ size_t final_size;
+
+#ifdef USE_ARRAY_STORE
+ uf_arraystore_expand(uf_v);
+#endif
+
+ final_size = sizeof(wchar_t) * (uf->len + 1);
+ memcpy(ef->textbuf, uf->textbuf, final_size);
+
+ final_size = sizeof(CharInfo) * (uf->len + 1);
+ memcpy(ef->textbufinfo, uf->textbufinfo, final_size);
+
+ ef->pos = uf->pos;
+ ef->len = uf->len;
+
+ ef->selstart = ef->selend = 0;
+
+#ifdef USE_ARRAY_STORE
+ uf_arraystore_expand_clear(uf_v);
+#endif
+}
+
+static void *editFont_to_undoFont(void *ecu, void *UNUSED(obdata))
+{
+ Curve *cu = (Curve *)ecu;
+ EditFont *ef = cu->editfont;
+
+ UndoFont *uf = MEM_callocN(sizeof(*uf), __func__);
+
+ size_t final_size;
+
+ final_size = sizeof(wchar_t) * (ef->len + 1);
+ uf->textbuf = MEM_mallocN(final_size, __func__);
+ memcpy(uf->textbuf, ef->textbuf, final_size);
+
+ final_size = sizeof(CharInfo) * (ef->len + 1);
+ uf->textbufinfo = MEM_mallocN(final_size, __func__);
+ memcpy(uf->textbufinfo, ef->textbufinfo, final_size);
+
+ uf->pos = ef->pos;
+ uf->len = ef->len;
+
+#ifdef USE_ARRAY_STORE
+ {
+ const UndoFont *uf_ref = uf_arraystore.local_links.last ?
+ ((LinkData *)uf_arraystore.local_links.last)->data : NULL;
+
+ /* add oursrlves */
+ BLI_addtail(&uf_arraystore.local_links, BLI_genericNodeN(uf));
+
+ uf_arraystore_compact_with_info(uf, uf_ref);
+ }
+#endif
+
+ return uf;
+}
+
+static void free_undoFont(void *uf_v)
+{
+ UndoFont *uf = uf_v;
+
+#ifdef USE_ARRAY_STORE
+ {
+ LinkData *link = BLI_findptr(&uf_arraystore.local_links, uf, offsetof(LinkData, data));
+ BLI_remlink(&uf_arraystore.local_links, link);
+ MEM_freeN(link);
+ }
+ uf_arraystore_free(uf);
+#endif
+
+ if (uf->textbuf) {
+ MEM_freeN(uf->textbuf);
+ }
+ if (uf->textbufinfo) {
+ MEM_freeN(uf->textbufinfo);
+ }
+
+ MEM_freeN(uf);
+}
+
+static void *get_undoFont(bContext *C)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ if (obedit && obedit->type == OB_FONT) {
+ return obedit->data;
+ }
+ return NULL;
+}
+
+/* and this is all the undo system needs to know */
+void undo_push_font(bContext *C, const char *name)
+{
+ undo_editmode_push(C, name, get_undoFont, free_undoFont, undoFont_to_editFont, editFont_to_undoFont, NULL);
+}
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 0329598d711..79a2c494239 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -763,6 +763,7 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
}
glEnd();
+ glShadeModel(GL_SMOOTH);
}
/* draw debug points of curve on top? (original stroke points) */
diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c
index a49b3362155..738496a67c6 100644
--- a/source/blender/editors/gpencil/editaction_gpencil.c
+++ b/source/blender/editors/gpencil/editaction_gpencil.c
@@ -205,6 +205,36 @@ void ED_gplayer_frames_select_border(bGPDlayer *gpl, float min, float max, short
}
}
+/* select the frames in this layer that occur within the lasso/circle region specified */
+void ED_gplayer_frames_select_region(KeyframeEditData *ked, bGPDlayer *gpl, short tool, short select_mode)
+{
+ bGPDframe *gpf;
+
+ if (gpl == NULL)
+ return;
+
+ /* only select frames which are within the region */
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ /* construct a dummy point coordinate to do this testing with */
+ float pt[2] = {0};
+
+ pt[0] = gpf->framenum;
+ pt[1] = ked->channel_y;
+
+ /* check the necessary regions */
+ if (tool == BEZT_OK_CHANNEL_LASSO) {
+ /* Lasso */
+ if (keyframe_region_lasso_test(ked->data, pt))
+ gpframe_select(gpf, select_mode);
+ }
+ else if (tool == BEZT_OK_CHANNEL_CIRCLE) {
+ /* Circle */
+ if (keyframe_region_circle_test(ked->data, pt))
+ gpframe_select(gpf, select_mode);
+ }
+ }
+}
+
/* ***************************************** */
/* Frame Editing Tools */
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index bd1697b9a54..ac49a51c716 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -652,7 +652,7 @@ void GPENCIL_OT_active_frame_delete(wmOperatorType *ot)
/* identifiers */
ot->name = "Delete Active Frame";
ot->idname = "GPENCIL_OT_active_frame_delete";
- ot->description = "Delete the active frame for the active Grease Pencil datablock";
+ ot->description = "Delete the active frame for the active Grease Pencil Layer";
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -661,6 +661,64 @@ void GPENCIL_OT_active_frame_delete(wmOperatorType *ot)
ot->poll = gp_actframe_delete_poll;
}
+/* **************** Delete All Active Frames ****************** */
+
+static int gp_actframe_delete_all_poll(bContext *C)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+
+ /* 1) There must be grease pencil data
+ * 2) Hopefully some of the layers have stuff we can use
+ */
+ return (gpd && gpd->layers.first);
+}
+
+static int gp_actframe_delete_all_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ bool success = false;
+
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ /* try to get the "active" frame - but only if it actually occurs on this frame */
+ bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, 0);
+
+ if (gpf == NULL)
+ continue;
+
+ /* delete it... */
+ gpencil_layer_delframe(gpl, gpf);
+
+ /* we successfully modified something */
+ success = true;
+ }
+ CTX_DATA_END;
+
+ /* updates */
+ if (success) {
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "No active frame(s) to delete");
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void GPENCIL_OT_active_frames_delete_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Delete All Active Frames";
+ ot->idname = "GPENCIL_OT_active_frames_delete_all";
+ ot->description = "Delete the active frame(s) of all editable Grease Pencil layers";
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gp_actframe_delete_all_exec;
+ ot->poll = gp_actframe_delete_all_poll;
+}
+
/* ******************* Delete Operator ************************ */
typedef enum eGP_DeleteMode {
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index dd28f6ac531..53fb33eeb9b 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -218,6 +218,7 @@ void GPENCIL_OT_unlock_all(struct wmOperatorType *ot);
void GPENCIL_OT_layer_isolate(struct wmOperatorType *ot);
void GPENCIL_OT_active_frame_delete(struct wmOperatorType *ot);
+void GPENCIL_OT_active_frames_delete_all(struct wmOperatorType *ot);
void GPENCIL_OT_convert(struct wmOperatorType *ot);
diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c
index 405b673c42b..65ee1122b56 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -105,7 +105,7 @@ static void ed_keymap_gpencil_general(wmKeyConfig *keyconf)
/* 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);
+ WM_keymap_add_item(keymap, "GPENCIL_OT_active_frames_delete_all", XKEY, KM_PRESS, 0, DKEY);
}
/* ==================== */
@@ -238,7 +238,7 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
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);
+ WM_keymap_add_item(keymap, "GPENCIL_OT_active_frames_delete_all", XKEY, KM_PRESS, KM_SHIFT, 0);
/* copy + paste */
WM_keymap_add_item(keymap, "GPENCIL_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0);
@@ -364,6 +364,7 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_layer_isolate);
WM_operatortype_append(GPENCIL_OT_active_frame_delete);
+ WM_operatortype_append(GPENCIL_OT_active_frames_delete_all);
WM_operatortype_append(GPENCIL_OT_convert);
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index fba2f30e715..a570d586f50 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -97,7 +97,8 @@ typedef enum eGP_StrokeAdd_Result {
typedef enum eGPencil_PaintFlags {
GP_PAINTFLAG_FIRSTRUN = (1 << 0), /* operator just started */
GP_PAINTFLAG_STROKEADDED = (1 << 1),
- GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2)
+ GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2),
+ GP_PAINTFLAG_SELECTMASK = (1 << 3),
} eGPencil_PaintFlags;
@@ -813,18 +814,21 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
BLI_freelinkN(&gpf->strokes, gps);
}
else if (gps->totpoints == 1) {
- gp_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]);
-
- /* do boundbox check first */
- if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
- /* only check if point is inside */
- if (len_v2v2_int(mval, pc1) <= radius) {
- /* 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);
+ /* only process if it hasn't been masked out... */
+ if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) {
+ gp_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]);
+
+ /* do boundbox check first */
+ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
+ /* only check if point is inside */
+ if (len_v2v2_int(mval, pc1) <= radius) {
+ /* 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);
+ }
}
}
}
@@ -862,6 +866,11 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
pt1 = gps->points + i;
pt2 = gps->points + i + 1;
+ /* only process if it hasn't been masked out... */
+ if ((p->flags & GP_PAINTFLAG_SELECTMASK) && !(gps->points->flag & GP_SPOINT_SELECT))
+ continue;
+
+ /* get coordinates of point in screenspace */
gp_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]);
gp_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]);
@@ -1199,6 +1208,7 @@ static void gp_session_cleanup(tGPsdata *p)
static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
{
Scene *scene = p->scene;
+ ToolSettings *ts = scene->toolsettings;
/* get active layer (or add a new one if non-existent) */
p->gpl = gpencil_layer_getactive(p->gpd);
@@ -1242,6 +1252,15 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
/* Ensure this gets set... */
p->gpf = p->gpl->actframe;
+ /* Restrict eraser to only affecting selected strokes, if the "selection mask" is on
+ * (though this is only available in editmode)
+ */
+ if (p->gpd->flag & GP_DATA_STROKE_EDITMODE) {
+ if (ts->gp_sculpt.flag & GP_BRUSHEDIT_FLAG_SELECT_MASK) {
+ p->flags |= GP_PAINTFLAG_SELECTMASK;
+ }
+ }
+
if (p->gpf == NULL) {
p->status = GP_STATUS_ERROR;
//if (G.debug & G_DEBUG)
@@ -1251,7 +1270,6 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
}
else {
/* Drawing Modes - Add a new frame if needed on the active layer */
- ToolSettings *ts = p->scene->toolsettings;
short add_frame_mode;
if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST)
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index b2c6107ab61..d62625baaa4 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -552,8 +552,8 @@ bool gp_smooth_stroke(bGPDstroke *gps, int i, float inf, bool affect_pressure)
}
/* Only affect endpoints by a fraction of the normal strength,
- * to prevent the stroke from shrinking too much
- */
+ * to prevent the stroke from shrinking too much
+ */
if ((i == 0) || (i == gps->totpoints - 1)) {
inf *= 0.1f;
}
diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h
index 0ac5c17a552..d3d2c465d46 100644
--- a/source/blender/editors/include/BIF_glutil.h
+++ b/source/blender/editors/include/BIF_glutil.h
@@ -94,6 +94,7 @@ void glutil_draw_filled_arc(float start, float angle, float radius, int nsegment
* The param must cause only one value to be gotten from GL.
*/
float glaGetOneFloat(int param);
+int glaGetOneInt(int param);
/**
* Functions like glRasterPos2i, except ensures that the resulting
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index fb4897c6532..27e1051a336 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -608,7 +608,7 @@ typedef enum eAnimUnitConv_Flags {
ANIM_UNITCONV_SKIPKNOTS = (1 << 4),
/* Scale FCurve i a way it fits to -1..1 space */
ANIM_UNITCONV_NORMALIZE = (1 << 5),
- /* Only whennormalization is used: use scale factor from previous run,
+ /* Only when normalization is used: use scale factor from previous run,
* prevents curves from jumping all over the place when tweaking them.
*/
ANIM_UNITCONV_NORMALIZE_FREEZE = (1 << 6),
diff --git a/source/blender/editors/include/ED_buttons.h b/source/blender/editors/include/ED_buttons.h
index 9a987d7618c..64c16605dec 100644
--- a/source/blender/editors/include/ED_buttons.h
+++ b/source/blender/editors/include/ED_buttons.h
@@ -37,6 +37,4 @@ bool ED_texture_context_check_particles(const struct bContext *C);
bool ED_texture_context_check_linestyle(const struct bContext *C);
bool ED_texture_context_check_others(const struct bContext *C);
-void ED_buttons_id_unref(struct SpaceButs *sbuts, const struct ID *id);
-
#endif /* __ED_BUTTONS_H__ */
diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h
index 278e3f97ba7..859d45e9c86 100644
--- a/source/blender/editors/include/ED_curve.h
+++ b/source/blender/editors/include/ED_curve.h
@@ -72,8 +72,7 @@ void ED_curve_deselect_all(struct EditNurb *editnurb);
void ED_curve_select_all(struct EditNurb *editnurb);
void ED_curve_select_swap(struct EditNurb *editnurb, bool hide_handles);
-/* editfont.h */
-void undo_push_font(struct bContext *C, const char *name);
+/* editfont.c */
void ED_curve_editfont_load(struct Object *obedit);
void ED_curve_editfont_make(struct Object *obedit);
void ED_curve_editfont_free(struct Object *obedit);
@@ -89,6 +88,9 @@ bool ED_curve_active_center(struct Curve *cu, float center[3]);
bool ED_curve_editfont_select_pick(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
+/* editfont_undo.c */
+void undo_push_font(struct bContext *C, const char *name);
+
#if 0
/* debug only */
void printknots(struct Object *obedit);
diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h
index 186a2a26825..92acfa6c1d2 100644
--- a/source/blender/editors/include/ED_fileselect.h
+++ b/source/blender/editors/include/ED_fileselect.h
@@ -104,11 +104,12 @@ void ED_fileselect_clear(struct wmWindowManager *wm, struct ScrArea *sa, struct
void ED_fileselect_exit(struct wmWindowManager *wm, struct ScrArea *sa, struct SpaceFile *sfile);
-int ED_file_extension_icon(const char *relname);
+int ED_path_extension_type(const char *path);
+int ED_file_extension_icon(const char *path);
void ED_file_read_bookmarks(void);
-void ED_file_change_dir(struct bContext *C, const bool checkdir);
+void ED_file_change_dir(struct bContext *C);
/* File menu stuff */
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 255827db373..de5ab80a88f 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -42,6 +42,7 @@ struct bGPDlayer;
struct bGPDframe;
struct bGPDstroke;
struct bAnimContext;
+struct KeyframeEditData;
struct PointerRNA;
struct wmWindowManager;
struct wmKeyConfig;
@@ -120,6 +121,7 @@ void ED_gplayer_make_cfra_list(struct bGPDlayer *gpl, ListBase *elems, bool only
bool ED_gplayer_frame_select_check(struct bGPDlayer *gpl);
void ED_gplayer_frame_select_set(struct bGPDlayer *gpl, short mode);
void ED_gplayer_frames_select_border(struct bGPDlayer *gpl, float min, float max, short select_mode);
+void ED_gplayer_frames_select_region(struct KeyframeEditData *ked, struct bGPDlayer *gpl, short tool, short select_mode);
void ED_gpencil_select_frames(struct bGPDlayer *gpl, short select_mode);
void ED_gpencil_select_frame(struct bGPDlayer *gpl, int selx, short select_mode);
diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h
index fae3e3677a0..c0eb88cd982 100644
--- a/source/blender/editors/include/ED_keyframes_edit.h
+++ b/source/blender/editors/include/ED_keyframes_edit.h
@@ -45,14 +45,21 @@ struct Scene;
/* bezt validation */
typedef enum eEditKeyframes_Validate {
+ /* Frame range */
BEZT_OK_FRAME = 1,
BEZT_OK_FRAMERANGE,
+ /* Selection status */
BEZT_OK_SELECTED,
+ /* Values (y-val) only */
BEZT_OK_VALUE,
BEZT_OK_VALUERANGE,
+ /* For graph editor keyframes (2D tests) */
BEZT_OK_REGION,
BEZT_OK_REGION_LASSO,
BEZT_OK_REGION_CIRCLE,
+ /* Only for keyframes a certain Dopesheet channel */
+ BEZT_OK_CHANNEL_LASSO,
+ BEZT_OK_CHANNEL_CIRCLE,
} eEditKeyframes_Validate;
/* ------------ */
@@ -97,20 +104,20 @@ typedef enum eEditKeyframes_Mirror {
} eEditKeyframes_Mirror;
/* use with BEZT_OK_REGION_LASSO */
-struct KeyframeEdit_LassoData {
- const rctf *rectf_scaled;
+typedef struct KeyframeEdit_LassoData {
+ rctf *rectf_scaled;
const rctf *rectf_view;
const int (*mcords)[2];
int mcords_tot;
-};
+} KeyframeEdit_LassoData;
/* use with BEZT_OK_REGION_CIRCLE */
-struct KeyframeEdit_CircleData {
- const rctf *rectf_scaled;
+typedef struct KeyframeEdit_CircleData {
+ rctf *rectf_scaled;
const rctf *rectf_view;
float mval[2];
float radius_squared;
-};
+} KeyframeEdit_CircleData;
/* ************************************************ */
@@ -157,7 +164,8 @@ typedef struct KeyframeEditData {
/* current iteration data */
struct FCurve *fcu; /* F-Curve that is being iterated over */
int curIndex; /* index of current keyframe being iterated over */
-
+ float channel_y; /* y-position of midpoint of the channel (for the dopesheet) */
+
/* flags */
eKeyframeVertOk curflags; /* current flags for the keyframe we're reached in the iteration process */
eKeyframeIterFlags iterflags; /* settings for iteration process */
@@ -258,6 +266,18 @@ short bezt_to_cfraelem(KeyframeEditData *ked, struct BezTriple *bezt);
*/
void bezt_remap_times(KeyframeEditData *ked, struct BezTriple *bezt);
+/* ------ 1.5-D Region Testing Uitls (Lasso/Circle Select) ------- */
+/* XXX: These are temporary, until we can unify GP/Mask Keyframe handling and standard FCurve Keyframe handling */
+
+bool keyframe_region_lasso_test(
+ const KeyframeEdit_LassoData *data_lasso,
+ const float xy[2]);
+
+bool keyframe_region_circle_test(
+ const KeyframeEdit_CircleData *data_circle,
+ const float xy[2]);
+
+
/* ************************************************ */
/* Destructive Editing API (keyframes_general.c) */
diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h
index 1f13b46ff2a..2ab788d5e2a 100644
--- a/source/blender/editors/include/ED_mask.h
+++ b/source/blender/editors/include/ED_mask.h
@@ -35,6 +35,7 @@ struct bContext;
struct wmKeyConfig;
struct MaskLayer;
struct MaskLayerShape;
+struct KeyframeEditData;
/* mask_edit.c */
void ED_mask_get_size(struct ScrArea *sa, int *width, int *height);
@@ -80,6 +81,7 @@ void ED_masklayer_make_cfra_list(struct MaskLayer *masklay, ListBase *elems, boo
bool ED_masklayer_frame_select_check(struct MaskLayer *masklay);
void ED_masklayer_frame_select_set(struct MaskLayer *masklay, short mode);
void ED_masklayer_frames_select_border(struct MaskLayer *masklay, float min, float max, short select_mode);
+void ED_masklayer_frames_select_region(struct KeyframeEditData *ked, struct MaskLayer *masklay, short tool, short select_mode);
void ED_mask_select_frames(struct MaskLayer *masklay, short select_mode);
void ED_mask_select_frame(struct MaskLayer *masklay, int selx, short select_mode);
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index 7fe9a0c320c..f7b9d6b4f9e 100644
--- a/source/blender/editors/include/ED_node.h
+++ b/source/blender/editors/include/ED_node.h
@@ -103,8 +103,6 @@ void ED_node_set_active(struct Main *bmain, struct bNodeTree *ntree, struct bNod
void ED_node_composite_job(const struct bContext *C, struct bNodeTree *nodetree, struct Scene *scene_owner);
-void ED_node_id_unref(struct SpaceNode *snode, const ID *id);
-
/* node_ops.c */
void ED_operatormacros_node(void);
diff --git a/source/blender/editors/include/ED_outliner.h b/source/blender/editors/include/ED_outliner.h
index af4af8e2f5d..73ee2542247 100644
--- a/source/blender/editors/include/ED_outliner.h
+++ b/source/blender/editors/include/ED_outliner.h
@@ -27,10 +27,4 @@
#ifndef __ED_OUTLINER_H__
#define __ED_OUTLINER_H__
-struct ID;
-struct SpaceOops;
-
-/* Used to check whether a given texture context is valid in current context. */
-void ED_outliner_id_unref(struct SpaceOops *so, const struct ID *id);
-
#endif /* __ED_OUTLINER_H__ */
diff --git a/source/blender/editors/include/ED_physics.h b/source/blender/editors/include/ED_physics.h
index 584e9a92bb6..fed842c969e 100644
--- a/source/blender/editors/include/ED_physics.h
+++ b/source/blender/editors/include/ED_physics.h
@@ -45,12 +45,12 @@ int PE_hair_poll(struct bContext *C);
int PE_poll_view3d(struct bContext *C);
/* rigidbody_object.c */
-bool ED_rigidbody_object_add(struct Scene *scene, struct Object *ob, int type, struct ReportList *reports);
-void ED_rigidbody_object_remove(struct Scene *scene, struct Object *ob);
+bool ED_rigidbody_object_add(struct Main *bmain, struct Scene *scene, struct Object *ob, int type, struct ReportList *reports);
+void ED_rigidbody_object_remove(struct Main *bmain, struct Scene *scene, struct Object *ob);
/* rigidbody_constraint.c */
-bool ED_rigidbody_constraint_add(struct Scene *scene, struct Object *ob, int type, struct ReportList *reports);
-void ED_rigidbody_constraint_remove(struct Scene *scene, struct Object *ob);
+bool ED_rigidbody_constraint_add(struct Main *bmain, struct Scene *scene, struct Object *ob, int type, struct ReportList *reports);
+void ED_rigidbody_constraint_remove(struct Main *bmain, struct Scene *scene, struct Object *ob);
/* operators */
void ED_operatortypes_physics(void);
diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h
index baf4ed574cf..7944b434057 100644
--- a/source/blender/editors/include/ED_transform_snap_object_context.h
+++ b/source/blender/editors/include/ED_transform_snap_object_context.h
@@ -75,7 +75,7 @@ SnapObjectContext *ED_transform_snap_object_context_create(
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);
+ const struct ARegion *ar, const struct View3D *v3d);
void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx);
/* callbacks to filter how snap works */
diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h
index f143ea478c6..b6b80b93e0b 100644
--- a/source/blender/editors/include/ED_util.h
+++ b/source/blender/editors/include/ED_util.h
@@ -43,7 +43,7 @@ void ED_editors_exit(struct bContext *C);
bool ED_editors_flush_edits(const struct bContext *C, bool for_render);
-void ED_spacedata_id_unref(struct SpaceLink *sl, const struct ID *id);
+void ED_spacedata_id_remap(struct ScrArea *sa, struct SpaceLink *sl, struct ID *old_id, struct ID *new_id);
void ED_OT_flush_edits(struct wmOperatorType *ot);
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 54b4acec864..8bd8a14030f 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -208,10 +208,12 @@ eV3DProjStatus ED_view3d_project_float_global(const struct ARegion *ar, const fl
eV3DProjStatus ED_view3d_project_float_object(const struct ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag);
float ED_view3d_calc_zfac(const struct RegionView3D *rv3d, const float co[3], bool *r_flip);
-bool ED_view3d_win_to_ray(const struct ARegion *ar, struct View3D *v3d, const float mval[2],
- float ray_start[3], float ray_normal[3], const bool do_clip);
-bool ED_view3d_win_to_ray_ex(const struct ARegion *ar, struct View3D *v3d, const float mval[2],
- float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip);
+bool ED_view3d_win_to_ray(
+ const struct ARegion *ar, const struct View3D *v3d, const float mval[2],
+ float ray_start[3], float ray_normal[3], const bool do_clip);
+bool ED_view3d_win_to_ray_ex(
+ const struct ARegion *ar, const struct View3D *v3d, const float mval[2],
+ float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip);
void ED_view3d_global_to_vector(const struct RegionView3D *rv3d, const float coord[3], float vec[3]);
void ED_view3d_win_to_3d(const struct ARegion *ar, const float depth_pt[3], const float mval[2], float out[3]);
void ED_view3d_win_to_3d_int(const struct ARegion *ar, const float depth_pt[3], const int mval[2], float out[3]);
@@ -403,4 +405,6 @@ void ED_view3d_shade_update(struct Main *bmain, struct Scene *scene, struct View
#define V3D_IS_ZBUF(v3d) \
(((v3d)->flag & V3D_ZBUF_SELECT) && ((v3d)->drawtype > OB_WIRE))
+void ED_view3d_id_remap(struct View3D *v3d, const struct ID *old_id, struct ID *new_id);
+
#endif /* __ED_VIEW3D_H__ */
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 9aad340d2fb..a623f5cfb9c 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -1020,12 +1020,18 @@ bool UI_context_copy_to_selected_list(
/* Helpers for Operators */
uiBut *UI_context_active_but_get(const struct bContext *C);
-void UI_context_active_but_prop_get(const struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index);
+void UI_context_active_but_prop_get(
+ const struct bContext *C,
+ struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index);
void UI_context_active_but_prop_handle(struct bContext *C);
struct wmOperator *UI_context_active_operator_get(const struct bContext *C);
void UI_context_update_anim_flag(const struct bContext *C);
-void UI_context_active_but_prop_get_filebrowser(const struct bContext *C, struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, bool *r_is_undo);
-void UI_context_active_but_prop_get_templateID(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop);
+void UI_context_active_but_prop_get_filebrowser(
+ const struct bContext *C,
+ struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, bool *r_is_undo);
+void UI_context_active_but_prop_get_templateID(
+ struct bContext *C,
+ struct PointerRNA *r_ptr, struct PropertyRNA **r_prop);
/* Styled text draw */
void UI_fontstyle_set(const struct uiFontStyle *fs);
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index fac1267cc62..ba7240be5d8 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -2576,9 +2576,11 @@ static void ui_set_but_soft_range(uiBut *but)
}
else if (but->poin && (but->pointype & UI_BUT_POIN_TYPES)) {
float value = ui_but_value_get(but);
- CLAMP(value, but->hardmin, but->hardmax);
- but->softmin = min_ff(but->softmin, value);
- but->softmax = max_ff(but->softmax, value);
+ if (isfinite(value)) {
+ CLAMP(value, but->hardmin, but->hardmax);
+ but->softmin = min_ff(but->softmin, value);
+ but->softmax = max_ff(but->softmax, value);
+ }
}
else {
BLI_assert(0);
@@ -4323,7 +4325,7 @@ uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxle
/**
- * \param sfunc, bfunc: both get it as \a arg.
+ * \param search_func, bfunc: both get it as \a arg.
* \param arg: user value,
* \param active: when set, button opens with this item visible and selected.
*/
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index 8fbc545cb77..72a6a04feec 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -181,7 +181,6 @@ void UI_draw_roundbox_shade_x(
coldown[1] = max_ff(0.0f, color[1] + shadedown);
coldown[2] = max_ff(0.0f, color[2] + shadedown);
- glShadeModel(GL_SMOOTH);
glBegin(mode);
/* start with corner right-bottom */
@@ -260,7 +259,6 @@ void UI_draw_roundbox_shade_x(
}
glEnd();
- glShadeModel(GL_FLAT);
}
/* linear vertical shade within button or in outline */
@@ -291,7 +289,6 @@ void UI_draw_roundbox_shade_y(
colRight[1] = max_ff(0.0f, color[1] + shadeRight);
colRight[2] = max_ff(0.0f, color[2] + shadeRight);
- glShadeModel(GL_SMOOTH);
glBegin(mode);
/* start with corner right-bottom */
@@ -367,7 +364,6 @@ void UI_draw_roundbox_shade_y(
}
glEnd();
- glShadeModel(GL_FLAT);
}
/* plain antialiased unfilled rectangle */
@@ -531,7 +527,6 @@ static void histogram_draw_one(
}
else {
/* under the curve */
- glShadeModel(GL_FLAT);
glBegin(GL_TRIANGLE_STRIP);
glVertex2f(x, y);
glVertex2f(x, y + (data[0] * h));
@@ -1087,7 +1082,6 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti
GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
/* layer: color ramp */
- glShadeModel(GL_FLAT);
glEnable(GL_BLEND);
CBData *cbd = coba->data;
@@ -1133,7 +1127,6 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti
glEnd();
glDisable(GL_BLEND);
- glShadeModel(GL_SMOOTH);
/* layer: box outline */
glColor4f(0.0, 0.0, 0.0, 1.0);
@@ -1212,9 +1205,8 @@ void ui_draw_but_UNITVEC(uiBut *but, uiWidgetColors *wcol, const rcti *rect)
qobj = gluNewQuadric();
gluQuadricDrawStyle(qobj, GLU_FILL);
- glShadeModel(GL_SMOOTH);
+ GPU_basic_shader_bind(GPU_basic_shader_bound_options());
gluSphere(qobj, 100.0, 32, 24);
- glShadeModel(GL_FLAT);
gluDeleteQuadric(qobj);
glEndList();
@@ -1545,10 +1537,12 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wc
BLI_rctf_size_x(&rect),
BLI_rctf_size_y(&rect));
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE);
+
for (int a = 0; a < 2; a++) {
if (a == 1) {
- glLineStipple(3, 0xaaaa);
- glEnable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_enable(GPU_SHADER_STIPPLE);
+ GPU_basic_shader_line_stipple(3, 0xAAAA);
UI_ThemeColor(TH_SEL_MARKER);
}
else {
@@ -1562,9 +1556,10 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wc
glVertex2f(0.0f, 10.0f);
glEnd();
}
+
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
}
- glDisable(GL_LINE_STIPPLE);
glPopMatrix();
ok = true;
@@ -1677,7 +1672,6 @@ static void ui_shadowbox(float minx, float miny, float maxx, float maxy, float s
void UI_draw_box_shadow(unsigned char alpha, float minx, float miny, float maxx, float maxy)
{
glEnable(GL_BLEND);
- glShadeModel(GL_SMOOTH);
glBegin(GL_QUADS);
@@ -1689,7 +1683,6 @@ void UI_draw_box_shadow(unsigned char alpha, float minx, float miny, float maxx,
glEnd();
glDisable(GL_BLEND);
- glShadeModel(GL_FLAT);
}
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 5b8b8ae5bdb..e0b8003d8a9 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -6014,20 +6014,15 @@ static int ui_do_but_CURVE(bContext *C, uiBlock *block, uiBut *but, uiHandleButt
CurveMapping *cumap = (CurveMapping *)but->poin;
CurveMap *cuma = cumap->cm + cumap->cur;
CurveMapPoint *cmp;
- float fx, fy, zoomx, zoomy, offsx, offsy;
- float dist, mindist = 200.0f; // 14 pixels radius
+ const float m_xy[2] = {mx, my};
+ float dist_min_sq = SQUARE(14.0f); /* 14 pixels radius */
int sel = -1;
- zoomx = BLI_rctf_size_x(&but->rect) / BLI_rctf_size_x(&cumap->curr);
- zoomy = BLI_rctf_size_y(&but->rect) / BLI_rctf_size_y(&cumap->curr);
- offsx = cumap->curr.xmin;
- offsy = cumap->curr.ymin;
-
if (event->ctrl) {
- fx = ((float)mx - but->rect.xmin) / zoomx + offsx;
- fy = ((float)my - but->rect.ymin) / zoomy + offsy;
+ float f_xy[2];
+ BLI_rctf_transform_pt_v(&cumap->curr, &but->rect, f_xy, m_xy);
- curvemap_insert(cuma, fx, fy);
+ curvemap_insert(cuma, f_xy[0], f_xy[1]);
curvemapping_changed(cumap, false);
changed = true;
}
@@ -6035,33 +6030,37 @@ static int ui_do_but_CURVE(bContext *C, uiBlock *block, uiBut *but, uiHandleButt
/* check for selecting of a point */
cmp = cuma->curve; /* ctrl adds point, new malloc */
for (a = 0; a < cuma->totpoint; a++) {
- fx = but->rect.xmin + zoomx * (cmp[a].x - offsx);
- fy = but->rect.ymin + zoomy * (cmp[a].y - offsy);
- dist = (fx - mx) * (fx - mx) + (fy - my) * (fy - my);
- if (dist < mindist) {
+ float f_xy[2];
+ BLI_rctf_transform_pt_v(&but->rect, &cumap->curr, f_xy, &cmp[a].x);
+ const float dist_sq = len_squared_v2v2(m_xy, f_xy);
+ if (dist_sq < dist_min_sq) {
sel = a;
- mindist = dist;
+ dist_min_sq = dist_sq;
}
}
if (sel == -1) {
int i;
+ float f_xy[2], f_xy_prev[2];
/* if the click didn't select anything, check if it's clicked on the
* curve itself, and if so, add a point */
- fx = ((float)mx - but->rect.xmin) / zoomx + offsx;
- fy = ((float)my - but->rect.ymin) / zoomy + offsy;
-
cmp = cuma->table;
- /* loop through the curve segment table and find what's near the mouse.
- * 0.05 is kinda arbitrary, but seems to be what works nicely. */
- for (i = 0; i <= CM_TABLE; i++) {
- if ((fabsf(fx - cmp[i].x) < 0.05f) &&
- (fabsf(fy - cmp[i].y) < 0.05f))
- {
-
- curvemap_insert(cuma, fx, fy);
+ BLI_rctf_transform_pt_v(&but->rect, &cumap->curr, f_xy, &cmp[0].x);
+
+ /* with 160px height 8px should translate to the old 0.05 coefficient at no zoom */
+ dist_min_sq = SQUARE(8.0f);
+
+ /* loop through the curve segment table and find what's near the mouse. */
+ for (i = 1; i <= CM_TABLE; i++) {
+ copy_v2_v2(f_xy_prev, f_xy);
+ BLI_rctf_transform_pt_v(&but->rect, &cumap->curr, f_xy, &cmp[i].x);
+
+ if (dist_squared_to_line_segment_v2(m_xy, f_xy_prev, f_xy) < dist_min_sq) {
+ BLI_rctf_transform_pt_v(&cumap->curr, &but->rect, f_xy, m_xy);
+
+ curvemap_insert(cuma, f_xy[0], f_xy[1]);
curvemapping_changed(cumap, false);
changed = true;
@@ -6070,10 +6069,11 @@ static int ui_do_but_CURVE(bContext *C, uiBlock *block, uiBut *but, uiHandleButt
cmp = cuma->curve;
/* find newly added point and make it 'sel' */
- for (a = 0; a < cuma->totpoint; a++)
- if (cmp[a].x == fx)
+ for (a = 0; a < cuma->totpoint; a++) {
+ if (cmp[a].x == f_xy[0]) {
sel = a;
-
+ }
+ }
break;
}
}
@@ -6981,13 +6981,15 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
!IS_EVENT_MOD(event, shift, oskey) &&
(event->val == KM_PRESS))
{
- if (event->alt)
- ui_but_anim_remove_driver(C);
- else if (event->ctrl)
- ui_but_anim_add_driver(C);
-
- ED_region_tag_redraw(data->region);
-
+ /* quick check to prevent this opening within the popup menu its self */
+ if (!ELEM(NULL, but->rnapoin.data, but->rnaprop)) {
+ if (event->alt)
+ ui_but_anim_remove_driver(C);
+ else if (event->ctrl)
+ ui_but_anim_add_driver(C);
+
+ ED_region_tag_redraw(data->region);
+ }
return WM_UI_HANDLER_BREAK;
}
/* handle keyingsets */
@@ -8011,20 +8013,21 @@ uiBut *UI_context_active_but_get(const struct bContext *C)
}
/* helper function for insert keyframe, reset to default, etc operators */
-void UI_context_active_but_prop_get(const bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index)
+void UI_context_active_but_prop_get(
+ const bContext *C,
+ struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index)
{
uiBut *activebut = ui_context_rna_button_active(C);
- memset(ptr, 0, sizeof(*ptr));
-
if (activebut && activebut->rnapoin.data) {
- *ptr = activebut->rnapoin;
- *prop = activebut->rnaprop;
- *index = activebut->rnaindex;
+ *r_ptr = activebut->rnapoin;
+ *r_prop = activebut->rnaprop;
+ *r_index = activebut->rnaindex;
}
else {
- *prop = NULL;
- *index = 0;
+ memset(r_ptr, 0, sizeof(*r_ptr));
+ *r_prop = NULL;
+ *r_index = 0;
}
}
@@ -8436,6 +8439,7 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar,
uiListDyn *dyn_data;
int retval = WM_UI_HANDLER_CONTINUE;
int type = event->type, val = event->val;
+ bool redraw = false;
int mx, my;
ui_list = listbox->custom_data;
@@ -8525,7 +8529,7 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar,
ui_apply_but_undo(listbox);
ui_list->flag |= UILST_SCROLL_TO_ACTIVE_ITEM;
- ED_region_tag_redraw(ar);
+ redraw = true;
}
retval = WM_UI_HANDLER_BREAK;
}
@@ -8537,8 +8541,8 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar,
ui_list->list_grip += (type == WHEELUPMOUSE) ? -1 : 1;
ui_list->flag |= UILST_SCROLL_TO_ACTIVE_ITEM;
- ED_region_tag_redraw(ar);
+ redraw = true;
retval = WM_UI_HANDLER_BREAK;
}
else if (ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE)) {
@@ -8546,13 +8550,22 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar,
/* list template will clamp */
ui_list->list_scroll += (type == WHEELUPMOUSE) ? -1 : 1;
- ED_region_tag_redraw(ar);
-
+ redraw = true;
retval = WM_UI_HANDLER_BREAK;
}
}
}
+ if (redraw) {
+ if (listbox->block->flag & UI_BLOCK_POPUP) {
+ /* popups need special refreshing */
+ ED_region_tag_refresh_ui(ar);
+ }
+ else {
+ ED_region_tag_redraw(ar);
+ }
+ }
+
return retval;
}
@@ -9794,11 +9807,28 @@ static int ui_handle_menus_recursive(
}
else {
uiBlock *block = menu->region->uiblocks.first;
+ uiBut *listbox = ui_list_find_mouse_over(menu->region, event);
- if (block->flag & UI_BLOCK_RADIAL)
+ if (block->flag & UI_BLOCK_RADIAL) {
retval = ui_pie_handler(C, event, menu);
- else if (event->type == LEFTMOUSE || event->val != KM_DBL_CLICK)
- retval = ui_handle_menu_event(C, event, menu, level, is_parent_inside, is_parent_menu, is_floating);
+ }
+ else if (event->type == LEFTMOUSE || event->val != KM_DBL_CLICK) {
+ bool handled = false;
+
+ if (listbox) {
+ int retval_test = ui_handle_list_event(C, event, menu->region, listbox);
+ if (retval_test != WM_UI_HANDLER_CONTINUE) {
+ retval = retval_test;
+ handled = true;
+ }
+ }
+
+ if (handled == false) {
+ retval = ui_handle_menu_event(
+ C, event, menu, level,
+ is_parent_inside, is_parent_menu, is_floating);
+ }
+ }
}
}
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 0a25a8fb3c6..6dc60f1d70b 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -368,7 +368,6 @@ static void vicon_disclosure_tri_right_draw(int x, int y, int w, int UNUSED(h),
viconutil_set_point(pts[1], cx - d2, cy - d);
viconutil_set_point(pts[2], cx + d2, cy);
- glShadeModel(GL_SMOOTH);
glBegin(GL_TRIANGLES);
glColor4f(0.8f, 0.8f, 0.8f, alpha);
glVertex2iv(pts[0]);
@@ -376,7 +375,6 @@ static void vicon_disclosure_tri_right_draw(int x, int y, int w, int UNUSED(h),
glColor4f(0.3f, 0.3f, 0.3f, alpha);
glVertex2iv(pts[2]);
glEnd();
- glShadeModel(GL_FLAT);
glColor4f(0.0f, 0.0f, 0.0f, 1);
viconutil_draw_lineloop_smooth(pts, 3);
@@ -395,13 +393,11 @@ static void vicon_small_tri_right_draw(int x, int y, int w, int UNUSED(h), float
glColor4f(0.2f, 0.2f, 0.2f, alpha);
- glShadeModel(GL_SMOOTH);
glBegin(GL_TRIANGLES);
glVertex2iv(pts[0]);
glVertex2iv(pts[1]);
glVertex2iv(pts[2]);
glEnd();
- glShadeModel(GL_FLAT);
}
static void vicon_disclosure_tri_down_draw(int x, int y, int w, int UNUSED(h), float alpha)
@@ -415,7 +411,6 @@ static void vicon_disclosure_tri_down_draw(int x, int y, int w, int UNUSED(h), f
viconutil_set_point(pts[1], cx - d, cy + d2);
viconutil_set_point(pts[2], cx, cy - d2);
- glShadeModel(GL_SMOOTH);
glBegin(GL_TRIANGLES);
glColor4f(0.8f, 0.8f, 0.8f, alpha);
glVertex2iv(pts[0]);
@@ -423,7 +418,6 @@ static void vicon_disclosure_tri_down_draw(int x, int y, int w, int UNUSED(h), f
glColor4f(0.3f, 0.3f, 0.3f, alpha);
glVertex2iv(pts[2]);
glEnd();
- glShadeModel(GL_FLAT);
glColor4f(0.0f, 0.0f, 0.0f, 1);
viconutil_draw_lineloop_smooth(pts, 3);
@@ -1220,8 +1214,13 @@ static void icon_draw_rect(float x, float y, int w, int h, float UNUSED(aspect),
glaDrawPixelsSafe(draw_x, draw_y, draw_w, draw_h, draw_w, GL_RGBA, GL_UNSIGNED_BYTE, rect);
}
else {
+ int bound_options;
+ GPU_BASIC_SHADER_DISABLE_AND_STORE(bound_options);
+
glRasterPos2f(draw_x, draw_y);
glDrawPixels(draw_w, draw_h, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+
+ GPU_BASIC_SHADER_ENABLE_AND_RESTORE(bound_options);
}
if (ima)
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index 62b373c58c8..79961eae79d 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -1763,12 +1763,10 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active)
ui_panel_category_draw_tab(GL_LINE_STRIP, rct->xmin - px, rct->ymin - px, rct->xmax - px, rct->ymax + px,
tab_curve_radius, roundboxtype, true, true, NULL);
/* tab highlight (3d look) */
- glShadeModel(GL_SMOOTH);
glColor3ubv(is_active ? theme_col_tab_highlight : theme_col_tab_highlight_inactive);
ui_panel_category_draw_tab(GL_LINE_STRIP, rct->xmin, rct->ymin, rct->xmax, rct->ymax,
tab_curve_radius, roundboxtype, true, false,
is_active ? theme_col_back : theme_col_tab_inactive);
- glShadeModel(GL_FLAT);
}
/* tab blackline */
diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c
index 423c48e5f55..8b41302b5bb 100644
--- a/source/blender/editors/interface/interface_style.c
+++ b/source/blender/editors/interface/interface_style.c
@@ -417,6 +417,11 @@ void uiStyleInit(void)
blf_mono_font = -1;
}
+ if (blf_mono_font_render != -1) {
+ BLF_unload_id(blf_mono_font_render);
+ blf_mono_font_render = -1;
+ }
+
font = U.uifonts.first;
/* default builtin */
@@ -516,7 +521,12 @@ void uiStyleInit(void)
BLF_size(blf_mono_font, 12 * U.pixelsize, 72);
- /* second for rendering else we get threading problems */
+ /**
+ * Second for rendering else we get threading problems,
+ *
+ * \note This isn't good that the render font depends on the preferences,
+ * keep for now though, since without this there is no way to display many unicode chars.
+ */
if (blf_mono_font_render == -1)
blf_mono_font_render = BLF_load_mem_unique("monospace", monofont_ttf, monofont_size);
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index a3b04e1c9bc..7f276bcc634 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -232,15 +232,17 @@ static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
/* This is for browsing and editing the ID-blocks used */
/* for new/open operators */
-void UI_context_active_but_prop_get_templateID(bContext *C, PointerRNA *ptr, PropertyRNA **prop)
+void UI_context_active_but_prop_get_templateID(
+ bContext *C,
+ PointerRNA *r_ptr, PropertyRNA **r_prop)
{
TemplateID *template;
ARegion *ar = CTX_wm_region(C);
uiBlock *block;
uiBut *but;
- memset(ptr, 0, sizeof(*ptr));
- *prop = NULL;
+ memset(r_ptr, 0, sizeof(*r_ptr));
+ *r_prop = NULL;
if (!ar)
return;
@@ -251,8 +253,8 @@ void UI_context_active_but_prop_get_templateID(bContext *C, PointerRNA *ptr, Pro
if ((but->flag & (UI_BUT_LAST_ACTIVE | UI_ACTIVE))) {
if (but->func_argN) {
template = but->func_argN;
- *ptr = template->ptr;
- *prop = template->prop;
+ *r_ptr = template->ptr;
+ *r_prop = template->prop;
return;
}
}
@@ -2818,7 +2820,7 @@ static void uilist_prepare(
layoutdata->end_idx = min_ii(layoutdata->start_idx + rows * columns, len);
}
-static void uilist_resize_update_cb(bContext *UNUSED(C), void *arg1, void *UNUSED(arg2))
+static void uilist_resize_update_cb(bContext *C, void *arg1, void *UNUSED(arg2))
{
uiList *ui_list = arg1;
uiListDyn *dyn_data = ui_list->dyn_data;
@@ -2831,6 +2833,9 @@ static void uilist_resize_update_cb(bContext *UNUSED(C), void *arg1, void *UNUSE
dyn_data->resize_prev += diff * UI_UNIT_Y;
ui_list->flag |= UILST_SCROLL_TO_ACTIVE_ITEM;
}
+
+ /* In case uilist is in popup, we need special refreshing */
+ ED_region_tag_refresh_ui(CTX_wm_menu(C));
}
static void *uilist_item_use_dynamic_tooltip(PointerRNA *itemptr, const char *propname)
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 19e0b55374e..5098e701638 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -712,8 +712,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
unsigned char *col_pt = col_array;
shadecolors4(col1, col2, wcol->inner, wcol->shadetop, wcol->shadedown);
-
- glShadeModel(GL_SMOOTH);
+
for (a = 0; a < wtb->totvert; a++, col_pt += 4) {
round_box_shade_col4_r(col_pt, col1, col2, wtb->inner_uv[a][wtb->draw_shadedir ? 1 : 0]);
}
@@ -725,8 +724,6 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
glDrawArrays(GL_POLYGON, 0, wtb->totvert);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
-
- glShadeModel(GL_FLAT);
}
}
@@ -2311,8 +2308,6 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti *
ui_color_picker_to_rgb(0.0f, 0.0f, hsv[2], colcent, colcent + 1, colcent + 2);
- glShadeModel(GL_SMOOTH);
-
glBegin(GL_TRIANGLE_FAN);
glColor3fv(colcent);
glVertex2f(centx, centy);
@@ -2330,8 +2325,6 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti *
}
glEnd();
- glShadeModel(GL_FLAT);
-
/* fully rounded outline */
glPushMatrix();
glTranslatef(centx, centy, 0.0f);
@@ -2363,7 +2356,6 @@ void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, cons
float col1[4][3]; /* right half, rect bottom to top */
/* draw series of gouraud rects */
- glShadeModel(GL_SMOOTH);
switch (type) {
case UI_GRAD_SV:
@@ -2486,8 +2478,6 @@ void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, cons
}
glEnd();
}
-
- glShadeModel(GL_FLAT);
}
bool ui_but_is_colorpicker_display_space(uiBut *but)
diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c
index b1ca95efe04..b74c4b5f526 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -400,7 +400,7 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op)
C, filename,
import_units,
find_chains,
- auto_connect,
+ auto_connect,
fix_orientation,
min_chain_length))
{
@@ -482,7 +482,7 @@ void WM_OT_collada_import(wmOperatorType *ot)
RNA_def_boolean(ot->srna,
"auto_connect", 0, "Auto Connect",
- "set use_connect for parent bones which have exactly one child bone");
+ "Set use_connect for parent bones which have exactly one child bone");
RNA_def_int(ot->srna,
"min_chain_length",
diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c
index 9a8382b2136..2b4f94a37ef 100644
--- a/source/blender/editors/mask/mask_draw.c
+++ b/source/blender/editors/mask/mask_draw.c
@@ -51,6 +51,8 @@
#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "GPU_basic_shader.h"
+
#include "UI_resources.h"
#include "UI_view2d.h"
@@ -100,10 +102,10 @@ static void draw_spline_parents(MaskLayer *UNUSED(masklay), MaskSpline *spline)
if (!spline->tot_point)
return;
- glColor3ub(0, 0, 0);
- glEnable(GL_LINE_STIPPLE);
- glLineStipple(1, 0xAAAA);
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ GPU_basic_shader_line_stipple(1, 0xAAAA);
+ glColor3ub(0, 0, 0);
glBegin(GL_LINES);
for (i = 0; i < spline->tot_point; i++) {
@@ -121,7 +123,7 @@ static void draw_spline_parents(MaskLayer *UNUSED(masklay), MaskSpline *spline)
glEnd();
- glDisable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
}
#endif
@@ -455,7 +457,8 @@ static void mask_draw_curve_type(const bContext *C, MaskSpline *spline, float (*
case MASK_DT_DASH:
default:
- glEnable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ GPU_basic_shader_line_stipple(3, 0xAAAA);
#ifdef USE_XOR
glEnable(GL_COLOR_LOGIC_OP);
@@ -463,7 +466,6 @@ static void mask_draw_curve_type(const bContext *C, MaskSpline *spline, float (*
#endif
mask_color_active_tint(rgb_tmp, rgb_spline, is_active);
glColor4ubv(rgb_tmp);
- glLineStipple(3, 0xaaaa);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, points);
glDrawArrays(draw_method, 0, tot_point);
@@ -473,10 +475,10 @@ static void mask_draw_curve_type(const bContext *C, MaskSpline *spline, float (*
#endif
mask_color_active_tint(rgb_tmp, rgb_black, is_active);
glColor4ubv(rgb_tmp);
- glLineStipple(3, 0x5555);
+ GPU_basic_shader_line_stipple(3, 0x5555);
glDrawArrays(draw_method, 0, tot_point);
- glDisable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
break;
diff --git a/source/blender/editors/mask/mask_editaction.c b/source/blender/editors/mask/mask_editaction.c
index bcf9ee5c88d..16147bdc7f8 100644
--- a/source/blender/editors/mask/mask_editaction.c
+++ b/source/blender/editors/mask/mask_editaction.c
@@ -201,6 +201,36 @@ void ED_masklayer_frames_select_border(MaskLayer *masklay, float min, float max,
}
}
+/* select the frames in this layer that occur within the lasso/circle region specified */
+void ED_masklayer_frames_select_region(KeyframeEditData *ked, MaskLayer *masklay, short tool, short select_mode)
+{
+ MaskLayerShape *masklay_shape;
+
+ if (masklay == NULL)
+ return;
+
+ /* only select frames which are within the region */
+ for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape->next) {
+ /* construct a dummy point coordinate to do this testing with */
+ float pt[2] = {0};
+
+ pt[0] = masklay_shape->frame;
+ pt[1] = ked->channel_y;
+
+ /* check the necessary regions */
+ if (tool == BEZT_OK_CHANNEL_LASSO) {
+ /* Lasso */
+ if (keyframe_region_lasso_test(ked->data, pt))
+ masklayshape_select(masklay_shape, select_mode);
+ }
+ else if (tool == BEZT_OK_CHANNEL_CIRCLE) {
+ /* Circle */
+ if (keyframe_region_circle_test(ked->data, pt))
+ masklayshape_select(masklay_shape, select_mode);
+ }
+ }
+}
+
/* ***************************************** */
/* Frame Editing Tools */
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c
index 01be8f848aa..c4e87614732 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.c
@@ -53,6 +53,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "GPU_draw.h"
#include "GPU_buffers.h"
/* own include */
@@ -433,7 +434,7 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, bool select, bool exten
if (ENDIAN_ORDER == B_ENDIAN) {
IMB_convert_rgba_to_abgr(ibuf);
}
- WM_framebuffer_to_index_array(ibuf->rect, size[0] * size[1]);
+ GPU_select_to_index_array(ibuf->rect, size[0] * size[1]);
a = size[0] * size[1];
while (a--) {
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index 242cbf79a83..302ca407add 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -58,26 +58,45 @@
#define MVAL_PIXEL_MARGIN 5.0f
+/* until implement profile = 0 case, need to clamp somewhat above zero */
+#define PROFILE_HARD_MIN 0.15f
+
+#define SEGMENTS_HARD_MAX 1000
+
+/* which value is mouse movement and numeric input controlling? */
+#define OFFSET_VALUE 0
+#define OFFSET_VALUE_PERCENT 1
+#define PROFILE_VALUE 2
+#define SEGMENTS_VALUE 3
+#define NUM_VALUE_KINDS 4
+
+static const char *value_rna_name[NUM_VALUE_KINDS] = {"offset", "offset", "profile", "segments"};
+static const float value_clamp_min[NUM_VALUE_KINDS] = {0.0f, 0.0f, PROFILE_HARD_MIN, 1.0f};
+static const float value_clamp_max[NUM_VALUE_KINDS] = {1e6, 100.0f, 1.0f, SEGMENTS_HARD_MAX};
+static const float value_start[NUM_VALUE_KINDS] = {0.0f, 0.0f, 0.5f, 1.0f};
+static const float value_scale_per_inch[NUM_VALUE_KINDS] = { 0.0f, 100.0f, 1.0f, 4.0f};
+
typedef struct {
BMEditMesh *em;
- float initial_length;
- float pixel_size; /* use when mouse input is interpreted as spatial distance */
+ float initial_length[NUM_VALUE_KINDS];
+ float scale[NUM_VALUE_KINDS];
+ NumInput num_input[NUM_VALUE_KINDS];
+ float shift_value[NUM_VALUE_KINDS]; /* The current value when shift is pressed. Negative when shift not active. */
bool is_modal;
- NumInput num_input;
- float shift_factor; /* The current factor when shift is pressed. Negative when shift not active. */
/* modal only */
float mcenter[2];
BMBackup mesh_backup;
void *draw_handle_pixel;
short twtype;
+ short value_mode; /* Which value does mouse movement and numeric input affect? */
float segments; /* Segments as float so smooth mouse pan works in small increments */
} BevelData;
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");
+ "Vertex Only: %s (V), Profile Control: %s (P), Offset: %s, Segments: %d, Profile: %.3f");
char msg[UI_MAX_DRAW_STR];
ScrArea *sa = CTX_wm_area(C);
@@ -89,8 +108,8 @@ static void edbm_bevel_update_header(bContext *C, wmOperator *op)
const char *type_str;
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "offset_type");
- if (hasNumInput(&opdata->num_input)) {
- outputNumInput(&opdata->num_input, offset_str, &sce->unit);
+ if (hasNumInput(&opdata->num_input[OFFSET_VALUE])) {
+ outputNumInput(&opdata->num_input[OFFSET_VALUE], offset_str, &sce->unit);
}
else {
BLI_snprintf(offset_str, NUM_STR_REP_LEN, "%f", RNA_float_get(op->ptr, "offset"));
@@ -101,7 +120,8 @@ static void edbm_bevel_update_header(bContext *C, wmOperator *op)
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"));
+ WM_bool_as_string(opdata->value_mode == PROFILE_VALUE),
+ offset_str, RNA_int_get(op->ptr, "segments"), RNA_float_get(op->ptr, "profile"));
ED_area_headerprint(sa, msg);
}
@@ -113,6 +133,8 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
Scene *scene = CTX_data_scene(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BevelData *opdata;
+ float pixels_per_inch;
+ int i;
if (em->bm->totvertsel == 0) {
return false;
@@ -122,13 +144,25 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
opdata->em = em;
opdata->is_modal = is_modal;
- opdata->shift_factor = -1.0f;
-
- initNumInput(&opdata->num_input);
- opdata->num_input.idx_max = 0;
- opdata->num_input.val_flag[0] |= NUM_NO_NEGATIVE;
- opdata->num_input.unit_sys = scene->unit.system;
- opdata->num_input.unit_type[0] = B_UNIT_NONE; /* Not sure this is a factor or a unit? */
+ opdata->value_mode = OFFSET_VALUE;
+ pixels_per_inch = U.dpi * U.pixelsize;
+
+ for (i = 0; i < NUM_VALUE_KINDS; i++) {
+ opdata->shift_value[i] = -1.0f;
+ /* note: scale for OFFSET_VALUE will get overwritten in edbm_bevel_invoke */
+ opdata->scale[i] = value_scale_per_inch[i] / pixels_per_inch;
+
+ initNumInput(&opdata->num_input[i]);
+ opdata->num_input[i].idx_max = 0;
+ opdata->num_input[i].val_flag[0] |= NUM_NO_NEGATIVE;
+ if (i == SEGMENTS_VALUE) {
+ opdata->num_input[i].val_flag[0] |= NUM_NO_FRACTION | NUM_NO_ZERO;
+ }
+ if (i == OFFSET_VALUE) {
+ opdata->num_input[i].unit_sys = scene->unit.system;
+ }
+ opdata->num_input[i].unit_type[0] = B_UNIT_NONE; /* Not sure this is a factor or a unit? */
+ }
/* avoid the cost of allocating a bm copy */
if (is_modal) {
@@ -136,7 +170,8 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
ARegion *ar = CTX_wm_region(C);
opdata->mesh_backup = EDBM_redo_state_store(em);
- opdata->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL);
+ opdata->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ED_region_draw_mouse_line_cb,
+ opdata->mcenter, REGION_DRAW_POST_PIXEL);
G.moving = G_TRANSFORM_EDIT;
if (v3d) {
@@ -167,13 +202,15 @@ static bool edbm_bevel_calc(wmOperator *op)
EDBM_redo_state_restore(opdata->mesh_backup, em, false);
}
- if (em->ob)
+ if (em->ob) {
material = CLAMPIS(material, -1, em->ob->totcol - 1);
+ }
EDBM_op_init(em, &bmop, op,
"bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i profile=%f clamp_overlap=%b "
"material=%i loop_slide=%b",
- BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile, clamp_overlap, material, loop_slide);
+ BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile,
+ clamp_overlap, material, loop_slide);
BMO_op_exec(em->bm, &bmop);
@@ -185,8 +222,9 @@ static bool edbm_bevel_calc(wmOperator *op)
}
/* no need to de-select existing geometry */
- if (!EDBM_op_finish(em, &bmop, op, true))
+ if (!EDBM_op_finish(em, &bmop, op, true)) {
return false;
+ }
EDBM_mesh_normals_update(opdata->em);
@@ -250,12 +288,37 @@ static int edbm_bevel_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+static void edbm_bevel_calc_initial_length(wmOperator *op, const wmEvent *event, bool mode_changed)
+{
+ BevelData *opdata;
+ float mlen[2], len, value, sc, st;
+ int vmode;
+
+ opdata = op->customdata;
+ mlen[0] = opdata->mcenter[0] - event->mval[0];
+ mlen[1] = opdata->mcenter[1] - event->mval[1];
+ len = len_v2(mlen);
+ vmode = opdata->value_mode;
+ if (mode_changed) {
+ /* If current value is not default start value, adjust len so that
+ * the scaling and offset in edbm_bevel_mouse_set_value will
+ * start at current value */
+ value = (vmode == SEGMENTS_VALUE) ?
+ opdata->segments : RNA_float_get(op->ptr, value_rna_name[vmode]);
+ sc = opdata->scale[vmode];
+ st = value_start[vmode];
+ if (value != value_start[vmode]) {
+ len = (st + sc * (len - MVAL_PIXEL_MARGIN) - value) / sc;
+ }
+ }
+ opdata->initial_length[opdata->value_mode] = len;
+}
+
static int edbm_bevel_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
/* TODO make modal keymap (see fly mode) */
RegionView3D *rv3d = CTX_wm_region_view3d(C);
BevelData *opdata;
- float mlen[2];
float center_3d[3];
if (!edbm_bevel_init(C, op, true)) {
@@ -270,10 +333,10 @@ static int edbm_bevel_invoke(bContext *C, wmOperator *op, const wmEvent *event)
* ideally this will never happen and should be checked for above */
opdata->mcenter[0] = opdata->mcenter[1] = 0;
}
- mlen[0] = opdata->mcenter[0] - event->mval[0];
- mlen[1] = opdata->mcenter[1] - event->mval[1];
- opdata->initial_length = len_v2(mlen);
- opdata->pixel_size = rv3d ? ED_view3d_pixel_size(rv3d, center_3d) : 1.0f;
+ edbm_bevel_calc_initial_length(op, event, false);
+
+ /* for OFFSET_VALUE only, the scale is the size of a pixel under the mouse in 3d space */
+ opdata->scale[OFFSET_VALUE] = rv3d ? ED_view3d_pixel_size(rv3d, center_3d) : 1.0f;
edbm_bevel_update_header(C, op);
@@ -287,59 +350,72 @@ static int edbm_bevel_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
-static float edbm_bevel_mval_factor(wmOperator *op, const wmEvent *event)
+static void edbm_bevel_mouse_set_value(wmOperator *op, const wmEvent *event)
{
BevelData *opdata = op->customdata;
- bool use_dist;
- bool is_percent;
+ int vmode = opdata->value_mode;
float mdiff[2];
- float factor;
+ float value;
mdiff[0] = opdata->mcenter[0] - event->mval[0];
mdiff[1] = opdata->mcenter[1] - event->mval[1];
- is_percent = (RNA_enum_get(op->ptr, "offset_type") == BEVEL_AMT_PERCENT);
- use_dist = !is_percent;
- factor = ((len_v2(mdiff) - MVAL_PIXEL_MARGIN) - opdata->initial_length) * opdata->pixel_size;
+ value = ((len_v2(mdiff) - MVAL_PIXEL_MARGIN) - opdata->initial_length[vmode]);
+
+ /* Scale according to value mode */
+ value = value_start[vmode] + value * opdata->scale[vmode];
/* Fake shift-transform... */
if (event->shift) {
- if (opdata->shift_factor < 0.0f) {
- opdata->shift_factor = RNA_float_get(op->ptr, "offset");
- if (is_percent) {
- opdata->shift_factor /= 100.0f;
- }
+ if (opdata->shift_value[vmode] < 0.0f) {
+ opdata->shift_value[vmode] = (vmode == SEGMENTS_VALUE) ?
+ opdata->segments : RNA_float_get(op->ptr, value_rna_name[vmode]);
}
- factor = (factor - opdata->shift_factor) * 0.1f + opdata->shift_factor;
+ value = (value - opdata->shift_value[vmode]) * 0.1f + opdata->shift_value[vmode];
}
- else if (opdata->shift_factor >= 0.0f) {
- opdata->shift_factor = -1.0f;
+ else if (opdata->shift_value[vmode] >= 0.0f) {
+ opdata->shift_value[vmode] = -1.0f;
}
- /* clamp differently based on distance/factor */
- if (use_dist) {
- if (factor < 0.0f) factor = 0.0f;
+ /* clamp accordingto value mode, and store value back */
+ CLAMP(value, value_clamp_min[vmode], value_clamp_max[vmode]);
+ if (vmode == SEGMENTS_VALUE) {
+ opdata->segments = value;
+ RNA_int_set(op->ptr, "segments", (int)(value + 0.5f));
}
else {
- CLAMP(factor, 0.0f, 1.0f);
- if (is_percent) {
- factor *= 100.0f;
- }
+ RNA_float_set(op->ptr, value_rna_name[vmode], value);
}
+}
- return factor;
+static void edbm_bevel_numinput_set_value(wmOperator *op)
+{
+ BevelData *opdata = op->customdata;
+ float value;
+ int vmode;
+
+ vmode = opdata->value_mode;
+ value = (vmode == SEGMENTS_VALUE) ?
+ opdata->segments : RNA_float_get(op->ptr, value_rna_name[vmode]);
+ applyNumInput(&opdata->num_input[vmode], &value);
+ CLAMP(value, value_clamp_min[vmode], value_clamp_max[vmode]);
+ if (vmode == SEGMENTS_VALUE) {
+ opdata->segments = value;
+ RNA_int_set(op->ptr, "segments", (int)value);
+ }
+ else {
+ RNA_float_set(op->ptr, value_rna_name[vmode], value);
+ }
}
static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
BevelData *opdata = op->customdata;
- const bool has_numinput = hasNumInput(&opdata->num_input);
+ const bool has_numinput = hasNumInput(&opdata->num_input[opdata->value_mode]);
/* Modal numinput active, try to handle numeric inputs first... */
- if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &opdata->num_input, event)) {
- float value = RNA_float_get(op->ptr, "offset");
- applyNumInput(&opdata->num_input, &value);
- RNA_float_set(op->ptr, "offset", value);
+ if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &opdata->num_input[opdata->value_mode], event)) {
+ edbm_bevel_numinput_set_value(op);
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
return OPERATOR_RUNNING_MODAL;
@@ -354,9 +430,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
case MOUSEMOVE:
if (!has_numinput) {
- const float factor = edbm_bevel_mval_factor(op, event);
- RNA_float_set(op->ptr, "offset", factor);
-
+ edbm_bevel_mouse_set_value(op, event);
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
handled = true;
@@ -426,12 +500,18 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (type > BEVEL_AMT_PERCENT) {
type = BEVEL_AMT_OFFSET;
}
+ if (opdata->value_mode == OFFSET_VALUE && type == BEVEL_AMT_PERCENT)
+ opdata->value_mode = OFFSET_VALUE_PERCENT;
+ else if (opdata->value_mode == OFFSET_VALUE_PERCENT && type != BEVEL_AMT_PERCENT)
+ opdata->value_mode = OFFSET_VALUE;
RNA_property_enum_set(op->ptr, prop, type);
}
- /* Update factor accordingly to new offset_type. */
- if (!has_numinput) {
- RNA_float_set(op->ptr, "offset", edbm_bevel_mval_factor(op, event));
- }
+ /* Update offset accordingly to new offset_type. */
+ if (!has_numinput &&
+ (opdata->value_mode == OFFSET_VALUE || opdata->value_mode == OFFSET_VALUE_PERCENT))
+ {
+ edbm_bevel_mouse_set_value(op, event);
+ }
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
handled = true;
@@ -448,6 +528,28 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
edbm_bevel_update_header(C, op);
handled = true;
break;
+ case PKEY:
+ if (event->val == KM_RELEASE)
+ break;
+ if (opdata->value_mode == PROFILE_VALUE) {
+ opdata->value_mode = OFFSET_VALUE;
+ }
+ else {
+ opdata->value_mode = PROFILE_VALUE;
+ }
+ edbm_bevel_calc_initial_length(op, event, true);
+ break;
+ case SKEY:
+ if (event->val == KM_RELEASE)
+ break;
+ if (opdata->value_mode == SEGMENTS_VALUE) {
+ opdata->value_mode = OFFSET_VALUE;
+ }
+ else {
+ opdata->value_mode = SEGMENTS_VALUE;
+ }
+ edbm_bevel_calc_initial_length(op, event, true);
+ break;
case VKEY:
if (event->val == KM_RELEASE)
break;
@@ -464,10 +566,8 @@ static int edbm_bevel_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, &opdata->num_input, event)) {
- float value = RNA_float_get(op->ptr, "offset");
- applyNumInput(&opdata->num_input, &value);
- RNA_float_set(op->ptr, "offset", value);
+ if (!handled && event->val == KM_PRESS && handleNumInput(C, &opdata->num_input[opdata->value_mode], event)) {
+ edbm_bevel_numinput_set_value(op);
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
return OPERATOR_RUNNING_MODAL;
@@ -518,11 +618,13 @@ void MESH_OT_bevel(wmOperatorType *ot)
RNA_def_enum(ot->srna, "offset_type", offset_type_items, 0, "Amount Type", "What distance Amount measures");
prop = RNA_def_float(ot->srna, "offset", 0.0f, -1e6f, 1e6f, "Amount", "", 0.0f, 1.0f);
RNA_def_property_float_array_funcs_runtime(prop, NULL, NULL, mesh_ot_bevel_offset_range_func);
- RNA_def_int(ot->srna, "segments", 1, 1, 50, "Segments", "Segments for curved edge", 1, 8);
- RNA_def_float(ot->srna, "profile", 0.5f, 0.15f, 1.0f, "Profile", "Controls profile shape (0.5 = round)", 0.15f, 1.0f);
+ RNA_def_int(ot->srna, "segments", 1, 1, SEGMENTS_HARD_MAX, "Segments", "Segments for curved edge", 1, 8);
+ RNA_def_float(ot->srna, "profile", 0.5f, PROFILE_HARD_MIN, 1.0f, "Profile",
+ "Controls profile shape (0.5 = round)", PROFILE_HARD_MIN, 1.0f);
RNA_def_boolean(ot->srna, "vertex_only", false, "Vertex Only", "Bevel only vertices");
RNA_def_boolean(ot->srna, "clamp_overlap", false, "Clamp Overlap",
- "Do not allow beveled edges/vertices to overlap each other");
+ "Do not allow beveled edges/vertices to overlap each other");
RNA_def_boolean(ot->srna, "loop_slide", true, "Loop Slide", "Prefer slide along edge to even widths");
- RNA_def_int(ot->srna, "material", -1, -1, INT_MAX, "Material", "Material for bevel faces (-1 means use adjacent faces)", -1, 100);
+ RNA_def_int(ot->srna, "material", -1, -1, INT_MAX, "Material",
+ "Material for bevel faces (-1 means use adjacent faces)", -1, 100);
}
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 0fd56fbcc4e..a84b8d9dcc8 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -2283,7 +2283,7 @@ static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfe
BMEdge **edge_array = BLI_array_alloca(edge_array, edge_array_len);
- /* point to knife edges we've created edges in, edge_array aligned */
+ /* point to knife edges we've created edges in, edge_array aligned */
KnifeEdge **kfe_array = BLI_array_alloca(kfe_array, edge_array_len);
BLI_assert(BLI_gset_size(kcd->edgenet.edge_visit) == 0);
diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c
index 9e71e646b1a..8868827a11f 100644
--- a/source/blender/editors/mesh/editmesh_rip.c
+++ b/source/blender/editors/mesh/editmesh_rip.c
@@ -463,7 +463,7 @@ static void edbm_tagged_loop_pairs_do_fill_faces(BMesh *bm, UnorderedLoopPair *u
if ((ulp->l_pair[0] && ulp->l_pair[1]) &&
(ulp->l_pair[0]->e != ulp->l_pair[1]->e))
{
- /* time has come to make a face! */
+ /* time has come to make a face! */
BMVert *v_shared = BM_edge_share_vert(ulp->l_pair[0]->e, ulp->l_pair[1]->e);
BMFace *f, *f_example = ulp->l_pair[0]->f;
BMLoop *l_iter;
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index 84ae35fae6e..5d5731a7e16 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -2453,7 +2453,7 @@ static void select_linked_delimit_begin(BMesh *bm, int delimit)
const bool is_walk_ok = (
(select_linked_delimit_test(e, delimit, &delimit_data) == false));
- BMO_elem_flag_set(bm, e, BMO_ELE_TAG, is_walk_ok);
+ BMO_edge_flag_set(bm, e, BMO_ELE_TAG, is_walk_ok);
}
}
}
@@ -2496,7 +2496,7 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op)
if (delimit) {
BMEdge *e;
BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (!BMO_elem_flag_test(bm, e, BMO_ELE_TAG)) {
+ if (!BMO_edge_flag_test(bm, e, BMO_ELE_TAG)) {
BM_elem_flag_disable(e->v1, BM_ELEM_TAG);
BM_elem_flag_disable(e->v2, BM_ELEM_TAG);
}
@@ -2552,7 +2552,7 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op)
BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
BM_elem_flag_set(
e, BM_ELEM_TAG,
- (BM_elem_flag_test(e, BM_ELEM_SELECT) && BMO_elem_flag_test(bm, e, BMO_ELE_TAG)));
+ (BM_elem_flag_test(e, BM_ELEM_SELECT) && BMO_edge_flag_test(bm, e, BMO_ELE_TAG)));
}
}
else {
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index efe179790da..9f1602ccfaf 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -2910,7 +2910,7 @@ static int edbm_knife_cut_exec(bContext *C, wmOperator *op)
}
}
- BMO_elem_flag_set(bm, be, ELE_EDGE_CUT, is_cut);
+ BMO_edge_flag_set(bm, be, ELE_EDGE_CUT, is_cut);
}
@@ -2982,7 +2982,9 @@ static Base *mesh_separate_tagged(Main *bmain, Scene *scene, Base *base_old, BMe
Object *obedit = base_old->object;
BMesh *bm_new;
- bm_new = BM_mesh_create(&bm_mesh_allocsize_default);
+ bm_new = BM_mesh_create(
+ &bm_mesh_allocsize_default,
+ &((struct BMeshCreateParams){.use_toolflags = true,}));
BM_mesh_elem_toolflags_ensure(bm_new); /* needed for 'duplicate' bmo */
CustomData_copy(&bm_old->vdata, &bm_new->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
@@ -3294,7 +3296,9 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
BMesh *bm_old = NULL;
int retval_iter = 0;
- bm_old = BM_mesh_create(&bm_mesh_allocsize_default);
+ bm_old = BM_mesh_create(
+ &bm_mesh_allocsize_default,
+ &((struct BMeshCreateParams){.use_toolflags = true,}));
BM_mesh_bm_from_me(bm_old, me, (&(struct BMeshFromMeshParams){0}));
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c
index b9d3fd6c8be..b44fbc3ce45 100644
--- a/source/blender/editors/mesh/editmesh_undo.c
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -49,7 +49,7 @@
# endif
# include "BLI_array_store.h"
-# include "BLI_math_base.h"
+# include "BLI_array_store_utils.h"
/* check on best size later... */
# define ARRAY_CHUNK_SIZE 256
@@ -89,8 +89,7 @@ typedef struct UndoMesh {
#ifdef USE_ARRAY_STORE
/* NULL arrays are considered empty */
- struct {
- /* most data is stored as 'custom' data */
+ struct { /* most data is stored as 'custom' data */
BArrayCustomData *vdata, *edata, *ldata, *pdata;
BArrayState **keyblocks;
BArrayState *mselect;
@@ -105,8 +104,7 @@ typedef struct UndoMesh {
* \{ */
static struct {
- BArrayStore **bs_all;
- int bs_all_len;
+ struct BArrayStore_AtSize bs_stride;
int users;
/* We could have the undo API pass in the previous state, for now store a local list */
@@ -118,57 +116,6 @@ static struct {
} um_arraystore = {NULL};
-static BArrayStore *array_store_at_size_ensure(const int stride)
-{
- if (um_arraystore.bs_all_len < stride) {
- um_arraystore.bs_all_len = stride;
- um_arraystore.bs_all = MEM_recallocN(um_arraystore.bs_all, sizeof(*um_arraystore.bs_all) * stride);
- }
- BArrayStore **bs_p = &um_arraystore.bs_all[stride - 1];
-
- if ((*bs_p) == NULL) {
-#if 0
- unsigned int chunk_count = ARRAY_CHUNK_SIZE;
-#else
- /* calculate best chunk-count to fit a power of two */
- unsigned int chunk_count = ARRAY_CHUNK_SIZE;
- {
- unsigned int size = chunk_count * stride;
- size = power_of_2_max_u(size);
- size = MEM_SIZE_OPTIMAL(size);
- chunk_count = size / stride;
- }
-#endif
-
- (*bs_p) = BLI_array_store_create(stride, chunk_count);
- }
- return *bs_p;
-}
-
-static BArrayStore *array_store_at_size_get(const int stride)
-{
- BLI_assert(stride > 0 && stride <= um_arraystore.bs_all_len);
- return um_arraystore.bs_all[stride - 1];
-}
-
-#ifdef DEBUG_PRINT
-static void um_arraystore_memory_usage(size_t *r_size_expanded, size_t *r_size_compacted)
-{
- size_t size_compacted = 0;
- size_t size_expanded = 0;
- for (int i = 0; i < um_arraystore.bs_all_len; i++) {
- BArrayStore *bs = um_arraystore.bs_all[i];
- if (bs) {
- size_compacted += BLI_array_store_calc_size_compacted_get(bs);
- size_expanded += BLI_array_store_calc_size_expanded_get(bs);
- }
- }
-
- *r_size_expanded = size_expanded;
- *r_size_compacted = size_compacted;
-}
-#endif
-
static void um_arraystore_cd_compact(
struct CustomData *cdata, const size_t data_len,
bool create,
@@ -194,7 +141,7 @@ static void um_arraystore_cd_compact(
}
const int stride = CustomData_sizeof(type);
- BArrayStore *bs = create ? array_store_at_size_ensure(stride) : NULL;
+ BArrayStore *bs = create ? BLI_array_store_at_size_ensure(&um_arraystore.bs_stride, stride, ARRAY_CHUNK_SIZE) : NULL;
const int layer_len = layer_end - layer_start;
if (create) {
@@ -299,7 +246,7 @@ static void um_arraystore_cd_free(BArrayCustomData *bcd)
while (bcd) {
BArrayCustomData *bcd_next = bcd->next;
const int stride = CustomData_sizeof(bcd->type);
- BArrayStore *bs = array_store_at_size_get(stride);
+ BArrayStore *bs = BLI_array_store_at_size_get(&um_arraystore.bs_stride, stride);
for (int i = 0; i < bcd->states_len; i++) {
if (bcd->states[i]) {
BLI_array_store_state_remove(bs, bcd->states[i]);
@@ -328,7 +275,7 @@ static void um_arraystore_compact_ex(
if (me->key && me->key->totkey) {
const size_t stride = me->key->elemsize;
- BArrayStore *bs = create ? array_store_at_size_ensure(stride) : NULL;
+ BArrayStore *bs = create ? BLI_array_store_at_size_ensure(&um_arraystore.bs_stride, stride, ARRAY_CHUNK_SIZE) : NULL;
if (create) {
um->store.keyblocks = MEM_mallocN(me->key->totkey * sizeof(*um->store.keyblocks), __func__);
}
@@ -355,7 +302,7 @@ static void um_arraystore_compact_ex(
if (create) {
BArrayState *state_reference = um_ref ? um_ref->store.mselect : NULL;
const size_t stride = sizeof(*me->mselect);
- BArrayStore *bs = array_store_at_size_ensure(stride);
+ BArrayStore *bs = BLI_array_store_at_size_ensure(&um_arraystore.bs_stride, stride, ARRAY_CHUNK_SIZE);
um->store.mselect = BLI_array_store_state_add(
bs, me->mselect, (size_t)me->totselect * stride, state_reference);
}
@@ -384,7 +331,7 @@ static void um_arraystore_compact_with_info(UndoMesh *um, const UndoMesh *um_ref
{
#ifdef DEBUG_PRINT
size_t size_expanded_prev, size_compacted_prev;
- um_arraystore_memory_usage(&size_expanded_prev, &size_compacted_prev);
+ BLI_array_store_at_size_calc_memory_usage(&um_arraystore.bs_stride, &size_expanded_prev, &size_compacted_prev);
#endif
#ifdef DEBUG_TIME
@@ -400,7 +347,7 @@ static void um_arraystore_compact_with_info(UndoMesh *um, const UndoMesh *um_ref
#ifdef DEBUG_PRINT
{
size_t size_expanded, size_compacted;
- um_arraystore_memory_usage(&size_expanded, &size_compacted);
+ BLI_array_store_at_size_calc_memory_usage(&um_arraystore.bs_stride, &size_expanded, &size_compacted);
const double percent_total = size_expanded ?
(((double)size_compacted / (double)size_expanded) * 100.0) : -1.0;
@@ -483,7 +430,7 @@ static void um_arraystore_free(UndoMesh *um)
if (um->store.keyblocks) {
const size_t stride = me->key->elemsize;
- BArrayStore *bs = array_store_at_size_get(stride);
+ BArrayStore *bs = BLI_array_store_at_size_get(&um_arraystore.bs_stride, stride);
for (int i = 0; i < me->key->totkey; i++) {
BArrayState *state = um->store.keyblocks[i];
BLI_array_store_state_remove(bs, state);
@@ -494,7 +441,7 @@ static void um_arraystore_free(UndoMesh *um)
if (um->store.mselect) {
const size_t stride = sizeof(*me->mselect);
- BArrayStore *bs = array_store_at_size_get(stride);
+ BArrayStore *bs = BLI_array_store_at_size_get(&um_arraystore.bs_stride, stride);
BArrayState *state = um->store.mselect;
BLI_array_store_state_remove(bs, state);
um->store.mselect = NULL;
@@ -508,15 +455,7 @@ static void um_arraystore_free(UndoMesh *um)
#ifdef DEBUG_PRINT
printf("mesh undo store: freeing all data!\n");
#endif
- for (int i = 0; i < um_arraystore.bs_all_len; i += 1) {
- if (um_arraystore.bs_all[i]) {
- BLI_array_store_destroy(um_arraystore.bs_all[i]);
- }
- }
-
- MEM_freeN(um_arraystore.bs_all);
- um_arraystore.bs_all = NULL;
- um_arraystore.bs_all_len = 0;
+ BLI_array_store_at_size_clear(&um_arraystore.bs_stride);
#ifdef USE_ARRAY_STORE_THREAD
BLI_task_pool_free(um_arraystore.task_pool);
@@ -624,7 +563,9 @@ static void undoMesh_to_editbtMesh(void *um_v, void *em_v, void *obdata)
EDBM_mesh_free(em);
- bm = BM_mesh_create(&allocsize);
+ bm = BM_mesh_create(
+ &allocsize,
+ &((struct BMeshCreateParams){.use_toolflags = true,}));
BM_mesh_bm_from_me(
bm, &um->me, (&(struct BMeshFromMeshParams){
@@ -698,7 +639,7 @@ static void free_undo(void *um_v)
MEM_freeN(me->key);
}
- BKE_mesh_free(me, false);
+ BKE_mesh_free(me);
MEM_freeN(me);
}
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 99be37845ee..5101608246a 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -354,7 +354,9 @@ void EDBM_mesh_make(ToolSettings *ts, Object *ob, const bool add_key_index)
BKE_mesh_convert_mfaces_to_mpolys(me);
}
- bm = BKE_mesh_to_bmesh(me, ob, add_key_index);
+ bm = BKE_mesh_to_bmesh(
+ me, ob, add_key_index,
+ &((struct BMeshCreateParams){.use_toolflags = true,}));
if (me->edit_btmesh) {
/* this happens when switching shape keys */
@@ -399,10 +401,25 @@ void EDBM_mesh_load(Object *ob)
BKE_mesh_tessface_calc(me);
#endif
- /* free derived mesh. usually this would happen through depsgraph but there
+ /* Free derived mesh. usually this would happen through depsgraph but there
* are exceptions like file save that will not cause this, and we want to
- * avoid ending up with an invalid derived mesh then */
- BKE_object_free_derived_caches(ob);
+ * avoid ending up with an invalid derived mesh then.
+ *
+ * Do it for all objects which shares the same mesh datablock, since their
+ * derived meshes might also be referencing data which was just freed,
+ *
+ * Annoying enough, but currently seems most efficient way to avoid access
+ * of freed data on scene update, especially in cases when there are dependency
+ * cycles.
+ */
+ for (Object *other_object = G.main->object.first;
+ other_object != NULL;
+ other_object = other_object->id.next)
+ {
+ if (other_object->data == ob->data) {
+ BKE_object_free_derived_caches(other_object);
+ }
+ }
}
/**
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 880417a00cf..08ed9813456 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -73,6 +73,7 @@
#include "BKE_lamp.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
#include "BKE_key.h"
#include "BKE_main.h"
#include "BKE_material.h"
@@ -1112,12 +1113,18 @@ static void object_delete_check_glsl_update(Object *ob)
/* note: now unlinks constraints as well */
void ED_base_object_free_and_unlink(Main *bmain, Scene *scene, Base *base)
{
- DAG_id_type_tag(bmain, ID_OB);
+ if (BKE_library_ID_is_indirectly_used(bmain, base->object) && ID_REAL_USERS(base->object) <= 1) {
+ /* We cannot delete indirectly used object... */
+ printf("WARNING, undeletable object '%s', should have been catched before reaching this function!",
+ base->object->id.name + 2);
+ return;
+ }
+
BKE_scene_base_unlink(scene, base);
object_delete_check_glsl_update(base->object);
BKE_libblock_free_us(bmain, base->object);
- if (scene->basact == base) scene->basact = NULL;
MEM_freeN(base);
+ DAG_id_type_tag(bmain, ID_OB);
}
static int object_delete_exec(bContext *C, wmOperator *op)
@@ -1134,6 +1141,19 @@ static int object_delete_exec(bContext *C, wmOperator *op)
CTX_DATA_BEGIN (C, Base *, base, selected_bases)
{
+ const bool is_indirectly_used = BKE_library_ID_is_indirectly_used(bmain, base->object);
+ if (base->object->id.tag & LIB_TAG_INDIRECT) {
+ /* Can this case ever happen? */
+ BKE_reportf(op->reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", base->object->id.name + 2);
+ continue;
+ }
+ else if (is_indirectly_used && ID_REAL_USERS(base->object) <= 1) {
+ BKE_reportf(op->reports, RPT_WARNING,
+ "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user",
+ base->object->id.name + 2, scene->id.name + 2);
+ continue;
+ }
+
/* deselect object -- it could be used in other scenes */
base->object->flag &= ~SELECT;
@@ -1149,6 +1169,12 @@ static int object_delete_exec(bContext *C, wmOperator *op)
if (scene_iter != scene && !(scene_iter->id.lib)) {
base_other = BKE_scene_base_find(scene_iter, base->object);
if (base_other) {
+ if (is_indirectly_used && ID_REAL_USERS(base->object) <= 1) {
+ BKE_reportf(op->reports, RPT_WARNING,
+ "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user",
+ base->object->id.name + 2, scene_iter->id.name + 2);
+ break;
+ }
ED_base_object_free_and_unlink(bmain, scene_iter, base_other);
}
}
@@ -1292,7 +1318,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
basen->object = ob;
/* make sure apply works */
- BKE_animdata_free(&ob->id);
+ BKE_animdata_free(&ob->id, true);
ob->adt = NULL;
/* Proxies are not to be copied. */
@@ -1384,7 +1410,6 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
}
}
- /* The same how BKE_object_unlink detects which object proxies to clear. */
if (base->object->transflag & OB_DUPLIGROUP && base->object->dup_group) {
for (object = bmain->object.first; object; object = object->id.next) {
if (object->proxy_group == base->object) {
@@ -1605,7 +1630,7 @@ static int convert_exec(bContext *C, wmOperator *op)
if (newob->type == OB_CURVE) {
BKE_object_free_modifiers(newob); /* after derivedmesh calls! */
- ED_rigidbody_object_remove(scene, newob);
+ ED_rigidbody_object_remove(bmain, scene, newob);
}
}
else if (ob->type == OB_MESH && ob->modifiers.first) { /* converting a mesh with no modifiers causes a segfault */
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index efd1ebbd51b..d7b7fd7040e 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -1560,12 +1560,12 @@ void OBJECT_OT_constraints_copy(wmOperatorType *ot)
/************************ add constraint operators *********************/
/* get the Object and/or PoseChannel to use as target */
-static short get_new_constraint_target(bContext *C, int con_type, Object **tar_ob, bPoseChannel **tar_pchan, short add)
+static bool get_new_constraint_target(bContext *C, int con_type, Object **tar_ob, bPoseChannel **tar_pchan, bool add)
{
Object *obact = ED_object_active_context(C);
bPoseChannel *pchanact = BKE_pose_channel_active(obact);
- short only_curve = 0, only_mesh = 0, only_ob = 0;
- short found = 0;
+ bool only_curve = false, only_mesh = false, only_ob = false;
+ bool found = false;
/* clear tar_ob and tar_pchan fields before use
* - assume for now that both always exist...
@@ -1585,7 +1585,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
case CONSTRAINT_TYPE_ROTLIMIT:
case CONSTRAINT_TYPE_SIZELIMIT:
case CONSTRAINT_TYPE_SAMEVOL:
- return 0;
+ return false;
/* restricted target-type constraints -------------- */
/* NOTE: for these, we cannot try to add a target object if no valid ones are found, since that doesn't work */
@@ -1593,26 +1593,26 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
case CONSTRAINT_TYPE_CLAMPTO:
case CONSTRAINT_TYPE_FOLLOWPATH:
case CONSTRAINT_TYPE_SPLINEIK:
- only_curve = 1;
- only_ob = 1;
- add = 0;
+ only_curve = true;
+ only_ob = true;
+ add = false;
break;
/* mesh only? */
case CONSTRAINT_TYPE_SHRINKWRAP:
- only_mesh = 1;
- only_ob = 1;
- add = 0;
+ only_mesh = true;
+ only_ob = true;
+ add = false;
break;
/* object only - add here is ok? */
case CONSTRAINT_TYPE_RIGIDBODYJOINT:
- only_ob = 1;
+ only_ob = true;
break;
}
/* if the active Object is Armature, and we can search for bones, do so... */
- if ((obact->type == OB_ARMATURE) && (only_ob == 0)) {
+ if ((obact->type == OB_ARMATURE) && (only_ob == false)) {
/* search in list of selected Pose-Channels for target */
CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
{
@@ -1620,7 +1620,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
if (pchan != pchanact) {
*tar_ob = obact;
*tar_pchan = pchan;
- found = 1;
+ found = true;
break;
}
@@ -1629,36 +1629,50 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
}
/* if not yet found, try selected Objects... */
- if (found == 0) {
+ if (found == false) {
/* search in selected objects context */
CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
{
/* just use the first object we encounter (that isn't the active object)
* and which fulfills the criteria for the object-target that we've got
*/
- if ((ob != obact) &&
- ((!only_curve) || (ob->type == OB_CURVE)) &&
- ((!only_mesh) || (ob->type == OB_MESH)))
- {
- /* set target */
- *tar_ob = ob;
- found = 1;
-
- /* perform some special operations on the target */
- if (only_curve) {
- /* Curve-Path option must be enabled for follow-path constraints to be able to work */
- Curve *cu = (Curve *)ob->data;
- cu->flag |= CU_PATH;
+ if (ob != obact) {
+ /* for armatures in pose mode, look inside the armature for the active bone
+ * so that we set up cross-armature constraints with less effort
+ */
+ if ((ob->type == OB_ARMATURE) && (ob->mode & OB_MODE_POSE) &&
+ (!only_curve && !only_mesh))
+ {
+ /* just use the active bone, and assume that it is visible + usable */
+ *tar_ob = ob;
+ *tar_pchan = BKE_pose_channel_active(ob);
+ found = true;
+
+ break;
+ }
+ else if (((!only_curve) || (ob->type == OB_CURVE)) &&
+ ((!only_mesh) || (ob->type == OB_MESH)))
+ {
+ /* set target */
+ *tar_ob = ob;
+ found = true;
+
+ /* perform some special operations on the target */
+ if (only_curve) {
+ /* Curve-Path option must be enabled for follow-path constraints to be able to work */
+ Curve *cu = (Curve *)ob->data;
+ cu->flag |= CU_PATH;
+ }
+
+ break;
}
-
- break;
}
}
CTX_DATA_END;
}
/* if still not found, add a new empty to act as a target (if allowed) */
- if ((found == 0) && (add)) {
+ if ((found == false) && (add)) {
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Base *base = BASACT, *newbase = NULL;
@@ -1692,7 +1706,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
/* make our new target the new object */
*tar_ob = obt;
- found = 1;
+ found = true;
}
/* return whether there's any target */
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 06200778ee5..01a567931b3 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -946,6 +946,7 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event)
cu1 = base->object->data;
cu1->spacemode = cu->spacemode;
+ cu1->align_y = cu->align_y;
cu1->spacing = cu->spacing;
cu1->linedist = cu->linedist;
cu1->shear = cu->shear;
diff --git a/source/blender/editors/object/object_group.c b/source/blender/editors/object/object_group.c
index 76a8a68c42d..bcdd170c53c 100644
--- a/source/blender/editors/object/object_group.c
+++ b/source/blender/editors/object/object_group.c
@@ -43,6 +43,7 @@
#include "BKE_depsgraph.h"
#include "BKE_group.h"
#include "BKE_library.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_object.h"
@@ -527,7 +528,8 @@ static int group_unlink_exec(bContext *C, wmOperator *UNUSED(op))
if (!group)
return OPERATOR_CANCELLED;
- BKE_group_unlink(bmain, group);
+ BKE_libblock_unlink(bmain, group, false, false);
+ BKE_libblock_free(bmain, group);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 2f10f83e276..94d1a258063 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -437,7 +437,7 @@ typedef enum eObClearParentTypes {
EnumPropertyItem prop_clear_parent_types[] = {
{CLEAR_PARENT_ALL, "CLEAR", 0, "Clear Parent",
- "Completely clear the parenting relationship, including involved modifiers is any"},
+ "Completely clear the parenting relationship, including involved modifiers if any"},
{CLEAR_PARENT_KEEP_TRANSFORM, "CLEAR_KEEP_TRANSFORM", 0, "Clear and Keep Transformation",
"As 'Clear Parent', but keep the current visual transformations of the object"},
{CLEAR_PARENT_INVERSE, "CLEAR_INVERSE", 0, "Clear Parent Inverse",
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 3da3a451d66..30c102b70c5 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -1173,7 +1173,7 @@ static void PE_update_selection(Scene *scene, Object *ob, int useflag)
}
}
- psys_cache_edit_paths(scene, ob, edit, CFRA);
+ psys_cache_edit_paths(scene, ob, edit, CFRA, G.is_rendering);
/* disable update flag */
@@ -1289,7 +1289,7 @@ void PE_update_object(Scene *scene, Object *ob, int useflag)
PE_hide_keys_time(scene, edit, CFRA);
/* regenerate path caches */
- psys_cache_edit_paths(scene, ob, edit, CFRA);
+ psys_cache_edit_paths(scene, ob, edit, CFRA, G.is_rendering);
/* disable update flag */
LOOP_POINTS {
@@ -1634,7 +1634,7 @@ static int select_random_exec(bContext *C, wmOperator *op)
int p;
int k;
- const float randfac = RNA_float_get (op->ptr, "percent") / 100.0f;
+ const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f;
const int seed = WM_operator_properties_select_random_seed_increment_get(op);
const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
RNG *rng;
@@ -2288,7 +2288,7 @@ static int remove_tagged_particles(Object *ob, ParticleSystem *psys, int mirror)
npoint= new_points= MEM_callocN(new_totpart * sizeof(PTCacheEditPoint), "PTCacheEditKey array");
if (ELEM(NULL, new_pars, new_points)) {
- /* allocation error! */
+ /* allocation error! */
if (new_pars)
MEM_freeN(new_pars);
if (new_points)
diff --git a/source/blender/editors/physics/rigidbody_constraint.c b/source/blender/editors/physics/rigidbody_constraint.c
index f95599592b2..1bfc162a331 100644
--- a/source/blender/editors/physics/rigidbody_constraint.c
+++ b/source/blender/editors/physics/rigidbody_constraint.c
@@ -41,6 +41,7 @@
#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_group.h"
+#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_rigidbody.h"
@@ -70,7 +71,7 @@ static int ED_operator_rigidbody_con_active_poll(bContext *C)
}
-bool ED_rigidbody_constraint_add(Scene *scene, Object *ob, int type, ReportList *reports)
+bool ED_rigidbody_constraint_add(Main *bmain, Scene *scene, Object *ob, int type, ReportList *reports)
{
RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
@@ -81,7 +82,7 @@ bool ED_rigidbody_constraint_add(Scene *scene, Object *ob, int type, ReportList
}
/* create constraint group if it doesn't already exits */
if (rbw->constraints == NULL) {
- rbw->constraints = BKE_group_add(G.main, "RigidBodyConstraints");
+ rbw->constraints = BKE_group_add(bmain, "RigidBodyConstraints");
}
/* make rigidbody constraint settings */
ob->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, ob, type);
@@ -90,11 +91,12 @@ bool ED_rigidbody_constraint_add(Scene *scene, Object *ob, int type, ReportList
/* add constraint to rigid body constraint group */
BKE_group_object_add(rbw->constraints, ob, scene, NULL);
+ DAG_relations_tag_update(bmain);
DAG_id_tag_update(&ob->id, OB_RECALC_OB);
return true;
}
-void ED_rigidbody_constraint_remove(Scene *scene, Object *ob)
+void ED_rigidbody_constraint_remove(Main *bmain, Scene *scene, Object *ob)
{
RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
@@ -102,6 +104,7 @@ void ED_rigidbody_constraint_remove(Scene *scene, Object *ob)
if (rbw)
BKE_group_object_unlink(rbw->constraints, ob, scene, NULL);
+ DAG_relations_tag_update(bmain);
DAG_id_tag_update(&ob->id, OB_RECALC_OB);
}
@@ -112,6 +115,7 @@ void ED_rigidbody_constraint_remove(Scene *scene, Object *ob)
static int rigidbody_con_add_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
Object *ob = (scene) ? OBACT : NULL;
@@ -124,7 +128,7 @@ static int rigidbody_con_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
/* apply to active object */
- changed = ED_rigidbody_constraint_add(scene, ob, type, op->reports);
+ changed = ED_rigidbody_constraint_add(bmain, scene, ob, type, op->reports);
if (changed) {
/* send updates */
@@ -160,6 +164,7 @@ void RIGIDBODY_OT_constraint_add(wmOperatorType *ot)
static int rigidbody_con_remove_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob = (scene) ? OBACT : NULL;
@@ -173,7 +178,7 @@ static int rigidbody_con_remove_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
else {
- ED_rigidbody_constraint_remove(scene, ob);
+ ED_rigidbody_constraint_remove(bmain, scene, ob);
}
/* send updates */
diff --git a/source/blender/editors/physics/rigidbody_object.c b/source/blender/editors/physics/rigidbody_object.c
index 26d8af82b2d..30597d95497 100644
--- a/source/blender/editors/physics/rigidbody_object.c
+++ b/source/blender/editors/physics/rigidbody_object.c
@@ -46,6 +46,7 @@
#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_group.h"
+#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_rigidbody.h"
@@ -87,7 +88,7 @@ static int ED_operator_rigidbody_add_poll(bContext *C)
/* ----------------- */
-bool ED_rigidbody_object_add(Scene *scene, Object *ob, int type, ReportList *reports)
+bool ED_rigidbody_object_add(Main *bmain, Scene *scene, Object *ob, int type, ReportList *reports)
{
RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
@@ -107,7 +108,7 @@ bool ED_rigidbody_object_add(Scene *scene, Object *ob, int type, ReportList *rep
scene->rigidbody_world = rbw;
}
if (rbw->group == NULL) {
- rbw->group = BKE_group_add(G.main, "RigidBodyWorld");
+ rbw->group = BKE_group_add(bmain, "RigidBodyWorld");
}
/* make rigidbody object settings */
@@ -120,12 +121,13 @@ bool ED_rigidbody_object_add(Scene *scene, Object *ob, int type, ReportList *rep
/* add object to rigid body group */
BKE_group_object_add(rbw->group, ob, scene, NULL);
+ DAG_relations_tag_update(bmain);
DAG_id_tag_update(&ob->id, OB_RECALC_OB);
return true;
}
-void ED_rigidbody_object_remove(Scene *scene, Object *ob)
+void ED_rigidbody_object_remove(Main *bmain, Scene *scene, Object *ob)
{
RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
@@ -133,6 +135,7 @@ void ED_rigidbody_object_remove(Scene *scene, Object *ob)
if (rbw)
BKE_group_object_unlink(rbw->group, ob, scene, NULL);
+ DAG_relations_tag_update(bmain);
DAG_id_tag_update(&ob->id, OB_RECALC_OB);
}
@@ -143,13 +146,14 @@ void ED_rigidbody_object_remove(Scene *scene, Object *ob)
static int rigidbody_object_add_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob = ED_object_active_context(C);
int type = RNA_enum_get(op->ptr, "type");
bool changed;
/* apply to active object */
- changed = ED_rigidbody_object_add(scene, ob, type, op->reports);
+ changed = ED_rigidbody_object_add(bmain, scene, ob, type, op->reports);
if (changed) {
/* send updates */
@@ -186,13 +190,14 @@ void RIGIDBODY_OT_object_add(wmOperatorType *ot)
static int rigidbody_object_remove_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob = ED_object_active_context(C);
bool changed = false;
/* apply to active object */
if (!ELEM(NULL, ob, ob->rigidbody_object)) {
- ED_rigidbody_object_remove(scene, ob);
+ ED_rigidbody_object_remove(bmain, scene, ob);
changed = true;
}
@@ -232,13 +237,14 @@ void RIGIDBODY_OT_object_remove(wmOperatorType *ot)
static int rigidbody_objects_add_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
int type = RNA_enum_get(op->ptr, "type");
bool changed = false;
/* create rigid body objects and add them to the world's group */
CTX_DATA_BEGIN(C, Object *, ob, selected_objects) {
- changed |= ED_rigidbody_object_add(scene, ob, type, op->reports);
+ changed |= ED_rigidbody_object_add(bmain, scene, ob, type, op->reports);
}
CTX_DATA_END;
@@ -277,6 +283,7 @@ void RIGIDBODY_OT_objects_add(wmOperatorType *ot)
static int rigidbody_objects_remove_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
bool changed = false;
@@ -284,7 +291,7 @@ static int rigidbody_objects_remove_exec(bContext *C, wmOperator *UNUSED(op))
CTX_DATA_BEGIN(C, Object *, ob, selected_objects)
{
if (ob->rigidbody_object) {
- ED_rigidbody_object_remove(scene, ob);
+ ED_rigidbody_object_remove(bmain, scene, ob);
changed = true;
}
}
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index f4260a0cd33..132c3fa5438 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -70,6 +70,7 @@
#include "BKE_icons.h"
#include "BKE_lamp.h"
#include "BKE_library.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_node.h"
@@ -830,7 +831,7 @@ static void shader_preview_free(void *customdata)
/* get rid of copied material */
BLI_remlink(&pr_main->mat, sp->matcopy);
- BKE_material_free_ex(sp->matcopy, false);
+ BKE_material_free(sp->matcopy);
properties = IDP_GetProperties((ID *)sp->matcopy, false);
if (properties) {
@@ -862,7 +863,9 @@ static void shader_preview_free(void *customdata)
/* get rid of copied world */
BLI_remlink(&pr_main->world, sp->worldcopy);
- BKE_world_free_ex(sp->worldcopy, true); /* [#32865] - we need to unlink the texture copies, unlike for materials */
+ /* T32865 - we need to unlink the texture copies, unlike for materials */
+ BKE_libblock_relink_ex(sp->worldcopy, NULL, NULL, true);
+ BKE_world_free(sp->worldcopy);
properties = IDP_GetProperties((ID *)sp->worldcopy, false);
if (properties) {
@@ -878,6 +881,7 @@ static void shader_preview_free(void *customdata)
/* get rid of copied lamp */
BLI_remlink(&pr_main->lamp, sp->lampcopy);
+ BKE_libblock_relink_ex(sp->lampcopy, NULL, NULL, true);
BKE_lamp_free(sp->lampcopy);
properties = IDP_GetProperties((ID *)sp->lampcopy, false);
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index cbf87062955..93bac3f6660 100644
--- a/source/blender/editors/screen/glutil.c
+++ b/source/blender/editors/screen/glutil.c
@@ -327,6 +327,13 @@ float glaGetOneFloat(int param)
return v;
}
+int glaGetOneInt(int param)
+{
+ GLint v;
+ glGetIntegerv(param, &v);
+ return v;
+}
+
void glaRasterPosSafe2f(float x, float y, float known_good_x, float known_good_y)
{
GLubyte dummy = 0;
@@ -579,6 +586,10 @@ void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int fo
draw_h = min_ii(img_h - off_y, ceil((scissor[3] - rast_y) / yzoom));
if (draw_w > 0 && draw_h > 0) {
+
+ int bound_options;
+ GPU_BASIC_SHADER_DISABLE_AND_STORE(bound_options);
+
/* Don't use safe RasterPos (slower) if we can avoid it. */
if (rast_x >= 0 && rast_y >= 0) {
glRasterPos2f(rast_x, rast_y);
@@ -610,6 +621,8 @@ void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int fo
}
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+
+ GPU_BASIC_SHADER_ENABLE_AND_RESTORE(bound_options);
}
}
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index a459f982ada..62aeca4b9d1 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -45,6 +45,7 @@
#include "BKE_image.h"
#include "BKE_global.h"
#include "BKE_library.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_screen.h"
@@ -1755,7 +1756,9 @@ bool ED_screen_delete_scene(bContext *C, Scene *scene)
ED_screen_set_scene(C, CTX_wm_screen(C), newscene);
- BKE_scene_unlink(bmain, scene, newscene);
+ BKE_libblock_remap(bmain, scene, newscene, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE);
+
+ BKE_libblock_free(bmain, scene);
return true;
}
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index f340f716ccb..0c0a6c93b3e 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -2479,7 +2479,7 @@ static void SCREEN_OT_screen_full_area(wmOperatorType *ot)
{
PropertyRNA *prop;
- ot->name = "Toggle Fullscreen Area";
+ ot->name = "Toggle Maximize Area";
ot->description = "Toggle display selected area as fullscreen/maximized";
ot->idname = "SCREEN_OT_screen_full_area";
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index a716cae56dd..941f19ca0f0 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -401,7 +401,7 @@ static void image_undo_end(void)
UndoImageTile *tmp_tile = tile->next;
deallocsize += allocsize * ((tile->use_float) ? sizeof(float) : sizeof(char));
MEM_freeN(tile->rect.pt);
- BLI_freelinkN (lb, tile);
+ BLI_freelinkN(lb, tile);
tile = tmp_tile;
}
else {
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index d273f8320a1..6ed969cb270 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -202,7 +202,7 @@ typedef struct ProjPaintImage {
*/
typedef struct ProjStrokeHandle {
/* Support for painting from multiple views at once,
- * currently used to impliment summetry painting,
+ * currently used to impliment symmetry painting,
* we can assume at least the first is set while painting. */
struct ProjPaintState *ps_views[8];
int ps_views_tot;
@@ -717,7 +717,7 @@ static bool project_paint_PickColor(
}
/**
- * Check if 'pt' is infront of the 3 verts on the Z axis (used for screenspace occlusuion test)
+ * Check if 'pt' is infront of the 3 verts on the Z axis (used for screenspace occlusion test)
* \return
* - `0`: no occlusion
* - `-1`: no occlusion but 2D intersection is true
@@ -3717,7 +3717,7 @@ static void project_paint_prepare_all_faces(
}
/* tfbase here should be non-null! */
- BLI_assert (mloopuv_base != NULL);
+ BLI_assert(mloopuv_base != NULL);
if (is_face_sel && tpage) {
ProjPaintFaceCoSS coSS;
@@ -5858,7 +5858,9 @@ static int add_simple_uvs_exec(bContext *C, wmOperator *UNUSED(op))
Mesh *me = ob->data;
bool synch_selection = (scene->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
- BMesh *bm = BM_mesh_create(&bm_mesh_allocsize_default);
+ BMesh *bm = BM_mesh_create(
+ &bm_mesh_allocsize_default,
+ &((struct BMeshCreateParams){.use_toolflags = false,}));
/* turn synch selection off, since we are not in edit mode we need to ensure only the uv flags are tested */
scene->toolsettings->uv_flag &= ~UV_SYNC_SELECTION;
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index b6a7d671882..7e05ab929ae 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -101,6 +101,10 @@ bool ED_wpaint_fill(struct VPaint *wp, struct Object *ob, float paintweight);
bool ED_vpaint_smooth(struct Object *ob);
+typedef void (*VPaintTransform_Callback)(const float col[3], const void *user_data, float r_col[3]);
+
+bool ED_vpaint_color_transform(struct Object *ob, VPaintTransform_Callback vpaint_tx_fn, const void *user_data);
+
void PAINT_OT_weight_paint_toggle(struct wmOperatorType *ot);
void PAINT_OT_weight_paint(struct wmOperatorType *ot);
void PAINT_OT_weight_set(struct wmOperatorType *ot);
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index da7667c775e..bf923415f01 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -315,6 +315,241 @@ static void PAINT_OT_vertex_color_smooth(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+/** \name Vertex Color Transformations
+ * \{ */
+
+struct VPaintTx_BrightContrastData {
+ /* pre-calculated */
+ float gain;
+ float offset;
+};
+
+static void vpaint_tx_brightness_contrast(const float col[3], const void *user_data, float r_col[3])
+{
+ const struct VPaintTx_BrightContrastData *data = user_data;
+
+ for (int i = 0; i < 3; i++) {
+ r_col[i] = data->gain * col[i] + data->offset;
+ }
+}
+
+static int vertex_color_brightness_contrast_exec(bContext *C, wmOperator *op)
+{
+ Object *obact = CTX_data_active_object(C);
+
+ float gain, offset;
+ {
+ float brightness = RNA_float_get(op->ptr, "brightness");
+ float contrast = RNA_float_get(op->ptr, "contrast");
+ brightness /= 100.0f;
+ float delta = contrast / 200.0f;
+ gain = 1.0f - delta * 2.0f;
+ /*
+ * The algorithm is by Werner D. Streidt
+ * (http://visca.com/ffactory/archives/5-99/msg00021.html)
+ * Extracted of OpenCV demhist.c
+ */
+ if (contrast > 0) {
+ gain = 1.0f / ((gain != 0.0f) ? gain : FLT_EPSILON);
+ offset = gain * (brightness - delta);
+ }
+ else {
+ delta *= -1;
+ offset = gain * (brightness + delta);
+ }
+ }
+
+ const struct VPaintTx_BrightContrastData user_data = {
+ .gain = gain,
+ .offset = offset,
+ };
+
+ if (ED_vpaint_color_transform(obact, vpaint_tx_brightness_contrast, &user_data)) {
+ ED_region_tag_redraw(CTX_wm_region(C));
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static void PAINT_OT_vertex_color_brightness_contrast(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Vertex Paint Bright/Contrast";
+ ot->idname = "PAINT_OT_vertex_color_brightness_contrast";
+ ot->description = "Adjust vertex color brightness/contrast";
+
+ /* api callbacks */
+ ot->exec = vertex_color_brightness_contrast_exec;
+ ot->poll = vertex_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* params */
+ const float min = -100, max = +100;
+ prop = RNA_def_float(ot->srna, "brightness", 0.0f, min, max, "Brightness", "", min, max);
+ prop = RNA_def_float(ot->srna, "contrast", 0.0f, min, max, "Contrast", "", min, max);
+ RNA_def_property_ui_range(prop, min, max, 1, 1);
+}
+
+struct VPaintTx_HueSatData {
+ float hue;
+ float sat;
+ float val;
+};
+
+static void vpaint_tx_hsv(const float col[3], const void *user_data, float r_col[3])
+{
+ const struct VPaintTx_HueSatData *data = user_data;
+ float hsv[3];
+ rgb_to_hsv_v(col, hsv);
+
+ hsv[0] += (data->hue - 0.5f);
+ if (hsv[0] > 1.0f) {
+ hsv[0] -= 1.0f;
+ }
+ else if (hsv[0] < 0.0f) {
+ hsv[0] += 1.0f;
+ }
+ hsv[1] *= data->sat;
+ hsv[2] *= data->val;
+
+ hsv_to_rgb_v(hsv, r_col);
+}
+
+static int vertex_color_hsv_exec(bContext *C, wmOperator *op)
+{
+ Object *obact = CTX_data_active_object(C);
+
+ const struct VPaintTx_HueSatData user_data = {
+ .hue = RNA_float_get(op->ptr, "h"),
+ .sat = RNA_float_get(op->ptr, "s"),
+ .val = RNA_float_get(op->ptr, "v"),
+ };
+
+ if (ED_vpaint_color_transform(obact, vpaint_tx_hsv, &user_data)) {
+ ED_region_tag_redraw(CTX_wm_region(C));
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static void PAINT_OT_vertex_color_hsv(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Vertex Paint Hue Saturation Value";
+ ot->idname = "PAINT_OT_vertex_color_hsv";
+ ot->description = "Adjust vertex color HSV values";
+
+ /* api callbacks */
+ ot->exec = vertex_color_hsv_exec;
+ ot->poll = vertex_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* params */
+ RNA_def_float(ot->srna, "h", 0.5f, 0.0f, 1.0f, "Hue", "", 0.0f, 1.0f);
+ RNA_def_float(ot->srna, "s", 1.0f, 0.0f, 2.0f, "Saturation", "", 0.0f, 2.0f);
+ RNA_def_float(ot->srna, "v", 1.0f, 0.0f, 2.0f, "Value", "", 0.0f, 2.0f);
+}
+
+static void vpaint_tx_invert(const float col[3], const void *UNUSED(user_data), float r_col[3])
+{
+ for (int i = 0; i < 3; i++) {
+ r_col[i] = 1.0f - col[i];
+ }
+}
+
+static int vertex_color_invert_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obact = CTX_data_active_object(C);
+
+ if (ED_vpaint_color_transform(obact, vpaint_tx_invert, NULL)) {
+ ED_region_tag_redraw(CTX_wm_region(C));
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static void PAINT_OT_vertex_color_invert(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Vertex Paint Invert";
+ ot->idname = "PAINT_OT_vertex_color_invert";
+ ot->description = "Invert RGB values";
+
+ /* api callbacks */
+ ot->exec = vertex_color_invert_exec;
+ ot->poll = vertex_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
+struct VPaintTx_LevelsData {
+ float gain;
+ float offset;
+};
+
+static void vpaint_tx_levels(const float col[3], const void *user_data, float r_col[3])
+{
+ const struct VPaintTx_LevelsData *data = user_data;
+ for (int i = 0; i < 3; i++) {
+ r_col[i] = data->gain * (col[i] + data->offset);
+ }
+}
+
+static int vertex_color_levels_exec(bContext *C, wmOperator *op)
+{
+ Object *obact = CTX_data_active_object(C);
+
+ const struct VPaintTx_LevelsData user_data = {
+ .gain = RNA_float_get(op->ptr, "gain"),
+ .offset = RNA_float_get(op->ptr, "offset"),
+ };
+
+ if (ED_vpaint_color_transform(obact, vpaint_tx_levels, &user_data)) {
+ ED_region_tag_redraw(CTX_wm_region(C));
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static void PAINT_OT_vertex_color_levels(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Vertex Paint Levels";
+ ot->idname = "PAINT_OT_vertex_color_levels";
+ ot->description = "Adjust levels of vertex colors";
+
+ /* api callbacks */
+ ot->exec = vertex_color_levels_exec;
+ ot->poll = vertex_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* params */
+ RNA_def_float(ot->srna, "offset", 0.0f, -1.0f, 1.0f, "Offset", "Value to add to colors", -1.0f, 1.0f);
+ RNA_def_float(ot->srna, "gain", 1.0f, 0.0f, FLT_MAX, "Gain", "Value to multiply colors by", 0.0f, 10.0f);
+}
+
+/** \} */
+
+
static int brush_reset_exec(bContext *C, wmOperator *UNUSED(op))
{
Paint *paint = BKE_paint_get_active_from_context(C);
@@ -1112,6 +1347,11 @@ void ED_operatortypes_paint(void)
WM_operatortype_append(PAINT_OT_vertex_color_set);
WM_operatortype_append(PAINT_OT_vertex_color_smooth);
+ WM_operatortype_append(PAINT_OT_vertex_color_brightness_contrast);
+ WM_operatortype_append(PAINT_OT_vertex_color_hsv);
+ WM_operatortype_append(PAINT_OT_vertex_color_invert);
+ WM_operatortype_append(PAINT_OT_vertex_color_levels);
+
/* face-select */
WM_operatortype_append(PAINT_OT_face_select_linked);
WM_operatortype_append(PAINT_OT_face_select_linked_pick);
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index 65857cccb15..aa17cb02fe5 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -58,6 +58,8 @@
#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "GPU_basic_shader.h"
+
#include "ED_screen.h"
#include "ED_view3d.h"
@@ -160,11 +162,11 @@ static void paint_draw_line_cursor(bContext *C, int x, int y, void *customdata)
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
- glEnable(GL_LINE_STIPPLE);
- glLineStipple(3, 0xAAAA);
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ GPU_basic_shader_line_stipple(3, 0xAAAA);
+ GPU_basic_shader_line_width(3.0);
glColor4ub(0, 0, 0, paint->paint_cursor_col[3]);
- glLineWidth(3.0);
if (stroke->constrain_line) {
sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1],
stroke->constrained_pos[0], stroke->constrained_pos[1]);
@@ -175,7 +177,7 @@ static void paint_draw_line_cursor(bContext *C, int x, int y, void *customdata)
}
glColor4ub(255, 255, 255, paint->paint_cursor_col[3]);
- glLineWidth(1.0);
+ GPU_basic_shader_line_width(1.0);
if (stroke->constrain_line) {
sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1],
stroke->constrained_pos[0], stroke->constrained_pos[1]);
@@ -185,7 +187,7 @@ static void paint_draw_line_cursor(bContext *C, int x, int y, void *customdata)
x, y);
}
- glDisable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
@@ -1156,7 +1158,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (event->val == KM_RELEASE) {
copy_v2_fl2(mouse, event->mval[0], event->mval[1]);
paint_stroke_line_constrain(stroke, mouse);
- paint_stroke_line_end (C, op, stroke, mouse);
+ paint_stroke_line_end(C, op, stroke, mouse);
stroke_done(C, op);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 15ab4ca04a7..87855879ec5 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -502,6 +502,51 @@ bool ED_vpaint_smooth(Object *ob)
return true;
}
+/**
+ * Apply callback to each vertex of the active vertex color layer.
+ */
+bool ED_vpaint_color_transform(
+ struct Object *ob,
+ VPaintTransform_Callback vpaint_tx_fn,
+ const void *user_data)
+{
+ Mesh *me;
+ const MPoly *mp;
+
+ if (((me = BKE_mesh_from_object(ob)) == NULL) ||
+ (me->mloopcol == NULL && (make_vertexcol(ob) == false)))
+ {
+ return false;
+ }
+
+ const bool do_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ mp = me->mpoly;
+
+ for (int i = 0; i < me->totpoly; i++, mp++) {
+ MLoopCol *lcol = &me->mloopcol[mp->loopstart];
+
+ if (do_face_sel && !(mp->flag & ME_FACE_SEL)) {
+ continue;
+ }
+
+ for (int j = 0; j < mp->totloop; j++, lcol++) {
+ float col[3];
+ rgb_uchar_to_float(col, &lcol->r);
+
+ vpaint_tx_fn(col, user_data, col);
+
+ rgb_float_to_uchar(&lcol->r, col);
+ }
+ }
+
+ /* remove stale me->mcol, will be added later */
+ BKE_mesh_tessface_clear(me);
+
+ DAG_id_tag_update(&me->id, 0);
+
+ return true;
+}
+
/* XXX: should be re-implemented as a vertex/weight paint 'color correct' operator */
#if 0
void vpaint_dogamma(Scene *scene)
@@ -1323,7 +1368,7 @@ static bool do_weight_paint_normalize_all_locked(
/**
* \note same as function above except it does a second pass without active group
- * if nomalize fails with it.
+ * if normalize fails with it.
*/
static void do_weight_paint_normalize_all_locked_try_active(
MDeformVert *dvert, const int defbase_tot, const bool *vgroup_validmap,
@@ -1340,7 +1385,7 @@ static void do_weight_paint_normalize_all_locked_try_active(
* - With 1.0 weight painted into active:
* nonzero locked weight; first pass zeroed out unlocked weight; scale 1 down to fit.
* - With 0.0 weight painted into active:
- * no unlocked groups; first pass did nothing; increaze 0 to fit.
+ * no unlocked groups; first pass did nothing; increase 0 to fit.
*/
do_weight_paint_normalize_all_locked(dvert, defbase_tot, vgroup_validmap, lock_flags);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index c173156de3a..0931456058d 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -5001,7 +5001,9 @@ void sculpt_dynamic_topology_enable(bContext *C)
BKE_mesh_mselect_clear(me);
/* Create triangles-only BMesh */
- ss->bm = BM_mesh_create(&allocsize);
+ ss->bm = BM_mesh_create(
+ &allocsize,
+ &((struct BMeshCreateParams){.use_toolflags = false,}));
BM_mesh_bm_from_me(
ss->bm, me, (&(struct BMeshFromMeshParams){
@@ -5011,7 +5013,9 @@ void sculpt_dynamic_topology_enable(bContext *C)
BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK);
sculpt_dyntopo_node_layers_add(ss);
/* make sure the data for existing faces are initialized */
- BM_mesh_normals_update(ss->bm);
+ if (me->totpoly != ss->bm->totface) {
+ BM_mesh_normals_update(ss->bm);
+ }
/* Enable dynamic topology */
me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
@@ -5088,6 +5092,8 @@ static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(o
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
+ WM_cursor_wait(1);
+
if (ss->bm) {
sculpt_undo_push_begin("Dynamic topology disable");
sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_END);
@@ -5100,16 +5106,24 @@ static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(o
}
sculpt_undo_push_end(C);
+ WM_cursor_wait(0);
+
return OPERATOR_FINISHED;
}
+enum eDynTopoWarnFlag {
+ DYNTOPO_WARN_VDATA = (1 << 0),
+ DYNTOPO_WARN_EDATA = (1 << 1),
+ DYNTOPO_WARN_LDATA = (1 << 2),
+ DYNTOPO_WARN_MODIFIER = (1 << 3),
+};
-static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, bool vdata, bool modifiers)
+static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, enum eDynTopoWarnFlag flag)
{
uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Warning!"), ICON_ERROR);
uiLayout *layout = UI_popup_menu_layout(pup);
- if (vdata) {
+ if (flag & (DYNTOPO_WARN_VDATA | DYNTOPO_WARN_EDATA | DYNTOPO_WARN_LDATA)) {
const char *msg_error = TIP_("Vertex Data Detected!");
const char *msg = TIP_("Dyntopo will not preserve vertex colors, UVs, or other customdata");
uiItemL(layout, msg_error, ICON_INFO);
@@ -5117,7 +5131,7 @@ static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, bool vdata, bo
uiItemS(layout);
}
- if (modifiers) {
+ if (flag & DYNTOPO_WARN_MODIFIER) {
const char *msg_error = TIP_("Generative Modifiers Detected!");
const char *msg = TIP_("Keeping the modifiers will increase polycount when returning to object mode");
@@ -5133,33 +5147,35 @@ static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, bool vdata, bo
return OPERATOR_INTERFACE;
}
-
-static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+static enum eDynTopoWarnFlag sculpt_dynamic_topology_check(bContext *C)
{
Object *ob = CTX_data_active_object(C);
Mesh *me = ob->data;
SculptSession *ss = ob->sculpt;
- if (!ss->bm) {
- Scene *scene = CTX_data_scene(C);
- ModifierData *md;
- VirtualModifierData virtualModifierData;
- int i;
- bool vdata = false;
- bool modifiers = false;
-
- for (i = 0; i < CD_NUMTYPES; i++) {
- if (!ELEM(i, CD_MVERT, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX) &&
- (CustomData_has_layer(&me->vdata, i) ||
- CustomData_has_layer(&me->edata, i) ||
- CustomData_has_layer(&me->ldata, i)))
- {
- vdata = true;
- break;
+ Scene *scene = CTX_data_scene(C);
+ enum eDynTopoWarnFlag flag = 0;
+
+ BLI_assert(ss->bm == NULL);
+ UNUSED_VARS_NDEBUG(ss);
+
+ for (int i = 0; i < CD_NUMTYPES; i++) {
+ if (!ELEM(i, CD_MVERT, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX)) {
+ if (CustomData_has_layer(&me->vdata, i)) {
+ flag |= DYNTOPO_WARN_VDATA;
+ }
+ if (CustomData_has_layer(&me->edata, i)) {
+ flag |= DYNTOPO_WARN_EDATA;
+ }
+ if (CustomData_has_layer(&me->ldata, i)) {
+ flag |= DYNTOPO_WARN_LDATA;
}
}
+ }
- md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ {
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
/* exception for shape keys because we can edit those */
for (; md; md = md->next) {
@@ -5167,14 +5183,26 @@ static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, co
if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue;
if (mti->type == eModifierTypeType_Constructive) {
- modifiers = true;
+ flag |= DYNTOPO_WARN_MODIFIER;
break;
}
}
+ }
- if (vdata || modifiers) {
+ return flag;
+}
+
+static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+
+ if (!ss->bm) {
+ enum eDynTopoWarnFlag flag = sculpt_dynamic_topology_check(C);
+
+ if (flag) {
/* The mesh has customdata that will be lost, let the user confirm this is OK */
- return dyntopo_warning_popup(C, op->type, vdata, modifiers);
+ return dyntopo_warning_popup(C, op->type, flag);
}
}
@@ -5249,6 +5277,8 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op))
sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_SYMMETRIZE);
BM_log_before_all_removed(ss->bm, ss->bm_log);
+ BM_mesh_toolflags_set(ss->bm, true);
+
/* Symmetrize and re-triangulate */
BMO_op_callf(ss->bm, BMO_FLAG_DEFAULTS,
"symmetrize input=%avef direction=%i dist=%f",
@@ -5258,6 +5288,8 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op))
/* bisect operator flags edges (keep tags clean for edge queue) */
BM_mesh_elem_hflag_disable_all(ss->bm, BM_EDGE, BM_ELEM_TAG, false);
+ BM_mesh_toolflags_set(ss->bm, false);
+
/* Finish undo */
BM_log_all_added(ss->bm, ss->bm_log);
sculpt_undo_push_end(C);
@@ -5327,6 +5359,9 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
* mode to ensure the undo stack stays in a consistent
* state */
sculpt_dynamic_topology_toggle_exec(C, NULL);
+
+ /* store so we know to re-enable when entering sculpt mode */
+ me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
}
/* Leave sculptmode */
@@ -5340,12 +5375,6 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
/* Enter sculptmode */
ob->mode |= mode_flag;
- /* Remove dynamic-topology flag; this will be enabled if the
- * file was saved with dynamic topology on, but we don't
- * automatically re-enter dynamic-topology mode when loading a
- * file. */
- me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
-
if (flush_recalc)
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
@@ -5399,6 +5428,49 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
BKE_paint_init(scene, ePaintSculpt, PAINT_CURSOR_SCULPT);
paint_cursor_start(C, sculpt_poll_view3d);
+
+ /* Check dynamic-topology flag; re-enter dynamic-topology mode when changing modes,
+ * As long as no data was added that is not supported. */
+ if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
+ const char *message_unsupported = NULL;
+ if (me->totloop != me->totpoly * 3) {
+ message_unsupported = TIP_("non-triangle face");
+ }
+ else if (mmd != NULL) {
+ message_unsupported = TIP_("multi-res modifier");
+ }
+ else {
+ enum eDynTopoWarnFlag flag = sculpt_dynamic_topology_check(C);
+ if (flag == 0) {
+ /* pass */
+ }
+ else if (flag & DYNTOPO_WARN_VDATA) {
+ message_unsupported = TIP_("vertex data");
+ }
+ else if (flag & DYNTOPO_WARN_EDATA) {
+ message_unsupported = TIP_("edge data");
+ }
+ else if (flag & DYNTOPO_WARN_LDATA) {
+ message_unsupported = TIP_("face data");
+ }
+ else if (flag & DYNTOPO_WARN_MODIFIER) {
+ message_unsupported = TIP_("constructive modifier");
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+
+ if (message_unsupported == NULL) {
+ sculpt_dynamic_topology_enable(C);
+ }
+ else {
+ BKE_reportf(op->reports, RPT_WARNING,
+ "Dynamic Topology found: %s, disabled",
+ message_unsupported);
+ me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
+ }
+ }
}
if (ob->derivedFinal) /* VBO no longer valid */
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index ceefda99002..44bd872d107 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -366,7 +366,9 @@ static void sculpt_undo_bmesh_enable(Object *ob,
sculpt_pbvh_clear(ob);
/* Create empty BMesh and enable logging */
- ss->bm = BM_mesh_create(&bm_mesh_allocsize_default);
+ ss->bm = BM_mesh_create(
+ &bm_mesh_allocsize_default,
+ &((struct BMeshCreateParams){.use_toolflags = false,}));
BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK);
sculpt_dyntopo_node_layers_add(ss);
me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c
index a4d9a920cbb..4931426d62e 100644
--- a/source/blender/editors/sound/sound_ops.c
+++ b/source/blender/editors/sound/sound_ops.c
@@ -116,7 +116,7 @@ static int sound_open_exec(bContext *C, wmOperator *op)
info = AUD_getInfo(sound->playback_handle);
if (info.specs.channels == AUD_CHANNELS_INVALID) {
- BKE_sound_delete(bmain, sound);
+ BKE_libblock_free(bmain, sound);
if (op->customdata) MEM_freeN(op->customdata);
BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
return OPERATOR_CANCELLED;
diff --git a/source/blender/editors/space_action/action_intern.h b/source/blender/editors/space_action/action_intern.h
index 50e10e7e154..408eb38d386 100644
--- a/source/blender/editors/space_action/action_intern.h
+++ b/source/blender/editors/space_action/action_intern.h
@@ -59,6 +59,8 @@ void draw_channel_strips(struct bAnimContext *ac, struct SpaceAction *saction, s
void ACTION_OT_select_all_toggle(struct wmOperatorType *ot);
void ACTION_OT_select_border(struct wmOperatorType *ot);
+void ACTION_OT_select_lasso(struct wmOperatorType *ot);
+void ACTION_OT_select_circle(struct wmOperatorType *ot);
void ACTION_OT_select_column(struct wmOperatorType *ot);
void ACTION_OT_select_linked(struct wmOperatorType *ot);
void ACTION_OT_select_more(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_action/action_ops.c b/source/blender/editors/space_action/action_ops.c
index f69f9944f8a..a261202b690 100644
--- a/source/blender/editors/space_action/action_ops.c
+++ b/source/blender/editors/space_action/action_ops.c
@@ -59,6 +59,8 @@ void action_operatortypes(void)
WM_operatortype_append(ACTION_OT_clickselect);
WM_operatortype_append(ACTION_OT_select_all_toggle);
WM_operatortype_append(ACTION_OT_select_border);
+ WM_operatortype_append(ACTION_OT_select_lasso);
+ WM_operatortype_append(ACTION_OT_select_circle);
WM_operatortype_append(ACTION_OT_select_column);
WM_operatortype_append(ACTION_OT_select_linked);
WM_operatortype_append(ACTION_OT_select_more);
@@ -178,6 +180,14 @@ static void action_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_border", BKEY, KM_PRESS, KM_ALT, 0);
RNA_boolean_set(kmi->ptr, "axis_range", true);
+ /* region select */
+ kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0);
+ RNA_boolean_set(kmi->ptr, "deselect", false);
+ kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "deselect", true);
+
+ WM_keymap_add_item(keymap, "ACTION_OT_select_circle", CKEY, KM_PRESS, 0, 0);
+
/* column select */
RNA_enum_set(WM_keymap_add_item(keymap, "ACTION_OT_select_column", KKEY, KM_PRESS, 0, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_KEYS);
RNA_enum_set(WM_keymap_add_item(keymap, "ACTION_OT_select_column", KKEY, KM_PRESS, KM_CTRL, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_CFRA);
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index f2813b2a8d3..7900217e28e 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -36,6 +36,7 @@
#include "BLI_blenlib.h"
#include "BLI_dlrbTree.h"
+#include "BLI_lasso.h"
#include "BLI_utildefines.h"
#include "DNA_anim_types.h"
@@ -375,6 +376,264 @@ void ACTION_OT_select_border(wmOperatorType *ot)
ot->prop = RNA_def_boolean(ot->srna, "axis_range", 0, "Axis Range", "");
}
+/* ******************** Region Select Operators ***************************** */
+/* "Region Select" operators include the Lasso and Circle Select operators.
+ * These two ended up being lumped together, as it was easier in the
+ * original Graph Editor implementation of these to do it this way.
+ */
+
+static void region_select_action_keys(bAnimContext *ac, const rctf *rectf_view, short mode, short selectmode, void *data)
+{
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+
+ KeyframeEditData ked;
+ KeyframeEditFunc ok_cb, select_cb;
+ View2D *v2d = &ac->ar->v2d;
+ rctf rectf, scaled_rectf;
+ float ymin = 0, ymax = (float)(-ACHANNEL_HEIGHT_HALF);
+
+ /* convert mouse coordinates to frame ranges and channel coordinates corrected for view pan/zoom */
+ UI_view2d_region_to_view_rctf(v2d, rectf_view, &rectf);
+
+ /* filter data */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS);
+ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+
+ /* get beztriple editing/validation funcs */
+ select_cb = ANIM_editkeyframes_select(selectmode);
+ ok_cb = ANIM_editkeyframes_ok(mode);
+
+ /* init editing data */
+ memset(&ked, 0, sizeof(KeyframeEditData));
+ if (mode == BEZT_OK_CHANNEL_LASSO) {
+ KeyframeEdit_LassoData *data_lasso = data;
+ data_lasso->rectf_scaled = &scaled_rectf;
+ ked.data = data_lasso;
+ }
+ else if (mode == BEZT_OK_CHANNEL_CIRCLE) {
+ KeyframeEdit_CircleData *data_circle = data;
+ data_circle->rectf_scaled = &scaled_rectf;
+ ked.data = data;
+ }
+ else {
+ ked.data = &scaled_rectf;
+ }
+
+ /* loop over data, doing region select */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt = ANIM_nla_mapping_get(ac, ale);
+
+ /* get new vertical minimum extent of channel */
+ ymin = ymax - ACHANNEL_STEP;
+
+ /* compute midpoint of channel (used for testing if the key is in the region or not) */
+ ked.channel_y = ymin + ACHANNEL_HEIGHT_HALF;
+
+ /* if channel is mapped in NLA, apply correction
+ * - Apply to the bounds being checked, not all the keyframe points,
+ * to avoid having scaling everything
+ * - Save result to the scaled_rect, which is all that these operators
+ * will read from
+ */
+ if (adt) {
+ ked.iterflags &= ~(KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP);
+ ked.f1 = BKE_nla_tweakedit_remap(adt, rectf.xmin, NLATIME_CONVERT_UNMAP);
+ ked.f2 = BKE_nla_tweakedit_remap(adt, rectf.xmax, NLATIME_CONVERT_UNMAP);
+ }
+ else {
+ ked.iterflags |= (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP); /* for summary tracks */
+ ked.f1 = rectf.xmin;
+ ked.f2 = rectf.xmax;
+ }
+
+ /* Update values for scaled_rectf - which is used to compute the mapping in the callbacks
+ * NOTE: Since summary tracks need late-binding remapping, the callbacks may overwrite these
+ * with the properly remapped ked.f1/f2 values, when needed
+ */
+ scaled_rectf.xmin = ked.f1;
+ scaled_rectf.xmax = ked.f2;
+ scaled_rectf.ymin = ymin;
+ scaled_rectf.ymax = ymax;
+
+ /* perform vertical suitability check (if applicable) */
+ if ((mode == ACTKEYS_BORDERSEL_FRAMERANGE) ||
+ !((ymax < rectf.ymin) || (ymin > rectf.ymax)))
+ {
+ /* loop over data selecting */
+ switch (ale->type) {
+ case ANIMTYPE_GPDATABLOCK:
+ {
+ bGPdata *gpd = ale->data;
+ bGPDlayer *gpl;
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ ED_gplayer_frames_select_region(&ked, ale->data, mode, selectmode);
+ }
+ break;
+ }
+ case ANIMTYPE_GPLAYER:
+ {
+ ED_gplayer_frames_select_region(&ked, ale->data, mode, selectmode);
+ break;
+ }
+ case ANIMTYPE_MASKDATABLOCK:
+ {
+ Mask *mask = ale->data;
+ MaskLayer *masklay;
+ for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
+ ED_masklayer_frames_select_region(&ked, masklay, mode, selectmode);
+ }
+ break;
+ }
+ case ANIMTYPE_MASKLAYER:
+ {
+ ED_masklayer_frames_select_region(&ked, ale->data, mode, selectmode);
+ break;
+ }
+ default:
+ ANIM_animchannel_keyframes_loop(&ked, ac->ads, ale, ok_cb, select_cb, NULL);
+ break;
+ }
+ }
+
+ /* set minimum extent to be the maximum of the next channel */
+ ymax = ymin;
+ }
+
+ /* cleanup */
+ ANIM_animdata_freelist(&anim_data);
+}
+
+/* ----------------------------------- */
+
+static int actkeys_lassoselect_exec(bContext *C, wmOperator *op)
+{
+ bAnimContext ac;
+
+ KeyframeEdit_LassoData data_lasso;
+ rcti rect;
+ rctf rect_fl;
+
+ short selectmode;
+ bool extend;
+
+ /* get editor data */
+ if (ANIM_animdata_get_context(C, &ac) == 0)
+ return OPERATOR_CANCELLED;
+
+ data_lasso.rectf_view = &rect_fl;
+ data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot);
+ if (data_lasso.mcords == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* clear all selection if not extending selection */
+ extend = RNA_boolean_get(op->ptr, "extend");
+ if (!extend)
+ deselect_action_keys(&ac, 1, SELECT_SUBTRACT);
+
+ if (!RNA_boolean_get(op->ptr, "deselect"))
+ selectmode = SELECT_ADD;
+ else
+ selectmode = SELECT_SUBTRACT;
+
+ /* get settings from operator */
+ BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot);
+ BLI_rctf_rcti_copy(&rect_fl, &rect);
+
+ /* apply borderselect action */
+ region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_LASSO, selectmode, &data_lasso);
+
+ MEM_freeN((void *)data_lasso.mcords);
+
+ /* send notifier that keyframe selection has changed */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void ACTION_OT_select_lasso(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Lasso Select";
+ ot->description = "Select keyframe points using lasso selection";
+ ot->idname = "ACTION_OT_select_lasso";
+
+ /* api callbacks */
+ ot->invoke = WM_gesture_lasso_invoke;
+ ot->modal = WM_gesture_lasso_modal;
+ ot->exec = actkeys_lassoselect_exec;
+ ot->poll = ED_operator_action_active;
+ ot->cancel = WM_gesture_lasso_cancel;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
+ RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Deselect rather than select items");
+ RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first");
+}
+
+/* ------------------- */
+
+static int action_circle_select_exec(bContext *C, wmOperator *op)
+{
+ bAnimContext ac;
+ const int gesture_mode = RNA_int_get(op->ptr, "gesture_mode");
+ const short selectmode = (gesture_mode == GESTURE_MODAL_SELECT) ? SELECT_ADD : SELECT_SUBTRACT;
+
+ KeyframeEdit_CircleData data = {0};
+ rctf rect_fl;
+
+ float x = RNA_int_get(op->ptr, "x");
+ float y = RNA_int_get(op->ptr, "y");
+ float radius = RNA_int_get(op->ptr, "radius");
+
+ /* get editor data */
+ if (ANIM_animdata_get_context(C, &ac) == 0)
+ return OPERATOR_CANCELLED;
+
+ data.mval[0] = x;
+ data.mval[1] = y;
+ data.radius_squared = radius * radius;
+ data.rectf_view = &rect_fl;
+
+ rect_fl.xmin = x - radius;
+ rect_fl.xmax = x + radius;
+ rect_fl.ymin = y - radius;
+ rect_fl.ymax = y + radius;
+
+ /* apply region select action */
+ region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_CIRCLE, selectmode, &data);
+
+ /* send notifier that keyframe selection has changed */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void ACTION_OT_select_circle(wmOperatorType *ot)
+{
+ ot->name = "Circle Select";
+ ot->description = "Select keyframe points using circle selection";
+ ot->idname = "ACTION_OT_select_circle";
+
+ ot->invoke = WM_gesture_circle_invoke;
+ ot->modal = WM_gesture_circle_modal;
+ ot->exec = action_circle_select_exec;
+ ot->poll = ED_operator_action_active;
+ ot->cancel = WM_gesture_circle_cancel;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
+ RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
+ RNA_def_int(ot->srna, "radius", 1, 1, INT_MAX, "Radius", "", 1, INT_MAX);
+ RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
+}
+
/* ******************** Column Select Operator **************************** */
/* This operator works in one of four ways:
* - 1) select all keyframes in the same frame as a selected one (KKEY)
diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c
index 60240109432..671d6bb083e 100644
--- a/source/blender/editors/space_action/space_action.c
+++ b/source/blender/editors/space_action/space_action.c
@@ -33,6 +33,7 @@
#include <stdio.h>
#include "DNA_action_types.h"
+#include "DNA_group_types.h"
#include "DNA_scene_types.h"
#include "MEM_guardedalloc.h"
@@ -614,6 +615,19 @@ static void action_refresh(const bContext *C, ScrArea *sa)
// XXX re-sizing y-extents of tot should go here?
}
+static void action_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceAction *sact = (SpaceAction *)slink;
+
+ if (!ELEM(GS(old_id->name), ID_GR)) {
+ return;
+ }
+
+ if ((ID *)sact->ads.filter_grp == old_id) {
+ sact->ads.filter_grp = (Group *)new_id;
+ }
+}
+
/* only called once, from space/spacetypes.c */
void ED_spacetype_action(void)
{
@@ -631,7 +645,8 @@ void ED_spacetype_action(void)
st->keymap = action_keymap;
st->listener = action_listener;
st->refresh = action_refresh;
-
+ st->id_remap = action_id_remap;
+
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype action region");
art->regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c
index 42e2d6b90f0..5b03bdd7761 100644
--- a/source/blender/editors/space_buttons/buttons_context.c
+++ b/source/blender/editors/space_buttons/buttons_context.c
@@ -1180,33 +1180,3 @@ ID *buttons_context_id_path(const bContext *C)
return NULL;
}
-
-void ED_buttons_id_unref(SpaceButs *sbuts, const ID *id)
-{
- if (sbuts->pinid == id) {
- sbuts->pinid = NULL;
- sbuts->flag &= ~SB_PIN_CONTEXT;
- }
-
- if (sbuts->path) {
- ButsContextPath *path = sbuts->path;
- int i;
-
- for (i = 0; i < path->len; i++) {
- if (path->ptr[i].id.data == id) {
- break;
- }
- }
-
- if (i == path->len) {
- /* pass */
- }
- else if (i == 0) {
- MEM_SAFE_FREE(sbuts->path);
- }
- else {
- memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));
- path->len = i;
- }
- }
-}
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index 126a27c36cb..e4c23ad74f8 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -45,6 +45,8 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "RNA_access.h"
+
#include "buttons_intern.h" /* own include */
/* ******************** default callbacks for buttons space ***************** */
@@ -389,6 +391,59 @@ static void buttons_area_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *
ED_area_tag_redraw(sa);
}
+static void buttons_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceButs *sbuts = (SpaceButs *)slink;
+
+ if (sbuts->pinid == old_id) {
+ sbuts->pinid = new_id;
+ if (new_id == NULL) {
+ sbuts->flag &= ~SB_PIN_CONTEXT;
+ }
+ }
+
+ if (sbuts->path) {
+ ButsContextPath *path = sbuts->path;
+ int i;
+
+ for (i = 0; i < path->len; i++) {
+ if (path->ptr[i].id.data == old_id) {
+ break;
+ }
+ }
+
+ if (i == path->len) {
+ /* pass */
+ }
+ else if (new_id == NULL) {
+ if (i == 0) {
+ MEM_SAFE_FREE(sbuts->path);
+ }
+ else {
+ memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));
+ path->len = i;
+ }
+ }
+ else {
+ RNA_id_pointer_create(new_id, &path->ptr[i]);
+ /* There is no easy way to check/make path downwards valid, just nullify it.
+ * Next redraw will rebuild this anyway. */
+ i++;
+ memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));
+ path->len = i;
+ }
+ }
+
+ if (sbuts->texuser) {
+ ButsContextTexture *ct = sbuts->texuser;
+ if ((ID *)ct->texture == old_id) {
+ ct->texture = (Tex *)new_id;
+ }
+ BLI_freelistN(&ct->users);
+ ct->user = NULL;
+ }
+}
+
/* only called once, from space/spacetypes.c */
void ED_spacetype_buttons(void)
{
@@ -406,7 +461,8 @@ void ED_spacetype_buttons(void)
st->keymap = buttons_keymap;
st->listener = buttons_area_listener;
st->context = buttons_context;
-
+ st->id_remap = buttons_id_remap;
+
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype buttons region");
art->regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c
index 1c5be3d1fb5..695d04d3850 100644
--- a/source/blender/editors/space_clip/clip_draw.c
+++ b/source/blender/editors/space_clip/clip_draw.c
@@ -336,8 +336,10 @@ static void draw_stabilization_border(SpaceClip *sc, ARegion *ar, int width, int
/* draw boundary border for frame if stabilization is enabled */
if (sc->flag & SC_SHOW_STABLE && clip->tracking.stabilization.flag & TRACKING_2D_STABILIZATION) {
glColor3f(0.0f, 0.0f, 0.0f);
- glLineStipple(3, 0xaaaa);
- glEnable(GL_LINE_STIPPLE);
+
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ GPU_basic_shader_line_stipple(3, 0xAAAA);
+
glEnable(GL_COLOR_LOGIC_OP);
glLogicOp(GL_NOR);
@@ -357,7 +359,7 @@ static void draw_stabilization_border(SpaceClip *sc, ARegion *ar, int width, int
glPopMatrix();
glDisable(GL_COLOR_LOGIC_OP);
- glDisable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
}
}
@@ -627,8 +629,8 @@ static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTra
glEnd();
glColor3f(0.0f, 0.0f, 0.0f);
- glLineStipple(3, 0xaaaa);
- glEnable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ GPU_basic_shader_line_stipple(3, 0xAAAA);
glEnable(GL_COLOR_LOGIC_OP);
glLogicOp(GL_NOR);
@@ -638,7 +640,7 @@ static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTra
glEnd();
glDisable(GL_COLOR_LOGIC_OP);
- glDisable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
}
}
@@ -647,8 +649,11 @@ static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTra
glTranslate2fv(marker_pos);
if (tiny) {
- glLineStipple(3, 0xaaaa);
- glEnable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ GPU_basic_shader_line_stipple(3, 0xAAAA);
+ }
+ else {
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE);
}
if ((track->pat_flag & SELECT) == sel && (sc->flag & SC_SHOW_MARKER_PATTERN)) {
@@ -713,8 +718,12 @@ static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTra
glEnd();
}
- if (tiny)
- glDisable(GL_LINE_STIPPLE);
+ if (tiny) {
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ }
+ else {
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE);
+ }
glPopMatrix();
}
@@ -852,16 +861,12 @@ static void draw_marker_slide_zones(SpaceClip *sc, MovieTrackingTrack *track, Mo
glLineWidth(outline ? 3.0f : 1.0f);
- glEnable(GL_LINE_STIPPLE);
- glLineStipple(3, 0xaaaa);
-
glBegin(GL_LINES);
glVertex2f(0.0f, 0.0f);
glVertex2fv(tilt_ctrl);
glEnd();
- glDisable(GL_LINE_STIPPLE);
-
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
/* slider to control pattern tilt */
draw_marker_slide_square(tilt_ctrl[0], tilt_ctrl[1], patdx, patdy, outline, px);
@@ -1133,11 +1138,14 @@ static void draw_plane_marker_ex(SpaceClip *sc, Scene *scene, MovieTrackingPlane
const bool thick = draw_outline && !tiny;
if (stipple) {
- glLineStipple(3, 0xaaaa);
- glEnable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ GPU_basic_shader_line_stipple(3, 0xAAAA);
+ }
+ else {
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE);
}
- glLineWidth(thick ? 3.0f : 1.0f);
+ GPU_basic_shader_line_width(thick ? 3.0f : 1.0f);
/* Draw rectangle itself. */
glBegin(GL_LINE_LOOP);
@@ -1169,8 +1177,12 @@ static void draw_plane_marker_ex(SpaceClip *sc, Scene *scene, MovieTrackingPlane
glPopAttrib();
}
- if (stipple)
- glDisable(GL_LINE_STIPPLE);
+ if (stipple) {
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ }
+ else {
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE);
+ }
}
/* Draw sliders. */
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index e1d4e4fabc5..415839ab761 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -45,6 +45,7 @@
#include "BKE_context.h"
#include "BKE_screen.h"
+#include "BKE_library.h"
#include "BKE_movieclip.h"
#include "BKE_tracking.h"
@@ -1512,6 +1513,25 @@ static void clip_properties_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED
/********************* registration ********************/
+static void clip_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceClip *sclip = (SpaceClip *)slink;
+
+ if (!ELEM(GS(old_id->name), ID_MC, ID_MSK)) {
+ return;
+ }
+
+ if ((ID *)sclip->clip == old_id) {
+ sclip->clip = (MovieClip *)new_id;
+ id_us_ensure_real(new_id);
+ }
+
+ if ((ID *)sclip->mask_info.mask == old_id) {
+ sclip->mask_info.mask = (Mask *)new_id;
+ id_us_ensure_real(new_id);
+ }
+}
+
/* only called once, from space/spacetypes.c */
void ED_spacetype_clip(void)
{
@@ -1531,6 +1551,7 @@ void ED_spacetype_clip(void)
st->context = clip_context;
st->dropboxes = clip_dropboxes;
st->refresh = clip_refresh;
+ st->id_remap = clip_id_remap;
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype clip region");
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index 71e38f72a7a..a55b18a2212 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -128,6 +128,7 @@ void file_panels_register(struct ARegionType *art);
/* file_utils.c */
void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, rcti *r_bounds);
+bool file_is_dir(struct SpaceFile *sfile, const char *path);
#endif /* __FILE_INTERN_H__ */
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index d83a7d5ea62..c42ff120102 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -208,7 +208,7 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
BLI_add_slash(params->dir);
}
- ED_file_change_dir(C, false);
+ ED_file_change_dir(C);
retval = FILE_SELECT_DIR;
}
}
@@ -826,7 +826,7 @@ static int bookmark_select_exec(bContext *C, wmOperator *op)
RNA_property_string_get(op->ptr, prop, entry);
BLI_strncpy(params->dir, entry, sizeof(params->dir));
BLI_cleanup_dir(G.main->name, params->dir);
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
@@ -1379,7 +1379,7 @@ int file_exec(bContext *C, wmOperator *exec_op)
BLI_add_slash(sfile->params->dir);
}
- ED_file_change_dir(C, false);
+ ED_file_change_dir(C);
}
/* opening file - sends events now, so things get handled on windowqueue level */
else if (sfile->op) {
@@ -1447,19 +1447,7 @@ int file_parent_exec(bContext *C, wmOperator *UNUSED(unused))
if (sfile->params) {
if (BLI_parent_dir(sfile->params->dir)) {
BLI_cleanup_dir(G.main->name, sfile->params->dir);
- /* if not browsing in .blend file, we still want to check whether the path is a directory */
- if (sfile->params->type == FILE_LOADLIB) {
- char tdir[FILE_MAX];
- if (BLO_library_path_explode(sfile->params->dir, tdir, NULL, NULL)) {
- ED_file_change_dir(C, false);
- }
- else {
- ED_file_change_dir(C, true);
- }
- }
- else {
- ED_file_change_dir(C, true);
- }
+ ED_file_change_dir(C);
if (sfile->params->recursion_level > 1) {
/* Disable 'dirtree' recursion when going up in tree. */
sfile->params->recursion_level = 0;
@@ -1529,7 +1517,7 @@ int file_previous_exec(bContext *C, wmOperator *UNUSED(unused))
folderlist_popdir(sfile->folders_prev, sfile->params->dir);
folderlist_pushdir(sfile->folders_next, sfile->params->dir);
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
}
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@@ -1561,7 +1549,7 @@ int file_next_exec(bContext *C, wmOperator *UNUSED(unused))
// update folders_prev so we can check for it in folderlist_clear_next()
folderlist_pushdir(sfile->folders_prev, sfile->params->dir);
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
}
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@@ -1809,7 +1797,7 @@ int file_directory_new_exec(bContext *C, wmOperator *op)
if (RNA_boolean_get(op->ptr, "open")) {
BLI_strncpy(sfile->params->dir, path, sizeof(sfile->params->dir));
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
}
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@@ -1906,17 +1894,35 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
file_expand_directory(C);
/* special case, user may have pasted a filepath into the directory */
- if (BLI_is_file(sfile->params->dir)) {
- char path[sizeof(sfile->params->dir)];
- BLI_strncpy(path, sfile->params->dir, sizeof(path));
- BLI_split_dirfile(path, sfile->params->dir, sfile->params->file, sizeof(sfile->params->dir), sizeof(sfile->params->file));
+ if (!file_is_dir(sfile, sfile->params->dir)) {
+ char tdir[FILE_MAX_LIBEXTRA];
+ char *group, *name;
+
+ if (BLI_is_file(sfile->params->dir)) {
+ char path[sizeof(sfile->params->dir)];
+ BLI_strncpy(path, sfile->params->dir, sizeof(path));
+ BLI_split_dirfile(path, sfile->params->dir, sfile->params->file,
+ sizeof(sfile->params->dir), sizeof(sfile->params->file));
+ }
+ else if (BLO_library_path_explode(sfile->params->dir, tdir, &group, &name)) {
+ if (group) {
+ BLI_path_append(tdir, sizeof(tdir), group);
+ }
+ BLI_strncpy(sfile->params->dir, tdir, sizeof(sfile->params->dir));
+ if (name) {
+ BLI_strncpy(sfile->params->file, name, sizeof(sfile->params->file));
+ }
+ else {
+ sfile->params->file[0] = '\0';
+ }
+ }
}
BLI_cleanup_dir(G.main->name, sfile->params->dir);
- if (BLI_exists(sfile->params->dir)) {
+ if (file_is_dir(sfile, sfile->params->dir)) {
/* if directory exists, enter it immediately */
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
/* don't do for now because it selects entire text instead of
* placing cursor at the end */
@@ -1931,20 +1937,26 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
#endif
else {
const char *lastdir = folderlist_peeklastdir(sfile->folders_prev);
+ char tdir[FILE_MAX_LIBEXTRA];
- /* if not, ask to create it and enter if confirmed */
- wmOperatorType *ot = WM_operatortype_find("FILE_OT_directory_new", false);
- PointerRNA ptr;
- WM_operator_properties_create_ptr(&ptr, ot);
- RNA_string_set(&ptr, "directory", sfile->params->dir);
- RNA_boolean_set(&ptr, "open", true);
-
- if (lastdir)
+ /* If we are 'inside' a blend library, we cannot do anything... */
+ if (lastdir && BLO_library_path_explode(lastdir, tdir, NULL, NULL)) {
BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir));
-
-
- WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
- WM_operator_properties_free(&ptr);
+ }
+ else {
+ /* if not, ask to create it and enter if confirmed */
+ wmOperatorType *ot = WM_operatortype_find("FILE_OT_directory_new", false);
+ PointerRNA ptr;
+ WM_operator_properties_create_ptr(&ptr, ot);
+ RNA_string_set(&ptr, "directory", sfile->params->dir);
+ RNA_boolean_set(&ptr, "open", true);
+
+ if (lastdir)
+ BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir));
+
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
+ WM_operator_properties_free(&ptr);
+ }
}
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@@ -1971,8 +1983,6 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg
BLI_filename_make_safe(sfile->params->file);
if (matches) {
- /* int i, numfiles = filelist_numfiles(sfile->files); */ /* XXX UNUSED */
- sfile->params->file[0] = '\0';
/* replace the pattern (or filename that the user typed in, with the first selected file of the match */
BLI_strncpy(sfile->params->file, matched_file, sizeof(sfile->params->file));
@@ -1980,30 +1990,17 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg
}
if (matches == 1) {
-
BLI_join_dirfile(filepath, sizeof(sfile->params->dir), sfile->params->dir, sfile->params->file);
/* if directory, open it and empty filename field */
- if (BLI_is_dir(filepath)) {
+ if (file_is_dir(sfile, filepath)) {
BLI_cleanup_dir(G.main->name, filepath);
BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir));
sfile->params->file[0] = '\0';
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
UI_textbutton_activate_but(C, but);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
}
- else if (sfile->params->type == FILE_LOADLIB) {
- char tdir[FILE_MAX];
- BLI_add_slash(filepath);
- if (BLO_library_path_explode(filepath, tdir, NULL, NULL)) {
- BLI_cleanup_dir(G.main->name, filepath);
- BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir));
- sfile->params->file[0] = '\0';
- ED_file_change_dir(C, false);
- UI_textbutton_activate_but(C, but);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
- }
- }
}
else if (matches > 1) {
file_draw_check(C);
diff --git a/source/blender/editors/space_file/file_utils.c b/source/blender/editors/space_file/file_utils.c
index 3c007f25da3..f19e301064d 100644
--- a/source/blender/editors/space_file/file_utils.c
+++ b/source/blender/editors/space_file/file_utils.c
@@ -25,6 +25,9 @@
*/
#include "BLI_rect.h"
+#include "BLI_fileops.h"
+
+#include "BLO_readfile.h"
#include "BKE_context.h"
@@ -45,3 +48,17 @@ void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, r
BLI_rcti_init(r_bounds, xmin, xmin + layout->tile_w + layout->tile_border_x,
ymax - layout->tile_h - layout->tile_border_y, ymax);
}
+
+/* Cannot directly use BLI_is_dir in libloading context... */
+bool file_is_dir(struct SpaceFile *sfile, const char *path)
+{
+ if (sfile->params->type == FILE_LOADLIB) {
+ char tdir[FILE_MAX_LIBEXTRA];
+ char *name;
+ if (BLO_library_path_explode(sfile->params->dir, tdir, NULL, &name) && BLI_is_file(tdir)) {
+ /* .blend file itself and group are considered as directories, not final datablock names. */
+ return name ? false : true;
+ }
+ }
+ return BLI_is_dir(path);
+}
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 8e1f781827a..5e9eb1f9207 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -624,7 +624,7 @@ static bool is_filtered_file(FileListInternEntry *file, const char *UNUSED(root)
static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileListFilter *filter)
{
bool is_filtered;
- char path[FILE_MAX_LIBEXTRA], dir[FILE_MAXDIR], *group, *name;
+ char path[FILE_MAX_LIBEXTRA], dir[FILE_MAX_LIBEXTRA], *group, *name;
BLI_join_dirfile(path, sizeof(path), root, file->relpath);
@@ -697,7 +697,7 @@ void filelist_filter(FileList *filelist)
if (filelist->max_recursion) {
/* Never show lib ID 'categories' directories when we are in 'flat' mode, unless
* root path is a blend file. */
- char dir[FILE_MAXDIR];
+ char dir[FILE_MAX_LIBEXTRA];
if (!filelist_islibrary(filelist, dir, NULL)) {
filelist->filter_data.flags |= FLF_HIDE_LIB_DIR;
}
@@ -947,7 +947,7 @@ static void filelist_checkdir_dir(struct FileList *UNUSED(filelist), char *r_dir
static void filelist_checkdir_lib(struct FileList *UNUSED(filelist), char *r_dir)
{
- char dir[FILE_MAXDIR];
+ char dir[FILE_MAX_LIBEXTRA];
if (!BLO_library_path_explode(r_dir, dir, NULL, NULL)) {
/* if not a valid library, we need it to be a valid directory! */
BLI_make_exist(r_dir);
@@ -1925,7 +1925,8 @@ static bool file_is_blend_backup(const char *str)
return (retval);
}
-static int path_extension_type(const char *path)
+/* TODO: Maybe we should move this to BLI? On the other hand, it's using defines from spacefile area, so not sure... */
+int ED_path_extension_type(const char *path)
{
if (BLO_has_bfile_extension(path)) {
return FILE_TYPE_BLENDER;
@@ -1977,12 +1978,12 @@ static int file_extension_type(const char *dir, const char *relpath)
{
char path[FILE_MAX];
BLI_join_dirfile(path, sizeof(path), dir, relpath);
- return path_extension_type(path);
+ return ED_path_extension_type(path);
}
int ED_file_extension_icon(const char *path)
{
- int type = path_extension_type(path);
+ const int type = ED_path_extension_type(path);
switch (type) {
case FILE_TYPE_BLENDER:
@@ -2112,6 +2113,7 @@ unsigned int filelist_entry_select_index_get(FileList *filelist, const int index
return 0;
}
+/* WARNING! dir must be FILE_MAX_LIBEXTRA long! */
bool filelist_islibrary(struct FileList *filelist, char *dir, char **group)
{
return BLO_library_path_explode(filelist->filelist.root, dir, group, NULL);
@@ -2207,7 +2209,7 @@ static int filelist_readjob_list_lib(const char *root, ListBase *entries, const
FileListInternEntry *entry;
LinkNode *ln, *names;
int i, nnames, idcode = 0, nbr_entries = 0;
- char dir[FILE_MAX], *group;
+ char dir[FILE_MAX_LIBEXTRA], *group;
bool ok;
struct BlendHandle *libfiledata = NULL;
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index bf90a4ea170..175d83506c6 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -576,7 +576,7 @@ FileLayout *ED_fileselect_get_layout(struct SpaceFile *sfile, ARegion *ar)
return sfile->layout;
}
-void ED_file_change_dir(bContext *C, const bool checkdir)
+void ED_file_change_dir(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
@@ -590,7 +590,7 @@ void ED_file_change_dir(bContext *C, const bool checkdir)
sfile->params->filter_search[0] = '\0';
sfile->params->active_file = -1;
- if (checkdir && !BLI_is_dir(sfile->params->dir)) {
+ if (!file_is_dir(sfile, sfile->params->dir)) {
BLI_strncpy(sfile->params->dir, filelist_dir(sfile->files), sizeof(sfile->params->dir));
/* could return but just refresh the current dir */
}
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index 6b860990c10..478dbd3d9c0 100644
--- a/source/blender/editors/space_graph/graph_ops.c
+++ b/source/blender/editors/space_graph/graph_ops.c
@@ -555,19 +555,20 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_ALT, 0);
RNA_boolean_set(kmi->ptr, "axis_range", true);
RNA_boolean_set(kmi->ptr, "include_handles", false);
-
+
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_CTRL, 0);
RNA_boolean_set(kmi->ptr, "axis_range", false);
RNA_boolean_set(kmi->ptr, "include_handles", true);
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
RNA_boolean_set(kmi->ptr, "axis_range", true);
RNA_boolean_set(kmi->ptr, "include_handles", true);
-
+
+ /* region select */
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0);
RNA_boolean_set(kmi->ptr, "deselect", false);
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "deselect", true);
-
+
WM_keymap_add_item(keymap, "GRAPH_OT_select_circle", CKEY, KM_PRESS, 0, 0);
/* column select */
diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c
index eb786d872ec..67b960bfa53 100644
--- a/source/blender/editors/space_graph/graph_select.c
+++ b/source/blender/editors/space_graph/graph_select.c
@@ -210,6 +210,8 @@ void GRAPH_OT_select_all_toggle(wmOperatorType *ot)
* -> ALT-BKEY - depending on which axis of the region was larger...
* -> 2) x-axis, so select all frames within frame range (validation with BEZT_OK_FRAMERANGE)
* -> 3) y-axis, so select all frames within channels that region included (validation with BEZT_OK_VALUERANGE)
+ *
+ * The selection backend is also reused for the Lasso and Circle select operators.
*/
/* Borderselect only selects keyframes now, as overshooting handles often get caught too,
@@ -245,12 +247,12 @@ static void borderselect_graphkeys(
/* init editing data */
memset(&ked, 0, sizeof(KeyframeEditData));
if (mode == BEZT_OK_REGION_LASSO) {
- struct KeyframeEdit_LassoData *data_lasso = data;
+ KeyframeEdit_LassoData *data_lasso = data;
data_lasso->rectf_scaled = &scaled_rectf;
ked.data = data_lasso;
}
else if (mode == BEZT_OK_REGION_CIRCLE) {
- struct KeyframeEdit_CircleData *data_circle = data;
+ KeyframeEdit_CircleData *data_circle = data;
data_circle->rectf_scaled = &scaled_rectf;
ked.data = data;
}
@@ -265,27 +267,27 @@ static void borderselect_graphkeys(
}
else
mapping_flag = ANIM_UNITCONV_ONLYKEYS;
-
+
mapping_flag |= ANIM_get_normalization_flags(ac);
-
+
/* loop over data, doing border select */
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
FCurve *fcu = (FCurve *)ale->key_data;
float offset;
float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset);
-
+
/* apply NLA mapping to all the keyframes, since it's easier than trying to
* guess when a callback might use something different
*/
if (adt)
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, incl_handles == 0);
-
+
scaled_rectf.xmin = rectf.xmin;
scaled_rectf.xmax = rectf.xmax;
scaled_rectf.ymin = rectf.ymin / unit_scale - offset;
scaled_rectf.ymax = rectf.ymax / unit_scale - offset;
-
+
/* set horizontal range (if applicable)
* NOTE: these values are only used for x-range and y-range but not region
* (which uses ked.data, i.e. rectf)
@@ -406,37 +408,41 @@ void GRAPH_OT_select_border(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "include_handles", 0, "Include Handles", "Are handles tested individually against the selection criteria");
}
+
+/* ------------------- */
+
static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
+
+ KeyframeEdit_LassoData data_lasso = {0};
rcti rect;
rctf rect_fl;
+
short selectmode;
bool incl_handles;
bool extend;
-
- struct KeyframeEdit_LassoData data_lasso;
-
+
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
-
+
data_lasso.rectf_view = &rect_fl;
data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot);
if (data_lasso.mcords == NULL)
return OPERATOR_CANCELLED;
-
+
/* clear all selection if not extending selection */
extend = RNA_boolean_get(op->ptr, "extend");
if (!extend)
deselect_graph_keys(&ac, 1, SELECT_SUBTRACT, true);
-
+
if (!RNA_boolean_get(op->ptr, "deselect"))
selectmode = SELECT_ADD;
else
selectmode = SELECT_SUBTRACT;
-
- if (ac.spacetype == SPACE_IPO) {
+
+ {
SpaceIpo *sipo = (SpaceIpo *)ac.sl;
if (selectmode == SELECT_ADD) {
incl_handles = ((sipo->flag & SIPO_SELVHANDLESONLY) ||
@@ -446,60 +452,57 @@ static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op)
incl_handles = (sipo->flag & SIPO_NOHANDLES) == 0;
}
}
- else {
- incl_handles = false;
- }
-
-
+
/* get settings from operator */
BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot);
-
BLI_rctf_rcti_copy(&rect_fl, &rect);
-
+
/* apply borderselect action */
borderselect_graphkeys(&ac, &rect_fl, BEZT_OK_REGION_LASSO, selectmode, incl_handles, &data_lasso);
-
+
MEM_freeN((void *)data_lasso.mcords);
-
-
+
/* send notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+
return OPERATOR_FINISHED;
}
-
void GRAPH_OT_select_lasso(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Lasso Select";
ot->description = "Select keyframe points using lasso selection";
ot->idname = "GRAPH_OT_select_lasso";
-
+
/* api callbacks */
ot->invoke = WM_gesture_lasso_invoke;
ot->modal = WM_gesture_lasso_modal;
ot->exec = graphkeys_lassoselect_exec;
ot->poll = graphop_visible_keyframes_poll;
ot->cancel = WM_gesture_lasso_cancel;
-
+
/* flags */
ot->flag = OPTYPE_UNDO;
-
+
/* properties */
RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Deselect rather than select items");
RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first");
}
+/* ------------------- */
+
static int graph_circle_select_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
const int gesture_mode = RNA_int_get(op->ptr, "gesture_mode");
- short selectmode;
- bool incl_handles;
+ const short selectmode = (gesture_mode == GESTURE_MODAL_SELECT) ? SELECT_ADD : SELECT_SUBTRACT;
+ bool incl_handles = false;
+
+ KeyframeEdit_CircleData data = {0};
rctf rect_fl;
- struct KeyframeEdit_CircleData data;
+
float x = RNA_int_get(op->ptr, "x");
float y = RNA_int_get(op->ptr, "y");
float radius = RNA_int_get(op->ptr, "radius");
@@ -507,23 +510,18 @@ static int graph_circle_select_exec(bContext *C, wmOperator *op)
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
-
+
data.mval[0] = x;
data.mval[1] = y;
data.radius_squared = radius * radius;
data.rectf_view = &rect_fl;
- if (gesture_mode == GESTURE_MODAL_SELECT)
- selectmode = SELECT_ADD;
- else
- selectmode = SELECT_SUBTRACT;
-
rect_fl.xmin = x - radius;
rect_fl.xmax = x + radius;
rect_fl.ymin = y - radius;
rect_fl.ymax = y + radius;
- if (ac.spacetype == SPACE_IPO) {
+ {
SpaceIpo *sipo = (SpaceIpo *)ac.sl;
if (selectmode == SELECT_ADD) {
incl_handles = ((sipo->flag & SIPO_SELVHANDLESONLY) ||
@@ -533,10 +531,7 @@ static int graph_circle_select_exec(bContext *C, wmOperator *op)
incl_handles = (sipo->flag & SIPO_NOHANDLES) == 0;
}
}
- else {
- incl_handles = false;
- }
-
+
/* apply borderselect action */
borderselect_graphkeys(&ac, &rect_fl, BEZT_OK_REGION_CIRCLE, selectmode, incl_handles, &data);
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index c6a8a9753d1..8ae5932f3fd 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -33,6 +33,7 @@
#include <stdio.h>
#include "DNA_anim_types.h"
+#include "DNA_group_types.h"
#include "DNA_scene_types.h"
#include "MEM_guardedalloc.h"
@@ -610,6 +611,51 @@ static void graph_refresh(const bContext *C, ScrArea *sa)
}
break;
}
+ case FCURVE_COLOR_AUTO_YRGB:
+ {
+ /* Like FCURVE_COLOR_AUTO_RGB, except this is for quaternions... */
+ float *col = fcu->color;
+
+ switch (fcu->array_index) {
+ case 1:
+ UI_GetThemeColor3fv(TH_AXIS_X, col);
+ break;
+ case 2:
+ UI_GetThemeColor3fv(TH_AXIS_Y, col);
+ break;
+ case 3:
+ UI_GetThemeColor3fv(TH_AXIS_Z, col);
+ break;
+
+ case 0:
+ {
+ /* Special Case: "W" channel should be yellowish, so blend X and Y channel colors... */
+ float c1[3], c2[3];
+ float h1[3], h2[3];
+ float hresult[3];
+
+ /* - get colors (rgb) */
+ UI_GetThemeColor3fv(TH_AXIS_X, c1);
+ UI_GetThemeColor3fv(TH_AXIS_Y, c2);
+
+ /* - perform blending in HSV space (to keep brightness similar) */
+ rgb_to_hsv_v(c1, h1);
+ rgb_to_hsv_v(c2, h2);
+
+ interp_v3_v3v3(hresult, h1, h2, 0.5f);
+
+ /* - convert back to RGB for display */
+ hsv_to_rgb_v(hresult, col);
+ break;
+ }
+
+ default:
+ /* 'unknown' color - bluish so as to not conflict with handles */
+ col[0] = 0.3f; col[1] = 0.8f; col[2] = 1.0f;
+ break;
+ }
+ break;
+ }
case FCURVE_COLOR_AUTO_RAINBOW:
default:
{
@@ -627,6 +673,19 @@ static void graph_refresh(const bContext *C, ScrArea *sa)
}
}
+static void graph_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceIpo *sgraph = (SpaceIpo *)slink;
+
+ if (!ELEM(GS(old_id->name), ID_GR)) {
+ return;
+ }
+
+ if ((ID *)sgraph->ads->filter_grp == old_id) {
+ sgraph->ads->filter_grp = (Group *)new_id;
+ }
+}
+
/* only called once, from space/spacetypes.c */
void ED_spacetype_ipo(void)
{
@@ -644,7 +703,8 @@ void ED_spacetype_ipo(void)
st->keymap = graphedit_keymap;
st->listener = graph_listener;
st->refresh = graph_refresh;
-
+ st->id_remap = graph_id_remap;
+
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype graphedit region");
art->regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 8db5a8f9bd3..06caf930988 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -2979,7 +2979,7 @@ 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) {
+ if (ibuf->zbuf == (int *)ibuf->rect) {
info->colp = NULL;
}
}
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index 168f9c0dfdf..35a658eac23 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -28,6 +28,7 @@
* \ingroup spimage
*/
+#include "DNA_gpencil_types.h"
#include "DNA_mesh_types.h"
#include "DNA_mask_types.h"
#include "DNA_meshdata_types.h"
@@ -44,6 +45,7 @@
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_image.h"
+#include "BKE_library.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
@@ -981,6 +983,31 @@ static void image_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa
}
}
+static void image_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceImage *simg = (SpaceImage *)slink;
+
+ if (!ELEM(GS(old_id->name), ID_IM, ID_GD, ID_MSK)) {
+ return;
+ }
+
+ if ((ID *)simg->image == old_id) {
+ simg->image = (Image *)new_id;
+ id_us_ensure_real(new_id);
+ }
+
+ if ((ID *)simg->gpd == old_id) {
+ simg->gpd = (bGPdata *)new_id;
+ id_us_min(old_id);
+ id_us_plus(new_id);
+ }
+
+ if ((ID *)simg->mask_info.mask == old_id) {
+ simg->mask_info.mask = (Mask *)new_id;
+ id_us_ensure_real(new_id);
+ }
+}
+
/**************************** spacetype *****************************/
/* only called once, from space/spacetypes.c */
@@ -1002,7 +1029,8 @@ void ED_spacetype_image(void)
st->refresh = image_refresh;
st->listener = image_listener;
st->context = image_context;
-
+ st->id_remap = image_id_remap;
+
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype image region");
art->regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/space_logic/space_logic.c b/source/blender/editors/space_logic/space_logic.c
index 243a522011b..69966e9bf34 100644
--- a/source/blender/editors/space_logic/space_logic.c
+++ b/source/blender/editors/space_logic/space_logic.c
@@ -38,7 +38,10 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "DNA_gpencil_types.h"
+
#include "BKE_context.h"
+#include "BKE_library.h"
#include "BKE_screen.h"
#include "ED_space_api.h"
@@ -300,6 +303,21 @@ static void logic_header_region_draw(const bContext *C, ARegion *ar)
/**************************** spacetype *****************************/
+static void logic_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceLogic *slog = (SpaceLogic *)slink;
+
+ if (!ELEM(GS(old_id->name), ID_GD)) {
+ return;
+ }
+
+ if ((ID *)slog->gpd == old_id) {
+ slog->gpd = (bGPdata *)new_id;
+ id_us_min(old_id);
+ id_us_plus(new_id);
+ }
+}
+
/* only called once, from space/spacetypes.c */
void ED_spacetype_logic(void)
{
@@ -317,7 +335,8 @@ void ED_spacetype_logic(void)
st->keymap = logic_keymap;
st->refresh = logic_refresh;
st->context = logic_context;
-
+ st->id_remap = logic_id_remap;
+
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype logic region");
art->regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c
index e2b36c5b5ae..3b5604087b9 100644
--- a/source/blender/editors/space_nla/space_nla.c
+++ b/source/blender/editors/space_nla/space_nla.c
@@ -33,6 +33,7 @@
#include <stdio.h>
#include "DNA_anim_types.h"
+#include "DNA_group_types.h"
#include "DNA_scene_types.h"
#include "MEM_guardedalloc.h"
@@ -501,6 +502,19 @@ static void nla_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
}
}
+static void nla_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceNla *snla = (SpaceNla *)slink;
+
+ if (!ELEM(GS(old_id->name), ID_GR)) {
+ return;
+ }
+
+ if ((ID *)snla->ads->filter_grp == old_id) {
+ snla->ads->filter_grp = (Group *)new_id;
+ }
+}
+
/* only called once, from space/spacetypes.c */
void ED_spacetype_nla(void)
{
@@ -517,7 +531,8 @@ void ED_spacetype_nla(void)
st->operatortypes = nla_operatortypes;
st->listener = nla_listener;
st->keymap = nla_keymap;
-
+ st->id_remap = nla_id_remap;
+
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype nla region");
art->regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index 6ae72e2a164..ffe510016ff 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -740,34 +740,6 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
}
}
-void ED_node_id_unref(SpaceNode *snode, const ID *id)
-{
- if (GS(id->name) == ID_SCE) {
- if (snode->id == id) {
- /* nasty DNA logic for SpaceNode:
- * ideally should be handled by editor code, but would be bad level call
- */
- bNodeTreePath *path, *path_next;
- for (path = snode->treepath.first; path; path = path_next) {
- path_next = path->next;
- MEM_freeN(path);
- }
- BLI_listbase_clear(&snode->treepath);
-
- snode->id = NULL;
- snode->from = NULL;
- snode->nodetree = NULL;
- snode->edittree = NULL;
- }
- }
- else if (GS(id->name) == ID_OB) {
- if (snode->from == id) {
- snode->flag &= ~SNODE_PIN;
- snode->from = NULL;
- }
- }
-}
-
void ED_node_post_apply_transform(bContext *UNUSED(C), bNodeTree *UNUSED(ntree))
{
/* XXX This does not work due to layout functions relying on node->block,
diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c
index df484724fc5..4ef703c8994 100644
--- a/source/blender/editors/space_node/space_node.c
+++ b/source/blender/editors/space_node/space_node.c
@@ -28,6 +28,7 @@
* \ingroup spnode
*/
+#include "DNA_gpencil_types.h"
#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
#include "DNA_node_types.h"
@@ -821,6 +822,41 @@ static int node_context(const bContext *C, const char *member, bContextDataResul
return 0;
}
+static void node_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceNode *snode = (SpaceNode *)slink;
+
+ if (GS(old_id->name) == ID_SCE) {
+ if (snode->id == old_id) {
+ /* nasty DNA logic for SpaceNode:
+ * ideally should be handled by editor code, but would be bad level call
+ */
+ BLI_freelistN(&snode->treepath);
+
+ /* XXX Untested in case new_id != NULL... */
+ snode->id = new_id;
+ snode->from = NULL;
+ snode->nodetree = NULL;
+ snode->edittree = NULL;
+ }
+ }
+ else if (GS(old_id->name) == ID_OB) {
+ if (snode->from == old_id) {
+ if (new_id == NULL) {
+ snode->flag &= ~SNODE_PIN;
+ }
+ snode->from = new_id;
+ }
+ }
+ else if (GS(old_id->name) == ID_GD) {
+ if ((ID *)snode->gpd == old_id) {
+ snode->gpd = (bGPdata *)new_id;
+ id_us_min(old_id);
+ id_us_plus(new_id);
+ }
+ }
+}
+
/* only called once, from space/spacetypes.c */
void ED_spacetype_node(void)
{
@@ -840,6 +876,7 @@ void ED_spacetype_node(void)
st->refresh = node_area_refresh;
st->context = node_context;
st->dropboxes = node_dropboxes;
+ st->id_remap = node_id_remap;
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype node region");
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index b624c7cba75..43e9c262172 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -502,6 +502,11 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
BKE_reportf(CTX_wm_reports(C), RPT_ERROR,
"Library path '%s' does not exist, correct this before saving", expanded);
}
+ else if (lib->id.tag & LIB_TAG_MISSING) {
+ BKE_reportf(CTX_wm_reports(C), RPT_INFO,
+ "Library path '%s' is now valid, please reload the library", expanded);
+ lib->id.tag &= ~LIB_TAG_MISSING;
+ }
}
}
else {
@@ -1579,11 +1584,19 @@ static void outliner_draw_tree_element(
glDisable(GL_BLEND);
/* name */
- if (active == OL_DRAWSEL_NORMAL) UI_ThemeColor(TH_TEXT_HI);
- else if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) UI_ThemeColorBlend(TH_BACK, TH_TEXT, 0.75f);
- else UI_ThemeColor(TH_TEXT);
-
- UI_fontstyle_draw_simple(fstyle, startx + offsx, *starty + 5 * ufac, te->name);
+ if ((tselem->flag & TSE_TEXTBUT) == 0) {
+ if (active == OL_DRAWSEL_NORMAL) {
+ UI_ThemeColor(TH_TEXT_HI);
+ }
+ else if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
+ UI_ThemeColorBlend(TH_BACK, TH_TEXT, 0.75f);
+ }
+ else {
+ UI_ThemeColor(TH_TEXT);
+ }
+
+ UI_fontstyle_draw_simple(fstyle, startx + offsx, *starty + 5 * ufac, te->name);
+ }
offsx += (int)(UI_UNIT_X + UI_fontstyle_string_width(fstyle, te->name));
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 2627b978b40..07608b59d2e 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -29,17 +29,23 @@
* \ingroup spoutliner
*/
+#include <string.h>
+
#include "MEM_guardedalloc.h"
#include "DNA_anim_types.h"
#include "DNA_group_types.h"
+#include "DNA_ID.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "DNA_material_types.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_path_util.h"
#include "BLI_mempool.h"
+#include "BLI_stack.h"
+#include "BLI_string.h"
#include "BLT_translation.h"
@@ -47,7 +53,10 @@
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_global.h"
+#include "BKE_idcode.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_outliner_treehash.h"
#include "BKE_report.h"
@@ -55,6 +64,8 @@
#include "BKE_material.h"
#include "BKE_group.h"
+#include "../blenloader/BLO_readfile.h"
+
#include "ED_object.h"
#include "ED_outliner.h"
#include "ED_screen.h"
@@ -70,6 +81,9 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "GPU_material.h"
#include "outliner_intern.h"
@@ -230,8 +244,9 @@ static void do_item_rename(ARegion *ar, TreeElement *te, TreeStoreElem *tselem,
}
}
-void item_rename_cb(bContext *C, Scene *UNUSED(scene), TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+void item_rename_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te,
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
ARegion *ar = CTX_wm_region(C);
ReportList *reports = CTX_wm_reports(C); // XXX
@@ -291,64 +306,315 @@ void OUTLINER_OT_item_rename(wmOperatorType *ot)
ot->poll = ED_operator_outliner_active;
}
-/* Library delete --------------------------------------------------- */
+/* ID delete --------------------------------------------------- */
-static void lib_delete(bContext *C, TreeElement *te, TreeStoreElem *tselem, ReportList *reports)
+static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeStoreElem *tselem)
{
- Library *lib = (Library *)tselem->id;
- ListBase *lbarray[MAX_LIBARRAY];
- int a;
+ Main *bmain = CTX_data_main(C);
+ ID *id = tselem->id;
- BLI_assert(te->idcode == ID_LI && lib != NULL);
+ BLI_assert(te->idcode != 0 && id != NULL);
+ BLI_assert(te->idcode != ID_LI || ((Library *)id)->parent == NULL);
UNUSED_VARS_NDEBUG(te);
- /* We simply set all ID from given lib (including lib itself) to zero user count.
- * It is not possible to do a proper cleanup without a save/reload in current master. */
- a = set_listbasepointers(CTX_data_main(C), lbarray);
- while (a--) {
- ListBase *lb = lbarray[a];
- ID *id;
-
- for (id = lb->first; id; id = id->next) {
- if (id->lib == lib) {
- id_fake_user_clear(id);
- id->us = 0;
+ if (id->tag & LIB_TAG_INDIRECT) {
+ BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked id '%s'", id->name);
+ return;
+ }
+ else if (BKE_library_ID_is_indirectly_used(bmain, id) && ID_REAL_USERS(id) <= 1) {
+ BKE_reportf(reports, RPT_WARNING,
+ "Cannot delete id '%s', indirectly used datablocks need at least one user",
+ id->name);
+ return;
+ }
+
+
+ BKE_libblock_delete(bmain, id);
+
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+}
+
+void id_delete_cb(
+ bContext *C, ReportList *reports, Scene *UNUSED(scene),
+ TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+{
+ id_delete(C, reports, te, tselem);
+}
+
+static int outliner_id_delete_invoke_do(bContext *C, ReportList *reports, TreeElement *te, const float mval[2])
+{
+ if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ if (te->idcode != 0 && tselem->id) {
+ if (te->idcode == ID_LI && ((Library *)tselem->id)->parent) {
+ BKE_reportf(reports, RPT_ERROR_INVALID_INPUT,
+ "Cannot delete indirectly linked library '%s'", ((Library *)tselem->id)->filepath);
+ return OPERATOR_CANCELLED;
+ }
+ id_delete(C, reports, te, tselem);
+ return OPERATOR_FINISHED;
+ }
+ }
+ else {
+ for (te = te->subtree.first; te; te = te->next) {
+ int ret;
+ if ((ret = outliner_id_delete_invoke_do(C, reports, te, mval))) {
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int outliner_id_delete_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ARegion *ar = CTX_wm_region(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ TreeElement *te;
+ float fmval[2];
+
+ BLI_assert(ar && soops);
+
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
+
+ for (te = soops->tree.first; te; te = te->next) {
+ int ret;
+
+ if ((ret = outliner_id_delete_invoke_do(C, op->reports, te, fmval))) {
+ return ret;
+ }
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+void OUTLINER_OT_id_delete(wmOperatorType *ot)
+{
+ ot->name = "Delete Datablock";
+ ot->idname = "OUTLINER_OT_id_delete";
+ ot->description = "Delete the ID under cursor";
+
+ ot->invoke = outliner_id_delete_invoke;
+ ot->poll = ED_operator_outliner_active;
+}
+
+/* ID remap --------------------------------------------------- */
+
+static int outliner_id_remap_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+
+ const short id_type = (short)RNA_enum_get(op->ptr, "id_type");
+ ID *old_id = BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "old_id"));
+ ID *new_id = BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "new_id"));
+
+ /* check for invalid states */
+ if (soops == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!(old_id && (old_id != new_id) && (GS(old_id->name) == GS(new_id->name)))) {
+ BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT, "Invalid old/new ID pair ('%s' / '%s')",
+ old_id->name, new_id->name);
+ return OPERATOR_CANCELLED;
+ }
+
+ if (old_id->lib) {
+ BKE_reportf(op->reports, RPT_WARNING,
+ "Old ID '%s' is linked from a library, indirect usages of this datablock will not be remapped",
+ old_id->name);
+ }
+
+ BKE_libblock_remap(bmain, old_id, new_id,
+ ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE);
+
+ BKE_main_lib_objects_recalc_all(bmain);
+
+ /* recreate dependency graph to include new objects */
+ DAG_scene_relations_rebuild(bmain, scene);
+
+ /* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */
+ GPU_materials_free();
+
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+static bool outliner_id_remap_find_tree_element(bContext *C, wmOperator *op, ListBase *tree, const float y)
+{
+ TreeElement *te;
+
+ for (te = tree->first; te; te = te->next) {
+ if (y > te->ys && y < te->ys + UI_UNIT_Y) {
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ if (tselem->type == 0 && tselem->id) {
+ printf("found id %s (%p)!\n", tselem->id->name, tselem->id);
+
+ RNA_enum_set(op->ptr, "id_type", GS(tselem->id->name));
+ RNA_enum_set_identifier(C, op->ptr, "new_id", tselem->id->name + 2);
+ RNA_enum_set_identifier(C, op->ptr, "old_id", tselem->id->name + 2);
+ return true;
}
}
+ if (outliner_id_remap_find_tree_element(C, op, &te->subtree, y)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static int outliner_id_remap_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ ARegion *ar = CTX_wm_region(C);
+ float fmval[2];
+
+ if (!RNA_property_is_set(op->ptr, RNA_struct_find_property(op->ptr, "id_type"))) {
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
+
+ outliner_id_remap_find_tree_element(C, op, &soops->tree, fmval[1]);
}
- BKE_reportf(reports, RPT_WARNING,
- "Please save and reload .blend file to complete deletion of '%s' library",
- ((Library *)tselem->id)->filepath);
+ return WM_operator_props_dialog_popup(C, op, 200, 100);
+}
+
+static EnumPropertyItem *outliner_id_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ EnumPropertyItem item_tmp = {0}, *item = NULL;
+ int totitem = 0;
+ int i = 0;
+
+ short id_type = (short)RNA_enum_get(ptr, "id_type");
+ ID *id = which_libbase(CTX_data_main(C), id_type)->first;
+
+ for (; id; id = id->next) {
+ item_tmp.identifier = item_tmp.name = id->name + 2;
+ item_tmp.value = i++;
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+void OUTLINER_OT_id_remap(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Outliner ID data Remap";
+ ot->idname = "OUTLINER_OT_id_remap";
+ ot->description = "";
+
+ /* callbacks */
+ ot->invoke = outliner_id_remap_invoke;
+ ot->exec = outliner_id_remap_exec;
+ ot->poll = ED_operator_outliner_active;
+
+ ot->flag = 0;
+
+ RNA_def_enum(ot->srna, "id_type", rna_enum_id_type_items, ID_OB, "ID Type", "");
+
+ prop = RNA_def_enum(ot->srna, "old_id", DummyRNA_NULL_items, 0, "Old ID", "Old ID to replace");
+ RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, outliner_id_itemf);
+ RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE | PROP_HIDDEN);
+
+ ot->prop = RNA_def_enum(ot->srna, "new_id", DummyRNA_NULL_items, 0,
+ "New ID", "New ID to remap all selected IDs' users to");
+ RNA_def_property_enum_funcs_runtime(ot->prop, NULL, NULL, outliner_id_itemf);
+ RNA_def_property_flag(ot->prop, PROP_ENUM_NO_TRANSLATE);
}
-void lib_delete_cb(
- bContext *C, Scene *UNUSED(scene), TreeElement *te,
+void id_remap_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
- lib_delete(C, te, tselem, CTX_wm_reports(C));
+ wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_id_remap", false);
+ PointerRNA op_props;
+
+ BLI_assert(tselem->id != NULL);
+
+ WM_operator_properties_create_ptr(&op_props, ot);
+
+ RNA_enum_set(&op_props, "id_type", GS(tselem->id->name));
+ RNA_enum_set_identifier(C, &op_props, "old_id", tselem->id->name + 2);
+
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_props);
+
+ WM_operator_properties_free(&op_props);
+}
+
+/* Library relocate/reload --------------------------------------------------- */
+
+static int lib_relocate(
+ bContext *C, TreeElement *te, TreeStoreElem *tselem, wmOperatorType *ot, const bool reload)
+{
+ PointerRNA op_props;
+ int ret = 0;
+
+ BLI_assert(te->idcode == ID_LI && tselem->id != NULL);
+ UNUSED_VARS_NDEBUG(te);
+
+ WM_operator_properties_create_ptr(&op_props, ot);
+
+ RNA_string_set(&op_props, "library", tselem->id->name + 2);
+
+ if (reload) {
+ Library *lib = (Library *)tselem->id;
+ char dir[FILE_MAXDIR], filename[FILE_MAX];
+
+ BLI_split_dirfile(lib->filepath, dir, filename, sizeof(dir), sizeof(filename));
+
+ printf("%s, %s\n", tselem->id->name, lib->filepath);
+
+ /* We assume if both paths in lib are not the same then lib->name was relative... */
+ RNA_boolean_set(&op_props, "relative_path", BLI_path_cmp(lib->filepath, lib->name) != 0);
+
+ RNA_string_set(&op_props, "directory", dir);
+ RNA_string_set(&op_props, "filename", filename);
+
+ ret = WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &op_props);
+ }
+ else {
+ ret = WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_props);
+ }
+
+ WM_operator_properties_free(&op_props);
+
+ return ret;
}
-static int outliner_lib_delete_invoke_do(bContext *C, ReportList *reports, TreeElement *te, const float mval[2])
+static int outliner_lib_relocate_invoke_do(
+ bContext *C, ReportList *reports, TreeElement *te, const float mval[2], const bool reload)
{
if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
TreeStoreElem *tselem = TREESTORE(te);
if (te->idcode == ID_LI && tselem->id) {
- if (((Library *)tselem->id)->parent) {
+ if (((Library *)tselem->id)->parent && !reload) {
BKE_reportf(reports, RPT_ERROR_INVALID_INPUT,
- "Cannot delete indirectly linked library '%s'", ((Library *)tselem->id)->filepath);
+ "Cannot relocate indirectly linked library '%s'", ((Library *)tselem->id)->filepath);
return OPERATOR_CANCELLED;
}
+ else {
+ wmOperatorType *ot = WM_operatortype_find(reload ? "WM_OT_lib_reload" : "WM_OT_lib_relocate", false);
- lib_delete(C, te, tselem, reports);
- return OPERATOR_FINISHED;
+ return lib_relocate(C, te, tselem, ot, reload);
+ }
}
}
else {
for (te = te->subtree.first; te; te = te->next) {
int ret;
- if ((ret = outliner_lib_delete_invoke_do(C, reports, te, mval))) {
+ if ((ret = outliner_lib_relocate_invoke_do(C, reports, te, mval, reload))) {
return ret;
}
}
@@ -357,7 +623,51 @@ static int outliner_lib_delete_invoke_do(bContext *C, ReportList *reports, TreeE
return 0;
}
-static int outliner_lib_delete_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int outliner_lib_relocate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ARegion *ar = CTX_wm_region(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ TreeElement *te;
+ float fmval[2];
+
+ BLI_assert(ar && soops);
+
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
+
+ for (te = soops->tree.first; te; te = te->next) {
+ int ret;
+
+ if ((ret = outliner_lib_relocate_invoke_do(C, op->reports, te, fmval, false))) {
+ return ret;
+ }
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+void OUTLINER_OT_lib_relocate(wmOperatorType *ot)
+{
+ ot->name = "Relocate Library";
+ ot->idname = "OUTLINER_OT_lib_relocate";
+ ot->description = "Relocate the library under cursor";
+
+ ot->invoke = outliner_lib_relocate_invoke;
+ ot->poll = ED_operator_outliner_active;
+}
+
+/* XXX This does not work with several items
+ * (it is only called once in the end, due to the 'deferred' filebrowser invocation through event system...). */
+void lib_relocate_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te,
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+{
+ wmOperatorType *ot = WM_operatortype_find("WM_OT_lib_relocate", false);
+
+ lib_relocate(C, te, tselem, ot, false);
+}
+
+
+static int outliner_lib_reload_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
@@ -371,7 +681,7 @@ static int outliner_lib_delete_invoke(bContext *C, wmOperator *op, const wmEvent
for (te = soops->tree.first; te; te = te->next) {
int ret;
- if ((ret = outliner_lib_delete_invoke_do(C, op->reports, te, fmval))) {
+ if ((ret = outliner_lib_relocate_invoke_do(C, op->reports, te, fmval, true))) {
return ret;
}
}
@@ -379,16 +689,25 @@ static int outliner_lib_delete_invoke(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_CANCELLED;
}
-void OUTLINER_OT_lib_delete(wmOperatorType *ot)
+void OUTLINER_OT_lib_reload(wmOperatorType *ot)
{
- ot->name = "Delete Library";
- ot->idname = "OUTLINER_OT_lib_delete";
- ot->description = "Delete the library under cursor (needs a save/reload)";
+ ot->name = "Reload Library";
+ ot->idname = "OUTLINER_OT_lib_reload";
+ ot->description = "Reload the library under cursor";
- ot->invoke = outliner_lib_delete_invoke;
+ ot->invoke = outliner_lib_reload_invoke;
ot->poll = ED_operator_outliner_active;
}
+void lib_reload_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te,
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+{
+ wmOperatorType *ot = WM_operatortype_find("WM_OT_lib_reload", false);
+
+ lib_relocate(C, te, tselem, ot, true);
+}
+
/* ************************************************************** */
/* Setting Toggling Operators */
@@ -468,8 +787,9 @@ int common_restrict_check(bContext *C, Object *ob)
/* Toggle Visibility ---------------------------------------- */
-void object_toggle_visibility_cb(bContext *C, Scene *scene, TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+void object_toggle_visibility_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *scene, TreeElement *te,
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Base *base = (Base *)te->directdata;
Object *ob = (Object *)tselem->id;
@@ -484,21 +804,22 @@ void object_toggle_visibility_cb(bContext *C, Scene *scene, TreeElement *te,
}
}
-void group_toggle_visibility_cb(bContext *UNUSED(C), Scene *scene, TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+void group_toggle_visibility_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Group *group = (Group *)tselem->id;
restrictbutton_gr_restrict_flag(scene, group, OB_RESTRICT_VIEW);
}
-static int outliner_toggle_visibility_exec(bContext *C, wmOperator *UNUSED(op))
+static int outliner_toggle_visibility_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
- outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_visibility_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_visibility_cb);
DAG_id_type_tag(bmain, ID_OB);
WM_event_add_notifier(C, NC_SCENE | ND_OB_VISIBLE, scene);
@@ -523,8 +844,9 @@ void OUTLINER_OT_visibility_toggle(wmOperatorType *ot)
/* Toggle Selectability ---------------------------------------- */
-void object_toggle_selectability_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+void object_toggle_selectability_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *te,
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Base *base = (Base *)te->directdata;
@@ -534,20 +856,21 @@ void object_toggle_selectability_cb(bContext *UNUSED(C), Scene *scene, TreeEleme
}
}
-void group_toggle_selectability_cb(bContext *UNUSED(C), Scene *scene, TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+void group_toggle_selectability_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Group *group = (Group *)tselem->id;
restrictbutton_gr_restrict_flag(scene, group, OB_RESTRICT_SELECT);
}
-static int outliner_toggle_selectability_exec(bContext *C, wmOperator *UNUSED(op))
+static int outliner_toggle_selectability_exec(bContext *C, wmOperator *op)
{
SpaceOops *soops = CTX_wm_space_outliner(C);
Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
- outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_selectability_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_selectability_cb);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
ED_region_tag_redraw(ar);
@@ -571,8 +894,9 @@ void OUTLINER_OT_selectability_toggle(wmOperatorType *ot)
/* Toggle Renderability ---------------------------------------- */
-void object_toggle_renderability_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+void object_toggle_renderability_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *te,
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Base *base = (Base *)te->directdata;
@@ -582,20 +906,21 @@ void object_toggle_renderability_cb(bContext *UNUSED(C), Scene *scene, TreeEleme
}
}
-void group_toggle_renderability_cb(bContext *UNUSED(C), Scene *scene, TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+void group_toggle_renderability_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Group *group = (Group *)tselem->id;
restrictbutton_gr_restrict_flag(scene, group, OB_RESTRICT_RENDER);
}
-static int outliner_toggle_renderability_exec(bContext *C, wmOperator *UNUSED(op))
+static int outliner_toggle_renderability_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
Scene *scene = CTX_data_scene(C);
- outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_renderability_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_renderability_cb);
DAG_id_type_tag(bmain, ID_OB);
WM_event_add_notifier(C, NC_SCENE | ND_OB_RENDER, scene);
@@ -2079,36 +2404,3 @@ void OUTLINER_OT_group_link(wmOperatorType *ot)
/* properties */
RNA_def_string(ot->srna, "object", "Object", MAX_ID_NAME, "Object", "Target Object");
}
-
-/******** Utils to clear any ref to freed ID... **********/
-
-void ED_outliner_id_unref(SpaceOops *so, const ID *id)
-{
- /* Some early out checks. */
- if (!TREESTORE_ID_TYPE(id)) {
- return; /* ID type is not used by outilner... */
- }
-
- if (so->search_tse.id == id) {
- so->search_tse.id = NULL;
- }
-
- if (so->treestore) {
- TreeStoreElem *tselem;
- BLI_mempool_iter iter;
- bool changed = false;
-
- BLI_mempool_iternew(so->treestore, &iter);
- while ((tselem = BLI_mempool_iterstep(&iter))) {
- if (tselem->id == id) {
- tselem->id = NULL;
- changed = true;
- }
- }
- if (so->treehash && changed) {
- /* rebuild hash table, because it depends on ids too */
- /* postpone a full rebuild because this can be called many times on-free */
- so->storeflag |= SO_TREESTORE_REBUILD;
- }
- }
-}
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index dc81be7a8e0..d2666cd0b6d 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -153,35 +153,58 @@ eOLDrawState tree_element_active(struct bContext *C, struct Scene *scene, SpaceO
int outliner_item_do_activate(struct bContext *C, int x, int y, bool extend, bool recursive);
/* outliner_edit.c ---------------------------------------------- */
+typedef void (*outliner_operation_cb)(
+ struct bContext *C, struct ReportList *, struct Scene *scene,
+ struct TreeElement *, struct TreeStoreElem *, TreeStoreElem *, void *);
void outliner_do_object_operation_ex(
- struct bContext *C, struct Scene *scene, struct SpaceOops *soops, struct ListBase *lb,
- void (*operation_cb)(struct bContext *C, struct Scene *scene,
- struct TreeElement *, struct TreeStoreElem *, TreeStoreElem *, void *),
- bool recurse_selected);
+ struct bContext *C, ReportList *reports, struct Scene *scene, struct SpaceOops *soops, struct ListBase *lb,
+ outliner_operation_cb operation_cb, bool recurse_selected);
void outliner_do_object_operation(
- struct bContext *C, struct Scene *scene, struct SpaceOops *soops, struct ListBase *lb,
- void (*operation_cb)(struct bContext *C, struct Scene *scene,
- struct TreeElement *, struct TreeStoreElem *, TreeStoreElem *, void *));
+ struct bContext *C, ReportList *reports, struct Scene *scene, struct SpaceOops *soops, struct ListBase *lb,
+ outliner_operation_cb operation_cb);
int common_restrict_check(struct bContext *C, struct Object *ob);
int outliner_has_one_flag(struct SpaceOops *soops, ListBase *lb, short flag, const int curlevel);
void outliner_set_flag(struct SpaceOops *soops, ListBase *lb, short flag, short set);
-void object_toggle_visibility_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
-void object_toggle_selectability_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
-void object_toggle_renderability_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
-
-
-void group_toggle_visibility_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
-void group_toggle_selectability_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
-void group_toggle_renderability_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
-
-void item_rename_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+void object_toggle_visibility_cb(
+ struct bContext *C, struct ReportList *reports, struct Scene *scene,
+ TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+void object_toggle_selectability_cb(
+ struct bContext *C, struct ReportList *reports, struct Scene *scene,
+ TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+void object_toggle_renderability_cb(
+ struct bContext *C, struct ReportList *reports, struct Scene *scene,
+ TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+
+
+void group_toggle_visibility_cb(
+ struct bContext *C, struct ReportList *reports, struct Scene *scene,
+ TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+void group_toggle_selectability_cb(
+ struct bContext *C, struct ReportList *reports, struct Scene *scene,
+ TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+void group_toggle_renderability_cb(
+ struct bContext *C, struct ReportList *reports, struct Scene *scene,
+ TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+
+void item_rename_cb(
+ struct bContext *C, struct ReportList *reports, struct Scene *scene,
+ TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+void lib_relocate_cb(
+ struct bContext *C, struct ReportList *reports, struct Scene *scene, struct TreeElement *te,
+ struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+void lib_reload_cb(
+ struct bContext *C, struct ReportList *reports, struct Scene *scene, struct TreeElement *te,
+ struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
-void lib_delete_cb(
- struct bContext *C, struct Scene *scene, struct TreeElement *te,
+void id_delete_cb(
+ struct bContext *C, struct ReportList *reports, struct Scene *scene, struct TreeElement *te,
+ struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+void id_remap_cb(
+ struct bContext *C, struct ReportList *reports, struct Scene *scene, struct TreeElement *te,
struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
TreeElement *outliner_dropzone_find(const struct SpaceOops *soops, const float fmval[2], const bool children);
@@ -190,8 +213,10 @@ TreeElement *outliner_dropzone_find(const struct SpaceOops *soops, const float f
void OUTLINER_OT_item_activate(struct wmOperatorType *ot);
void OUTLINER_OT_item_openclose(struct wmOperatorType *ot);
void OUTLINER_OT_item_rename(struct wmOperatorType *ot);
+void OUTLINER_OT_lib_relocate(struct wmOperatorType *ot);
+void OUTLINER_OT_lib_reload(struct wmOperatorType *ot);
-void OUTLINER_OT_lib_delete(struct wmOperatorType *ot);
+void OUTLINER_OT_id_delete(struct wmOperatorType *ot);
void OUTLINER_OT_show_one_level(struct wmOperatorType *ot);
void OUTLINER_OT_show_active(struct wmOperatorType *ot);
@@ -230,6 +255,7 @@ void OUTLINER_OT_object_operation(struct wmOperatorType *ot);
void OUTLINER_OT_group_operation(struct wmOperatorType *ot);
void OUTLINER_OT_lib_operation(struct wmOperatorType *ot);
void OUTLINER_OT_id_operation(struct wmOperatorType *ot);
+void OUTLINER_OT_id_remap(struct wmOperatorType *ot);
void OUTLINER_OT_data_operation(struct wmOperatorType *ot);
void OUTLINER_OT_animdata_operation(struct wmOperatorType *ot);
void OUTLINER_OT_action_set(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c
index 720cfe12567..776717c8443 100644
--- a/source/blender/editors/space_outliner/outliner_ops.c
+++ b/source/blender/editors/space_outliner/outliner_ops.c
@@ -47,13 +47,15 @@ void outliner_operatortypes(void)
WM_operatortype_append(OUTLINER_OT_select_border);
WM_operatortype_append(OUTLINER_OT_item_openclose);
WM_operatortype_append(OUTLINER_OT_item_rename);
- WM_operatortype_append(OUTLINER_OT_lib_delete);
WM_operatortype_append(OUTLINER_OT_operation);
WM_operatortype_append(OUTLINER_OT_scene_operation);
WM_operatortype_append(OUTLINER_OT_object_operation);
WM_operatortype_append(OUTLINER_OT_group_operation);
WM_operatortype_append(OUTLINER_OT_lib_operation);
+ WM_operatortype_append(OUTLINER_OT_lib_relocate);
WM_operatortype_append(OUTLINER_OT_id_operation);
+ WM_operatortype_append(OUTLINER_OT_id_delete);
+ WM_operatortype_append(OUTLINER_OT_id_remap);
WM_operatortype_append(OUTLINER_OT_data_operation);
WM_operatortype_append(OUTLINER_OT_animdata_operation);
WM_operatortype_append(OUTLINER_OT_action_set);
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index 83677b6bd86..bfec62997e1 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -57,6 +57,8 @@
#include "BKE_fcurve.h"
#include "BKE_group.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_scene.h"
@@ -133,15 +135,17 @@ static void set_operation_types(SpaceOops *soops, ListBase *lb,
}
}
-static void unlink_action_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data))
+static void unlink_action_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data))
{
/* just set action to NULL */
BKE_animdata_set_action(CTX_wm_reports(C), tsep->id, NULL);
}
-static void unlink_material_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *te,
- TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data))
+static void unlink_material_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te,
+ TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data))
{
Material **matar = NULL;
int a, totcol = 0;
@@ -180,8 +184,9 @@ static void unlink_material_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeEl
}
}
-static void unlink_texture_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *te,
- TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data))
+static void unlink_texture_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te,
+ TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data))
{
MTex **mtex = NULL;
int a;
@@ -217,7 +222,7 @@ static void unlink_texture_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeEle
}
static void unlink_group_cb(
- bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
{
Group *group = (Group *)tselem->id;
@@ -230,12 +235,14 @@ static void unlink_group_cb(
}
else {
Main *bmain = CTX_data_main(C);
- BKE_group_unlink(bmain, group);
+ BKE_libblock_unlink(bmain, group, false, false);
+ BKE_libblock_free(bmain, group);
}
}
-static void unlink_world_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
+static void unlink_world_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
{
Scene *parscene = (Scene *)tsep->id;
World *wo = (World *)tselem->id;
@@ -246,8 +253,8 @@ static void unlink_world_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeEleme
}
static void outliner_do_libdata_operation(
- bContext *C, Scene *scene, SpaceOops *soops, ListBase *lb,
- void (*operation_cb)(bContext *C, Scene *scene, TreeElement *, TreeStoreElem *, TreeStoreElem *, void *),
+ bContext *C, ReportList *reports, Scene *scene, SpaceOops *soops, ListBase *lb,
+ outliner_operation_cb operation_cb,
void *user_data)
{
TreeElement *te;
@@ -258,11 +265,11 @@ static void outliner_do_libdata_operation(
if (tselem->flag & TSE_SELECTED) {
if (tselem->type == 0) {
TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL;
- operation_cb(C, scene, te, tsep, tselem, user_data);
+ operation_cb(C, reports, scene, te, tsep, tselem, user_data);
}
}
if (TSELEM_OPEN(tselem, soops)) {
- outliner_do_libdata_operation(C, scene, soops, &te->subtree, operation_cb, user_data);
+ outliner_do_libdata_operation(C, reports, scene, soops, &te->subtree, operation_cb, user_data);
}
}
}
@@ -352,8 +359,9 @@ void OUTLINER_OT_scene_operation(wmOperatorType *ot)
}
/* ******************************************** */
-static void object_select_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+static void object_select_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *te,
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Base *base = (Base *)te->directdata;
@@ -364,8 +372,9 @@ static void object_select_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te,
}
}
-static void object_select_hierarchy_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data))
+static void object_select_hierarchy_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data))
{
/* From where do i get the x,y coordinate of the mouse event ? */
wmWindow *win = CTX_wm_window(C);
@@ -375,8 +384,9 @@ static void object_select_hierarchy_cb(bContext *C, Scene *UNUSED(scene), TreeEl
}
-static void object_deselect_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+static void object_deselect_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *te,
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Base *base = (Base *)te->directdata;
@@ -387,14 +397,27 @@ static void object_deselect_cb(bContext *UNUSED(C), Scene *scene, TreeElement *t
}
}
-static void object_delete_cb(bContext *C, Scene *scene, TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+static void object_delete_cb(
+ bContext *C, ReportList *reports, Scene *scene, TreeElement *te,
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Base *base = (Base *)te->directdata;
if (base == NULL)
base = BKE_scene_base_find(scene, (Object *)tselem->id);
if (base) {
+ Main *bmain = CTX_data_main(C);
+ if (base->object->id.tag & LIB_TAG_INDIRECT) {
+ BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", base->object->id.name + 2);
+ return;
+ }
+ else if (BKE_library_ID_is_indirectly_used(bmain, base->object) && ID_REAL_USERS(base->object) <= 1) {
+ BKE_reportf(reports, RPT_WARNING,
+ "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user",
+ base->object->id.name + 2, scene->id.name + 2);
+ return;
+ }
+
// check also library later
if (scene->obedit == base->object)
ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO);
@@ -408,8 +431,9 @@ static void object_delete_cb(bContext *C, Scene *scene, TreeElement *te,
}
}
-static void id_local_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+static void id_local_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
if (tselem->id->lib && (tselem->id->tag & LIB_TAG_EXTERN)) {
/* if the ID type has no special local function,
@@ -421,32 +445,36 @@ static void id_local_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(t
}
}
-static void id_fake_user_set_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+static void id_fake_user_set_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
ID *id = tselem->id;
id_fake_user_set(id);
}
-static void id_fake_user_clear_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+static void id_fake_user_clear_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
ID *id = tselem->id;
id_fake_user_clear(id);
}
-static void id_select_linked_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+static void id_select_linked_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
ID *id = tselem->id;
ED_object_select_linked_by_id(C, id);
}
-static void singleuser_action_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
+static void singleuser_action_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
{
ID *id = tselem->id;
@@ -462,8 +490,9 @@ static void singleuser_action_cb(bContext *C, Scene *UNUSED(scene), TreeElement
}
}
-static void singleuser_world_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
+static void singleuser_world_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
{
ID *id = tselem->id;
@@ -480,8 +509,9 @@ static void singleuser_world_cb(bContext *C, Scene *UNUSED(scene), TreeElement *
}
}
-static void group_linkobs2scene_cb(bContext *UNUSED(C), Scene *scene, TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+static void group_linkobs2scene_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Group *group = (Group *)tselem->id;
GroupObject *gob;
@@ -506,8 +536,9 @@ static void group_linkobs2scene_cb(bContext *UNUSED(C), Scene *scene, TreeElemen
}
}
-static void group_instance_cb(bContext *C, Scene *scene, TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+static void group_instance_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Group *group = (Group *)tselem->id;
@@ -521,10 +552,8 @@ static void group_instance_cb(bContext *C, Scene *scene, TreeElement *UNUSED(te)
* \param select_recurse: Set to false for operations which are already recursively operating on their children.
*/
void outliner_do_object_operation_ex(
- bContext *C, Scene *scene_act, SpaceOops *soops, ListBase *lb,
- void (*operation_cb)(bContext *C, Scene *scene, TreeElement *,
- TreeStoreElem *, TreeStoreElem *, void *),
- bool select_recurse)
+ bContext *C, ReportList *reports, Scene *scene_act, SpaceOops *soops, ListBase *lb,
+ outliner_operation_cb operation_cb, bool select_recurse)
{
TreeElement *te;
@@ -541,23 +570,24 @@ void outliner_do_object_operation_ex(
/* important to use 'scene_owner' not scene_act else deleting objects can crash.
* only use 'scene_act' when 'scene_owner' is NULL, which can happen when the
* outliner isn't showing scenes: Visible Layer draw mode for eg. */
- operation_cb(C, scene_owner ? scene_owner : scene_act, te, NULL, tselem, NULL);
+ operation_cb(C, reports, scene_owner ? scene_owner : scene_act, te, NULL, tselem, NULL);
select_handled = true;
}
}
if (TSELEM_OPEN(tselem, soops)) {
if ((select_handled == false) || select_recurse) {
- outliner_do_object_operation_ex(C, scene_act, soops, &te->subtree, operation_cb, select_recurse);
+ outliner_do_object_operation_ex(
+ C, reports, scene_act, soops, &te->subtree, operation_cb, select_recurse);
}
}
}
}
void outliner_do_object_operation(
- bContext *C, Scene *scene_act, SpaceOops *soops, ListBase *lb,
- void (*operation_cb)(bContext *, Scene *, TreeElement *, TreeStoreElem *, TreeStoreElem *, void *))
+ bContext *C, ReportList *reports, Scene *scene_act, SpaceOops *soops, ListBase *lb,
+ outliner_operation_cb operation_cb)
{
- outliner_do_object_operation_ex(C, scene_act, soops, lb, operation_cb, true);
+ outliner_do_object_operation_ex(C, reports, scene_act, soops, lb, operation_cb, true);
}
/* ******************************************** */
@@ -565,7 +595,7 @@ void outliner_do_object_operation(
static void clear_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te),
TreeStoreElem *tselem, void *UNUSED(arg))
{
- BKE_animdata_free(tselem->id);
+ BKE_animdata_free(tselem->id, true);
}
@@ -792,7 +822,7 @@ static void outliner_do_data_operation(SpaceOops *soops, int type, int event, Li
}
}
-static Base *outline_delete_hierarchy(bContext *C, Scene *scene, Base *base)
+static Base *outline_delete_hierarchy(bContext *C, ReportList *reports, Scene *scene, Base *base)
{
Base *child_base, *base_next;
Object *parent;
@@ -805,17 +835,30 @@ static Base *outline_delete_hierarchy(bContext *C, Scene *scene, Base *base)
base_next = child_base->next;
for (parent = child_base->object->parent; parent && (parent != base->object); parent = parent->parent);
if (parent) {
- base_next = outline_delete_hierarchy(C, scene, child_base);
+ base_next = outline_delete_hierarchy(C, reports, scene, child_base);
}
}
base_next = base->next;
+
+ Main *bmain = CTX_data_main(C);
+ if (base->object->id.tag & LIB_TAG_INDIRECT) {
+ BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", base->object->id.name + 2);
+ return base_next;
+ }
+ else if (BKE_library_ID_is_indirectly_used(bmain, base->object) && ID_REAL_USERS(base->object) <= 1) {
+ BKE_reportf(reports, RPT_WARNING,
+ "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user",
+ base->object->id.name + 2, scene->id.name + 2);
+ return base_next;
+ }
ED_base_object_free_and_unlink(CTX_data_main(C), scene, base);
return base_next;
}
static void object_delete_hierarchy_cb(
- bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+ bContext *C, ReportList *reports, Scene *scene,
+ TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Base *base = (Base *)te->directdata;
Object *obedit = scene->obedit;
@@ -830,7 +873,7 @@ static void object_delete_hierarchy_cb(
ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO);
}
- outline_delete_hierarchy(C, scene, base);
+ outline_delete_hierarchy(C, reports, scene, base);
/* leave for ED_outliner_id_unref to handle */
#if 0
te->directdata = NULL;
@@ -849,6 +892,7 @@ enum {
OL_OP_SELECT_HIERARCHY,
OL_OP_DELETE,
OL_OP_DELETE_HIERARCHY,
+ OL_OP_REMAP,
OL_OP_LOCALIZED, /* disabled, see below */
OL_OP_TOGVIS,
OL_OP_TOGSEL,
@@ -862,6 +906,8 @@ static EnumPropertyItem prop_object_op_types[] = {
{OL_OP_SELECT_HIERARCHY, "SELECT_HIERARCHY", 0, "Select Hierarchy", ""},
{OL_OP_DELETE, "DELETE", 0, "Delete", ""},
{OL_OP_DELETE_HIERARCHY, "DELETE_HIERARCHY", 0, "Delete Hierarchy", ""},
+ {OL_OP_REMAP, "REMAP", 0, "Remap Users",
+ "Make all users of selected datablocks to use instead a new chosen one"},
{OL_OP_TOGVIS, "TOGVIS", 0, "Toggle Visible", ""},
{OL_OP_TOGSEL, "TOGSEL", 0, "Toggle Selectable", ""},
{OL_OP_TOGREN, "TOGREN", 0, "Toggle Renderable", ""},
@@ -885,7 +931,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
if (event == OL_OP_SELECT) {
Scene *sce = scene; // to be able to delete, scenes are set...
- outliner_do_object_operation(C, scene, soops, &soops->tree, object_select_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_select_cb);
if (scene != sce) {
ED_screen_set_scene(C, CTX_wm_screen(C), sce);
}
@@ -895,7 +941,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
}
else if (event == OL_OP_SELECT_HIERARCHY) {
Scene *sce = scene; // to be able to delete, scenes are set...
- outliner_do_object_operation_ex(C, scene, soops, &soops->tree, object_select_hierarchy_cb, false);
+ outliner_do_object_operation_ex(C, op->reports, scene, soops, &soops->tree, object_select_hierarchy_cb, false);
if (scene != sce) {
ED_screen_set_scene(C, CTX_wm_screen(C), sce);
}
@@ -903,12 +949,12 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
else if (event == OL_OP_DESELECT) {
- outliner_do_object_operation(C, scene, soops, &soops->tree, object_deselect_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_deselect_cb);
str = "Deselect Objects";
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
else if (event == OL_OP_DELETE) {
- outliner_do_object_operation(C, scene, soops, &soops->tree, object_delete_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_delete_cb);
/* XXX: tree management normally happens from draw_outliner(), but when
* you're clicking to fast on Delete object from context menu in
@@ -922,7 +968,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
}
else if (event == OL_OP_DELETE_HIERARCHY) {
- outliner_do_object_operation_ex(C, scene, soops, &soops->tree, object_delete_hierarchy_cb, false);
+ outliner_do_object_operation_ex(C, op->reports, scene, soops, &soops->tree, object_delete_hierarchy_cb, false);
/* XXX: See OL_OP_DELETE comment above. */
outliner_cleanup_tree(soops);
@@ -931,27 +977,31 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
str = "Delete Object Hierarchy";
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
}
+ else if (event == OL_OP_REMAP) {
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL);
+ str = "Remap ID";
+ }
else if (event == OL_OP_LOCALIZED) { /* disabled, see above enum (ton) */
- outliner_do_object_operation(C, scene, soops, &soops->tree, id_local_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb);
str = "Localized Objects";
}
else if (event == OL_OP_TOGVIS) {
- outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_visibility_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_visibility_cb);
str = "Toggle Visibility";
WM_event_add_notifier(C, NC_SCENE | ND_OB_VISIBLE, scene);
}
else if (event == OL_OP_TOGSEL) {
- outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_selectability_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_selectability_cb);
str = "Toggle Selectability";
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
else if (event == OL_OP_TOGREN) {
- outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_renderability_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_renderability_cb);
str = "Toggle Renderability";
WM_event_add_notifier(C, NC_SCENE | ND_OB_RENDER, scene);
}
else if (event == OL_OP_RENAME) {
- outliner_do_object_operation(C, scene, soops, &soops->tree, item_rename_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb);
str = "Rename Object";
}
else {
@@ -988,6 +1038,8 @@ typedef enum eOutliner_PropGroupOps {
OL_GROUPOP_UNLINK = 1,
OL_GROUPOP_LOCAL,
OL_GROUPOP_LINK,
+ OL_GROUPOP_DELETE,
+ OL_GROUPOP_REMAP,
OL_GROUPOP_INSTANCE,
OL_GROUPOP_TOGVIS,
OL_GROUPOP_TOGSEL,
@@ -999,6 +1051,9 @@ static EnumPropertyItem prop_group_op_types[] = {
{OL_GROUPOP_UNLINK, "UNLINK", 0, "Unlink Group", ""},
{OL_GROUPOP_LOCAL, "LOCAL", 0, "Make Local Group", ""},
{OL_GROUPOP_LINK, "LINK", 0, "Link Group Objects to Scene", ""},
+ {OL_GROUPOP_DELETE, "DELETE", 0, "Delete Group", "WARNING: no undo"},
+ {OL_GROUPOP_REMAP, "REMAP", 0, "Remap Users",
+ "Make all users of selected datablocks to use instead current (clicked) one"},
{OL_GROUPOP_INSTANCE, "INSTANCE", 0, "Instance Groups in Scene", ""},
{OL_GROUPOP_TOGVIS, "TOGVIS", 0, "Toggle Visible Group", ""},
{OL_GROUPOP_TOGSEL, "TOGSEL", 0, "Toggle Selectable", ""},
@@ -1021,38 +1076,41 @@ static int outliner_group_operation_exec(bContext *C, wmOperator *op)
switch (event) {
case OL_GROUPOP_UNLINK:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_group_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_group_cb, NULL);
break;
case OL_GROUPOP_LOCAL:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_local_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb, NULL);
break;
case OL_GROUPOP_LINK:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_linkobs2scene_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_linkobs2scene_cb, NULL);
break;
case OL_GROUPOP_INSTANCE:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_instance_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_instance_cb, NULL);
+ /* works without this except if you try render right after, see: 22027 */
+ DAG_relations_tag_update(CTX_data_main(C));
+ break;
+ case OL_GROUPOP_DELETE:
+ WM_operator_name_call(C, "OUTLINER_OT_id_delete", WM_OP_INVOKE_REGION_WIN, NULL);
+ break;
+ case OL_GROUPOP_REMAP:
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL);
break;
case OL_GROUPOP_TOGVIS:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_visibility_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_toggle_visibility_cb, NULL);
break;
case OL_GROUPOP_TOGSEL:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_selectability_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_toggle_selectability_cb, NULL);
break;
case OL_GROUPOP_TOGREN:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_renderability_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_toggle_renderability_cb, NULL);
break;
case OL_GROUPOP_RENAME:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, item_rename_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL);
break;
default:
BLI_assert(0);
}
- if (event == 3) { /* instance */
- /* works without this except if you try render right after, see: 22027 */
- DAG_relations_tag_update(CTX_data_main(C));
- }
-
ED_undo_push(C, prop_group_op_types[event - 1].name);
WM_event_add_notifier(C, NC_GROUP, NULL);
@@ -1085,6 +1143,8 @@ typedef enum eOutlinerIdOpTypes {
OUTLINER_IDOP_UNLINK,
OUTLINER_IDOP_LOCAL,
OUTLINER_IDOP_SINGLE,
+ OUTLINER_IDOP_DELETE,
+ OUTLINER_IDOP_REMAP,
OUTLINER_IDOP_FAKE_ADD,
OUTLINER_IDOP_FAKE_CLEAR,
@@ -1098,6 +1158,9 @@ static EnumPropertyItem prop_id_op_types[] = {
{OUTLINER_IDOP_UNLINK, "UNLINK", 0, "Unlink", ""},
{OUTLINER_IDOP_LOCAL, "LOCAL", 0, "Make Local", ""},
{OUTLINER_IDOP_SINGLE, "SINGLE", 0, "Make Single User", ""},
+ {OUTLINER_IDOP_DELETE, "DELETE", 0, "Delete", "WARNING: no undo"},
+ {OUTLINER_IDOP_REMAP, "REMAP", 0, "Remap Users",
+ "Make all users of selected datablocks to use instead current (clicked) one"},
{OUTLINER_IDOP_FAKE_ADD, "ADD_FAKE", 0, "Add Fake User",
"Ensure datablock gets saved even if it isn't in use (e.g. for motion and material libraries)"},
{OUTLINER_IDOP_FAKE_CLEAR, "CLEAR_FAKE", 0, "Clear Fake User", ""},
@@ -1127,25 +1190,25 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
/* unlink datablock from its parent */
switch (idlevel) {
case ID_AC:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_action_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_action_cb, NULL);
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
ED_undo_push(C, "Unlink action");
break;
case ID_MA:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_material_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_material_cb, NULL);
WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, NULL);
ED_undo_push(C, "Unlink material");
break;
case ID_TE:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_texture_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_texture_cb, NULL);
WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, NULL);
ED_undo_push(C, "Unlink texture");
break;
case ID_WO:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_world_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_world_cb, NULL);
WM_event_add_notifier(C, NC_SCENE | ND_WORLD, NULL);
ED_undo_push(C, "Unlink world");
@@ -1159,7 +1222,7 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_IDOP_LOCAL:
{
/* make local */
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_local_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb, NULL);
ED_undo_push(C, "Localized Data");
break;
}
@@ -1168,14 +1231,14 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
/* make single user */
switch (idlevel) {
case ID_AC:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, singleuser_action_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, singleuser_action_cb, NULL);
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
ED_undo_push(C, "Single-User Action");
break;
case ID_WO:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, singleuser_world_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, singleuser_world_cb, NULL);
WM_event_add_notifier(C, NC_SCENE | ND_WORLD, NULL);
ED_undo_push(C, "Single-User World");
@@ -1187,10 +1250,24 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
}
break;
}
+ case OUTLINER_IDOP_DELETE:
+ {
+ if (idlevel > 0) {
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_delete_cb, NULL);
+ }
+ break;
+ }
+ case OUTLINER_IDOP_REMAP:
+ {
+ if (idlevel > 0) {
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL);
+ }
+ break;
+ }
case OUTLINER_IDOP_FAKE_ADD:
{
/* set fake user */
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_fake_user_set_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_fake_user_set_cb, NULL);
WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
ED_undo_push(C, "Add Fake User");
@@ -1199,7 +1276,7 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_IDOP_FAKE_CLEAR:
{
/* clear fake user */
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_fake_user_clear_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_fake_user_clear_cb, NULL);
WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
ED_undo_push(C, "Clear Fake User");
@@ -1208,14 +1285,14 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_IDOP_RENAME:
{
/* rename */
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, item_rename_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL);
WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
ED_undo_push(C, "Rename");
break;
}
case OUTLINER_IDOP_SELECT_LINKED:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_select_linked_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_select_linked_cb, NULL);
ED_undo_push(C, "Select");
break;
@@ -1258,13 +1335,16 @@ typedef enum eOutlinerLibOpTypes {
OL_LIB_RENAME,
OL_LIB_DELETE,
+ OL_LIB_RELOCATE,
+ OL_LIB_RELOAD,
} eOutlinerLibOpTypes;
static EnumPropertyItem outliner_lib_op_type_items[] = {
{OL_LIB_RENAME, "RENAME", 0, "Rename", ""},
- {OL_LIB_DELETE, "DELETE", 0, "Delete", "Delete this library and all its item from Blender (needs a save/reload)"},
+ {OL_LIB_DELETE, "DELETE", 0, "Delete", "Delete this library and all its item from Blender - WARNING: no undo"},
+ {OL_LIB_RELOCATE, "RELOCATE", 0, "Relocate", "Select a new path for this library, and reload all its data"},
+ {OL_LIB_RELOAD, "RELOAD", 0, "Reload", "Reload all data from this library"},
{0, NULL, 0, NULL, NULL}
-
};
static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
@@ -1286,7 +1366,7 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
case OL_LIB_RENAME:
{
/* rename */
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, item_rename_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL);
WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
ED_undo_push(C, "Rename");
@@ -1294,13 +1374,19 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
}
case OL_LIB_DELETE:
{
- /* delete */
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, lib_delete_cb, NULL);
-
- WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
- /* Note: no undo possible here really, not 100% sure why...
- * Probably because of library optimizations in undo/redo process? */
- /* ED_undo_push(C, "Rename"); */
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_delete_cb, NULL);
+ break;
+ }
+ case OL_LIB_RELOCATE:
+ {
+ /* rename */
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, lib_relocate_cb, NULL);
+ break;
+ }
+ case OL_LIB_RELOAD:
+ {
+ /* rename */
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, lib_reload_cb, NULL);
break;
}
default:
diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c
index 1dd66366e5d..76bf9c701ed 100644
--- a/source/blender/editors/space_outliner/space_outliner.c
+++ b/source/blender/editors/space_outliner/space_outliner.c
@@ -486,6 +486,39 @@ static SpaceLink *outliner_duplicate(SpaceLink *sl)
return (SpaceLink *)soutlinern;
}
+static void outliner_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceOops *so = (SpaceOops *)slink;
+
+ /* Some early out checks. */
+ if (!TREESTORE_ID_TYPE(old_id)) {
+ return; /* ID type is not used by outilner... */
+ }
+
+ if (so->search_tse.id == old_id) {
+ so->search_tse.id = new_id;
+ }
+
+ if (so->treestore) {
+ TreeStoreElem *tselem;
+ BLI_mempool_iter iter;
+ bool changed = false;
+
+ BLI_mempool_iternew(so->treestore, &iter);
+ while ((tselem = BLI_mempool_iterstep(&iter))) {
+ if (tselem->id == old_id) {
+ tselem->id = new_id;
+ changed = true;
+ }
+ }
+ if (so->treehash && changed) {
+ /* rebuild hash table, because it depends on ids too */
+ /* postpone a full rebuild because this can be called many times on-free */
+ so->storeflag |= SO_TREESTORE_REBUILD;
+ }
+ }
+}
+
/* only called once, from space_api/spacetypes.c */
void ED_spacetype_outliner(void)
{
@@ -502,7 +535,8 @@ void ED_spacetype_outliner(void)
st->operatortypes = outliner_operatortypes;
st->keymap = outliner_keymap;
st->dropboxes = outliner_dropboxes;
-
+ st->id_remap = outliner_id_remap;
+
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype outliner region");
art->regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 9c2d115108d..adb7cf4940c 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -593,7 +593,6 @@ void draw_shadedstrip(Sequence *seq, unsigned char col[3], float x1, float y1, f
ymid1 = (y2 - y1) * 0.25f + y1;
ymid2 = (y2 - y1) * 0.65f + y1;
- glShadeModel(GL_SMOOTH);
glBegin(GL_QUADS);
if (seq->flag & SEQ_INVALID_EFFECT) { col[0] = 255; col[1] = 0; col[2] = 255; }
@@ -840,25 +839,25 @@ static void draw_seq_strip(const bContext *C, SpaceSeq *sseq, Scene *scene, AReg
else
UI_GetColorPtrShade3ubv(col, col, outline_tint);
- glColor3ubv((GLubyte *)col);
-
+ if ((seq->type == SEQ_TYPE_META) ||
+ ((seq->type == SEQ_TYPE_SCENE) && (seq->flag & SEQ_SCENE_STRIPS)))
+ {
+ drawmeta_contents(scene, seq, x1, y1, x2, y2);
+ }
+
if (seq->flag & SEQ_MUTE) {
glEnable(GL_LINE_STIPPLE);
glLineStipple(1, 0x8888);
}
+ glColor3ubv((GLubyte *)col);
+
UI_draw_roundbox_shade_x(GL_LINE_LOOP, x1, y1, x2, y2, 0.0, 0.1, 0.0);
if (seq->flag & SEQ_MUTE) {
glDisable(GL_LINE_STIPPLE);
}
- if ((seq->type == SEQ_TYPE_META) ||
- ((seq->type == SEQ_TYPE_SCENE) && (seq->flag & SEQ_SCENE_STRIPS)))
- {
- drawmeta_contents(scene, seq, x1, y1, x2, y2);
- }
-
/* calculate if seq is long enough to print a name */
x1 = seq->startdisp + handsize_clamped;
x2 = seq->enddisp - handsize_clamped;
@@ -1630,7 +1629,8 @@ void draw_timeline_seq(const bContext *C, ARegion *ar)
// NOTE: the gridlines are currently spaced every 25 frames, which is only fine for 25 fps, but maybe not for 30...
UI_view2d_constant_grid_draw(v2d);
- if (sseq->draw_flag & SEQ_DRAW_BACKDROP) {
+ /* Only draw backdrop in pure sequence view. */
+ if (sseq->view == SEQ_VIEW_SEQUENCE && sseq->draw_flag & SEQ_DRAW_BACKDROP) {
draw_image_seq(C, scene, ar, sseq, scene->r.cfra, 0, false, true);
UI_view2d_view_ortho(v2d);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index 3c2a66cd3af..48c49f36471 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -107,6 +107,7 @@ static void select_active_side(ListBase *seqbase, int sel_side, int channel, int
break;
case SEQ_SIDE_BOTH:
seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
+ seq->flag |= SELECT;
break;
}
}
@@ -812,7 +813,7 @@ static int sequencer_select_handles_exec(bContext *C, wmOperator *op)
seq->flag |= SEQ_RIGHTSEL;
break;
case SEQ_SIDE_BOTH:
- seq->flag |= SEQ_LEFTSEL + SEQ_RIGHTSEL;
+ seq->flag |= SEQ_LEFTSEL | SEQ_RIGHTSEL;
break;
}
}
@@ -942,16 +943,26 @@ void SEQUENCER_OT_select_border(wmOperatorType *ot)
/* ****** Selected Grouped ****** */
+enum {
+ SEQ_SELECT_GROUP_TYPE,
+ SEQ_SELECT_GROUP_TYPE_BASIC,
+ SEQ_SELECT_GROUP_TYPE_EFFECT,
+ SEQ_SELECT_GROUP_DATA,
+ SEQ_SELECT_GROUP_EFFECT,
+ SEQ_SELECT_GROUP_EFFECT_LINK,
+ SEQ_SELECT_GROUP_OVERLAP,
+};
+
static EnumPropertyItem sequencer_prop_select_grouped_types[] = {
- {1, "TYPE", 0, "Type", "Shared strip type"},
- {2, "TYPE_BASIC", 0, "Global Type", "All strips of same basic type (Graphical or Sound)"},
- {3, "TYPE_EFFECT", 0, "Effect Type",
+ {SEQ_SELECT_GROUP_TYPE, "TYPE", 0, "Type", "Shared strip type"},
+ {SEQ_SELECT_GROUP_TYPE_BASIC, "TYPE_BASIC", 0, "Global Type", "All strips of same basic type (Graphical or Sound)"},
+ {SEQ_SELECT_GROUP_TYPE_EFFECT, "TYPE_EFFECT", 0, "Effect Type",
"Shared strip effect type (if active strip is not an effect one, select all non-effect strips)"},
- {4, "DATA", 0, "Data", "Shared data (scene, image, sound, etc.)"},
- {5, "EFFECT", 0, "Effect", "Shared effects"},
- {6, "EFFECT_LINK", 0, "Effect/Linked",
+ {SEQ_SELECT_GROUP_DATA, "DATA", 0, "Data", "Shared data (scene, image, sound, etc.)"},
+ {SEQ_SELECT_GROUP_EFFECT, "EFFECT", 0, "Effect", "Shared effects"},
+ {SEQ_SELECT_GROUP_EFFECT_LINK, "EFFECT_LINK", 0, "Effect/Linked",
"Other strips affected by the active one (sharing some time, and below or effect-assigned)"},
- {7, "OVERLAP", 0, "Overlap", "Overlapping time"},
+ {SEQ_SELECT_GROUP_OVERLAP, "OVERLAP", 0, "Overlap", "Overlapping time"},
{0, NULL, 0, NULL, NULL}
};
@@ -961,14 +972,16 @@ static EnumPropertyItem sequencer_prop_select_grouped_types[] = {
#define SEQ_USE_DATA(_seq) (ELEM(_seq->type, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIECLIP, SEQ_TYPE_MASK) || SEQ_HAS_PATH(_seq))
-static bool select_grouped_type(Editing *ed, Sequence *actseq)
+#define SEQ_CHANNEL_CHECK(_seq, _chan) (ELEM((_chan), 0, (_seq)->machine))
+
+static bool select_grouped_type(Editing *ed, Sequence *actseq, const int channel)
{
Sequence *seq;
bool changed = false;
SEQP_BEGIN (ed, seq)
{
- if (seq->type == actseq->type) {
+ if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == actseq->type) {
seq->flag |= SELECT;
changed = true;
}
@@ -978,7 +991,7 @@ static bool select_grouped_type(Editing *ed, Sequence *actseq)
return changed;
}
-static bool select_grouped_type_basic(Editing *ed, Sequence *actseq)
+static bool select_grouped_type_basic(Editing *ed, Sequence *actseq, const int channel)
{
Sequence *seq;
bool changed = false;
@@ -986,7 +999,7 @@ static bool select_grouped_type_basic(Editing *ed, Sequence *actseq)
SEQP_BEGIN (ed, seq)
{
- if (is_sound ? SEQ_IS_SOUND(seq) : !SEQ_IS_SOUND(seq)) {
+ if (SEQ_CHANNEL_CHECK(seq, channel) && (is_sound ? SEQ_IS_SOUND(seq) : !SEQ_IS_SOUND(seq))) {
seq->flag |= SELECT;
changed = true;
}
@@ -996,7 +1009,7 @@ static bool select_grouped_type_basic(Editing *ed, Sequence *actseq)
return changed;
}
-static bool select_grouped_type_effect(Editing *ed, Sequence *actseq)
+static bool select_grouped_type_effect(Editing *ed, Sequence *actseq, const int channel)
{
Sequence *seq;
bool changed = false;
@@ -1004,7 +1017,7 @@ static bool select_grouped_type_effect(Editing *ed, Sequence *actseq)
SEQP_BEGIN (ed, seq)
{
- if (is_effect ? SEQ_IS_EFFECT(seq) : !SEQ_IS_EFFECT(seq)) {
+ if (SEQ_CHANNEL_CHECK(seq, channel) && (is_effect ? SEQ_IS_EFFECT(seq) : !SEQ_IS_EFFECT(seq))) {
seq->flag |= SELECT;
changed = true;
}
@@ -1014,7 +1027,7 @@ static bool select_grouped_type_effect(Editing *ed, Sequence *actseq)
return changed;
}
-static bool select_grouped_data(Editing *ed, Sequence *actseq)
+static bool select_grouped_data(Editing *ed, Sequence *actseq, const int channel)
{
Sequence *seq;
bool changed = false;
@@ -1026,7 +1039,7 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq)
if (SEQ_HAS_PATH(actseq) && dir) {
SEQP_BEGIN (ed, seq)
{
- if (SEQ_HAS_PATH(seq) && seq->strip && STREQ(seq->strip->dir, dir)) {
+ if (SEQ_CHANNEL_CHECK(seq, channel) && SEQ_HAS_PATH(seq) && seq->strip && STREQ(seq->strip->dir, dir)) {
seq->flag |= SELECT;
changed = true;
}
@@ -1037,7 +1050,7 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq)
Scene *sce = actseq->scene;
SEQP_BEGIN (ed, seq)
{
- if (seq->type == SEQ_TYPE_SCENE && seq->scene == sce) {
+ if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_SCENE && seq->scene == sce) {
seq->flag |= SELECT;
changed = true;
}
@@ -1048,7 +1061,7 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq)
MovieClip *clip = actseq->clip;
SEQP_BEGIN (ed, seq)
{
- if (seq->type == SEQ_TYPE_MOVIECLIP && seq->clip == clip) {
+ if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_MOVIECLIP && seq->clip == clip) {
seq->flag |= SELECT;
changed = true;
}
@@ -1059,7 +1072,7 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq)
struct Mask *mask = actseq->mask;
SEQP_BEGIN (ed, seq)
{
- if (seq->type == SEQ_TYPE_MASK && seq->mask == mask) {
+ if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_MASK && seq->mask == mask) {
seq->flag |= SELECT;
changed = true;
}
@@ -1070,7 +1083,7 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq)
return changed;
}
-static bool select_grouped_effect(Editing *ed, Sequence *actseq)
+static bool select_grouped_effect(Editing *ed, Sequence *actseq, const int channel)
{
Sequence *seq;
bool changed = false;
@@ -1082,7 +1095,9 @@ static bool select_grouped_effect(Editing *ed, Sequence *actseq)
SEQP_BEGIN (ed, seq)
{
- if ((seq->type & SEQ_TYPE_EFFECT) && ELEM(actseq, seq->seq1, seq->seq2, seq->seq3)) {
+ if (SEQ_CHANNEL_CHECK(seq, channel) && (seq->type & SEQ_TYPE_EFFECT) &&
+ ELEM(actseq, seq->seq1, seq->seq2, seq->seq3))
+ {
effects[seq->type] = true;
}
}
@@ -1090,7 +1105,7 @@ static bool select_grouped_effect(Editing *ed, Sequence *actseq)
SEQP_BEGIN (ed, seq)
{
- if (effects[seq->type]) {
+ if (SEQ_CHANNEL_CHECK(seq, channel) && effects[seq->type]) {
if (seq->seq1) seq->seq1->flag |= SELECT;
if (seq->seq2) seq->seq2->flag |= SELECT;
if (seq->seq3) seq->seq3->flag |= SELECT;
@@ -1119,7 +1134,7 @@ static bool select_grouped_time_overlap(Editing *ed, Sequence *actseq)
return changed;
}
-static bool select_grouped_effect_link(Editing *ed, Sequence *actseq)
+static bool select_grouped_effect_link(Editing *ed, Sequence *actseq, const int channel)
{
Sequence *seq = NULL;
bool changed = false;
@@ -1143,7 +1158,8 @@ static bool select_grouped_effect_link(Editing *ed, Sequence *actseq)
/* Ignore all seqs already selected! */
/* Ignore all seqs not sharing some time with active one. */
/* Ignore all seqs of incompatible types (audio vs video). */
- if ((seq->flag & SELECT) || (seq->startdisp >= enddisp) || (seq->enddisp < startdisp) ||
+ if (!SEQ_CHANNEL_CHECK(seq, channel) ||
+ (seq->flag & SELECT) || (seq->startdisp >= enddisp) || (seq->enddisp < startdisp) ||
(!is_audio && SEQ_IS_SOUND(seq)) ||
(is_audio && !((seq->type == SEQ_TYPE_META) || SEQ_IS_SOUND(seq))))
{
@@ -1189,17 +1205,19 @@ static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, false);
Sequence *seq, *actseq = BKE_sequencer_active_get(scene);
- int type = RNA_enum_get(op->ptr, "type");
- bool changed = false, extend;
- extend = RNA_boolean_get(op->ptr, "extend");
+ const int type = RNA_enum_get(op->ptr, "type");
+ const int channel = RNA_boolean_get(op->ptr, "use_active_channel") ? actseq->machine : 0;
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
+
+ bool changed = false;
if (actseq == NULL) {
BKE_report(op->reports, RPT_ERROR, "No active sequence!");
return OPERATOR_CANCELLED;
}
- if (extend == 0) {
+ if (!extend) {
SEQP_BEGIN (ed, seq)
{
seq->flag &= ~SELECT;
@@ -1208,13 +1226,32 @@ static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
SEQ_END;
}
- if (type == 1) changed |= select_grouped_type(ed, actseq);
- else if (type == 2) changed |= select_grouped_type_basic(ed, actseq);
- else if (type == 3) changed |= select_grouped_type_effect(ed, actseq);
- else if (type == 4) changed |= select_grouped_data(ed, actseq);
- else if (type == 5) changed |= select_grouped_effect(ed, actseq);
- else if (type == 6) changed |= select_grouped_effect_link(ed, actseq);
- else if (type == 7) changed |= select_grouped_time_overlap(ed, actseq);
+ switch (type) {
+ case SEQ_SELECT_GROUP_TYPE:
+ changed |= select_grouped_type(ed, actseq, channel);
+ break;
+ case SEQ_SELECT_GROUP_TYPE_BASIC:
+ changed |= select_grouped_type_basic(ed, actseq, channel);
+ break;
+ case SEQ_SELECT_GROUP_TYPE_EFFECT:
+ changed |= select_grouped_type_effect(ed, actseq, channel);
+ break;
+ case SEQ_SELECT_GROUP_DATA:
+ changed |= select_grouped_data(ed, actseq, channel);
+ break;
+ case SEQ_SELECT_GROUP_EFFECT:
+ changed |= select_grouped_effect(ed, actseq, channel);
+ break;
+ case SEQ_SELECT_GROUP_EFFECT_LINK:
+ changed |= select_grouped_effect_link(ed, actseq, channel);
+ break;
+ case SEQ_SELECT_GROUP_OVERLAP:
+ changed |= select_grouped_time_overlap(ed, actseq);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
if (changed) {
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
@@ -1240,7 +1277,9 @@ void SEQUENCER_OT_select_grouped(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting everything first");
ot->prop = RNA_def_enum(ot->srna, "type", sequencer_prop_select_grouped_types, 0, "Type", "");
+ RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting everything first");
+ RNA_def_boolean(ot->srna, "use_active_channel", false, "Same Channel",
+ "Only consider strips on the same channel as the active one");
}
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index fce40f8ca59..a2a80297041 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -32,6 +32,7 @@
#include <string.h>
#include <stdio.h>
+#include "DNA_gpencil_types.h"
#include "DNA_scene_types.h"
#include "DNA_mask_types.h"
@@ -41,6 +42,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_library.h"
#include "BKE_screen.h"
#include "BKE_sequencer.h"
#include "BKE_global.h"
@@ -687,6 +689,22 @@ static void sequencer_buttons_region_listener(bScreen *UNUSED(sc), ScrArea *UNUS
break;
}
}
+
+static void sequencer_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceSeq *sseq = (SpaceSeq *)slink;
+
+ if (!ELEM(GS(old_id->name), ID_GD)) {
+ return;
+ }
+
+ if ((ID *)sseq->gpd == old_id) {
+ sseq->gpd = (bGPdata *)new_id;
+ id_us_min(old_id);
+ id_us_plus(new_id);
+ }
+}
+
/* ************************************* */
/* only called once, from space/spacetypes.c */
@@ -708,6 +726,7 @@ void ED_spacetype_sequencer(void)
st->dropboxes = sequencer_dropboxes;
st->refresh = sequencer_refresh;
st->listener = sequencer_listener;
+ st->id_remap = sequencer_id_remap;
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region");
diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c
index 0a6a9a81e63..686a10fc785 100644
--- a/source/blender/editors/space_text/space_text.c
+++ b/source/blender/editors/space_text/space_text.c
@@ -38,6 +38,7 @@
#include "BLI_blenlib.h"
#include "BKE_context.h"
+#include "BKE_library.h"
#include "BKE_screen.h"
#include "BKE_text.h"
@@ -562,6 +563,20 @@ static void text_properties_region_draw(const bContext *C, ARegion *ar)
}
}
+static void text_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceText *stext = (SpaceText *)slink;
+
+ if (!ELEM(GS(old_id->name), ID_TXT)) {
+ return;
+ }
+
+ if ((ID *)stext->text == old_id) {
+ stext->text = (Text *)new_id;
+ id_us_ensure_real(new_id);
+ }
+}
+
/********************* registration ********************/
/* only called once, from space/spacetypes.c */
@@ -582,7 +597,8 @@ void ED_spacetype_text(void)
st->listener = text_listener;
st->context = text_context;
st->dropboxes = text_dropboxes;
-
+ st->id_remap = text_id_remap;
+
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype text region");
art->regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/space_text/text_autocomplete.c b/source/blender/editors/space_text/text_autocomplete.c
index 04cff288b03..c38c57b9528 100644
--- a/source/blender/editors/space_text/text_autocomplete.c
+++ b/source/blender/editors/space_text/text_autocomplete.c
@@ -259,10 +259,8 @@ static void confirm_suggestion(Text *text)
// for (i = 0; i < skipleft; i++)
// txt_move_left(text, 0);
- for (i = 0; i < over; i++)
- txt_move_left(text, 1);
-
- txt_insert_buf(text, sel->name);
+ BLI_assert(memcmp(sel->name, &line[i], over) == 0);
+ txt_insert_buf(text, sel->name + over);
// for (i = 0; i < skipleft; i++)
// txt_move_right(text, 0);
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index d404e7aaf15..94ed280f792 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -384,8 +384,7 @@ static int text_unlink_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- BKE_text_unlink(bmain, text);
- BKE_libblock_free(bmain, text);
+ BKE_libblock_delete(bmain, text);
text_drawcache_tag_update(st, 1);
WM_event_add_notifier(C, NC_TEXT | NA_REMOVED, NULL);
diff --git a/source/blender/editors/space_view3d/drawanimviz.c b/source/blender/editors/space_view3d/drawanimviz.c
index 9872b05da63..cf738de0202 100644
--- a/source/blender/editors/space_view3d/drawanimviz.c
+++ b/source/blender/editors/space_view3d/drawanimviz.c
@@ -130,7 +130,6 @@ void draw_motion_path_instance(Scene *scene,
mpv_start = (mpath->points + sind);
/* draw curve-line of path */
- glShadeModel(GL_SMOOTH);
glBegin(GL_LINE_STRIP);
for (i = 0, mpv = mpv_start; i < len; i++, mpv++) {
@@ -187,7 +186,6 @@ void draw_motion_path_instance(Scene *scene,
}
glEnd();
- glShadeModel(GL_FLAT);
glPointSize(1.0);
diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c
index f7c1e2ee981..1d9a515a5f2 100644
--- a/source/blender/editors/space_view3d/drawarmature.c
+++ b/source/blender/editors/space_view3d/drawarmature.c
@@ -431,10 +431,9 @@ static void draw_bonevert_solid(void)
glNewList(displist, GL_COMPILE);
qobj = gluNewQuadric();
- gluQuadricDrawStyle(qobj, GLU_FILL);
- glShadeModel(GL_SMOOTH);
+ gluQuadricDrawStyle(qobj, GLU_FILL);
+ /* Draw tips of a bone */
gluSphere(qobj, 0.05, 8, 5);
- glShadeModel(GL_FLAT);
gluDeleteQuadric(qobj);
glEndList();
@@ -890,7 +889,6 @@ static void draw_sphere_bone(const short dt, int armflag, int boneflag, short co
GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR);
gluQuadricDrawStyle(qobj, GLU_FILL);
- glShadeModel(GL_SMOOTH);
}
else {
gluQuadricDrawStyle(qobj, GLU_SILHOUETTE);
@@ -968,7 +966,6 @@ static void draw_sphere_bone(const short dt, int armflag, int boneflag, short co
/* restore */
if (dt == OB_SOLID) {
- glShadeModel(GL_FLAT);
GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
@@ -986,10 +983,11 @@ static GLubyte bm_dot7[] = {0x0, 0x38, 0x7C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38};
static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned int id,
bPoseChannel *pchan, EditBone *ebone)
{
+ /* call this once, avoid constant changing */
+ BLI_assert(glaGetOneInt(GL_UNPACK_ALIGNMENT) == 1);
+
float length;
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-
if (pchan)
length = pchan->bone->length;
else
@@ -1769,7 +1767,6 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
/* and draw blended distances */
if (arm->flag & ARM_POSEMODE) {
glEnable(GL_BLEND);
- //glShadeModel(GL_SMOOTH);
if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
@@ -1792,7 +1789,6 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
- //glShadeModel(GL_FLAT);
}
}
@@ -2216,7 +2212,6 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt)
/* and draw blended distances */
glEnable(GL_BLEND);
- //glShadeModel(GL_SMOOTH);
if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
@@ -2231,7 +2226,6 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt)
if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
- //glShadeModel(GL_FLAT);
}
/* if solid we draw it first */
@@ -2699,6 +2693,11 @@ bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
if (v3d->flag2 & V3D_RENDER_OVERRIDE)
return true;
+ /* needed for 'draw_line_bone' which draws pixel. */
+ if (arm->drawtype == ARM_LINE) {
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ }
+
if (dt > OB_WIRE) {
/* we use color for solid lighting */
if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) {
@@ -2774,5 +2773,9 @@ bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
/* restore */
glFrontFace(GL_CCW);
+ if (arm->drawtype == ARM_LINE) {
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+ }
+
return retval;
}
diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c
index 0bc6447d028..755d4985518 100644
--- a/source/blender/editors/space_view3d/drawmesh.c
+++ b/source/blender/editors/space_view3d/drawmesh.c
@@ -369,15 +369,18 @@ static bool set_draw_settings_cached(int clearcache, MTexPoly *texface, Material
}
if (c_badtex) lit = 0;
- if (lit != c_lit || ma != c_ma) {
- if (lit) {
- int options = GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR;
+ if (lit != c_lit || ma != c_ma || textured != c_textured) {
+ int options = GPU_SHADER_USE_COLOR;
- if (gtexdraw.two_sided_lighting)
- options |= GPU_SHADER_TWO_SIDED;
- if (c_textured && !c_badtex)
- options |= GPU_SHADER_TEXTURE_2D;
+ if (c_textured && !c_badtex) {
+ options |= GPU_SHADER_TEXTURE_2D;
+ }
+ if (gtexdraw.two_sided_lighting) {
+ options |= GPU_SHADER_TWO_SIDED;
+ }
+ if (lit) {
+ options |= GPU_SHADER_LIGHTING;
if (!ma)
ma = give_current_material_or_def(NULL, 0); /* default material */
@@ -385,12 +388,10 @@ static bool set_draw_settings_cached(int clearcache, MTexPoly *texface, Material
mul_v3_v3fl(specular, &ma->specr, ma->spec);
GPU_basic_shader_colors(NULL, specular, ma->har, 1.0f);
- GPU_basic_shader_bind(options);
- }
- else {
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
+ GPU_basic_shader_bind(options);
+
c_lit = lit;
c_ma = ma;
}
@@ -495,7 +496,6 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O
memcpy(Gtexdraw.obcol, obcol, sizeof(obcol));
set_draw_settings_cached(1, NULL, NULL, Gtexdraw);
- glShadeModel(GL_SMOOTH);
glCullFace(GL_BACK);
}
@@ -527,7 +527,6 @@ static void draw_textured_end(void)
GPU_set_tpage(NULL, 0, 0);
}
- glShadeModel(GL_FLAT);
glDisable(GL_CULL_FACE);
GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
@@ -980,10 +979,17 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d
if (ob == OBACT) {
if (ob->mode & OB_MODE_WEIGHT_PAINT) {
dm_draw_flag |= DM_DRAW_USE_COLORS | DM_DRAW_ALWAYS_SMOOTH | DM_DRAW_SKIP_HIDDEN;
-
}
else if (ob->mode & OB_MODE_SCULPT) {
- dm_draw_flag |= DM_DRAW_SKIP_HIDDEN;
+ dm_draw_flag |= DM_DRAW_SKIP_HIDDEN | DM_DRAW_USE_COLORS;
+ }
+ else if ((ob->mode & OB_MODE_TEXTURE_PAINT) == 0) {
+ dm_draw_flag |= DM_DRAW_USE_COLORS;
+ }
+ }
+ else {
+ if ((ob->mode & OB_MODE_TEXTURE_PAINT) == 0) {
+ dm_draw_flag |= DM_DRAW_USE_COLORS;
}
}
@@ -1311,8 +1317,8 @@ void draw_mesh_paint_weight_edges(RegionView3D *rv3d, DerivedMesh *dm,
}
glColor4ub(255, 255, 255, 96);
- glEnable(GL_LINE_STIPPLE);
- glLineStipple(1, 0xAAAA);
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ GPU_basic_shader_line_stipple(1, 0xAAAA);
dm->drawMappedEdges(dm, (DMSetDrawOptions)edgemask_cb, user_data);
@@ -1324,7 +1330,7 @@ void draw_mesh_paint_weight_edges(RegionView3D *rv3d, DerivedMesh *dm,
glEnable(GL_DEPTH_TEST);
}
- glDisable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
if (use_alpha) {
glDisable(GL_BLEND);
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 5768a37a0d9..acc20997b27 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -1209,7 +1209,7 @@ static void drawlamp(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
if ((drawcone || drawshadowbox) && !v3d->transp) {
/* in this case we need to draw delayed */
- ED_view3d_after_add(&v3d->afterdraw_transp, base, dflag);
+ ED_view3d_after_add(v3d->xray ? &v3d->afterdraw_xraytransp : &v3d->afterdraw_transp, base, dflag);
return;
}
@@ -1409,8 +1409,8 @@ static void drawlamp(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
float blend = z_abs * (1.0f - pow2f(la->spotblend));
/* hide line if it is zero size or overlaps with outer border,
- * previously it adjusted to always to show it but that seems
- * confusing because it doesn't show the actual blend size */
+ * previously it adjusted to always to show it but that seems
+ * confusing because it doesn't show the actual blend size */
if (blend != 0.0f && blend != z_abs) {
circ(0.0f, 0.0f, blend);
}
@@ -1600,12 +1600,9 @@ static void draw_bundle_sphere(void)
displist = glGenLists(1);
glNewList(displist, GL_COMPILE);
-
qobj = gluNewQuadric();
gluQuadricDrawStyle(qobj, GLU_FILL);
- glShadeModel(GL_SMOOTH);
gluSphere(qobj, 0.05, 8, 8);
- glShadeModel(GL_FLAT);
gluDeleteQuadric(qobj);
glEndList();
@@ -1787,8 +1784,6 @@ static void draw_viewport_reconstruction(
GPU_basic_shader_colors(NULL, NULL, 0, 1.0f);
GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR);
- glShadeModel(GL_SMOOTH);
-
tracking_object = tracking->objects.first;
while (tracking_object) {
draw_viewport_object_reconstruction(
@@ -1799,7 +1794,6 @@ static void draw_viewport_reconstruction(
}
/* restore */
- glShadeModel(GL_FLAT);
GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
if ((dflag & DRAW_CONSTCOLOR) == 0) {
@@ -1938,16 +1932,15 @@ static void drawcamera_stereo3d(
if (is_stereo3d_cameras) {
/* draw connecting lines */
- glPushAttrib(GL_ENABLE_BIT);
-
- glLineStipple(2, 0xAAAA);
- glEnable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ GPU_basic_shader_line_stipple(2, 0xAAAA);
glBegin(GL_LINES);
glVertex3fv(origin[0]);
glVertex3fv(origin[1]);
glEnd();
- glPopAttrib();
+
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
}
/* draw convergence plane */
@@ -2359,7 +2352,6 @@ static void drawlattice(View3D *v3d, Object *ob)
if (ob->defbase.first && lt->dvert) {
actdef_wcol = ob->actdef;
- glShadeModel(GL_SMOOTH);
}
}
@@ -2388,10 +2380,6 @@ static void drawlattice(View3D *v3d, Object *ob)
}
}
glEnd();
-
- /* restoration for weight colors */
- if (actdef_wcol)
- glShadeModel(GL_FLAT);
if (is_edit) {
BPoint *actbp = BKE_lattice_active_point_get(lt);
@@ -3256,17 +3244,15 @@ static void draw_em_fancy_edges(BMEditMesh *em, Scene *scene, View3D *v3d,
((ts->selectmode & SCE_SELECT_VERTEX) || (me->drawflag & ME_DRAWEIGHT)))
{
if (draw_dm_edges_weight_check(me, v3d)) {
- glShadeModel(GL_SMOOTH);
+ // Interpolate vertex weights
draw_dm_edges_weight_interp(em, cageDM, ts->weightuser);
- glShadeModel(GL_FLAT);
}
else if (ts->selectmode == SCE_SELECT_FACE) {
draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act);
}
else {
- glShadeModel(GL_SMOOTH);
+ // Interpolate vertex selection
draw_dm_edges_sel_interp(em, cageDM, wireCol, selCol);
- glShadeModel(GL_FLAT);
}
}
else {
@@ -3766,7 +3752,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
}
if ((dt > OB_WIRE) && (v3d->flag2 & V3D_RENDER_SHADOW)) {
- /* pass */
+ /* pass */
}
else {
/* annoying but active faces is stored differently */
@@ -4272,12 +4258,15 @@ static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3
if (ob == obedit || drawlinked) {
DerivedMesh *finalDM, *cageDM;
- if (obedit != ob)
- finalDM = cageDM = editbmesh_get_derived_base(ob, em);
- else
+ if (obedit != ob) {
+ finalDM = cageDM = editbmesh_get_derived_base(
+ ob, em, scene->customdata_mask);
+ }
+ else {
cageDM = editbmesh_get_derived_cage_and_final(
scene, ob, em, scene->customdata_mask,
&finalDM);
+ }
const bool use_material = ((me->drawflag & ME_DRAWEIGHT) == 0);
@@ -4469,10 +4458,6 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
glEnableClientState(GL_VERTEX_ARRAY);
- if (ob->type == OB_MBALL) { /* mball always smooth shaded */
- glShadeModel(GL_SMOOTH);
- }
-
/* track current material, -1 for none (needed for lines) */
short col = -1;
@@ -4494,7 +4479,6 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
// glVertexPointer(3, GL_FLOAT, 0, dl->verts);
// glDrawArrays(GL_LINE_STRIP, 0, dl->nr);
-
glBegin(GL_LINE_STRIP);
for (int nr = dl->nr; nr; nr--, data += 3)
glVertex3fv(data);
@@ -4525,15 +4509,15 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
GPU_object_material_bind(dl->col + 1, use_glsl ? &gattribs : NULL);
col = dl->col;
}
-
- if (dl->rt & CU_SMOOTH) glShadeModel(GL_SMOOTH);
- else glShadeModel(GL_FLAT);
+ /* FLAT/SMOOTH shading for surfaces */
+ glShadeModel((dl->rt & CU_SMOOTH) ? GL_SMOOTH : GL_FLAT);
glEnableClientState(GL_NORMAL_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, dl->verts);
glNormalPointer(GL_FLOAT, 0, dl->nors);
glDrawElements(GL_QUADS, 4 * dl->totindex, GL_UNSIGNED_INT, dl->index);
glDisableClientState(GL_NORMAL_ARRAY);
+ glShadeModel(GL_SMOOTH);
}
break;
@@ -4578,7 +4562,6 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
}
glDisableClientState(GL_VERTEX_ARRAY);
- glShadeModel(GL_FLAT);
glFrontFace(GL_CCW);
if (col != -1) {
@@ -5043,7 +5026,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
unsigned char tcol[4] = {0, 0, 0, 255};
/* 1. */
- if (part == NULL || !psys_check_enabled(ob, psys))
+ if (part == NULL || !psys_check_enabled(ob, psys, G.is_rendering))
return;
if (pars == NULL) return;
@@ -5751,7 +5734,7 @@ static void draw_update_ptcache_edit(Scene *scene, Object *ob, PTCacheEdit *edit
/* create path and child path cache if it doesn't exist already */
if (edit->pathcache == NULL)
- psys_cache_edit_paths(scene, ob, edit, CFRA);
+ psys_cache_edit_paths(scene, ob, edit, CFRA, G.is_rendering);
}
static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
@@ -5788,8 +5771,6 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
- glShadeModel(GL_SMOOTH);
-
if (pset->brushtype == PE_BRUSH_WEIGHT)
glLineWidth(2.0f);
@@ -5904,7 +5885,6 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
- glShadeModel(GL_FLAT);
if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
}
@@ -8247,7 +8227,7 @@ static void bbs_obmode_mesh_verts__mapFunc(void *userData, int index, const floa
MVert *mv = &data->mvert[index];
if (!(mv->flag & ME_HIDE)) {
- WM_framebuffer_index_set(data->offset + index);
+ GPU_select_index_set(data->offset + index);
glVertex3fv(co);
}
}
@@ -8272,7 +8252,7 @@ static void bbs_mesh_verts__mapFunc(void *userData, int index, const float co[3]
BMVert *eve = BM_vert_at_index(data->bm, index);
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
- WM_framebuffer_index_set(data->offset + index);
+ GPU_select_index_set(data->offset + index);
glVertex3fv(co);
}
}
@@ -8291,7 +8271,7 @@ static DMDrawOption bbs_mesh_wire__setDrawOptions(void *userData, int index)
BMEdge *eed = BM_edge_at_index(data->bm, index);
if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- WM_framebuffer_index_set(data->offset + index);
+ GPU_select_index_set(data->offset + index);
return DM_DRAW_OPTION_NORMAL;
}
else {
@@ -8305,7 +8285,7 @@ static void bbs_mesh_wire(BMEditMesh *em, DerivedMesh *dm, int offset)
}
/**
- * dont set #WM_framebuffer_index_set. just use to mask other
+ * dont set #GPU_framebuffer_index_set. just use to mask other
*/
static DMDrawOption bbs_mesh_mask__setSolidDrawOptions(void *userData, int index)
{
@@ -8324,7 +8304,7 @@ static DMDrawOption bbs_mesh_solid__setSolidDrawOptions(void *userData, int inde
BMFace *efa = BM_face_at_index(userData, index);
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- WM_framebuffer_index_set(index + 1);
+ GPU_select_index_set(index + 1);
return DM_DRAW_OPTION_NORMAL;
}
else {
@@ -8337,7 +8317,7 @@ static void bbs_mesh_solid__drawCenter(void *userData, int index, const float ce
BMFace *efa = BM_face_at_index(userData, index);
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- WM_framebuffer_index_set(index + 1);
+ GPU_select_index_set(index + 1);
glVertex3fv(cent);
}
@@ -8368,7 +8348,7 @@ static void bbs_mesh_solid_EM(BMEditMesh *em, Scene *scene, View3D *v3d,
static DMDrawOption bbs_mesh_solid__setDrawOpts(void *UNUSED(userData), int index)
{
- WM_framebuffer_index_set(index + 1);
+ GPU_select_index_set(index + 1);
return DM_DRAW_OPTION_NORMAL;
}
@@ -8377,7 +8357,7 @@ static DMDrawOption bbs_mesh_solid_hide__setDrawOpts(void *userData, int index)
Mesh *me = userData;
if (!(me->mpoly[index].flag & ME_HIDE)) {
- WM_framebuffer_index_set(index + 1);
+ GPU_select_index_set(index + 1);
return DM_DRAW_OPTION_NORMAL;
}
else {
@@ -8385,7 +8365,7 @@ static DMDrawOption bbs_mesh_solid_hide__setDrawOpts(void *userData, int index)
}
}
-/* must have called WM_framebuffer_index_set beforehand */
+/* must have called GPU_framebuffer_index_set beforehand */
static DMDrawOption bbs_mesh_solid_hide2__setDrawOpts(void *userData, int index)
{
Mesh *me = userData;
@@ -8511,7 +8491,7 @@ static void draw_object_mesh_instance(Scene *scene, View3D *v3d, RegionView3D *r
DerivedMesh *dm = NULL, *edm = NULL;
if (ob->mode & OB_MODE_EDIT) {
- edm = editbmesh_get_derived_base(ob, me->edit_btmesh);
+ edm = editbmesh_get_derived_base(ob, me->edit_btmesh, CD_MASK_BAREMESH);
DM_update_materials(edm, ob);
}
else {
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 470fa80bb71..0805b81147f 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -1472,6 +1472,66 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes
return -1; /* found but not available */
}
+static void view3d_id_remap(ScrArea *sa, SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ View3D *v3d;
+ ARegion *ar;
+ bool is_local = false;
+
+ if (!ELEM(GS(old_id->name), ID_OB, ID_MA, ID_IM, ID_MC)) {
+ return;
+ }
+
+ for (v3d = (View3D *)slink; v3d; v3d = v3d->localvd, is_local = true) {
+ if ((ID *)v3d->camera == old_id) {
+ v3d->camera = (Object *)new_id;
+ if (!new_id) {
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->regiontype == RGN_TYPE_WINDOW) {
+ RegionView3D *rv3d = is_local ? ((RegionView3D *)ar->regiondata)->localvd : ar->regiondata;
+ if (rv3d && (rv3d->persp == RV3D_CAMOB)) {
+ rv3d->persp = RV3D_PERSP;
+ }
+ }
+ }
+ }
+ }
+ if ((ID *)v3d->ob_centre == old_id) {
+ v3d->ob_centre = (Object *)new_id;
+ if (new_id == NULL) { /* Otherwise, bonename may remain valid... We could be smart and check this, too? */
+ v3d->ob_centre_bone[0] = '\0';
+ }
+ }
+
+ if ((ID *)v3d->defmaterial == old_id) {
+ v3d->defmaterial = (Material *)new_id;
+ }
+#if 0 /* XXX Deprecated? */
+ if ((ID *)v3d->gpd == old_id) {
+ v3d->gpd = (bGPData *)new_id;
+ }
+#endif
+
+ if (ELEM(GS(old_id->name), ID_IM, ID_MC)) {
+ for (BGpic *bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
+ if ((ID *)bgpic->ima == old_id) {
+ bgpic->ima = (Image *)new_id;
+ id_us_min(old_id);
+ id_us_plus(new_id);
+ }
+ if ((ID *)bgpic->clip == old_id) {
+ bgpic->clip = (MovieClip *)new_id;
+ id_us_min(old_id);
+ id_us_plus(new_id);
+ }
+ }
+ }
+
+ if (is_local) {
+ break;
+ }
+ }
+}
/* only called once, from space/spacetypes.c */
void ED_spacetype_view3d(void)
@@ -1491,7 +1551,8 @@ void ED_spacetype_view3d(void)
st->keymap = view3d_keymap;
st->dropboxes = view3d_dropboxes;
st->context = view3d_context;
-
+ st->id_remap = view3d_id_remap;
+
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype view3d main region");
art->regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 9fe4f1cc283..62059766bd6 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -659,7 +659,6 @@ static void draw_rotation_guide(RegionView3D *rv3d)
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glShadeModel(GL_SMOOTH);
glPointSize(5);
glEnable(GL_POINT_SMOOTH);
glDepthMask(0); /* don't overwrite zbuf */
@@ -1491,7 +1490,7 @@ unsigned int ED_view3d_backbuf_sample(ViewContext *vc, int x, int y)
BLI_endian_switch_uint32(&col);
}
- return WM_framebuffer_to_index(col);
+ return GPU_select_to_index(col);
}
/* reads full rect, converts indices */
@@ -1524,7 +1523,7 @@ ImBuf *ED_view3d_backbuf_read(ViewContext *vc, int xmin, int ymin, int xmax, int
IMB_convert_rgba_to_abgr(ibuf_clip);
}
- WM_framebuffer_to_index_array(ibuf_clip->rect, size_clip[0] * size_clip[1]);
+ GPU_select_to_index_array(ibuf_clip->rect, size_clip[0] * size_clip[1]);
if ((clip.xmin == xmin) &&
(clip.xmax == xmax) &&
@@ -3399,17 +3398,15 @@ static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar)
glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
}
}
-
+ // Draw world
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_ALWAYS);
- glShadeModel(GL_SMOOTH);
glBegin(GL_TRIANGLE_STRIP);
glVertex3f(-1.0, -1.0, 1.0);
glVertex3f(1.0, -1.0, 1.0);
glVertex3f(-1.0, 1.0, 1.0);
glVertex3f(1.0, 1.0, 1.0);
glEnd();
- glShadeModel(GL_FLAT);
if (v3d->flag3 & V3D_SHOW_WORLD_DIFFUSE) {
GPU_probe_sh_shader_unbind();
@@ -3460,8 +3457,6 @@ static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar)
glPushMatrix();
glLoadIdentity();
- glShadeModel(GL_SMOOTH);
-
/* calculate buffers the first time only */
if (!buf_calculated) {
for (x = 0; x < VIEWGRAD_RES_X; x++) {
@@ -3547,8 +3542,6 @@ static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar)
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
- glShadeModel(GL_FLAT);
-
#undef VIEWGRAD_RES_X
#undef VIEWGRAD_RES_Y
}
@@ -3577,7 +3570,6 @@ static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar)
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_ALWAYS);
- glShadeModel(GL_SMOOTH);
glBegin(GL_QUADS);
UI_ThemeColor(TH_LOW_GRAD);
glVertex3f(-1.0, -1.0, 1.0);
@@ -3586,8 +3578,6 @@ static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar)
glVertex3f(1.0, 1.0, 1.0);
glVertex3f(-1.0, 1.0, 1.0);
glEnd();
- glShadeModel(GL_FLAT);
-
glDepthFunc(GL_LEQUAL);
glDisable(GL_DEPTH_TEST);
@@ -4506,6 +4496,10 @@ void view3d_main_region_draw(const bContext *C, ARegion *ar)
view3d_main_region_draw_info(C, scene, ar, v3d, grid_unit, render_border);
v3d->flag |= V3D_INVALID_BACKBUF;
+
+ BLI_assert(BLI_listbase_is_empty(&v3d->afterdraw_transp));
+ BLI_assert(BLI_listbase_is_empty(&v3d->afterdraw_xray));
+ BLI_assert(BLI_listbase_is_empty(&v3d->afterdraw_xraytransp));
}
#ifdef DEBUG_DRAW
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 155c7503acf..1bd0ec23d65 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -3620,7 +3620,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
dist_range[0] = v3d->near * 1.5f;
}
else { /* othographic */
- /* find the current window width and height */
+ /* find the current window width and height */
vb[0] = ar->winx;
vb[1] = ar->winy;
@@ -4911,7 +4911,7 @@ static float view_autodist_depth_margin(ARegion *ar, const int mval[2], int marg
* Get the world-space 3d location from a screen-space 2d point.
*
* \param mval: Input screen-space pixel location.
- * \param mouse_worldloc: Output world-space loction.
+ * \param mouse_worldloc: Output world-space location.
* \param fallback_depth_pt: Use this points depth when no depth can be found.
*/
bool ED_view3d_autodist(
diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c
index 797d97586c7..ac05853e6d0 100644
--- a/source/blender/editors/space_view3d/view3d_project.c
+++ b/source/blender/editors/space_view3d/view3d_project.c
@@ -302,8 +302,9 @@ float ED_view3d_calc_zfac(const RegionView3D *rv3d, const float co[3], bool *r_f
return zfac;
}
-static void view3d_win_to_ray_segment(const ARegion *ar, View3D *v3d, const float mval[2],
- float r_ray_co[3], float r_ray_dir[3], float r_ray_start[3], float r_ray_end[3])
+static void view3d_win_to_ray_segment(
+ const ARegion *ar, const View3D *v3d, const float mval[2],
+ float r_ray_co[3], float r_ray_dir[3], float r_ray_start[3], float r_ray_end[3])
{
RegionView3D *rv3d = ar->regiondata;
float _ray_co[3], _ray_dir[3], start_offset, end_offset;
@@ -346,7 +347,7 @@ static void view3d_win_to_ray_segment(const ARegion *ar, View3D *v3d, const floa
}
}
-BLI_INLINE bool view3d_clip_segment(RegionView3D *rv3d, float ray_start[3], float ray_end[3])
+BLI_INLINE bool view3d_clip_segment(const RegionView3D *rv3d, float ray_start[3], float ray_end[3])
{
if ((rv3d->rflag & RV3D_CLIPPING) &&
(clip_segment_v3_plane_n(ray_start, ray_end, rv3d->clip, 6,
@@ -373,8 +374,9 @@ BLI_INLINE bool view3d_clip_segment(RegionView3D *rv3d, float ray_start[3], floa
* \param do_clip Optionally clip the start of the ray by the view clipping planes.
* \return success, false if the ray is totally clipped.
*/
-bool ED_view3d_win_to_ray_ex(const ARegion *ar, View3D *v3d, const float mval[2],
- float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip)
+bool ED_view3d_win_to_ray_ex(
+ const ARegion *ar, const View3D *v3d, const float mval[2],
+ float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip)
{
float ray_end[3];
@@ -382,7 +384,7 @@ bool ED_view3d_win_to_ray_ex(const ARegion *ar, View3D *v3d, const float mval[2]
/* bounds clipping */
if (do_clip) {
- return view3d_clip_segment((RegionView3D *)ar->regiondata, r_ray_start, ray_end);
+ return view3d_clip_segment(ar->regiondata, r_ray_start, ray_end);
}
return true;
@@ -401,8 +403,9 @@ bool ED_view3d_win_to_ray_ex(const ARegion *ar, View3D *v3d, const float mval[2]
* \param do_clip Optionally clip the start of the ray by the view clipping planes.
* \return success, false if the ray is totally clipped.
*/
-bool ED_view3d_win_to_ray(const ARegion *ar, View3D *v3d, const float mval[2],
- float r_ray_start[3], float r_ray_normal[3], const bool do_clip)
+bool ED_view3d_win_to_ray(
+ const ARegion *ar, const View3D *v3d, const float mval[2],
+ float r_ray_start[3], float r_ray_normal[3], const bool do_clip)
{
return ED_view3d_win_to_ray_ex(ar, v3d, mval, NULL, r_ray_normal, r_ray_start, do_clip);
}
diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c
index c6951c79609..f46608b7d5e 100644
--- a/source/blender/editors/space_view3d/view3d_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_ruler.c
@@ -259,6 +259,37 @@ static bool view3d_ruler_pick(RulerInfo *ruler_info, const float mval[2],
}
}
+/**
+ * Ensure the 'snap_context' is only cached while dragging,
+ * needed since the user may toggle modes between tool use.
+ */
+static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state)
+{
+ if (state == ruler_info->state) {
+ return;
+ }
+
+ /* always remove */
+ if (ruler_info->snap_context) {
+ ED_transform_snap_object_context_destroy(ruler_info->snap_context);
+ ruler_info->snap_context = NULL;
+ }
+
+ if (state == RULER_STATE_NORMAL) {
+ /* pass */
+ }
+ else if (state == RULER_STATE_DRAG) {
+ ruler_info->snap_context = ED_transform_snap_object_context_create_view3d(
+ CTX_data_main(C), CTX_data_scene(C), SNAP_OBJECT_USE_CACHE,
+ ruler_info->ar, CTX_wm_view3d(C));
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ ruler_info->state = state;
+}
+
#define RULER_ID "RulerData3D"
static bool view3d_ruler_to_gpencil(bContext *C, RulerInfo *ruler_info)
{
@@ -640,7 +671,9 @@ static void view3d_ruler_free(RulerInfo *ruler_info)
{
BLI_freelistN(&ruler_info->items);
- ED_transform_snap_object_context_destroy(ruler_info->snap_context);
+ if (ruler_info->snap_context) {
+ ED_transform_snap_object_context_destroy(ruler_info->snap_context);
+ }
MEM_freeN(ruler_info);
}
@@ -757,10 +790,6 @@ static int view3d_ruler_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
op->customdata = ruler_info;
- ruler_info->snap_context = ED_transform_snap_object_context_create_view3d(
- CTX_data_main(C), CTX_data_scene(C), SNAP_OBJECT_USE_CACHE,
- ar, CTX_wm_view3d(C));
-
ruler_info->win = win;
ruler_info->sa = sa;
ruler_info->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ruler_info_draw_pixel,
@@ -818,7 +847,7 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event)
ruler_info->snap_flag &= ~RULER_SNAP_OK;
do_draw = true;
}
- ruler_info->state = RULER_STATE_NORMAL;
+ ruler_state_set(C, ruler_info, RULER_STATE_NORMAL);
}
}
else {
@@ -835,7 +864,7 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event)
RulerItem *ruler_item_prev = ruler_item_active_get(ruler_info);
RulerItem *ruler_item;
/* check if we want to drag an existing point or add a new one */
- ruler_info->state = RULER_STATE_DRAG;
+ ruler_state_set(C, ruler_info, RULER_STATE_DRAG);
ruler_item = ruler_item_add(ruler_info);
ruler_item_active_set(ruler_info, ruler_item);
@@ -877,7 +906,7 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event)
ruler_item_active_set(ruler_info, ruler_item_pick);
ruler_item_pick->flag |= RULERITEM_USE_ANGLE;
ruler_item_pick->co_index = 1;
- ruler_info->state = RULER_STATE_DRAG;
+ ruler_state_set(C, ruler_info, RULER_STATE_DRAG);
/* find the factor */
{
@@ -904,7 +933,7 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event)
else {
ruler_item_active_set(ruler_info, ruler_item_pick);
ruler_item_pick->co_index = co_index;
- ruler_info->state = RULER_STATE_DRAG;
+ ruler_state_set(C, ruler_info, RULER_STATE_DRAG);
/* store the initial depth */
copy_v3_v3(ruler_info->drag_start_co, ruler_item_pick->co[ruler_item_pick->co_index]);
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index bedcf413bfa..a460d8900b4 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -94,6 +94,8 @@
#include "UI_interface.h"
+#include "GPU_draw.h"
+
#include "view3d_intern.h" /* own include */
float ED_view3d_select_dist_px(void)
@@ -1690,7 +1692,7 @@ static int do_paintvert_box_select(ViewContext *vc, rcti *rect, bool select, boo
if (ENDIAN_ORDER == B_ENDIAN) {
IMB_convert_rgba_to_abgr(ibuf);
}
- WM_framebuffer_to_index_array(ibuf->rect, size[0] * size[1]);
+ GPU_select_to_index_array(ibuf->rect, size[0] * size[1]);
a = size[0] * size[1];
while (a--) {
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 5b1a58497f0..95864474fc0 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -1202,8 +1202,12 @@ int transformEvent(TransInfo *t, const wmEvent *event)
if (t->flag & T_PROP_EDIT) {
float fac = 1.0f + 0.005f *(event->y - event->prevy);
t->prop_size *= fac;
- if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO)
- t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far);
+ if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) {
+ t->prop_size = max_ff(min_ff(t->prop_size, ((View3D *)t->view)->far), T_PROP_SIZE_MIN);
+ }
+ else {
+ t->prop_size = max_ff(min_ff(t->prop_size, T_PROP_SIZE_MAX), T_PROP_SIZE_MIN);
+ }
calculatePropRatio(t);
t->redraw |= TREDRAW_HARD;
handled = true;
@@ -1212,8 +1216,12 @@ int transformEvent(TransInfo *t, const wmEvent *event)
case TFM_MODAL_PROPSIZE_UP:
if (t->flag & T_PROP_EDIT) {
t->prop_size *= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
- if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO)
+ if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) {
t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far);
+ }
+ else {
+ t->prop_size = min_ff(t->prop_size, T_PROP_SIZE_MAX);
+ }
calculatePropRatio(t);
t->redraw |= TREDRAW_HARD;
handled = true;
@@ -1222,6 +1230,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
case TFM_MODAL_PROPSIZE_DOWN:
if (t->flag & T_PROP_EDIT) {
t->prop_size /= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
+ t->prop_size = max_ff(t->prop_size, T_PROP_SIZE_MIN);
calculatePropRatio(t);
t->redraw |= TREDRAW_HARD;
handled = true;
@@ -4144,7 +4153,12 @@ static void initSnapSpatial(TransInfo *t, float r_snap[3])
r_snap[2] = r_snap[1] * 0.1f;
}
}
- else if (ELEM(t->spacetype, SPACE_IMAGE, SPACE_CLIP)) {
+ else if (t->spacetype == SPACE_IMAGE) {
+ r_snap[0] = 0.0f;
+ r_snap[1] = 0.0625f;
+ r_snap[2] = 0.03125f;
+ }
+ else if (t->spacetype == SPACE_CLIP) {
r_snap[0] = 0.0f;
r_snap[1] = 0.125f;
r_snap[2] = 0.0625f;
@@ -5361,7 +5375,9 @@ static void slide_origdata_init_data(
BMesh *bm = em->bm;
sod->origfaces = BLI_ghash_ptr_new(__func__);
- sod->bm_origfaces = BM_mesh_create(&bm_mesh_allocsize_default);
+ sod->bm_origfaces = BM_mesh_create(
+ &bm_mesh_allocsize_default,
+ &((struct BMeshCreateParams){.use_toolflags = false,}));
/* we need to have matching customdata */
BM_mesh_copy_init_customdata(sod->bm_origfaces, bm, NULL);
}
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 0e0d085bf6f..50168e78dda 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -592,6 +592,10 @@ typedef struct TransInfo {
#define POINT_INIT 4
#define MULTI_POINTS 8
+/* Hard min/max for proportional size. */
+#define T_PROP_SIZE_MIN 1e-6f
+#define T_PROP_SIZE_MAX 1e12f
+
bool initTransform(struct bContext *C, struct TransInfo *t, struct wmOperator *op, const struct wmEvent *event, int mode);
void saveTransform(struct bContext *C, struct TransInfo *t, struct wmOperator *op);
int transformEvent(TransInfo *t, const struct wmEvent *event);
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index fa5e86813fa..707c60f8701 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -2676,6 +2676,20 @@ void flushTransSeq(TransInfo *t)
BKE_sequence_calc(t->scene, seq);
}
}
+
+ /* update effects inside meta's */
+ for (a = 0, seq_prev = NULL, td = t->data, td2d = t->data2d;
+ a < t->total;
+ a++, td++, td2d++, seq_prev = seq)
+ {
+ tdsq = (TransDataSeq *)td->extra;
+ seq = tdsq->seq;
+ if ((seq != seq_prev) && (seq->depth != 0)) {
+ if (seq->seq1 || seq->seq2 || seq->seq3) {
+ BKE_sequence_calc(t->scene, seq);
+ }
+ }
+ }
}
/* need to do the overlap check in a new loop otherwise adjacent strips
@@ -4920,44 +4934,47 @@ static void freeSeqData(TransInfo *t, TransCustomData *custom_data)
{
int overlap = 0;
- seq_prev = NULL;
- for (a = 0; a < t->total; a++, td++) {
+ for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) {
seq = ((TransDataSeq *)td->extra)->seq;
if ((seq != seq_prev) && (seq->depth == 0) && (seq->flag & SEQ_OVERLAP)) {
overlap = 1;
break;
}
- seq_prev = seq;
}
if (overlap) {
- bool has_effect = false;
+ bool has_effect_root = false, has_effect_any = false;
for (seq = seqbasep->first; seq; seq = seq->next)
seq->tmp = NULL;
td = t->data;
- seq_prev = NULL;
- for (a = 0; a < t->total; a++, td++) {
+ for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) {
seq = ((TransDataSeq *)td->extra)->seq;
if ((seq != seq_prev)) {
/* check effects strips, we cant change their time */
if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
- has_effect = true;
+ has_effect_any = true;
+ if (seq->depth == 0) {
+ has_effect_root = true;
+ }
}
else {
- /* Tag seq with a non zero value, used by BKE_sequence_base_shuffle_time to identify the ones to shuffle */
- seq->tmp = (void *)1;
+ /* Tag seq with a non zero value,
+ * used by BKE_sequence_base_shuffle_time to identify the ones to shuffle */
+ if (seq->depth == 0) {
+ seq->tmp = (void *)1;
+ }
}
}
+
}
if (t->flag & T_ALT_TRANSFORM) {
int minframe = MAXFRAME;
td = t->data;
- seq_prev = NULL;
- for (a = 0; a < t->total; a++, td++) {
+ for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) {
seq = ((TransDataSeq *)td->extra)->seq;
- if ((seq != seq_prev)) {
+ if ((seq != seq_prev) && (seq->depth == 0)) {
minframe = min_ii(minframe, seq->startdisp);
}
}
@@ -4989,11 +5006,10 @@ static void freeSeqData(TransInfo *t, TransCustomData *custom_data)
BKE_sequence_base_shuffle_time(seqbasep, t->scene);
}
- if (has_effect) {
+ if (has_effect_any) {
/* update effects strips based on strips just moved in time */
td = t->data;
- seq_prev = NULL;
- for (a = 0; a < t->total; a++, td++) {
+ for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) {
seq = ((TransDataSeq *)td->extra)->seq;
if ((seq != seq_prev)) {
if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
@@ -5001,13 +5017,14 @@ static void freeSeqData(TransInfo *t, TransCustomData *custom_data)
}
}
}
+ }
+ if (has_effect_root) {
/* now if any effects _still_ overlap, we need to move them up */
td = t->data;
- seq_prev = NULL;
- for (a = 0; a < t->total; a++, td++) {
+ for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) {
seq = ((TransDataSeq *)td->extra)->seq;
- if ((seq != seq_prev)) {
+ if ((seq != seq_prev) && (seq->depth == 0)) {
if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
if (BKE_sequence_test_overlap(seqbasep, seq)) {
BKE_sequence_base_shuffle(seqbasep, seq, t->scene);
@@ -5874,6 +5891,7 @@ static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
BMesh *bm = em->bm;
char hflag;
+ bool has_face_sel = (bm->totfacesel != 0);
if (t->flag & T_MIRROR) {
TransData *td;
@@ -5897,8 +5915,10 @@ static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
EDBM_automerge(t->scene, t->obedit, true, hflag);
- if ((em->selectmode & SCE_SELECT_VERTEX) == 0) {
- EDBM_select_flush(em);
+ /* Special case, this is needed or faces won't re-select.
+ * Flush selected edges to faces. */
+ if (has_face_sel && (em->selectmode == SCE_SELECT_FACE)) {
+ EDBM_selectmode_flush_ex(em, SCE_SELECT_EDGE);
}
}
}
@@ -7587,7 +7607,7 @@ static void createTransPaintCurveVerts(bContext *C, TransInfo *t)
for (pcp = pc->points, i = 0; i < pc->tot_points; i++, pcp++) {
if (PC_IS_ANY_SEL(pcp)) {
- PaintCurvePointToTransData (pcp, td, td2d, tdpc);
+ PaintCurvePointToTransData(pcp, td, td2d, tdpc);
if (pcp->bez.f2 & SELECT) {
td += 3;
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 5d49d1d9315..6e399d9fde3 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -528,7 +528,8 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
prop = RNA_def_enum(ot->srna, "proportional_edit_falloff", rna_enum_proportional_falloff_items, 0,
"Proportional Editing Falloff", "Falloff type for proportional editing mode");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
- RNA_def_float(ot->srna, "proportional_size", 1, 0.00001f, FLT_MAX, "Proportional Size", "", 0.001, 100);
+ RNA_def_float(ot->srna, "proportional_size", 1, T_PROP_SIZE_MIN, T_PROP_SIZE_MAX,
+ "Proportional Size", "", 0.001f, 100.0f);
}
if (flags & P_SNAP) {
@@ -686,7 +687,7 @@ static void TRANSFORM_OT_tilt(struct wmOperatorType *ot)
{
/* identifiers */
ot->name = "Tilt";
- /* optionals -
+ /* optional -
* "Tilt selected vertices"
* "Specify an extra axis rotation for selected vertices of 3D curve" */
ot->description = "Tilt selected control vertices of 3D curve";
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index 59d2485c964..90a4aa3614d 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -636,7 +636,7 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- BM_face_calc_plane(efa, vec);
+ BM_face_calc_tangent_auto(efa, vec);
add_v3_v3(normal, efa->no);
add_v3_v3(plane, vec);
}
@@ -690,7 +690,7 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3
sub_v3_v3v3(plane, v_pair[0]->co, v_pair[1]->co);
}
else {
- BM_vert_tri_calc_plane(v_tri, plane);
+ BM_vert_tri_calc_tangent_edge(v_tri, plane);
}
}
else {
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index e1cf7436236..0bb64315845 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -599,15 +599,15 @@ static void initSnappingMode(TransInfo *t)
if (t->spacetype == SPACE_VIEW3D) {
if (t->tsnap.object_context == NULL) {
t->tsnap.object_context = ED_transform_snap_object_context_create_view3d(
- G.main, t->scene, 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)));
+ 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)));
}
}
}
@@ -842,6 +842,14 @@ static void ApplySnapTranslation(TransInfo *t, float vec[3])
vec[1] = point[1] - t->tsnap.snapTarget[1];
}
else {
+ if (t->spacetype == SPACE_VIEW3D) {
+ if (t->options & CTX_PAINT_CURVE) {
+ if (ED_view3d_project_float_global(t->ar, point, point, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) {
+ zero_v3(point); /* no good answer here... */
+ }
+ }
+ }
+
sub_v3_v3v3(vec, point, t->tsnap.snapTarget);
}
}
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index d7486372c36..e85b686b5b3 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -68,13 +68,13 @@ typedef struct SnapObjectData {
typedef struct SnapObjectData_Mesh {
SnapObjectData sd;
- BVHTreeFromMesh *bvh_trees[2];
+ BVHTreeFromMesh *bvh_trees[3];
} SnapObjectData_Mesh;
typedef struct SnapObjectData_EditMesh {
SnapObjectData sd;
- BVHTreeFromEditMesh *bvh_trees[2];
+ BVHTreeFromEditMesh *bvh_trees[3];
} SnapObjectData_EditMesh;
@@ -87,8 +87,8 @@ struct SnapObjectContext {
* otherwise this doesn't take viewport into account. */
bool use_v3d;
struct {
- struct View3D *v3d;
- struct ARegion *ar;
+ const struct View3D *v3d;
+ const struct ARegion *ar;
} v3d_data;
@@ -198,7 +198,7 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH
mul_m3_v3((float(*)[3])data->timat, normal);
normalize_v3(normal);
- /* currently unused, and causes issues when looptri's havn't been calculated.
+ /* currently unused, and causes issues when looptri's haven't been calculated.
* since theres some overhead in ensuring this data is valid, it may need to be optional. */
#if 0
if (data->dm) {
@@ -222,9 +222,12 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH
* \{ */
static bool snapEdge(
- ARegion *ar, const float v1co[3], const short v1no[3], const float v2co[3], const short v2no[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,
+ const ARegion *ar, const float v1co[3], const short v1no[3], const float v2co[3], const short v2no[3],
+ float obmat[4][4], float timat[3][3], const float mval_fl[2],
+ const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3],
+ /* read/write args */
+ float *ray_depth, float *dist_px,
+ /* return args */
float r_loc[3], float r_no[3])
{
float intersect[3] = {0, 0, 0}, ray_end[3], dvec[3];
@@ -312,9 +315,12 @@ static bool snapEdge(
}
static bool snapVertex(
- 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,
+ const ARegion *ar, const float vco[3], const float vno[3],
+ float obmat[4][4], float timat[3][3], const float mval_fl[2],
+ const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3],
+ /* read/write args */
+ float *ray_depth, float *dist_px,
+ /* return args */
float r_loc[3], float r_no[3])
{
bool retval = false;
@@ -362,9 +368,12 @@ static bool snapVertex(
}
static bool snapArmature(
- ARegion *ar, Object *ob, bArmature *arm, 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], float *ray_depth,
+ const ARegion *ar, Object *ob, bArmature *arm, float obmat[4][4],
+ const float mval[2], const short snap_to,
+ const float ray_start[3], const float ray_normal[3],
+ /* read/write args */
+ float *ray_depth, float *dist_px,
+ /* return args */
float r_loc[3], float *UNUSED(r_no))
{
float imat[4][4];
@@ -444,9 +453,12 @@ static bool snapArmature(
}
static bool snapCurve(
- ARegion *ar, Object *ob, Curve *cu, 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], float *ray_depth,
+ const ARegion *ar, Object *ob, Curve *cu, float obmat[4][4],
+ const float mval[2], const short snap_to,
+ const float ray_start[3], const float ray_normal[3],
+ /* read/write args */
+ float *ray_depth, float *dist_px,
+ /* return args */
float r_loc[3], float *UNUSED(r_no))
{
float imat[4][4];
@@ -481,24 +493,27 @@ static bool snapCurve(
break;
}
retval |= snapVertex(
- ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
+ ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval,
+ ray_start, ray_start_local, ray_normal_local,
+ ray_depth, dist_px,
r_loc, NULL);
/* don't snap if handle is selected (moving), or if it is aligning to a moving handle */
if (!(nu->bezt[u].f1 & SELECT) &&
!(nu->bezt[u].h1 & HD_ALIGN && nu->bezt[u].f3 & SELECT))
{
retval |= snapVertex(
- ar, nu->bezt[u].vec[0], NULL, obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
+ ar, nu->bezt[u].vec[0], NULL, obmat, NULL, mval,
+ ray_start, ray_start_local, ray_normal_local,
+ ray_depth, dist_px,
r_loc, NULL);
}
if (!(nu->bezt[u].f3 & SELECT) &&
!(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT))
{
retval |= snapVertex(
- ar, nu->bezt[u].vec[2], NULL, obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
+ ar, nu->bezt[u].vec[2], NULL, obmat, NULL, mval,
+ ray_start, ray_start_local, ray_normal_local,
+ ray_depth, dist_px,
r_loc, NULL);
}
}
@@ -508,8 +523,9 @@ static bool snapCurve(
break;
}
retval |= snapVertex(
- ar, nu->bp[u].vec, NULL, obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
+ ar, nu->bp[u].vec, NULL, obmat, NULL, mval,
+ ray_start, ray_start_local, ray_normal_local,
+ ray_depth, dist_px,
r_loc, NULL);
}
}
@@ -518,14 +534,16 @@ static bool snapCurve(
if (nu->pntsu > 1) {
if (nu->bezt) {
retval |= snapVertex(
- ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
+ ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval,
+ ray_start, ray_start_local, ray_normal_local,
+ ray_depth, dist_px,
r_loc, NULL);
}
else {
retval |= snapVertex(
- ar, nu->bp[u].vec, NULL, obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
+ ar, nu->bp[u].vec, NULL, obmat, NULL, mval,
+ ray_start, ray_start_local, ray_normal_local,
+ ray_depth, dist_px,
r_loc, NULL);
}
}
@@ -542,9 +560,12 @@ static bool snapCurve(
/* may extend later (for now just snaps to empty center) */
static bool snapEmpty(
- ARegion *ar, Object *ob, 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], float *ray_depth,
+ const ARegion *ar, Object *ob, float obmat[4][4],
+ const float mval[2], const short snap_to,
+ const float ray_start[3], const float ray_normal[3],
+ /* read/write args */
+ float *ray_depth, float *dist_px,
+ /* return args */
float r_loc[3], float *UNUSED(r_no))
{
float imat[4][4];
@@ -582,9 +603,12 @@ static bool snapEmpty(
}
static bool snapCamera(
- ARegion *ar, Scene *scene, Object *object, 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], float *ray_depth,
+ const ARegion *ar, Scene *scene, Object *object, float obmat[4][4],
+ const float mval[2], const short snap_to,
+ const float ray_start[3], const float ray_normal[3],
+ /* read/write args */
+ float *ray_depth, float *dist_px,
+ /* return args */
float r_loc[3], float *UNUSED(r_no))
{
float orig_camera_mat[4][4], orig_camera_imat[4][4], imat[4][4];
@@ -674,16 +698,166 @@ static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt)
return index_mp_to_orig ? index_mp_to_orig[lt->poly] : lt->poly;
}
+struct NearestDM_Data {
+ void *bvhdata;
+ bool is_persp;
+ const float *ray_depth_range;
+
+ float *ray_depth;
+};
+
+static bool test_vert(
+ const float vco[3], const float vno[3], const float ray_co[3], const float ray_dir[3],
+ const float ray_depth_range[2], const float scale[3], const bool is_persp,
+ /* read/write args */
+ float *ray_depth, float *dist_to_ray_sq,
+ /* return args */
+ float r_co[3], float r_no[3])
+{
+ const float vco_sc[3] = {
+ vco[0] * scale[0],
+ vco[1] * scale[1],
+ vco[2] * scale[2],
+ };
+ const float co_sc[3] = {
+ ray_co[0] * scale[0],
+ ray_co[1] * scale[1],
+ ray_co[2] * scale[2],
+ };
+ const float dir_sc[3] = {
+ ray_dir[0] * scale[0],
+ ray_dir[1] * scale[1],
+ ray_dir[2] * scale[2],
+ };
+
+ float depth;
+ float dist_sq = dist_squared_to_ray_v3(co_sc, dir_sc, vco_sc, &depth);
+
+ if (depth < ray_depth_range[0])
+ return false;
+
+ if (is_persp)
+ dist_sq /= SQUARE(depth);
+
+ if ((dist_sq < *dist_to_ray_sq) && (depth < *ray_depth)) {
+ *dist_to_ray_sq = dist_sq;
+
+ copy_v3_v3(r_co, vco);
+
+ if (vno) {
+ copy_v3_v3(r_no, vno);
+ }
+
+ *ray_depth = depth;
+ return true;
+ }
+ return false;
+}
+
+static bool test_edge(
+ const float v1[3], const float v2[3], const float ray_co[3], const float ray_dir[3],
+ const float ray_depth_range[2], const float scale[3], const bool is_persp,
+ /* read/write args */
+ float *ray_depth, float *dist_to_ray_sq,
+ /* return args */
+ float r_co[3], float r_no[3])
+{
+ const float v1_sc[3] = {
+ v1[0] * scale[0],
+ v1[1] * scale[1],
+ v1[2] * scale[2],
+ };
+ const float v2_sc[3] = {
+ v2[0] * scale[0],
+ v2[1] * scale[1],
+ v2[2] * scale[2],
+ };
+ const float co_sc[3] = {
+ ray_co[0] * scale[0],
+ ray_co[1] * scale[1],
+ ray_co[2] * scale[2],
+ };
+ const float dir_sc[3] = {
+ ray_dir[0] * scale[0],
+ ray_dir[1] * scale[1],
+ ray_dir[2] * scale[2],
+ };
+
+ float tmp_co[3], depth;
+ float dist_sq = dist_squared_ray_to_seg_v3(co_sc, dir_sc, v1_sc, v2_sc, tmp_co, &depth);
+
+ if (depth < ray_depth_range[0])
+ return false;
+
+ if (is_persp)
+ dist_sq /= SQUARE(depth);
+
+ if ((dist_sq < *dist_to_ray_sq) && (depth < *ray_depth)) {
+ *dist_to_ray_sq = dist_sq;
+
+ tmp_co[0] /= scale[0];
+ tmp_co[1] /= scale[1];
+ tmp_co[2] /= scale[2];
+
+ copy_v3_v3(r_co, tmp_co);
+
+ if (r_no) {
+ sub_v3_v3v3(r_no, v1, v2);
+ }
+
+ *ray_depth = depth;
+ return true;
+ }
+ return false;
+}
+
+static void test_vert_depth_cb(
+ void *userdata, const float origin[3], const float dir[3],
+ const float scale[3], int index, BVHTreeNearest *nearest)
+{
+ struct NearestDM_Data *ndata = userdata;
+ const BVHTreeFromMesh *data = ndata->bvhdata;
+ const MVert *vert = data->vert + index;
+
+ if (test_vert(
+ vert->co, NULL, origin, dir, ndata->ray_depth_range, scale, ndata->is_persp,
+ ndata->ray_depth, &nearest->dist_sq,
+ nearest->co, NULL))
+ {
+ normal_short_to_float_v3(nearest->no, vert->no);
+ nearest->index = index;
+ }
+}
+
+static void test_edge_depth_cb(
+ void *userdata, const float origin[3], const float dir[3],
+ const float scale[3], int index, BVHTreeNearest *nearest)
+{
+ struct NearestDM_Data *ndata = userdata;
+ const BVHTreeFromMesh *data = ndata->bvhdata;
+ const MVert *vert = data->vert;
+ const MEdge *edge = data->edge + index;
+
+ if (test_edge(
+ vert[edge->v1].co, vert[edge->v2].co, origin, dir, ndata->ray_depth_range, scale, ndata->is_persp,
+ ndata->ray_depth, &nearest->dist_sq,
+ nearest->co, nearest->no))
+ {
+ nearest->index = index;
+ }
+}
+
static bool snapDerivedMesh(
SnapObjectContext *sctx,
- 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, unsigned int ob_index,
+ Object *ob, DerivedMesh *dm, float obmat[4][4], const unsigned int ob_index,
+ const short snap_to, bool do_bb,
+ const float ray_origin[3], const float ray_start[3], const float ray_normal[3], const float ray_depth_range[2],
+ /* read/write args */
+ float *ray_depth, float *dist_to_ray_sq, float *dist_px,
+ /* return args */
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) {
@@ -703,10 +877,8 @@ static bool snapDerivedMesh(
}
{
- 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));
- bool need_ray_start_correction_init = do_ray_start_correction;
+ const bool is_persp = sctx->use_v3d && ((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp;
+ bool need_ray_start_correction_init = (snap_to == SCE_SNAP_MODE_FACE) && sctx->use_v3d && !is_persp;
float imat[4][4];
float timat[3][3]; /* transpose inverse matrix for normals */
@@ -735,7 +907,7 @@ static bool snapDerivedMesh(
if (bb) {
BoundBox bb_temp;
- /* We cannot aford a bbox with some null dimension, which may happen in some cases...
+ /* We cannot afford a bounding box 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);
@@ -772,6 +944,9 @@ static bool snapDerivedMesh(
int tree_index = -1;
switch (snap_to) {
case SCE_SNAP_MODE_FACE:
+ tree_index = 2;
+ break;
+ case SCE_SNAP_MODE_EDGE:
tree_index = 1;
break;
case SCE_SNAP_MODE_VERTEX:
@@ -793,10 +968,8 @@ static bool snapDerivedMesh(
}
}
else {
- if (ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX)) {
- treedata = &treedata_stack;
- memset(treedata, 0, sizeof(*treedata));
- }
+ treedata = &treedata_stack;
+ memset(treedata, 0, sizeof(*treedata));
}
if (treedata && treedata->tree == NULL) {
@@ -804,53 +977,56 @@ static bool snapDerivedMesh(
case SCE_SNAP_MODE_FACE:
bvhtree_from_mesh_looptri(treedata, dm, 0.0f, 4, 6);
break;
+ case SCE_SNAP_MODE_EDGE:
+ bvhtree_from_mesh_edges(treedata, dm, 0.0f, 2, 6);
+ break;
case SCE_SNAP_MODE_VERTEX:
bvhtree_from_mesh_verts(treedata, dm, 0.0f, 2, 6);
break;
}
}
-
- if (need_ray_start_correction_init) {
- /* 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);
- }
- }
- }
- /* 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) {
- 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:
{
+ /* 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 (sctx->use_v3d && !is_persp) { /* do_ray_start_correction */
+ if (need_ray_start_correction_init) {
+ /* 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) {
+ float dvec[3];
+ sub_v3_v3v3(dvec, nearest.co, ray_start_local);
+ len_diff = dot_v3v3(dvec, ray_normal_local);
+ }
+ }
+ }
+ 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 + ray_depth_range[0]);
+ local_depth -= len_diff;
+ }
+ else {
+ len_diff = 0.0f;
+ }
if (r_hit_list) {
struct RayCastAll_Data data;
@@ -861,7 +1037,7 @@ static bool snapDerivedMesh(
data.len_diff = len_diff;
data.local_scale = local_scale;
data.ob = ob;
- data.ob_uuid = ob_index,
+ data.ob_uuid = ob_index;
data.dm = dm;
data.hit_list = r_hit_list;
data.retval = retval;
@@ -907,40 +1083,90 @@ static bool snapDerivedMesh(
}
case SCE_SNAP_MODE_VERTEX:
{
+ float ray_org_local[3];
+
+ copy_v3_v3(ray_org_local, ray_origin);
+ mul_m4_v3(imat, ray_org_local);
+
BVHTreeNearest nearest;
nearest.index = -1;
- nearest.dist_sq = local_depth * local_depth;
- if (treedata->tree &&
+ nearest.dist_sq = *dist_to_ray_sq;
+
+ struct NearestDM_Data userdata;
+ userdata.bvhdata = treedata;
+ userdata.is_persp = is_persp;
+ userdata.ray_depth_range = ray_depth_range;
+ userdata.ray_depth = ray_depth;
+
+ float ob_scale[3];
+ mat4_to_size(ob_scale, obmat);
+
+ if (treedata->tree && (
+ is_persp ?
+ BLI_bvhtree_find_nearest_to_ray_angle(
+ treedata->tree, ray_org_local, ray_normal_local,
+ true, ob_scale, &nearest, test_vert_depth_cb, &userdata) :
BLI_bvhtree_find_nearest_to_ray(
- treedata->tree, ray_start_local, ray_normal_local,
- &nearest, NULL, NULL) != -1)
+ treedata->tree, ray_org_local, ray_normal_local,
+ true, ob_scale, &nearest, test_vert_depth_cb, &userdata)) != -1)
{
- const MVert *v = &treedata->vert[nearest.index];
- float vno[3];
- normal_short_to_float_v3(vno, v->no);
- retval = snapVertex(
- ar, v->co, vno, obmat, timat, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
- r_loc, r_no);
+ copy_v3_v3(r_loc, nearest.co);
+ mul_m4_v3(obmat, r_loc);
+ if (r_no) {
+ copy_v3_v3(r_no, nearest.no);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
+ }
+ *dist_px *= nearest.dist_sq / (*dist_to_ray_sq);
+ *dist_to_ray_sq = nearest.dist_sq;
+
+ retval = true;
}
break;
}
case SCE_SNAP_MODE_EDGE:
{
- MVert *verts = dm->getVertArray(dm);
- MEdge *edges = dm->getEdgeArray(dm);
- int totedge = dm->getNumEdges(dm);
-
- 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);
- }
+ float ray_org_local[3];
+
+ copy_v3_v3(ray_org_local, ray_origin);
+ mul_m4_v3(imat, ray_org_local);
+ BVHTreeNearest nearest;
+
+ nearest.index = -1;
+ nearest.dist_sq = *dist_to_ray_sq;
+
+ struct NearestDM_Data userdata;
+ userdata.bvhdata = treedata;
+ userdata.is_persp = is_persp;
+ userdata.ray_depth_range = ray_depth_range;
+ userdata.ray_depth = ray_depth;
+
+ float ob_scale[3];
+ mat4_to_size(ob_scale, obmat);
+
+ if (treedata->tree && (
+ is_persp ?
+ BLI_bvhtree_find_nearest_to_ray_angle(
+ treedata->tree, ray_org_local, ray_normal_local,
+ true, ob_scale, &nearest, test_edge_depth_cb, &userdata) :
+ BLI_bvhtree_find_nearest_to_ray(
+ treedata->tree, ray_org_local, ray_normal_local,
+ true, ob_scale, &nearest, test_edge_depth_cb, &userdata)) != -1)
+ {
+ copy_v3_v3(r_loc, nearest.co);
+ mul_m4_v3(obmat, r_loc);
+ if (r_no) {
+ copy_v3_v3(r_no, nearest.no);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
+ }
+ *dist_px *= nearest.dist_sq / (*dist_to_ray_sq);
+ *dist_to_ray_sq = nearest.dist_sq;
+
+ retval = true;
+ }
break;
}
}
@@ -955,17 +1181,51 @@ static bool snapDerivedMesh(
return retval;
}
+static void test_bmvert_depth_cb(
+ void *userdata, const float origin[3], const float dir[3],
+ const float scale[3], int index, BVHTreeNearest *nearest)
+{
+ struct NearestDM_Data *ndata = userdata;
+ const BMEditMesh *em = ndata->bvhdata;
+ BMVert *eve = BM_vert_at_index(em->bm, index);
+
+ if (test_vert(
+ eve->co, eve->no, origin, dir, ndata->ray_depth_range, scale, ndata->is_persp,
+ ndata->ray_depth, &nearest->dist_sq,
+ nearest->co, nearest->no))
+ {
+ nearest->index = index;
+ }
+}
+
+static void test_bmedge_depth_cb(
+ void *userdata, const float origin[3], const float dir[3],
+ const float scale[3], int index, BVHTreeNearest *nearest)
+{
+ struct NearestDM_Data *ndata = userdata;
+ const BMEditMesh *em = ndata->bvhdata;
+ BMEdge *eed = BM_edge_at_index(em->bm, index);
+
+ if (test_edge(
+ eed->v1->co, eed->v2->co, origin, dir, ndata->ray_depth_range, scale, ndata->is_persp,
+ ndata->ray_depth, &nearest->dist_sq,
+ nearest->co, nearest->no))
+ {
+ nearest->index = index;
+ }
+}
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,
+ Object *ob, BMEditMesh *em, float obmat[4][4], const unsigned int ob_index,
+ float *dist_px, const short snap_to,
+ const float ray_origin[3], const float ray_start[3], const float ray_normal[3], const float ray_depth_range[2],
+ /* read/write args */
+ float *ray_depth, float *dist_to_ray_sq,
+ /* return args */
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) {
@@ -985,31 +1245,19 @@ static bool snapEditMesh(
}
{
- 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));
+ const bool is_persp = (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;
+ float ray_normal_local[3];
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;
@@ -1027,6 +1275,9 @@ static bool snapEditMesh(
int tree_index = -1;
switch (snap_to) {
case SCE_SNAP_MODE_FACE:
+ tree_index = 2;
+ break;
+ case SCE_SNAP_MODE_EDGE:
tree_index = 1;
break;
case SCE_SNAP_MODE_VERTEX:
@@ -1041,10 +1292,8 @@ static bool snapEditMesh(
}
}
else {
- if (ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX)) {
- treedata = &treedata_stack;
- memset(treedata, 0, sizeof(*treedata));
- }
+ treedata = &treedata_stack;
+ memset(treedata, 0, sizeof(*treedata));
}
if (treedata && treedata->tree == NULL) {
@@ -1059,12 +1308,29 @@ static bool snapEditMesh(
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);
+ bvhtree_from_editmesh_looptri_ex(treedata, em, looptri_mask, looptri_num_active, 0.0f, 4, 6, NULL);
if (looptri_mask) {
MEM_freeN(looptri_mask);
}
break;
}
+ case SCE_SNAP_MODE_EDGE:
+ {
+ BLI_bitmap *edges_mask = NULL;
+ int edges_num_active = -1;
+ if (sctx->callbacks.edit_mesh.test_edge_fn) {
+ edges_mask = BLI_BITMAP_NEW(em->bm->totedge, __func__);
+ edges_num_active = BM_iter_mesh_bitmap_from_filter(
+ BM_EDGES_OF_MESH, em->bm, edges_mask,
+ (bool (*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_edge_fn,
+ sctx->callbacks.edit_mesh.user_data);
+ }
+ bvhtree_from_editmesh_edges_ex(treedata, em, edges_mask, edges_num_active, 0.0f, 2, 6);
+ if (edges_mask) {
+ MEM_freeN(edges_mask);
+ }
+ break;
+ }
case SCE_SNAP_MODE_VERTEX:
{
BLI_bitmap *verts_mask = NULL;
@@ -1085,43 +1351,56 @@ static bool snapEditMesh(
}
}
- /* 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!
- */
- float len_diff = 0.0f;
- 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. */
- if (BLI_bvhtree_find_nearest(
- treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata) != -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;
- }
- }
- }
-
switch (snap_to) {
case SCE_SNAP_MODE_FACE:
{
+ float ray_start_local[3];
+ copy_v3_v3(ray_start_local, ray_start);
+ mul_m4_v3(imat, ray_start_local);
+
+ /* local scale in normal direction */
+ float local_scale = normalize_v3(ray_normal_local);
+ float local_depth = *ray_depth;
+ if (local_depth != BVH_RAYCAST_DIST_MAX) {
+ local_depth *= local_scale;
+ }
+
+ /* 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!
+ */
+ float len_diff = 0.0f;
+ if (sctx->use_v3d && !is_persp) { /* 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. */
+ if (BLI_bvhtree_find_nearest(
+ treedata->tree, ray_start_local, &nearest, NULL, NULL) != -1)
+ {
+ float dvec[3];
+ sub_v3_v3v3(dvec, nearest.co, ray_start_local);
+ len_diff = dot_v3v3(dvec, ray_normal_local);
+ 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 + ray_depth_range[0]);
+ local_depth -= len_diff;
+ }
+ }
+ }
if (r_hit_list) {
struct RayCastAll_Data data;
@@ -1176,47 +1455,92 @@ static bool snapEditMesh(
}
break;
}
- case SCE_SNAP_MODE_VERTEX:
+ case SCE_SNAP_MODE_EDGE:
{
+ float ray_org_local[3];
+
+ copy_v3_v3(ray_org_local, ray_origin);
+ mul_m4_v3(imat, ray_org_local);
+
BVHTreeNearest nearest;
nearest.index = -1;
- nearest.dist_sq = local_depth * local_depth;
- if (treedata->tree &&
+ nearest.dist_sq = *dist_to_ray_sq;
+
+ struct NearestDM_Data userdata;
+ userdata.bvhdata = em;
+ userdata.is_persp = is_persp;
+ userdata.ray_depth_range = ray_depth_range;
+ userdata.ray_depth = ray_depth;
+
+ float ob_scale[3];
+ mat4_to_size(ob_scale, obmat);
+
+ if (treedata->tree && (
+ is_persp ?
+ BLI_bvhtree_find_nearest_to_ray_angle(
+ treedata->tree, ray_org_local, ray_normal_local,
+ false, ob_scale, &nearest, test_bmedge_depth_cb, &userdata) :
BLI_bvhtree_find_nearest_to_ray(
- treedata->tree, ray_start_local, ray_normal_local,
- &nearest, NULL, NULL) != -1)
+ treedata->tree, ray_org_local, ray_normal_local,
+ false, ob_scale, &nearest, test_bmedge_depth_cb, &userdata)) != -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);
+ copy_v3_v3(r_loc, nearest.co);
+ mul_m4_v3(obmat, r_loc);
+ if (r_no) {
+ copy_v3_v3(r_no, nearest.no);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
+ }
+ *dist_px *= nearest.dist_sq / (*dist_to_ray_sq);
+ *dist_to_ray_sq = nearest.dist_sq;
+
+ retval = true;
}
break;
}
- case SCE_SNAP_MODE_EDGE:
+ case SCE_SNAP_MODE_VERTEX:
{
- 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, 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);
+ float ray_org_local[3];
+
+ copy_v3_v3(ray_org_local, ray_origin);
+ mul_m4_v3(imat, ray_org_local);
+
+ BVHTreeNearest nearest;
+
+ nearest.index = -1;
+ nearest.dist_sq = *dist_to_ray_sq;
+
+ struct NearestDM_Data userdata;
+ userdata.bvhdata = em;
+ userdata.is_persp = is_persp;
+ userdata.ray_depth_range = ray_depth_range;
+ userdata.ray_depth = ray_depth;
+
+ float ob_scale[3];
+ mat4_to_size(ob_scale, obmat);
+
+ if (treedata->tree && (
+ is_persp ?
+ BLI_bvhtree_find_nearest_to_ray_angle(
+ treedata->tree, ray_org_local, ray_normal_local,
+ false, ob_scale, &nearest, test_bmvert_depth_cb, &userdata) :
+ BLI_bvhtree_find_nearest_to_ray(
+ treedata->tree, ray_org_local, ray_normal_local,
+ false, ob_scale, &nearest, test_bmedge_depth_cb, &userdata)) != -1)
+ {
+ copy_v3_v3(r_loc, nearest.co);
+ mul_m4_v3(obmat, r_loc);
+ if (r_no) {
+ copy_v3_v3(r_no, nearest.no);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
}
- }
+ *dist_px *= nearest.dist_sq / (*dist_to_ray_sq);
+ *dist_to_ray_sq = nearest.dist_sq;
+ retval = true;
+ }
break;
}
}
@@ -1231,18 +1555,28 @@ static bool snapEditMesh(
return retval;
}
+/**
+ * \param use_obedit: Uses the coordinates of BMesh (if any) to do the snapping;
+ * \param ray_depth_range:
+ * - 0: distance from the ray_origin to the clipping plane min (can be negative).
+ * - 1: maximum distance, elements outside this are ignored.
+ * \param ray_depth: maximum depth allowed for r_co.
+ *
+ * \note Duplicate args here are documented at #snapObjectsRay
+ */
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 unsigned int ob_index,
- const float ray_start[3], const float ray_normal[3], const float ray_origin[3],
- float *ray_depth,
+ Object *ob, float obmat[4][4], const unsigned int ob_index,
+ bool use_obedit, const short snap_to, const float mval[2],
+ const float ray_origin[3], const float ray_start[3], const float ray_normal[3], const float ray_depth_range[2],
+ /* read/write args */
+ float *ray_depth, float *dist_to_ray_sq, float *dist_px,
/* return args */
float r_loc[3], float r_no[3], int *r_index,
Object **r_ob, float r_obmat[4][4],
ListBase *r_hit_list)
{
- ARegion *ar = sctx->v3d_data.ar;
+ const ARegion *ar = sctx->v3d_data.ar;
bool retval = false;
if (ob->type == OB_MESH) {
@@ -1251,9 +1585,10 @@ static bool snapObject(
if (use_obedit) {
em = BKE_editmesh_from_object(ob);
retval = snapEditMesh(
- sctx, ob, em, obmat, mval, dist_px, snap_to,
- ray_start, ray_normal, ray_origin,
- ray_depth, ob_index,
+ sctx, ob, em, obmat, ob_index,
+ dist_px, snap_to,
+ ray_origin, ray_start, ray_normal, ray_depth_range,
+ ray_depth, dist_to_ray_sq,
r_loc, r_no, r_index,
r_hit_list);
}
@@ -1269,36 +1604,42 @@ static bool snapObject(
dm = mesh_get_derived_final(sctx->scene, ob, CD_MASK_BAREMESH);
}
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);
+ sctx, ob, dm, obmat, ob_index,
+ snap_to, true,
+ ray_origin, ray_start, ray_normal, ray_depth_range,
+ ray_depth, dist_to_ray_sq, dist_px,
+ r_loc, r_no,
+ r_index, r_hit_list);
dm->release(dm);
}
}
else if (ob->type == OB_ARMATURE) {
retval = snapArmature(
- ar, ob, ob->data, obmat, mval, dist_px, snap_to,
- ray_start, ray_normal, ray_depth,
+ ar, ob, ob->data, obmat, mval, snap_to,
+ ray_start, ray_normal,
+ ray_depth, dist_px,
r_loc, r_no);
}
else if (ob->type == OB_CURVE) {
retval = snapCurve(
- ar, ob, ob->data, obmat, mval, dist_px, snap_to,
- ray_start, ray_normal, ray_depth,
+ ar, ob, ob->data, obmat, mval, snap_to,
+ ray_start, ray_normal,
+ ray_depth, dist_px,
r_loc, r_no);
}
else if (ob->type == OB_EMPTY) {
retval = snapEmpty(
- ar, ob, obmat, mval, dist_px, snap_to,
- ray_start, ray_normal, ray_depth,
+ ar, ob, obmat, mval, snap_to,
+ ray_start, ray_normal,
+ ray_depth, dist_px,
r_loc, r_no);
}
else if (ob->type == OB_CAMERA) {
retval = snapCamera(
- ar, sctx->scene, ob, obmat, mval, dist_px, snap_to,
- ray_start, ray_normal, ray_depth,
+ ar, sctx->scene, ob, obmat, mval, snap_to,
+ ray_start, ray_normal,
+ ray_depth, dist_px,
r_loc, r_no);
}
@@ -1312,18 +1653,68 @@ static bool snapObject(
return retval;
}
+/**
+ * Main Snapping Function
+ * ======================
+ *
+ * Walks through all objects in the scene to find the closest snap element ray.
+ *
+ * \param sctx: Snap context to store data.
+ * \param snap_to: Element to snap, Vertice, Edge or Face.
+ * Currently only works one at a time, but can eventually operate as flag.
+ *
+ * \param snap_select: from enum SnapSelect.
+ *
+ * \param use_object_edit_cage: Uses the coordinates of BMesh (if any) to do the snapping.
+ * \param mval: Optional screen-space 2D location we're snapping to (may phase out).
+ * \param ray_origin: ray_start before being moved toward the ray_normal at the distance from vew3d clip_min.
+ * \param ray_start: ray_origin moved for the start clipping plane (clip_min).
+ * \param ray_normal: Unit length direction of the ray.
+ *
+ * Read/Write Args
+ * ---------------
+ *
+ * \param ray_depth: maximum depth allowed for r_co, elements deeper than this value will be ignored.
+ * \param dist_to_ray_sq: Real distance (3D) or Tangent (view cone radius at distance 1.0) squared.
+ * resulting of the function #dist_px_to_dist3d_or_tangent.
+ *
+ * \param dist_px: Pixel distance to element,
+ * note that this will eventually be replaced entirely by \a dist_to_ray_sq.
+ *
+ * Output Args
+ * -----------
+ *
+ * \param r_loc: Hit location.
+ * \param r_no: Hit normal (optional).
+ * \param r_index: Hit index or -1 when no valid index is found.
+ * (currently only set to the polygon index when when using ``snap_to == SCE_SNAP_MODE_FACE``).
+ * \param r_ob: Hit object.
+ * \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances).
+ * \param r_hit_list: List of #SnapObjectHitDepth (caller must free).
+ *
+ */
static bool snapObjectsRay(
SnapObjectContext *sctx,
const unsigned short snap_to, const SnapSelect snap_select,
- const bool use_object_edit_cage,
- 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 bool use_object_edit_cage, const float mval[2],
+ const float ray_origin[3], const float ray_start[3], const float ray_normal[3],
+ /* read/write args */
+ float *ray_depth, float *dist_to_ray_sq, float *dist_px,
/* return args */
float r_loc[3], float r_no[3], int *r_index,
Object **r_ob, float r_obmat[4][4],
ListBase *r_hit_list)
{
bool retval = false;
+
+ float dvec[3];
+ sub_v3_v3v3(dvec, ray_start, ray_origin);
+
+ const float ray_depth_range[2] = {
+ dot_v3v3(dvec, ray_normal),
+ *ray_depth,
+ };
+
unsigned int ob_index = 0;
Object *obedit = use_object_edit_cage ? sctx->scene->obedit : NULL;
@@ -1337,9 +1728,10 @@ static bool snapObjectsRay(
Object *ob = base_act->object;
retval |= snapObject(
- sctx, ob, ob->obmat, false, snap_to,
- mval, dist_px, ob_index++,
- ray_start, ray_normal, ray_origin, ray_depth,
+ sctx, ob, ob->obmat, ob_index++,
+ false, snap_to, mval,
+ ray_origin, ray_start, ray_normal, ray_depth_range,
+ ray_depth, dist_to_ray_sq, dist_px,
r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
}
@@ -1372,9 +1764,10 @@ static bool snapObjectsRay(
Object *dupli_snap = (use_obedit_dupli) ? obedit : dupli_ob->ob;
retval |= snapObject(
- sctx, dupli_snap, dupli_ob->mat, use_obedit_dupli, snap_to,
- mval, dist_px, ob_index++,
- ray_start, ray_normal, ray_origin, ray_depth,
+ sctx, dupli_snap, dupli_ob->mat, ob_index++,
+ use_obedit_dupli, snap_to, mval,
+ ray_origin, ray_start, ray_normal, ray_depth_range,
+ ray_depth, dist_to_ray_sq, dist_px,
r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
}
@@ -1385,9 +1778,10 @@ static bool snapObjectsRay(
Object *ob_snap = use_obedit ? obedit : ob;
retval |= snapObject(
- sctx, ob_snap, ob->obmat, use_obedit, snap_to,
- mval, dist_px, ob_index++,
- ray_start, ray_normal, ray_origin, ray_depth,
+ sctx, ob_snap, ob->obmat, ob_index++,
+ use_obedit, snap_to, mval,
+ ray_origin, ray_start, ray_normal, ray_depth_range,
+ ray_depth, dist_to_ray_sq, dist_px,
r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
}
}
@@ -1419,7 +1813,7 @@ SnapObjectContext *ED_transform_snap_object_context_create(
SnapObjectContext *ED_transform_snap_object_context_create_view3d(
Main *bmain, Scene *scene, int flag,
/* extra args for view3d */
- ARegion *ar, View3D *v3d)
+ const ARegion *ar, const View3D *v3d)
{
SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, flag);
@@ -1489,15 +1883,19 @@ bool ED_transform_snap_object_project_ray_ex(
SnapObjectContext *sctx,
const unsigned short snap_to,
const struct SnapObjectParams *params,
- const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ const float ray_start[3], const float ray_normal[3],
+ float *ray_depth,
float r_loc[3], float r_no[3], int *r_index,
Object **r_ob, float r_obmat[4][4])
{
+ float dist_to_ray_sq = 0.0f;
+
return snapObjectsRay(
sctx,
snap_to, params->snap_select, params->use_object_edit_cage,
- NULL, NULL,
- ray_start, ray_normal, ray_start, ray_depth,
+ NULL,
+ ray_start, ray_start, ray_normal,
+ ray_depth, &dist_to_ray_sq, NULL,
r_loc, r_no, r_index, r_ob, r_obmat, NULL);
}
@@ -1516,6 +1914,8 @@ bool ED_transform_snap_object_project_ray_all(
float ray_depth, bool sort,
ListBase *r_hit_list)
{
+ float dist_to_ray_sq = 0.0f;
+
if (ray_depth == -1.0f) {
ray_depth = BVH_RAYCAST_DIST_MAX;
}
@@ -1526,9 +1926,9 @@ bool ED_transform_snap_object_project_ray_all(
bool retval = snapObjectsRay(
sctx,
- snap_to, params->snap_select, params->use_object_edit_cage,
- NULL, NULL,
- ray_start, ray_normal, ray_start, &ray_depth,
+ snap_to, params->snap_select, params->use_object_edit_cage, NULL,
+ ray_start, ray_start, ray_normal,
+ &ray_depth, &dist_to_ray_sq, NULL,
NULL, NULL, NULL, NULL, NULL,
r_hit_list);
@@ -1637,12 +2037,27 @@ static bool transform_snap_context_project_view3d_mixed_impl(
}
/**
+ * From a threshold (maximum distance to snap in pixels) returns:
+ *
+ * - The *real* distance (3D) if you are in orthographic-view.
+ * - The *tangent* (view cone radius at distance 1.0) if you are in perspective-view.
+ */
+static float dist_px_to_dist3d_or_tangent(const ARegion *ar, const float dist_px)
+{
+ const RegionView3D *rv3d = ar->regiondata;
+ if (ar->winx >= ar->winy)
+ return 2 * (dist_px / ar->winx) / rv3d->winmat[0][0];
+ else
+ return 2 * (dist_px / ar->winy) / rv3d->winmat[1][1];
+}
+
+/**
* Convenience function for performing snapping.
*
* Given a 2D region value, snap to vert/edge/face.
*
* \param sctx: Snap context.
- * \param mval: Screenspace coordinate.
+ * \param mval_fl: Screenspace coordinate.
* \param dist_px: Maximum distance to snap (in pixels).
* \param use_depth: Snap to the closest element, use when using more than one snap type.
* \param r_co: hit location.
@@ -1672,7 +2087,7 @@ bool ED_transform_snap_object_project_view3d_ex(
float *ray_depth,
float r_loc[3], float r_no[3], int *r_index)
{
- float ray_start[3], ray_normal[3], ray_orgigin[3];
+ float ray_start[3], ray_normal[3], ray_origin[3];
float ray_depth_fallback;
if (ray_depth == NULL) {
@@ -1682,16 +2097,37 @@ bool ED_transform_snap_object_project_view3d_ex(
if (!ED_view3d_win_to_ray_ex(
sctx->v3d_data.ar, sctx->v3d_data.v3d,
- mval, ray_orgigin, ray_normal, ray_start, true))
+ mval, ray_origin, ray_normal, ray_start, true))
{
return false;
}
+ float dist_to_ray_sq;
+ {
+ float radius = dist_px_to_dist3d_or_tangent(sctx->v3d_data.ar, *dist_px);
+ /**
+ * Workaround to use of cone (Instead of project the radius on view plane):
+ * In perspective view, the radius of the cone may decrease depending on the ray direction.
+ * This is more evident with small values of the `Viewport lens angle`.
+ * The threshold becomes distorted that way.
+ */
+ RegionView3D *rv3d = sctx->v3d_data.ar->regiondata;
+ if (rv3d->is_persp) {
+ float view_dir[3];
+ negate_v3_v3(view_dir, rv3d->viewinv[2]);
+ normalize_v3(view_dir);
+ radius *= dot_v3v3(ray_normal, view_dir);
+ }
+
+ dist_to_ray_sq = SQUARE(radius);
+ }
+
return snapObjectsRay(
sctx,
snap_to, params->snap_select, params->use_object_edit_cage,
- mval, dist_px,
- ray_start, ray_normal, ray_orgigin, ray_depth,
+ mval,
+ ray_origin, ray_start, ray_normal,
+ ray_depth, &dist_to_ray_sq, dist_px,
r_loc, r_no, r_index, NULL, NULL, NULL);
}
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index 1f4ce926f16..e2f60955c81 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -57,6 +57,7 @@
#include "BKE_multires.h"
#include "BKE_packedFile.h"
#include "BKE_paint.h"
+#include "BKE_screen.h"
#include "ED_armature.h"
#include "ED_buttons.h"
@@ -326,22 +327,14 @@ void ED_region_draw_mouse_line_cb(const bContext *C, ARegion *ar, void *arg_info
/**
* Use to free ID references within runtime data (stored outside of DNA)
*
- * \note Typically notifiers take care of this,
- * but there are times we have to free references immediately, see: T44376
+ * \param new_id may be NULL to unlink \a old_id.
*/
-void ED_spacedata_id_unref(struct SpaceLink *sl, const ID *id)
+void ED_spacedata_id_remap(struct ScrArea *sa, struct SpaceLink *sl, ID *old_id, ID *new_id)
{
+ SpaceType *st = BKE_spacetype_from_id(sl->spacetype);
- switch (sl->spacetype) {
- case SPACE_OUTLINER:
- ED_outliner_id_unref((SpaceOops *)sl, id);
- break;
- case SPACE_BUTS:
- ED_buttons_id_unref((SpaceButs *)sl, id);
- break;
- case SPACE_NODE:
- ED_node_id_unref((SpaceNode *)sl, id);
- break;
+ if (st && st->id_remap) {
+ st->id_remap(sa, sl, old_id, new_id);
}
}
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index baa471e920b..94d69a0169f 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -279,8 +279,6 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe
col[3] = 0.5f; /* hard coded alpha, not that nice */
- glShadeModel(GL_SMOOTH);
-
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
@@ -344,8 +342,6 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe
BLI_buffer_free(&av_buf);
BLI_buffer_free(&auv_buf);
- glShadeModel(GL_FLAT);
-
break;
}
}
@@ -794,8 +790,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
UI_GetThemeColor4ubv(TH_EDGE_SELECT, col1);
if (interpedges) {
- glShadeModel(GL_SMOOTH);
-
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
continue;
@@ -810,8 +805,6 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
}
glEnd();
}
-
- glShadeModel(GL_FLAT);
}
else {
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c
index 59f9cd16908..b3190ef784f 100644
--- a/source/blender/editors/uvedit/uvedit_parametrizer.c
+++ b/source/blender/editors/uvedit/uvedit_parametrizer.c
@@ -740,6 +740,16 @@ static PVert *p_vert_add(PHandle *handle, PHashKey key, const float co[3], PEdge
{
PVert *v = (PVert *)BLI_memarena_alloc(handle->arena, sizeof(*v));
copy_v3_v3(v->co, co);
+
+ /* Sanity check, a single nan/inf point causes the entire result to be invalid.
+ * Note that values within the calculation may _become_ non-finite,
+ * so the rest of the code still needs to take this possability into account. */
+ for (int i = 0; i < 3; i++) {
+ if (UNLIKELY(!isfinite(v->co[i]))) {
+ v->co[i] = 0.0f;
+ }
+ }
+
v->u.key = key;
v->edge = e;
v->flag = 0;
@@ -3040,8 +3050,10 @@ static void p_chart_lscm_begin(PChart *chart, PBool live, PBool abf)
p_chart_boundaries(chart, NULL, &outer);
- if (!p_chart_symmetry_pins(chart, outer, &pin1, &pin2))
+ /* outer can be NULL with non-finite coords. */
+ if (outer && !p_chart_symmetry_pins(chart, outer, &pin1, &pin2)) {
p_chart_extrema_verts(chart, &pin1, &pin2);
+ }
chart->u.lscm.pin1 = pin1;
chart->u.lscm.pin2 = pin2;