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:
authorTamito Kajiyama <rd6t-kjym@asahi-net.or.jp>2013-03-18 04:48:59 +0400
committerTamito Kajiyama <rd6t-kjym@asahi-net.or.jp>2013-03-18 04:48:59 +0400
commitc1ceab1281ccf061f03f8000bf190a082a5385d8 (patch)
tree01b9a9cfca80432d316bdad6c18c74eb025e9eb0 /source/blender/editors
parent0d9c98c4bbfbc8c70c4772086dd09a51d01921ef (diff)
parent66a35e089a64d27bfc09c2225a530069eca05875 (diff)
Merged changes in the trunk up to revision 55357.
Resolved conflicts: release/datafiles/startup.blend source/blender/editors/space_nla/nla_buttons.c Also updated source/blender/blenkernel/intern/linestyle.c as a follow-up of recent changes for the use of bool.
Diffstat (limited to 'source/blender/editors')
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c42
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c8
-rw-r--r--source/blender/editors/animation/anim_filter.c41
-rw-r--r--source/blender/editors/animation/anim_ipo_utils.c6
-rw-r--r--source/blender/editors/animation/anim_markers.c95
-rw-r--r--source/blender/editors/animation/anim_ops.c6
-rw-r--r--source/blender/editors/animation/keyframing.c27
-rw-r--r--source/blender/editors/animation/keyingsets.c4
-rw-r--r--source/blender/editors/armature/armature_add.c6
-rw-r--r--source/blender/editors/armature/armature_naming.c12
-rw-r--r--source/blender/editors/armature/armature_relations.c2
-rw-r--r--source/blender/editors/armature/armature_select.c16
-rw-r--r--source/blender/editors/armature/armature_utils.c9
-rw-r--r--source/blender/editors/armature/editarmature_generate.c6
-rw-r--r--source/blender/editors/armature/editarmature_retarget.c6
-rw-r--r--source/blender/editors/armature/editarmature_sketch.c43
-rw-r--r--source/blender/editors/armature/pose_edit.c14
-rw-r--r--source/blender/editors/armature/pose_group.c2
-rw-r--r--source/blender/editors/armature/pose_lib.c12
-rw-r--r--source/blender/editors/armature/pose_select.c2
-rw-r--r--source/blender/editors/armature/pose_slide.c12
-rw-r--r--source/blender/editors/armature/reeb.c4
-rw-r--r--source/blender/editors/curve/editcurve.c209
-rw-r--r--source/blender/editors/curve/editfont.c26
-rw-r--r--source/blender/editors/datafiles/SConscript134
-rw-r--r--source/blender/editors/gpencil/gpencil_buttons.c35
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c17
-rw-r--r--source/blender/editors/include/BIF_glutil.h14
-rw-r--r--source/blender/editors/include/ED_anim_api.h5
-rw-r--r--source/blender/editors/include/ED_armature.h3
-rw-r--r--source/blender/editors/include/ED_curve.h2
-rw-r--r--source/blender/editors/include/ED_fileselect.h7
-rw-r--r--source/blender/editors/include/ED_mesh.h10
-rw-r--r--source/blender/editors/include/ED_numinput.h2
-rw-r--r--source/blender/editors/include/ED_screen.h1
-rw-r--r--source/blender/editors/include/ED_sequencer.h2
-rw-r--r--source/blender/editors/include/ED_space_api.h2
-rw-r--r--source/blender/editors/include/ED_transform.h14
-rw-r--r--source/blender/editors/include/ED_view3d.h69
-rw-r--r--source/blender/editors/include/UI_resources.h1
-rw-r--r--source/blender/editors/interface/interface.c86
-rw-r--r--source/blender/editors/interface/interface_draw.c38
-rw-r--r--source/blender/editors/interface/interface_handlers.c30
-rw-r--r--source/blender/editors/interface/interface_icons.c22
-rw-r--r--source/blender/editors/interface/interface_intern.h7
-rw-r--r--source/blender/editors/interface/interface_layout.c5
-rw-r--r--source/blender/editors/interface/interface_ops.c6
-rw-r--r--source/blender/editors/interface/interface_panel.c4
-rw-r--r--source/blender/editors/interface/interface_regions.c6
-rw-r--r--source/blender/editors/interface/interface_style.c26
-rw-r--r--source/blender/editors/interface/interface_templates.c44
-rw-r--r--source/blender/editors/interface/interface_widgets.c9
-rw-r--r--source/blender/editors/interface/resources.c8
-rw-r--r--source/blender/editors/interface/view2d.c8
-rw-r--r--source/blender/editors/interface/view2d_ops.c20
-rw-r--r--source/blender/editors/io/io_collada.c34
-rw-r--r--source/blender/editors/mask/mask_add.c4
-rw-r--r--source/blender/editors/mask/mask_ops.c6
-rw-r--r--source/blender/editors/mask/mask_select.c4
-rw-r--r--source/blender/editors/mesh/CMakeLists.txt2
-rw-r--r--source/blender/editors/mesh/editface.c39
-rw-r--r--source/blender/editors/mesh/editmesh_add.c5
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c519
-rw-r--r--source/blender/editors/mesh/editmesh_knife_project.c168
-rw-r--r--source/blender/editors/mesh/editmesh_loopcut.c7
-rw-r--r--source/blender/editors/mesh/editmesh_rip.c25
-rw-r--r--source/blender/editors/mesh/editmesh_select.c79
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c235
-rw-r--r--source/blender/editors/mesh/mesh_data.c5
-rw-r--r--source/blender/editors/mesh/mesh_intern.h7
-rw-r--r--source/blender/editors/mesh/mesh_ops.c2
-rw-r--r--source/blender/editors/mesh/meshtools.c4
-rw-r--r--source/blender/editors/metaball/mball_edit.c2
-rw-r--r--source/blender/editors/metaball/mball_ops.c10
-rw-r--r--source/blender/editors/object/object_add.c13
-rw-r--r--source/blender/editors/object/object_bake.c8
-rw-r--r--source/blender/editors/object/object_constraint.c24
-rw-r--r--source/blender/editors/object/object_edit.c6
-rw-r--r--source/blender/editors/object/object_intern.h1
-rw-r--r--source/blender/editors/object/object_lattice.c53
-rw-r--r--source/blender/editors/object/object_modifier.c30
-rw-r--r--source/blender/editors/object/object_ops.c3
-rw-r--r--source/blender/editors/object/object_relations.c33
-rw-r--r--source/blender/editors/object/object_transform.c16
-rw-r--r--source/blender/editors/object/object_vgroup.c2
-rw-r--r--source/blender/editors/physics/particle_edit.c24
-rw-r--r--source/blender/editors/physics/physics_fluid.c15
-rw-r--r--source/blender/editors/physics/physics_ops.c4
-rw-r--r--source/blender/editors/physics/rigidbody_object.c106
-rw-r--r--source/blender/editors/physics/rigidbody_world.c2
-rw-r--r--source/blender/editors/render/SConscript2
-rw-r--r--source/blender/editors/render/render_internal.c35
-rw-r--r--source/blender/editors/render/render_opengl.c4
-rw-r--r--source/blender/editors/render/render_preview.c45
-rw-r--r--source/blender/editors/render/render_shading.c2
-rw-r--r--source/blender/editors/render/render_update.c2
-rw-r--r--source/blender/editors/render/render_view.c2
-rw-r--r--source/blender/editors/screen/area.c24
-rw-r--r--source/blender/editors/screen/glutil.c43
-rw-r--r--source/blender/editors/screen/screen_edit.c24
-rw-r--r--source/blender/editors/screen/screen_ops.c44
-rw-r--r--source/blender/editors/screen/screendump.c2
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt6
-rw-r--r--source/blender/editors/sculpt_paint/SConscript5
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c60
-rw-r--r--source/blender/editors/sculpt_paint/paint_hide.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c5392
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c732
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c4465
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h47
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c1
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c28
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c288
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c42
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c81
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c359
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h3
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c57
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_uv.c73
-rw-r--r--source/blender/editors/sound/sound_ops.c6
-rw-r--r--source/blender/editors/space_action/action_edit.c2
-rw-r--r--source/blender/editors/space_action/action_select.c9
-rw-r--r--source/blender/editors/space_buttons/buttons_ops.c15
-rw-r--r--source/blender/editors/space_buttons/buttons_texture.c2
-rw-r--r--source/blender/editors/space_clip/SConscript3
-rw-r--r--source/blender/editors/space_clip/clip_dopesheet_ops.c61
-rw-r--r--source/blender/editors/space_clip/clip_draw.c2
-rw-r--r--source/blender/editors/space_clip/clip_graph_ops.c2
-rw-r--r--source/blender/editors/space_clip/clip_intern.h3
-rw-r--r--source/blender/editors/space_clip/clip_ops.c272
-rw-r--r--source/blender/editors/space_clip/clip_toolbar.c8
-rw-r--r--source/blender/editors/space_clip/space_clip.c8
-rw-r--r--source/blender/editors/space_clip/tracking_ops.c28
-rw-r--r--source/blender/editors/space_clip/tracking_select.c16
-rw-r--r--source/blender/editors/space_console/console_draw.c42
-rw-r--r--source/blender/editors/space_console/console_ops.c8
-rw-r--r--source/blender/editors/space_console/space_console.c4
-rw-r--r--source/blender/editors/space_file/file_draw.c7
-rw-r--r--source/blender/editors/space_file/file_ops.c32
-rw-r--r--source/blender/editors/space_file/filelist.c38
-rw-r--r--source/blender/editors/space_file/filelist.h15
-rw-r--r--source/blender/editors/space_file/filesel.c18
-rw-r--r--source/blender/editors/space_file/fsmenu.c28
-rw-r--r--source/blender/editors/space_file/space_file.c33
-rw-r--r--source/blender/editors/space_graph/graph_edit.c15
-rw-r--r--source/blender/editors/space_graph/graph_ops.c6
-rw-r--r--source/blender/editors/space_graph/graph_select.c9
-rw-r--r--source/blender/editors/space_image/SConscript2
-rw-r--r--source/blender/editors/space_image/image_buttons.c63
-rw-r--r--source/blender/editors/space_image/image_draw.c8
-rw-r--r--source/blender/editors/space_image/image_ops.c52
-rw-r--r--source/blender/editors/space_image/space_image.c2
-rw-r--r--source/blender/editors/space_info/info_ops.c12
-rw-r--r--source/blender/editors/space_info/info_report.c2
-rw-r--r--source/blender/editors/space_info/info_stats.c56
-rw-r--r--source/blender/editors/space_info/textview.c119
-rw-r--r--source/blender/editors/space_logic/logic_ops.c37
-rw-r--r--source/blender/editors/space_nla/nla_buttons.c53
-rw-r--r--source/blender/editors/space_nla/nla_channels.c185
-rw-r--r--source/blender/editors/space_nla/nla_draw.c8
-rw-r--r--source/blender/editors/space_nla/nla_edit.c19
-rw-r--r--source/blender/editors/space_nla/nla_intern.h4
-rw-r--r--source/blender/editors/space_nla/nla_ops.c8
-rw-r--r--source/blender/editors/space_nla/nla_select.c6
-rw-r--r--source/blender/editors/space_node/drawnode.c85
-rw-r--r--source/blender/editors/space_node/node_add.c2
-rw-r--r--source/blender/editors/space_node/node_draw.c2
-rw-r--r--source/blender/editors/space_node/node_edit.c114
-rw-r--r--source/blender/editors/space_node/node_group.c6
-rw-r--r--source/blender/editors/space_node/node_intern.h2
-rw-r--r--source/blender/editors/space_node/node_ops.c4
-rw-r--r--source/blender/editors/space_node/node_relationships.c10
-rw-r--r--source/blender/editors/space_node/node_select.c4
-rw-r--r--source/blender/editors/space_node/node_view.c10
-rw-r--r--source/blender/editors/space_node/space_node.c2
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c302
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c44
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h9
-rw-r--r--source/blender/editors/space_outliner/outliner_ops.c18
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c187
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c91
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c78
-rw-r--r--source/blender/editors/space_outliner/space_outliner.c12
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c14
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c16
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c8
-rw-r--r--source/blender/editors/space_sequencer/sequencer_view.c6
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c6
-rw-r--r--source/blender/editors/space_text/space_text.c2
-rw-r--r--source/blender/editors/space_text/text_autocomplete.c6
-rw-r--r--source/blender/editors/space_text/text_draw.c223
-rw-r--r--source/blender/editors/space_text/text_format.c2
-rw-r--r--source/blender/editors/space_text/text_format_lua.c2
-rw-r--r--source/blender/editors/space_text/text_format_osl.c10
-rw-r--r--source/blender/editors/space_text/text_format_py.c2
-rw-r--r--source/blender/editors/space_text/text_ops.c141
-rw-r--r--source/blender/editors/space_view3d/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_view3d/drawmesh.c8
-rw-r--r--source/blender/editors/space_view3d/drawobject.c29
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c39
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c164
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c94
-rw-r--r--source/blender/editors/space_view3d/view3d_fly.c8
-rw-r--r--source/blender/editors/space_view3d/view3d_header.c18
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h3
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_project.c96
-rw-r--r--source/blender/editors/space_view3d/view3d_ruler.c939
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c50
-rw-r--r--source/blender/editors/space_view3d/view3d_toolbar.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c41
-rw-r--r--source/blender/editors/transform/transform.c399
-rw-r--r--source/blender/editors/transform/transform.h23
-rw-r--r--source/blender/editors/transform/transform_constraints.c20
-rw-r--r--source/blender/editors/transform/transform_conversions.c22
-rw-r--r--source/blender/editors/transform/transform_generics.c16
-rw-r--r--source/blender/editors/transform/transform_input.c2
-rw-r--r--source/blender/editors/transform/transform_manipulator.c27
-rw-r--r--source/blender/editors/transform/transform_ops.c32
-rw-r--r--source/blender/editors/transform/transform_orientations.c12
-rw-r--r--source/blender/editors/transform/transform_snap.c121
-rw-r--r--source/blender/editors/util/ed_util.c3
-rw-r--r--source/blender/editors/util/editmode_undo.c8
-rw-r--r--source/blender/editors/util/numinput.c2
-rw-r--r--source/blender/editors/util/undo.c2
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c37
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c12
-rw-r--r--source/blender/editors/uvedit/uvedit_smart_stitch.c9
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c4
230 files changed, 11328 insertions, 8282 deletions
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index 533420ad641..d6188720cdf 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -384,6 +384,10 @@ static short acf_generic_dataexpand_setting_valid(bAnimContext *ac, bAnimListEle
case ACHANNEL_SETTING_MUTE:
return ((ac) && (ac->spacetype == SPACE_NLA));
+ /* select is ok for most "ds*" channels (e.g. dsmat) */
+ case ACHANNEL_SETTING_SELECT:
+ return 1;
+
/* other flags are never supported */
default:
return 0;
@@ -425,7 +429,7 @@ static void acf_summary_backdrop(bAnimContext *ac, bAnimListElem *ale, float ymi
static void acf_summary_name(bAnimListElem *UNUSED(ale), char *name)
{
if (name)
- BLI_strncpy(name, "DopeSheet Summary", ANIM_CHAN_NAME_SIZE);
+ BLI_strncpy(name, IFACE_("DopeSheet Summary"), ANIM_CHAN_NAME_SIZE);
}
// FIXME: this is really a temp icon I think
@@ -896,6 +900,27 @@ static void acf_fcurve_name(bAnimListElem *ale, char *name)
getname_anim_fcurve(name, ale->id, ale->data);
}
+/* "name" property for fcurve entries */
+static short acf_fcurve_name_prop(bAnimListElem *ale, PointerRNA *ptr, PropertyRNA **prop)
+{
+ FCurve *fcu = (FCurve *)ale->data;
+
+ /* Ctrl-Click Usability Convenience Hack:
+ * For disabled F-Curves, allow access to the RNA Path
+ * as our "name" so that user can perform quick fixes
+ */
+ if (fcu->flag & FCURVE_DISABLED) {
+ RNA_pointer_create(ale->id, &RNA_FCurve, ale->data, ptr);
+ *prop = RNA_struct_find_property(ptr, "data_path");
+ }
+ else {
+ /* for "normal" F-Curves - no editable name, but *prop may not be set properly yet... */
+ *prop = NULL;
+ }
+
+ return (*prop != NULL);
+}
+
/* check if some setting exists for this channel */
static short acf_fcurve_setting_valid(bAnimContext *ac, bAnimListElem *ale, int setting)
{
@@ -967,7 +992,7 @@ static bAnimChannelType ACF_FCURVE =
acf_generic_group_offset, /* offset */
acf_fcurve_name, /* name */
- NULL, /* name prop */
+ acf_fcurve_name_prop, /* name prop */
NULL, /* icon */
acf_fcurve_setting_valid, /* has setting */
@@ -1070,7 +1095,7 @@ static int acf_filldrivers_icon(bAnimListElem *UNUSED(ale))
static void acf_filldrivers_name(bAnimListElem *UNUSED(ale), char *name)
{
- BLI_strncpy(name, "Drivers", ANIM_CHAN_NAME_SIZE);
+ BLI_strncpy(name, IFACE_("Drivers"), ANIM_CHAN_NAME_SIZE);
}
/* check if some setting exists for this channel */
@@ -2338,7 +2363,7 @@ static void acf_shapekey_name(bAnimListElem *ale, char *name)
if (kb->name[0])
BLI_strncpy(name, kb->name, ANIM_CHAN_NAME_SIZE);
else
- BLI_snprintf(name, ANIM_CHAN_NAME_SIZE, "Key %d", ale->index);
+ BLI_snprintf(name, ANIM_CHAN_NAME_SIZE, IFACE_("Key %d"), ale->index);
}
}
@@ -3490,10 +3515,13 @@ void ANIM_channel_draw_widgets(bContext *C, bAnimContext *ac, bAnimListElem *ale
/* if rename index matches, add widget for this */
if (ac->ads->renameIndex == channel_index + 1) {
- PointerRNA ptr;
- PropertyRNA *prop;
+ PointerRNA ptr = {{NULL}};
+ PropertyRNA *prop = NULL;
- /* draw renaming widget if we can get RNA pointer for it */
+ /* draw renaming widget if we can get RNA pointer for it
+ * NOTE: property may only be available in some cases, even if we have
+ * a callback available (e.g. broken F-Curve rename)
+ */
if (acf->name_prop(ale, &ptr, &prop)) {
uiBut *but;
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index 15a8222dec2..dd18d07732d 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -2272,7 +2272,7 @@ static void rename_anim_channels(bAnimContext *ac, int channel_index)
ED_region_tag_redraw(ac->ar);
}
-static int animchannels_rename_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *evt)
+static int animchannels_rename_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
bAnimContext ac;
ARegion *ar;
@@ -2293,7 +2293,7 @@ static int animchannels_rename_invoke(bContext *C, wmOperator *UNUSED(op), wmEve
* so that the tops of channels get caught ok. Since ACHANNEL_FIRST is really ACHANNEL_HEIGHT, we simply use
* ACHANNEL_HEIGHT_HALF.
*/
- UI_view2d_region_to_view(v2d, evt->mval[0], evt->mval[1], &x, &y);
+ UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, &y);
if (ac.datatype == ANIMCONT_NLA) {
SpaceNla *snla = (SpaceNla *)ac.sl;
@@ -2609,7 +2609,7 @@ static int mouse_anim_channels(bAnimContext *ac, float UNUSED(x), int channel_in
/* ------------------- */
/* handle clicking */
-static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
bAnimContext ac;
ARegion *ar;
@@ -2667,7 +2667,7 @@ static void ANIM_OT_channels_click(wmOperatorType *ot)
ot->poll = animedit_poll_channels_active;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO;
/* properties */
/* NOTE: don't save settings, otherwise, can end up with some weird behaviour (sticky extend) */
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index 3480db2c5d8..7648d998216 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -449,7 +449,7 @@ short ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
if (ANIMDATA_HAS_NLA(id)) { \
nlaOk \
} \
- else if (!(ads->filterflag & ADS_FILTER_NLA_NOACT) && ANIMDATA_HAS_KEYS(id)) { \
+ else if (!(ads->filterflag & ADS_FILTER_NLA_NOACT) || ANIMDATA_HAS_KEYS(id)) { \
nlaOk \
} \
} \
@@ -1001,22 +1001,39 @@ static short skip_fcurve_with_name(bDopeSheet *ads, FCurve *fcu, ID *owner_id)
/* Check if F-Curve has errors and/or is disabled
* > returns: (bool) True if F-Curve has errors/is disabled
*/
-static short fcurve_has_errors(FCurve *fcu)
+static bool fcurve_has_errors(FCurve *fcu)
{
/* F-Curve disabled - path eval error */
if (fcu->flag & FCURVE_DISABLED) {
- return 1;
+ return true;
}
/* driver? */
if (fcu->driver) {
- /* for now, just check if the entire thing got disabled... */
- if (fcu->driver->flag & DRIVER_FLAG_INVALID)
- return 1;
+ ChannelDriver *driver = fcu->driver;
+ DriverVar *dvar;
+
+ /* error flag on driver usually means that there is an error
+ * BUT this may not hold with PyDrivers as this flag gets cleared
+ * if no critical errors prevent the driver from working...
+ */
+ if (driver->flag & DRIVER_FLAG_INVALID)
+ return true;
+
+ /* check variables for other things that need linting... */
+ // TODO: maybe it would be more efficient just to have a quick flag for this?
+ for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
+ DRIVER_TARGETS_USED_LOOPER(dvar)
+ {
+ if (dtar->flag & DTAR_FLAG_INVALID)
+ return true;
+ }
+ DRIVER_TARGETS_LOOPER_END
+ }
}
/* no errors found */
- return 0;
+ return false;
}
/* find the next F-Curve that is usable for inclusion */
@@ -1060,7 +1077,7 @@ static FCurve *animfilter_fcurve_next(bDopeSheet *ads, FCurve *first, bActionGro
/* error-based filtering... */
if ((ads) && (ads->filterflag & ADS_FILTER_ONLY_ERRORS)) {
/* skip if no errors... */
- if (fcurve_has_errors(fcu) == 0)
+ if (fcurve_has_errors(fcu) == false)
continue;
}
@@ -1297,7 +1314,9 @@ static size_t animfilter_block_data(bAnimContext *ac, ListBase *anim_data, bDope
ANIMDATA_FILTER_CASES(iat,
{ /* AnimData */
/* specifically filter animdata block */
- ANIMCHANNEL_NEW_CHANNEL(adt, ANIMTYPE_ANIMDATA, id);
+ if (ANIMCHANNEL_SELOK(SEL_ANIMDATA(adt)) ) {
+ ANIMCHANNEL_NEW_CHANNEL(adt, ANIMTYPE_ANIMDATA, id);
+ }
},
{ /* NLA */
items += animfilter_nla(ac, anim_data, ads, adt, filter_mode, id);
@@ -1347,7 +1366,9 @@ static size_t animdata_filter_shapekey(bAnimContext *ac, ListBase *anim_data, Ke
// TODO: somehow manage to pass dopesheet info down here too?
if (key->adt) {
if (filter_mode & ANIMFILTER_ANIMDATA) {
- ANIMCHANNEL_NEW_CHANNEL(key->adt, ANIMTYPE_ANIMDATA, key);
+ if (ANIMCHANNEL_SELOK(SEL_ANIMDATA(key->adt)) ) {
+ ANIMCHANNEL_NEW_CHANNEL(key->adt, ANIMTYPE_ANIMDATA, key);
+ }
}
else if (key->adt->action) {
items = animfilter_action(ac, anim_data, NULL, key->adt->action, filter_mode, (ID *)key);
diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c
index b6d24e21057..2352cad0cbc 100644
--- a/source/blender/editors/animation/anim_ipo_utils.c
+++ b/source/blender/editors/animation/anim_ipo_utils.c
@@ -42,6 +42,8 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLF_translation.h"
+
#include "DNA_anim_types.h"
#include "RNA_access.h"
@@ -63,9 +65,9 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu)
return icon;
else if (ELEM3(NULL, id, fcu, fcu->rna_path)) {
if (fcu == NULL)
- strcpy(name, "<invalid>");
+ strcpy(name, IFACE_("<invalid>"));
else if (fcu->rna_path == NULL)
- strcpy(name, "<no path>");
+ strcpy(name, IFACE_("<no path>"));
else /* id == NULL */
BLI_snprintf(name, 256, "%s[%d]", fcu->rna_path, fcu->array_index);
}
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index 62725cb6c70..7a3fc3a8d9b 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -28,7 +28,6 @@
* \ingroup edanimation
*/
-
#include <math.h>
#include "MEM_guardedalloc.h"
@@ -36,10 +35,6 @@
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
-#include "RNA_access.h"
-#include "RNA_define.h"
-#include "RNA_enum_types.h"
-
#include "BLI_blenlib.h"
#include "BLI_math_base.h"
#include "BLI_utildefines.h"
@@ -51,6 +46,10 @@
#include "BKE_scene.h"
#include "BKE_screen.h"
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -277,7 +276,9 @@ static void add_marker_to_cfra_elem(ListBase *lb, TimeMarker *marker, short only
ce->sel = marker->flag;
return;
}
- else if (ce->cfra > marker->frame) break;
+ else if (ce->cfra > marker->frame) {
+ break;
+ }
}
cen = MEM_callocN(sizeof(CfraElem), "add_to_cfra_elem");
@@ -513,8 +514,8 @@ static int ed_markers_poll_markers_exist(bContext *C)
* that operator would otherwise have used. If NULL, the operator's standard
* exec() callback will be called instead in the appropriate places.
*/
-static int ed_markers_opwrap_invoke_custom(bContext *C, wmOperator *op, wmEvent *evt,
- int (*invoke_func)(bContext *, wmOperator *, wmEvent *))
+static int ed_markers_opwrap_invoke_custom(bContext *C, wmOperator *op, const wmEvent *event,
+ int (*invoke_func)(bContext *, wmOperator *, const wmEvent *))
{
ScrArea *sa = CTX_wm_area(C);
int retval = OPERATOR_PASS_THROUGH;
@@ -523,7 +524,7 @@ static int ed_markers_opwrap_invoke_custom(bContext *C, wmOperator *op, wmEvent
/* allow operator to run now */
if (invoke_func)
- retval = invoke_func(C, op, evt);
+ retval = invoke_func(C, op, event);
else if (op->type->exec)
retval = op->type->exec(C, op);
else
@@ -544,9 +545,9 @@ static int ed_markers_opwrap_invoke_custom(bContext *C, wmOperator *op, wmEvent
* though will need to implement their own wrapper which calls the second-tier callback themselves
* (passing through the custom invoke function they use)
*/
-static int ed_markers_opwrap_invoke(bContext *C, wmOperator *op, wmEvent *evt)
+static int ed_markers_opwrap_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- return ed_markers_opwrap_invoke_custom(C, op, evt, NULL);
+ return ed_markers_opwrap_invoke_custom(C, op, event, NULL);
}
/* ************************** add markers *************************** */
@@ -684,14 +685,14 @@ static void ed_marker_move_exit(bContext *C, wmOperator *op)
ED_area_headerprint(CTX_wm_area(C), NULL);
}
-static int ed_marker_move_invoke(bContext *C, wmOperator *op, wmEvent *evt)
+static int ed_marker_move_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (ed_marker_move_init(C, op)) {
MarkerMove *mm = op->customdata;
- mm->evtx = evt->x;
- mm->firstx = evt->x;
- mm->event_type = evt->type;
+ mm->evtx = event->x;
+ mm->firstx = event->x;
+ mm->event_type = event->type;
/* add temp handler */
WM_event_add_modal_handler(C, op);
@@ -705,9 +706,9 @@ static int ed_marker_move_invoke(bContext *C, wmOperator *op, wmEvent *evt)
return OPERATOR_CANCELLED;
}
-static int ed_marker_move_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
+static int ed_marker_move_invoke_wrapper(bContext *C, wmOperator *op, const wmEvent *event)
{
- return ed_markers_opwrap_invoke_custom(C, op, evt, ed_marker_move_invoke);
+ return ed_markers_opwrap_invoke_custom(C, op, event, ed_marker_move_invoke);
}
/* note, init has to be called succesfully */
@@ -756,7 +757,7 @@ static int ed_marker_move_cancel(bContext *C, wmOperator *op)
-static int ed_marker_move_modal(bContext *C, wmOperator *op, wmEvent *evt)
+static int ed_marker_move_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
Scene *scene = CTX_data_scene(C);
MarkerMove *mm = op->customdata;
@@ -765,14 +766,14 @@ static int ed_marker_move_modal(bContext *C, wmOperator *op, wmEvent *evt)
float dx, fac;
char str[256];
- switch (evt->type) {
+ switch (event->type) {
case ESCKEY:
ed_marker_move_cancel(C, op);
return OPERATOR_CANCELLED;
case RIGHTMOUSE:
/* press = user manually demands transform to be canceled */
- if (evt->val == KM_PRESS) {
+ if (event->val == KM_PRESS) {
ed_marker_move_cancel(C, op);
return OPERATOR_CANCELLED;
}
@@ -782,7 +783,7 @@ static int ed_marker_move_modal(bContext *C, wmOperator *op, wmEvent *evt)
case PADENTER:
case LEFTMOUSE:
case MIDDLEMOUSE:
- if (WM_modal_tweak_exit(evt, mm->event_type)) {
+ if (WM_modal_tweak_exit(event, mm->event_type)) {
ed_marker_move_exit(C, op);
WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL);
WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);
@@ -795,17 +796,17 @@ static int ed_marker_move_modal(bContext *C, wmOperator *op, wmEvent *evt)
dx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask);
- if (evt->x != mm->evtx) { /* XXX maybe init for first time */
+ if (event->x != mm->evtx) { /* XXX maybe init for first time */
int a, offs, totmark = 0;
- mm->evtx = evt->x;
+ mm->evtx = event->x;
- fac = ((float)(evt->x - mm->firstx) * dx);
+ fac = ((float)(event->x - mm->firstx) * dx);
if (mm->slink->spacetype == SPACE_TIME)
- apply_keyb_grid(evt->shift, evt->ctrl, &fac, 0.0, FPS, 0.1 * FPS, 0);
+ apply_keyb_grid(event->shift, event->ctrl, &fac, 0.0, FPS, 0.1 * FPS, 0);
else
- apply_keyb_grid(evt->shift, evt->ctrl, &fac, 0.0, 1.0, 0.1, 0 /*was: U.flag & USER_AUTOGRABGRID*/);
+ apply_keyb_grid(event->shift, event->ctrl, &fac, 0.0, 1.0, 0.1, 0 /*was: U.flag & USER_AUTOGRABGRID*/);
offs = (int)fac;
RNA_int_set(op->ptr, "frames", offs);
@@ -864,8 +865,8 @@ static int ed_marker_move_modal(bContext *C, wmOperator *op, wmEvent *evt)
}
}
- if (evt->val == KM_PRESS) {
- if (handleNumInput(&mm->num, evt)) {
+ if (event->val == KM_PRESS) {
+ if (handleNumInput(&mm->num, event)) {
char str_tx[NUM_STR_REP_LEN];
float value = RNA_int_get(op->ptr, "frames");
applyNumInput(&mm->num, &value);
@@ -981,15 +982,15 @@ static int ed_marker_duplicate_exec(bContext *C, wmOperator *op)
}
-static int ed_marker_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *evt)
+static int ed_marker_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ed_marker_duplicate_apply(C);
- return ed_marker_move_invoke(C, op, evt);
+ return ed_marker_move_invoke(C, op, event);
}
-static int ed_marker_duplicate_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
+static int ed_marker_duplicate_invoke_wrapper(bContext *C, wmOperator *op, const wmEvent *event)
{
- return ed_markers_opwrap_invoke_custom(C, op, evt, ed_marker_duplicate_invoke);
+ return ed_markers_opwrap_invoke_custom(C, op, event, ed_marker_duplicate_invoke);
}
static void MARKER_OT_duplicate(wmOperatorType *ot)
@@ -1036,7 +1037,7 @@ static void select_timeline_marker_frame(ListBase *markers, int frame, unsigned
}
}
-static int ed_marker_select(bContext *C, wmEvent *evt, int extend, int camera)
+static int ed_marker_select(bContext *C, const wmEvent *event, int extend, int camera)
{
ListBase *markers = ED_context_get_markers(C);
ARegion *ar = CTX_wm_region(C);
@@ -1047,8 +1048,8 @@ static int ed_marker_select(bContext *C, wmEvent *evt, int extend, int camera)
if (markers == NULL)
return OPERATOR_PASS_THROUGH;
- x = evt->x - ar->winrct.xmin;
- y = evt->y - ar->winrct.ymin;
+ x = event->x - ar->winrct.xmin;
+ y = event->y - ar->winrct.ymin;
UI_view2d_region_to_view(v2d, x, y, &viewx, NULL);
@@ -1103,19 +1104,19 @@ static int ed_marker_select(bContext *C, wmEvent *evt, int extend, int camera)
return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
}
-static int ed_marker_select_invoke(bContext *C, wmOperator *op, wmEvent *evt)
+static int ed_marker_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
short extend = RNA_boolean_get(op->ptr, "extend");
short camera = 0;
#ifdef DURIAN_CAMERA_SWITCH
camera = RNA_boolean_get(op->ptr, "camera");
#endif
- return ed_marker_select(C, evt, extend, camera);
+ return ed_marker_select(C, event, extend, camera);
}
-static int ed_marker_select_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
+static int ed_marker_select_invoke_wrapper(bContext *C, wmOperator *op, const wmEvent *event)
{
- return ed_markers_opwrap_invoke_custom(C, op, evt, ed_marker_select_invoke);
+ return ed_markers_opwrap_invoke_custom(C, op, event, ed_marker_select_invoke);
}
static void MARKER_OT_select(wmOperatorType *ot)
@@ -1200,9 +1201,9 @@ static int ed_marker_border_select_exec(bContext *C, wmOperator *op)
return 1;
}
-static int ed_marker_select_border_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
+static int ed_marker_select_border_invoke_wrapper(bContext *C, wmOperator *op, const wmEvent *event)
{
- return ed_markers_opwrap_invoke_custom(C, op, evt, WM_border_select_invoke);
+ return ed_markers_opwrap_invoke_custom(C, op, event, WM_border_select_invoke);
}
static void MARKER_OT_select_border(wmOperatorType *ot)
@@ -1309,10 +1310,10 @@ static int ed_marker_delete_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-static int ed_marker_delete_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
+static int ed_marker_delete_invoke_wrapper(bContext *C, wmOperator *op, const wmEvent *event)
{
// XXX: must we keep these confirmations?
- return ed_markers_opwrap_invoke_custom(C, op, evt, WM_operator_confirm);
+ return ed_markers_opwrap_invoke_custom(C, op, event, WM_operator_confirm);
}
static void MARKER_OT_delete(wmOperatorType *ot)
@@ -1352,7 +1353,7 @@ static int ed_marker_rename_exec(bContext *C, wmOperator *op)
}
}
-static int ed_marker_rename_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
+static int ed_marker_rename_invoke_wrapper(bContext *C, wmOperator *op, const wmEvent *event)
{
/* must initialize the marker name first if there is a marker selected */
TimeMarker *marker = ED_markers_get_first_selected(ED_context_get_markers(C));
@@ -1360,7 +1361,7 @@ static int ed_marker_rename_invoke_wrapper(bContext *C, wmOperator *op, wmEvent
RNA_string_set(op->ptr, "name", marker->name);
/* now see if the operator is usable */
- return ed_markers_opwrap_invoke_custom(C, op, evt, WM_operator_props_popup);
+ return ed_markers_opwrap_invoke_custom(C, op, event, WM_operator_props_popup);
}
static void MARKER_OT_rename(wmOperatorType *ot)
@@ -1414,9 +1415,9 @@ static int ed_marker_make_links_scene_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int ed_marker_make_links_scene_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
+static int ed_marker_make_links_scene_invoke_wrapper(bContext *C, wmOperator *op, const wmEvent *event)
{
- return ed_markers_opwrap_invoke_custom(C, op, evt, WM_menu_invoke);
+ return ed_markers_opwrap_invoke_custom(C, op, event, WM_menu_invoke);
}
static void MARKER_OT_make_links_scene(wmOperatorType *ot)
diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c
index 6687cce88cd..b9a3daa4e51 100644
--- a/source/blender/editors/animation/anim_ops.c
+++ b/source/blender/editors/animation/anim_ops.c
@@ -115,7 +115,7 @@ static int change_frame_exec(bContext *C, wmOperator *op)
/* ---- */
/* Get frame from mouse coordinates */
-static int frame_from_event(bContext *C, wmEvent *event)
+static int frame_from_event(bContext *C, const wmEvent *event)
{
ARegion *region = CTX_wm_region(C);
float viewx;
@@ -128,7 +128,7 @@ static int frame_from_event(bContext *C, wmEvent *event)
}
/* Modal Operator init */
-static int change_frame_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
/* Change to frame that mouse is over before adding modal handler,
* as user could click on a single frame (jump to frame) as well as
@@ -145,7 +145,7 @@ static int change_frame_invoke(bContext *C, wmOperator *op, wmEvent *event)
}
/* Modal event handling of frame changing */
-static int change_frame_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int change_frame_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
/* execute the events */
switch (event->type) {
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 6d1e6eab26b..ed8398b7c8b 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -714,7 +714,6 @@ static float visualkey_get_value(PointerRNA *ptr, PropertyRNA *prop, int array_i
else if (ptr->type == &RNA_PoseBone) {
Object *ob = (Object *)ptr->id.data; /* we assume that this is always set, and is an object */
bPoseChannel *pchan = (bPoseChannel *)ptr->data;
- float tmat[4][4];
/* Although it is not strictly required for this particular space conversion,
* arg1 must not be null, as there is a null check for the other conversions to
@@ -1298,7 +1297,7 @@ void ANIM_OT_keyframe_insert(wmOperatorType *ot)
* then calls the menu if necessary before
*/
-static int insert_key_menu_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int insert_key_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Scene *scene = CTX_data_scene(C);
@@ -1308,7 +1307,7 @@ static int insert_key_menu_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(e
uiLayout *layout;
/* call the menu, which will call this operator again, hence the canceled */
- pup = uiPupMenuBegin(C, op->type->name, ICON_NONE);
+ pup = uiPupMenuBegin(C, RNA_struct_ui_name(op->type->srna), ICON_NONE);
layout = uiPupMenuLayout(pup);
uiItemsEnumO(layout, "ANIM_OT_keyframe_insert_menu", "type");
uiPupMenuEnd(C, pup);
@@ -1624,17 +1623,21 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
success += insert_keyframe_direct(op->reports, ptr, prop, fcu, cfra, 0);
}
else {
- if (G.debug & G_DEBUG)
- printf("Button Insert-Key: no path to property\n");
- BKE_report(op->reports, RPT_WARNING, "Failed to resolve path to property, try using a keying set instead");
+ BKE_report(op->reports, RPT_WARNING,
+ "Failed to resolve path to property, try manually specifying this using a Keying Set instead");
}
}
- else if (G.debug & G_DEBUG) {
- printf("ptr.data = %p, prop = %p,", (void *)ptr.data, (void *)prop);
- if (prop)
- printf("animatable = %d\n", RNA_property_animateable(&ptr, prop));
- else
- printf("animatable = NULL\n");
+ else {
+ if (prop && !RNA_property_animateable(&ptr, prop)) {
+ BKE_reportf(op->reports, RPT_WARNING,
+ "\"%s\" property cannot be animated",
+ RNA_property_identifier(prop));
+ }
+ else {
+ BKE_reportf(op->reports, RPT_WARNING,
+ "Button doesn't appear to have any property information attached (ptr.data = %p, prop = %p)",
+ (void *)ptr.data, (void *)prop);
+ }
}
if (success) {
diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c
index 4e8d7bdafe5..ad09fcb5966 100644
--- a/source/blender/editors/animation/keyingsets.c
+++ b/source/blender/editors/animation/keyingsets.c
@@ -468,7 +468,7 @@ void ANIM_OT_keyingset_button_remove(wmOperatorType *ot)
/* Change Active KeyingSet Operator ------------------------ */
/* This operator checks if a menu should be shown for choosing the KeyingSet to make the active one */
-static int keyingset_active_menu_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int keyingset_active_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
uiPopupMenu *pup;
uiLayout *layout;
@@ -879,7 +879,7 @@ short ANIM_validate_keyingset(bContext *C, ListBase *dsources, KeyingSet *ks)
if (ksi == NULL)
return MODIFYKEY_MISSING_TYPEINFO;
/* TODO: check for missing callbacks! */
-
+
/* check if it can be used in the current context */
if (ksi->poll(ksi, C)) {
/* if a list of data sources are provided, run a special iterator over them,
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index 531c0551c87..28fb74f0cdd 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -214,7 +214,7 @@ static int armature_click_extrude_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-static int armature_click_extrude_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int armature_click_extrude_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
/* TODO most of this code is copied from set3dcursor_invoke,
* it would be better to reuse code in set3dcursor_invoke */
@@ -320,8 +320,8 @@ void updateDuplicateSubtargetObjects(EditBone *dupBone, ListBase *editbones, Obj
bConstraint *curcon;
ListBase *conlist;
- if ( (pchan = BKE_pose_channel_verify(dst_ob->pose, dupBone->name)) ) {
- if ( (conlist = &pchan->constraints) ) {
+ if ((pchan = BKE_pose_channel_verify(dst_ob->pose, dupBone->name))) {
+ if ((conlist = &pchan->constraints)) {
for (curcon = conlist->first; curcon; curcon = curcon->next) {
/* does this constraint have a subtarget in
* this armature?
diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c
index 6417a795712..561e196bf41 100644
--- a/source/blender/editors/armature/armature_naming.c
+++ b/source/blender/editors/armature/armature_naming.c
@@ -72,7 +72,7 @@ EditBone *editbone_name_exists(ListBase *edbo, const char *name)
}
/* note: there's a unique_bone_name() too! */
-static int editbone_unique_check(void *arg, const char *name)
+static bool editbone_unique_check(void *arg, const char *name)
{
struct {ListBase *lb; void *bone; } *data = arg;
EditBone *dupli = editbone_name_exists(data->lb, name);
@@ -91,7 +91,7 @@ void unique_editbone_name(ListBase *edbo, char *name, EditBone *bone)
/* ************************************************** */
/* Bone Renaming - API */
-static int bone_unique_check(void *arg, const char *name)
+static bool bone_unique_check(void *arg, const char *name)
{
return BKE_armature_find_bone_name((bArmature *)arg, name) != NULL;
}
@@ -152,7 +152,9 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n
unique_editbone_name(arm->edbo, newname, NULL);
BLI_strncpy(eBone->name, newname, MAXBONENAME);
}
- else return;
+ else {
+ return;
+ }
}
else {
Bone *bone = BKE_armature_find_bone_name(arm, oldname);
@@ -161,7 +163,9 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n
unique_bone_name(arm, newname);
BLI_strncpy(bone->name, newname, MAXBONENAME);
}
- else return;
+ else {
+ return;
+ }
}
/* do entire dbase - objects */
diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c
index c64bb5c4683..3a4dc31c82d 100644
--- a/source/blender/editors/armature/armature_relations.c
+++ b/source/blender/editors/armature/armature_relations.c
@@ -671,7 +671,7 @@ static int armature_parent_set_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int armature_parent_set_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
+static int armature_parent_set_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
{
EditBone *actbone = CTX_data_active_bone(C);
uiPopupMenu *pup = uiPupMenuBegin(C, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Make Parent"), ICON_NONE);
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index b7a436cc209..7ff318bb6b6 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -166,7 +166,7 @@ void *get_nearest_bone(bContext *C, short findunsel, int x, int y)
/* called in space.c */
/* previously "selectconnected_armature" */
-static int armature_select_linked_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int armature_select_linked_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
bArmature *arm;
EditBone *bone, *curBone, *next;
@@ -323,7 +323,9 @@ static EditBone *get_nearest_editbonepoint(ViewContext *vc, const int mval[2],
else
dep = 2;
}
- else dep = 2;
+ else {
+ dep = 2;
+ }
}
else {
/* bone found */
@@ -333,7 +335,9 @@ static EditBone *get_nearest_editbonepoint(ViewContext *vc, const int mval[2],
else
dep = 3;
}
- else dep = 3;
+ else {
+ dep = 3;
+ }
}
if (ebone == ebone_next_act) {
@@ -390,8 +394,10 @@ void ED_armature_deselect_all(Object *obedit, int toggle)
// }
}
}
- else sel = toggle;
-
+ else {
+ sel = toggle;
+ }
+
/* Set the flags */
for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
if (sel == 2) {
diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c
index 05f48ad73f4..4120be08b46 100644
--- a/source/blender/editors/armature/armature_utils.c
+++ b/source/blender/editors/armature/armature_utils.c
@@ -147,6 +147,15 @@ void ED_armature_edit_bone_remove(bArmature *arm, EditBone *exBone)
bone_free(arm, exBone);
}
+bool ED_armature_ebone_is_child_recursive(EditBone *ebone_parent, EditBone *ebone_child)
+{
+ for (ebone_child = ebone_child->parent; ebone_child; ebone_child = ebone_child->parent) {
+ if (ebone_child == ebone_parent)
+ return true;
+ }
+ return false;
+}
+
/* *************************************************************** */
/* Mirroring */
diff --git a/source/blender/editors/armature/editarmature_generate.c b/source/blender/editors/armature/editarmature_generate.c
index 89772d38e8f..bade93af8c1 100644
--- a/source/blender/editors/armature/editarmature_generate.c
+++ b/source/blender/editors/armature/editarmature_generate.c
@@ -263,7 +263,7 @@ EditBone *subdivideArcBy(ToolSettings *toolsettings, bArmature *arm, ListBase *U
parent = ED_armature_edit_bone_add(arm, "Bone");
copy_v3_v3(parent->head, iter->p);
- if (iter->size > 0) {
+ if (iter->size > FLT_EPSILON) {
parent->rad_head = iter->size * size_buffer;
}
@@ -278,7 +278,7 @@ EditBone *subdivideArcBy(ToolSettings *toolsettings, bArmature *arm, ListBase *U
child->parent = parent;
child->flag |= BONE_CONNECTED;
- if (iter->size > 0) {
+ if (iter->size > FLT_EPSILON) {
child->rad_head = iter->size * size_buffer;
parent->rad_tail = iter->size * size_buffer;
}
@@ -299,7 +299,7 @@ EditBone *subdivideArcBy(ToolSettings *toolsettings, bArmature *arm, ListBase *U
iter->tail(iter);
copy_v3_v3(parent->tail, iter->p);
- if (iter->size > 0) {
+ if (iter->size > FLT_EPSILON) {
parent->rad_tail = iter->size * size_buffer;
}
diff --git a/source/blender/editors/armature/editarmature_retarget.c b/source/blender/editors/armature/editarmature_retarget.c
index 62cce6b2c1e..536c5ff1f7c 100644
--- a/source/blender/editors/armature/editarmature_retarget.c
+++ b/source/blender/editors/armature/editarmature_retarget.c
@@ -409,11 +409,11 @@ static void renameTemplateBone(char *name, char *template_name, ListBase *editbo
for (i = 0, j = 0; i < (MAXBONENAME - 1) && j < (MAXBONENAME - 1) && template_name[i] != '\0'; i++) {
if (template_name[i] == '&') {
if (template_name[i + 1] == 'S' || template_name[i + 1] == 's') {
- j += sprintf(name + j, "%s", side_string);
+ j += BLI_strncpy_rlen(name + j, side_string, MAXBONENAME);
i++;
}
else if (template_name[i + 1] == 'N' || template_name[i + 1] == 'n') {
- j += sprintf(name + j, "%s", num_string);
+ j += BLI_strncpy_rlen(name + j, num_string, MAXBONENAME);
i++;
}
else {
@@ -896,7 +896,7 @@ static void RIG_reconnectControlBones(RigGraph *rg)
/* look on deform bones first */
BLI_ghashIterator_init(&ghi, rg->bones_map);
- for (; !BLI_ghashIterator_isDone(&ghi); BLI_ghashIterator_step(&ghi)) {
+ for (; BLI_ghashIterator_notDone(&ghi); BLI_ghashIterator_step(&ghi)) {
EditBone *bone = (EditBone *)BLI_ghashIterator_getValue(&ghi);
/* don't link with parent */
diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c
index ec96c574f75..a3515e0983d 100644
--- a/source/blender/editors/armature/editarmature_sketch.c
+++ b/source/blender/editors/armature/editarmature_sketch.c
@@ -28,9 +28,6 @@
#include "DNA_scene_types.h"
#include "DNA_armature_types.h"
-#include "RNA_define.h"
-#include "RNA_access.h"
-
#include "BLI_blenlib.h"
#include "BLI_math.h"
@@ -39,6 +36,9 @@
#include "BKE_context.h"
#include "BKE_sketch.h"
+#include "RNA_define.h"
+#include "RNA_access.h"
+
#include "ED_view3d.h"
#include "ED_screen.h"
@@ -170,20 +170,20 @@ const char *BIF_listTemplates(const bContext *UNUSED(C))
GHashIterator ghi;
const char *menu_header = IFACE_("Template %t|None %x0|");
char *p;
+ const size_t template_size = (BLI_ghash_size(TEMPLATES_HASH) * 32 + 30);
if (TEMPLATES_MENU != NULL) {
MEM_freeN(TEMPLATES_MENU);
}
- TEMPLATES_MENU = MEM_callocN(sizeof(char) * (BLI_ghash_size(TEMPLATES_HASH) * 32 + 30), "skeleton template menu");
+ TEMPLATES_MENU = MEM_callocN(sizeof(char) * template_size, "skeleton template menu");
p = TEMPLATES_MENU;
-
- p += sprintf(TEMPLATES_MENU, "%s", menu_header);
+ p += BLI_strncpy_rlen(p, menu_header, template_size);
BLI_ghashIterator_init(&ghi, TEMPLATES_HASH);
- while (!BLI_ghashIterator_isDone(&ghi)) {
+ while (BLI_ghashIterator_notDone(&ghi)) {
Object *ob = BLI_ghashIterator_getValue(&ghi);
int key = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&ghi));
@@ -203,7 +203,7 @@ int BIF_currentTemplate(const bContext *C)
GHashIterator ghi;
BLI_ghashIterator_init(&ghi, TEMPLATES_HASH);
- while (!BLI_ghashIterator_isDone(&ghi)) {
+ while (BLI_ghashIterator_notDone(&ghi)) {
Object *ob = BLI_ghashIterator_getValue(&ghi);
int key = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&ghi));
@@ -922,17 +922,18 @@ static void sk_projectDrawPoint(bContext *C, float vec[3], SK_Stroke *stk, SK_Dr
float fp[3] = {0, 0, 0};
float dvec[3];
float mval_f[2];
+ float zfac;
if (last != NULL) {
copy_v3_v3(fp, last->p);
}
- initgrabz(ar->regiondata, fp[0], fp[1], fp[2]);
+ zfac = ED_view3d_calc_zfac(ar->regiondata, fp, NULL);
/* method taken from editview.c - mouse_cursor() */
if (ED_view3d_project_short_global(ar, fp, cval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
VECSUB2D(mval_f, cval, dd->mval);
- ED_view3d_win_to_delta(ar, mval_f, dvec);
+ ED_view3d_win_to_delta(ar, mval_f, dvec, zfac);
sub_v3_v3v3(vec, fp, dvec);
}
else {
@@ -2231,7 +2232,7 @@ void BDR_drawSketch(const bContext *C)
}
}
-static int sketch_delete(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
+static int sketch_delete(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
{
SK_Sketch *sketch = contextSketch(C, 0);
if (sketch) {
@@ -2328,7 +2329,7 @@ SK_Sketch *viewcontextSketch(ViewContext *vc, int create)
return sketch;
}
-static int sketch_convert(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
+static int sketch_convert(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
{
SK_Sketch *sketch = contextSketch(C, 0);
if (sketch != NULL) {
@@ -2338,7 +2339,7 @@ static int sketch_convert(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(e
return OPERATOR_FINISHED;
}
-static int sketch_cancel(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
+static int sketch_cancel(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
{
SK_Sketch *sketch = contextSketch(C, 0);
if (sketch != NULL) {
@@ -2349,7 +2350,7 @@ static int sketch_cancel(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(ev
return OPERATOR_PASS_THROUGH;
}
-static int sketch_finish(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
+static int sketch_finish(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
{
SK_Sketch *sketch = contextSketch(C, 0);
if (sketch != NULL) {
@@ -2361,7 +2362,7 @@ static int sketch_finish(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(ev
return OPERATOR_PASS_THROUGH;
}
-static int sketch_select(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
+static int sketch_select(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
SK_Sketch *sketch = contextSketch(C, 0);
if (sketch) {
@@ -2381,7 +2382,7 @@ static int sketch_draw_stroke_cancel(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
-static int sketch_draw_stroke(bContext *C, wmOperator *op, wmEvent *event)
+static int sketch_draw_stroke(bContext *C, wmOperator *op, const wmEvent *event)
{
short snap = RNA_boolean_get(op->ptr, "snap");
SK_DrawData *dd;
@@ -2407,7 +2408,7 @@ static int sketch_draw_gesture_cancel(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
-static int sketch_draw_gesture(bContext *C, wmOperator *op, wmEvent *event)
+static int sketch_draw_gesture(bContext *C, wmOperator *op, const wmEvent *event)
{
short snap = RNA_boolean_get(op->ptr, "snap");
SK_DrawData *dd;
@@ -2425,7 +2426,7 @@ static int sketch_draw_gesture(bContext *C, wmOperator *op, wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
-static int sketch_draw_modal(bContext *C, wmOperator *op, wmEvent *event, short gesture, SK_Stroke *stk)
+static int sketch_draw_modal(bContext *C, wmOperator *op, const wmEvent *event, short gesture, SK_Stroke *stk)
{
short snap = RNA_boolean_get(op->ptr, "snap");
SK_DrawData *dd = op->customdata;
@@ -2483,19 +2484,19 @@ static int sketch_draw_modal(bContext *C, wmOperator *op, wmEvent *event, short
return retval;
}
-static int sketch_draw_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int sketch_draw_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */
return sketch_draw_modal(C, op, event, 0, sketch->active_stroke);
}
-static int sketch_draw_gesture_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int sketch_draw_gesture_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */
return sketch_draw_modal(C, op, event, 1, sketch->gesture);
}
-static int sketch_draw_preview(bContext *C, wmOperator *op, wmEvent *event)
+static int sketch_draw_preview(bContext *C, wmOperator *op, const wmEvent *event)
{
short snap = RNA_boolean_get(op->ptr, "snap");
SK_Sketch *sketch = contextSketch(C, 0);
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index 3d1d5d2f6ba..40b96132699 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -201,7 +201,7 @@ void ED_pose_recalculate_paths(Scene *scene, Object *ob)
/* show popup to determine settings */
-static int pose_calculate_paths_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int pose_calculate_paths_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
@@ -793,7 +793,7 @@ void ARMATURE_OT_layers_show_all(wmOperatorType *ot)
/* ------------------- */
/* Present a popup to get the layers that should be used */
-static int pose_armature_layers_invoke(bContext *C, wmOperator *op, wmEvent *evt)
+static int pose_armature_layers_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
bArmature *arm = (ob) ? ob->data : NULL;
@@ -810,7 +810,7 @@ static int pose_armature_layers_invoke(bContext *C, wmOperator *op, wmEvent *evt
RNA_boolean_set_array(op->ptr, "layers", layers);
/* part to sync with other similar operators... */
- return WM_operator_props_popup(C, op, evt);
+ return WM_operator_props_popup(C, op, event);
}
/* Set the visible layers for the active armature (edit and pose modes) */
@@ -879,7 +879,7 @@ void ARMATURE_OT_armature_layers(wmOperatorType *ot)
/* ------------------- */
/* Present a popup to get the layers that should be used */
-static int pose_bone_layers_invoke(bContext *C, wmOperator *op, wmEvent *evt)
+static int pose_bone_layers_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
int layers[32] = {0}; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
@@ -900,7 +900,7 @@ static int pose_bone_layers_invoke(bContext *C, wmOperator *op, wmEvent *evt)
RNA_boolean_set_array(op->ptr, "layers", layers);
/* part to sync with other similar operators... */
- return WM_operator_props_popup(C, op, evt);
+ return WM_operator_props_popup(C, op, event);
}
/* Set the visible layers for the active armature (edit and pose modes) */
@@ -954,7 +954,7 @@ void POSE_OT_bone_layers(wmOperatorType *ot)
/* ------------------- */
/* Present a popup to get the layers that should be used */
-static int armature_bone_layers_invoke(bContext *C, wmOperator *op, wmEvent *evt)
+static int armature_bone_layers_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
int layers[32] = {0}; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
@@ -975,7 +975,7 @@ static int armature_bone_layers_invoke(bContext *C, wmOperator *op, wmEvent *evt
RNA_boolean_set_array(op->ptr, "layers", layers);
/* part to sync with other similar operators... */
- return WM_operator_props_popup(C, op, evt);
+ return WM_operator_props_popup(C, op, event);
}
/* Set the visible layers for the active armature (edit and pose modes) */
diff --git a/source/blender/editors/armature/pose_group.c b/source/blender/editors/armature/pose_group.c
index 06a88f013d7..99f54de134a 100644
--- a/source/blender/editors/armature/pose_group.c
+++ b/source/blender/editors/armature/pose_group.c
@@ -126,7 +126,7 @@ void POSE_OT_group_remove(wmOperatorType *ot)
/* ------------ */
/* invoke callback which presents a list of bone-groups for the user to choose from */
-static int pose_groups_menu_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(evt))
+static int pose_groups_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Object *ob = ED_pose_object_from_context(C);
bPose *pose;
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index 457874c7ae6..09c0f7e9647 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -389,7 +389,7 @@ static void poselib_add_menu_invoke__replacemenu(bContext *C, uiLayout *layout,
}
}
-static int poselib_add_menu_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(evt))
+static int poselib_add_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Scene *scene = CTX_data_scene(C);
Object *ob = get_poselib_object(C);
@@ -613,7 +613,7 @@ void POSELIB_OT_pose_remove(wmOperatorType *ot)
ot->prop = prop;
}
-static int poselib_rename_invoke(bContext *C, wmOperator *op, wmEvent *evt)
+static int poselib_rename_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Object *ob = get_poselib_object(C);
bAction *act = (ob) ? ob->poselib : NULL;
@@ -638,7 +638,7 @@ static int poselib_rename_invoke(bContext *C, wmOperator *op, wmEvent *evt)
}
/* part to sync with other similar operators... */
- return WM_operator_props_popup(C, op, evt);
+ return WM_operator_props_popup(C, op, event);
}
static int poselib_rename_exec(bContext *C, wmOperator *op)
@@ -1185,7 +1185,7 @@ static void poselib_preview_handle_search(tPoseLib_PreviewData *pld, unsigned sh
}
/* handle events for poselib_preview_poses */
-static int poselib_preview_handle_event(bContext *UNUSED(C), wmOperator *op, wmEvent *event)
+static int poselib_preview_handle_event(bContext *UNUSED(C), wmOperator *op, const wmEvent *event)
{
tPoseLib_PreviewData *pld = op->customdata;
int ret = OPERATOR_RUNNING_MODAL;
@@ -1539,7 +1539,7 @@ static int poselib_preview_cancel(bContext *C, wmOperator *op)
}
/* main modal status check */
-static int poselib_preview_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int poselib_preview_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
tPoseLib_PreviewData *pld = op->customdata;
int ret;
@@ -1559,7 +1559,7 @@ static int poselib_preview_modal(bContext *C, wmOperator *op, wmEvent *event)
}
/* Modal Operator init */
-static int poselib_preview_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int poselib_preview_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
tPoseLib_PreviewData *pld;
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index 186c7a1fe89..4fa1389426d 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -208,7 +208,7 @@ static void selectconnected_posebonechildren(Object *ob, Bone *bone, int extend)
/* within active object context */
/* previously known as "selectconnected_posearmature" */
-static int pose_select_connected_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int pose_select_connected_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
bArmature *arm = (bArmature *)ob->data;
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index fee37a9c0fb..4d6f8f520f5 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -614,12 +614,12 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *p
}
/* common code for modal() */
-static int pose_slide_modal(bContext *C, wmOperator *op, wmEvent *evt)
+static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
tPoseSlideOp *pso = op->customdata;
wmWindow *win = CTX_wm_window(C);
- switch (evt->type) {
+ switch (event->type) {
case LEFTMOUSE: /* confirm */
case RETKEY:
{
@@ -660,7 +660,7 @@ static int pose_slide_modal(bContext *C, wmOperator *op, wmEvent *evt)
/* calculate percentage based on position of mouse (we only use x-axis for now.
* since this is more convenient for users to do), and store new percentage value
*/
- pso->percentage = (evt->x - pso->ar->winrct.xmin) / ((float)pso->ar->winx);
+ pso->percentage = (event->x - pso->ar->winrct.xmin) / ((float)pso->ar->winx);
RNA_float_set(op->ptr, "percentage", pso->percentage);
/* update percentage indicator in header */
@@ -717,7 +717,7 @@ static void pose_slide_opdef_properties(wmOperatorType *ot)
/* ------------------------------------ */
/* invoke() - for 'push' mode */
-static int pose_slide_push_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(evt))
+static int pose_slide_push_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
tPoseSlideOp *pso;
@@ -774,7 +774,7 @@ void POSE_OT_push(wmOperatorType *ot)
/* ........................ */
/* invoke() - for 'relax' mode */
-static int pose_slide_relax_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(evt))
+static int pose_slide_relax_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
tPoseSlideOp *pso;
@@ -831,7 +831,7 @@ void POSE_OT_relax(wmOperatorType *ot)
/* ........................ */
/* invoke() - for 'breakdown' mode */
-static int pose_slide_breakdown_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(evt))
+static int pose_slide_breakdown_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
tPoseSlideOp *pso;
diff --git a/source/blender/editors/armature/reeb.c b/source/blender/editors/armature/reeb.c
index 454b0f0bceb..d04938fd59b 100644
--- a/source/blender/editors/armature/reeb.c
+++ b/source/blender/editors/armature/reeb.c
@@ -1659,7 +1659,7 @@ int filterSmartReebGraph(ReebGraph *UNUSED(rg), float UNUSED(threshold))
float avg_vec[3] = {0, 0, 0};
for (BLI_ghashIterator_init(&ghi, arc->faces);
- !BLI_ghashIterator_isDone(&ghi);
+ BLI_ghashIterator_notDone(&ghi);
BLI_ghashIterator_step(&ghi))
{
EditFace *efa = BLI_ghashIterator_getValue(&ghi);
@@ -2045,7 +2045,7 @@ void mergeArcFaces(ReebGraph *UNUSED(rg), ReebArc *aDst, ReebArc *aSrc)
GHashIterator ghi;
for (BLI_ghashIterator_init(&ghi, aSrc->faces);
- !BLI_ghashIterator_isDone(&ghi);
+ BLI_ghashIterator_notDone(&ghi);
BLI_ghashIterator_step(&ghi))
{
EditFace *efa = BLI_ghashIterator_getValue(&ghi);
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index d01e5c5d9bf..e134507600e 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -626,7 +626,9 @@ static void switch_keys_direction(Curve *cu, Nurb *actnu)
bezt++;
}
}
- else fp += a * 12;
+ else {
+ fp += a * 12;
+ }
}
else {
BPoint *bp = nu->bp;
@@ -640,7 +642,9 @@ static void switch_keys_direction(Curve *cu, Nurb *actnu)
bp++;
}
}
- else fp += a * 4;
+ else {
+ fp += a * 4;
+ }
}
nu = nu->next;
@@ -672,7 +676,7 @@ static GHash *dupli_keyIndexHash(GHash *keyindex)
gh = BLI_ghash_ptr_new("dupli_keyIndex gh");
for (hashIter = BLI_ghashIterator_new(keyindex);
- !BLI_ghashIterator_isDone(hashIter);
+ BLI_ghashIterator_notDone(hashIter);
BLI_ghashIterator_step(hashIter))
{
void *cv = BLI_ghashIterator_getKey(hashIter);
@@ -1473,7 +1477,9 @@ static short isNurbselUV(Nurb *nu, int *u, int *v, int flag)
if (*u == -1) *u = b;
else return 0;
}
- else if (sel > 1) return 0; /* because sel == 1 is still ok */
+ else if (sel > 1) {
+ return 0; /* because sel == 1 is still ok */
+ }
}
for (a = 0; a < nu->pntsu; a++) {
@@ -1486,7 +1492,9 @@ static short isNurbselUV(Nurb *nu, int *u, int *v, int flag)
if (*v == -1) *v = a;
else return 0;
}
- else if (sel > 1) return 0;
+ else if (sel > 1) {
+ return 0;
+ }
}
if (*u == -1 && *v > -1) return 1;
@@ -1781,7 +1789,7 @@ static short extrudeflagNurb(EditNurb *editnurb, int flag)
else {
/* which row or column is selected */
- if (isNurbselUV(nu, &u, &v, flag) ) {
+ if (isNurbselUV(nu, &u, &v, flag)) {
/* deselect all */
bp = nu->bp;
@@ -1872,7 +1880,7 @@ static void adduplicateflagNurb(Object *obedit, short flag)
for (a = 0; a < nu->pntsu; a++) {
enda = -1;
starta = a;
- while ( (bezt->f1 & flag) || (bezt->f2 & flag) || (bezt->f3 & flag) ) {
+ while ((bezt->f1 & flag) || (bezt->f2 & flag) || (bezt->f3 & flag)) {
select_beztriple(bezt, DESELECT, flag, HIDDEN);
enda = a;
if (a >= nu->pntsu - 1) break;
@@ -2431,12 +2439,12 @@ static void select_adjacent_cp(ListBase *editnurb, short next, short cont, short
BezTriple *bezt;
BPoint *bp;
int a;
- short lastsel = 0;
+ short lastsel = false;
if (next == 0) return;
for (nu = editnurb->first; nu; nu = nu->next) {
- lastsel = 0;
+ lastsel = false;
if (nu->type == CU_BEZIER) {
a = nu->pntsu;
bezt = nu->bezt;
@@ -2447,12 +2455,12 @@ static void select_adjacent_cp(ListBase *editnurb, short next, short cont, short
bezt += next;
if (!(bezt->f2 & SELECT) || (selstatus == 0)) {
short sel = select_beztriple(bezt, selstatus, 1, VISIBLE);
- if ((sel == 1) && (cont == 0)) lastsel = 1;
+ if ((sel == 1) && (cont == 0)) lastsel = true;
}
}
else {
bezt += next;
- lastsel = 0;
+ lastsel = false;
}
/* move around in zigzag way so that we go through each */
bezt -= (next - next / abs(next));
@@ -2468,12 +2476,12 @@ static void select_adjacent_cp(ListBase *editnurb, short next, short cont, short
bp += next;
if (!(bp->f1 & SELECT) || (selstatus == 0)) {
short sel = select_bpoint(bp, selstatus, 1, VISIBLE);
- if ((sel == 1) && (cont == 0)) lastsel = 1;
+ if ((sel == 1) && (cont == 0)) lastsel = true;
}
}
else {
bp += next;
- lastsel = 0;
+ lastsel = false;
}
/* move around in zigzag way so that we go through each */
bp -= (next - next / abs(next));
@@ -2878,7 +2886,7 @@ static void subdividenurb(Object *obedit, int number_cuts)
keyIndex_updateBezt(editnurb, prevbezt, beztn, 1);
beztn++;
- if (BEZSELECTED_HIDDENHANDLES(cu, prevbezt) && BEZSELECTED_HIDDENHANDLES(cu, bezt) ) {
+ if (BEZSELECTED_HIDDENHANDLES(cu, prevbezt) && BEZSELECTED_HIDDENHANDLES(cu, bezt)) {
float prevvec[3][3];
memcpy(prevvec, prevbezt->vec, sizeof(float) * 9);
@@ -3062,7 +3070,7 @@ static void subdividenurb(Object *obedit, int number_cuts)
bp++;
}
}
- if (sel == (nu->pntsu * nu->pntsv) ) { /* subdivide entire nurb */
+ if (sel == (nu->pntsu * nu->pntsv)) { /* subdivide entire nurb */
/* Global subdivision is a special case of partial
* subdivision. Strange it is considered separately... */
@@ -3332,7 +3340,7 @@ static void findselectedNurbvert(ListBase *editnurb, Nurb **nu, BezTriple **bezt
bezt1 = nu1->bezt;
a = nu1->pntsu;
while (a--) {
- if ( (bezt1->f1 & SELECT) || (bezt1->f2 & SELECT) || (bezt1->f3 & SELECT) ) {
+ if ((bezt1->f1 & SELECT) || (bezt1->f2 & SELECT) || (bezt1->f3 & SELECT)) {
if (*nu != NULL && *nu != nu1) {
*nu = NULL;
*bp = NULL;
@@ -3803,7 +3811,7 @@ static void merge_2_nurb(wmOperator *op, ListBase *editnurb, Nurb *nu1, Nurb *nu
/* first nurbs: u = resolu-1 selected */
- if (is_u_selected(nu1, nu1->pntsu - 1) ) {
+ if (is_u_selected(nu1, nu1->pntsu - 1)) {
/* pass */
}
else {
@@ -3835,7 +3843,7 @@ static void merge_2_nurb(wmOperator *op, ListBase *editnurb, Nurb *nu1, Nurb *nu
}
/* 2nd nurbs: u = 0 selected */
- if (is_u_selected(nu2, 0) ) {
+ if (is_u_selected(nu2, 0)) {
/* pass */
}
else {
@@ -4041,9 +4049,11 @@ static int make_segment_exec(bContext *C, wmOperator *op)
if ((nu->flagu & CU_NURB_CYCLIC) == 0) { /* not cyclic */
if (nu->type == CU_BEZIER) {
if (nu1 == NULL) {
- if (BEZSELECTED_HIDDENHANDLES(cu, nu->bezt) ) nu1 = nu;
+ if (BEZSELECTED_HIDDENHANDLES(cu, nu->bezt)) {
+ nu1 = nu;
+ }
else {
- if (BEZSELECTED_HIDDENHANDLES(cu, &(nu->bezt[nu->pntsu - 1])) ) {
+ if (BEZSELECTED_HIDDENHANDLES(cu, &(nu->bezt[nu->pntsu - 1]))) {
nu1 = nu;
BKE_nurb_direction_switch(nu);
keyData_switchDirectionNurb(cu, nu);
@@ -4051,23 +4061,27 @@ static int make_segment_exec(bContext *C, wmOperator *op)
}
}
else if (nu2 == NULL) {
- if (BEZSELECTED_HIDDENHANDLES(cu, nu->bezt) ) {
+ if (BEZSELECTED_HIDDENHANDLES(cu, nu->bezt)) {
nu2 = nu;
BKE_nurb_direction_switch(nu);
keyData_switchDirectionNurb(cu, nu);
}
else {
- if (BEZSELECTED_HIDDENHANDLES(cu, &(nu->bezt[nu->pntsu - 1])) ) {
+ if (BEZSELECTED_HIDDENHANDLES(cu, &(nu->bezt[nu->pntsu - 1]))) {
nu2 = nu;
}
}
}
- else break;
+ else {
+ break;
+ }
}
else if (nu->pntsv == 1) {
bp = nu->bp;
if (nu1 == NULL) {
- if (bp->f1 & SELECT) nu1 = nu;
+ if (bp->f1 & SELECT) {
+ nu1 = nu;
+ }
else {
bp = bp + (nu->pntsu - 1);
if (bp->f1 & SELECT) {
@@ -4090,7 +4104,9 @@ static int make_segment_exec(bContext *C, wmOperator *op)
}
}
}
- else break;
+ else {
+ break;
+ }
}
}
}
@@ -4421,7 +4437,7 @@ static int spin_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int spin_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int spin_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
@@ -4495,7 +4511,9 @@ static int addvert_Nurb(bContext *C, short mode, float location[3])
newnu->resolu = cu->resolu;
newnu->flag |= CU_SMOOTH;
}
- else memcpy(newnu, nu, sizeof(Nurb));
+ else {
+ memcpy(newnu, nu, sizeof(Nurb));
+ }
BLI_addtail(&editnurb->nurbs, newnu);
set_actNurb(obedit, newnu);
@@ -4609,7 +4627,9 @@ static int addvert_Nurb(bContext *C, short mode, float location[3])
bezt = newbezt;
ok = 1;
}
- else bezt = NULL;
+ else {
+ bezt = NULL;
+ }
if (bezt) {
if (!newnu) nu->pntsu++;
@@ -4687,7 +4707,9 @@ static int addvert_Nurb(bContext *C, short mode, float location[3])
bp = newbp;
ok = 1;
}
- else bp = NULL;
+ else {
+ bp = NULL;
+ }
if (bp) {
if (mode == 'e') {
@@ -4705,7 +4727,9 @@ static int addvert_Nurb(bContext *C, short mode, float location[3])
nu->pntsu++;
BKE_nurb_knot_calc_u(nu);
}
- else BKE_nurb_knot_calc_u(newnu);
+ else {
+ BKE_nurb_knot_calc_u(newnu);
+ }
}
}
@@ -4732,7 +4756,7 @@ static int add_vertex_exec(bContext *C, wmOperator *op)
return addvert_Nurb(C, 0, location);
}
-static int add_vertex_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
RegionView3D *rv3d = CTX_wm_region_view3d(C);
@@ -4761,7 +4785,7 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, wmEvent *event)
copy_v3_v3(location, give_cursor(vc.scene, vc.v3d));
}
- view3d_get_view_aligned_coordinate(&vc, location, event->mval, TRUE);
+ view3d_get_view_aligned_coordinate(vc.ar, location, event->mval, true);
RNA_float_set_array(op->ptr, "location", location);
}
@@ -4864,7 +4888,7 @@ static int toggle_cyclic_exec(bContext *C, wmOperator *op)
a = nu->pntsu;
bezt = nu->bezt;
while (a--) {
- if (BEZSELECTED_HIDDENHANDLES(cu, bezt) ) {
+ if (BEZSELECTED_HIDDENHANDLES(cu, bezt)) {
nu->flagu ^= CU_NURB_CYCLIC;
break;
}
@@ -4915,7 +4939,7 @@ static int toggle_cyclic_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int toggle_cyclic_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int toggle_cyclic_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Object *obedit = CTX_data_edit_object(C);
ListBase *editnurb = object_editcurve_get(obedit);
@@ -4983,7 +5007,7 @@ static int select_linked_exec(bContext *C, wmOperator *UNUSED(op))
bezt = nu->bezt;
a = nu->pntsu;
while (a--) {
- if ( (bezt->f1 & SELECT) || (bezt->f2 & SELECT) || (bezt->f3 & SELECT) ) {
+ if ((bezt->f1 & SELECT) || (bezt->f2 & SELECT) || (bezt->f3 & SELECT)) {
a = nu->pntsu;
bezt = nu->bezt;
while (a--) {
@@ -5018,7 +5042,7 @@ static int select_linked_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-static int select_linked_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int select_linked_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
return select_linked_exec(C, op);
}
@@ -5044,7 +5068,7 @@ void CURVE_OT_select_linked(wmOperatorType *ot)
/***************** select linked pick operator ******************/
-static int select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Object *obedit = CTX_data_edit_object(C);
ViewContext vc;
@@ -5333,7 +5357,7 @@ static int select_less_exec(bContext *C, wmOperator *UNUSED(op))
BPoint *bp;
BezTriple *bezt;
int a;
- short sel = 0, lastsel = 0;
+ short sel = 0, lastsel = false;
short *selbpoints;
if (obedit->type == OB_SURF) {
@@ -5344,44 +5368,54 @@ static int select_less_exec(bContext *C, wmOperator *UNUSED(op))
while (a--) {
if ((bp->hide == 0) && (bp->f1 & SELECT)) {
sel = 0;
-
+
/* check if neighbors have been selected */
/* edges of surface are an exception */
- if ((a + 1) % nu->pntsu == 0) sel++;
+ if ((a + 1) % nu->pntsu == 0) {
+ sel++;
+ }
else {
bp--;
if ((selbpoints[a + 1] == 1) || ((bp->hide == 0) && (bp->f1 & SELECT))) sel++;
bp++;
}
- if ((a + 1) % nu->pntsu == 1) sel++;
+ if ((a + 1) % nu->pntsu == 1) {
+ sel++;
+ }
else {
bp++;
if ((bp->hide == 0) && (bp->f1 & SELECT)) sel++;
bp--;
}
- if (a + 1 > nu->pntsu * nu->pntsv - nu->pntsu) sel++;
+ if (a + 1 > nu->pntsu * nu->pntsv - nu->pntsu) {
+ sel++;
+ }
else {
bp -= nu->pntsu;
if ((selbpoints[a + nu->pntsu] == 1) || ((bp->hide == 0) && (bp->f1 & SELECT))) sel++;
bp += nu->pntsu;
}
-
- if (a < nu->pntsu) sel++;
+
+ if (a < nu->pntsu) {
+ sel++;
+ }
else {
bp += nu->pntsu;
if ((bp->hide == 0) && (bp->f1 & SELECT)) sel++;
bp -= nu->pntsu;
}
-
+
if (sel != 4) {
select_bpoint(bp, DESELECT, 1, VISIBLE);
selbpoints[a] = 1;
}
}
- else lastsel = 0;
-
+ else {
+ lastsel = false;
+ }
+
bp++;
}
@@ -5390,26 +5424,29 @@ static int select_less_exec(bContext *C, wmOperator *UNUSED(op))
}
else {
for (nu = editnurb->first; nu; nu = nu->next) {
- lastsel = 0;
+ lastsel = false;
/* check what type of curve/nurb it is */
if (nu->type == CU_BEZIER) {
a = nu->pntsu;
bezt = nu->bezt;
while (a--) {
if ((bezt->hide == 0) && (bezt->f2 & SELECT)) {
- if (lastsel == 1) sel = 1;
- else sel = 0;
-
+ sel = (lastsel == 1);
+
/* check if neighbors have been selected */
/* first and last are exceptions */
- if (a == nu->pntsu - 1) sel++;
+ if (a == nu->pntsu - 1) {
+ sel++;
+ }
else {
bezt--;
if ((bezt->hide == 0) && (bezt->f2 & SELECT)) sel++;
bezt++;
}
- if (a == 0) sel++;
+ if (a == 0) {
+ sel++;
+ }
else {
bezt++;
if ((bezt->hide == 0) && (bezt->f2 & SELECT)) sel++;
@@ -5418,12 +5455,16 @@ static int select_less_exec(bContext *C, wmOperator *UNUSED(op))
if (sel != 2) {
select_beztriple(bezt, DESELECT, 1, VISIBLE);
- lastsel = 1;
+ lastsel = true;
+ }
+ else {
+ lastsel = false;
}
- else lastsel = 0;
}
- else lastsel = 0;
-
+ else {
+ lastsel = false;
+ }
+
bezt++;
}
}
@@ -5436,28 +5477,36 @@ static int select_less_exec(bContext *C, wmOperator *UNUSED(op))
else sel = 0;
/* first and last are exceptions */
- if (a == nu->pntsu * nu->pntsv - 1) sel++;
+ if (a == nu->pntsu * nu->pntsv - 1) {
+ sel++;
+ }
else {
bp--;
if ((bp->hide == 0) && (bp->f1 & SELECT)) sel++;
bp++;
}
- if (a == 0) sel++;
+ if (a == 0) {
+ sel++;
+ }
else {
bp++;
if ((bp->hide == 0) && (bp->f1 & SELECT)) sel++;
bp--;
}
-
+
if (sel != 2) {
select_bpoint(bp, DESELECT, 1, VISIBLE);
- lastsel = 1;
+ lastsel = true;
+ }
+ else {
+ lastsel = false;
}
- else lastsel = 0;
}
- else lastsel = 0;
-
+ else {
+ lastsel = false;
+ }
+
bp++;
}
}
@@ -5820,7 +5869,7 @@ static int delete_exec(bContext *C, wmOperator *op)
int delta = 0;
bezt = nu->bezt;
for (a = 0; a < nu->pntsu; a++) {
- if (BEZSELECTED_HIDDENHANDLES(cu, bezt) ) {
+ if (BEZSELECTED_HIDDENHANDLES(cu, bezt)) {
memmove(bezt, bezt + 1, (nu->pntsu - a - 1) * sizeof(BezTriple));
keyIndex_delBezt(editnurb, bezt + delta);
keyIndex_updateBezt(editnurb, bezt + 1, bezt, nu->pntsu - a - 1);
@@ -5829,7 +5878,9 @@ static int delete_exec(bContext *C, wmOperator *op)
type = 1;
delta++;
}
- else bezt++;
+ else {
+ bezt++;
+ }
}
if (type) {
bezt1 = (BezTriple *)MEM_mallocN((nu->pntsu) * sizeof(BezTriple), "delNurb");
@@ -5889,16 +5940,16 @@ static int delete_exec(bContext *C, wmOperator *op)
if (nu->type == CU_BEZIER) {
bezt = nu->bezt;
for (a = 0; a < nu->pntsu - 1; a++) {
- if (BEZSELECTED_HIDDENHANDLES(cu, bezt) ) {
+ if (BEZSELECTED_HIDDENHANDLES(cu, bezt)) {
bezt1 = bezt;
bezt2 = bezt + 1;
if ((bezt2->f1 & SELECT) || (bezt2->f2 & SELECT) || (bezt2->f3 & SELECT)) {
/* pass */
}
else { /* maybe do not make cyclic */
- if (a == 0 && (nu->flagu & CU_NURB_CYCLIC) ) {
+ if (a == 0 && (nu->flagu & CU_NURB_CYCLIC)) {
bezt2 = bezt + (nu->pntsu - 1);
- if ( (bezt2->f1 & SELECT) || (bezt2->f2 & SELECT) || (bezt2->f3 & SELECT) ) {
+ if ((bezt2->f1 & SELECT) || (bezt2->f2 & SELECT) || (bezt2->f3 & SELECT)) {
nu->flagu &= ~CU_NURB_CYCLIC;
BKE_nurb_handles_calc(nu);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
@@ -5925,7 +5976,7 @@ static int delete_exec(bContext *C, wmOperator *op)
/* pass */
}
else { /* maybe do not make cyclic */
- if (a == 0 && (nu->flagu & CU_NURB_CYCLIC) ) {
+ if (a == 0 && (nu->flagu & CU_NURB_CYCLIC)) {
bp2 = bp + (nu->pntsu - 1);
if (bp2->f1 & SELECT) {
nu->flagu &= ~CU_NURB_CYCLIC;
@@ -6046,7 +6097,7 @@ static int delete_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int delete_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int delete_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Object *obedit = CTX_data_edit_object(C);
uiPopupMenu *pup;
@@ -6187,10 +6238,12 @@ int join_curve_exec(bContext *C, wmOperator *UNUSED(op))
if (ob->totcol) { /* TODO, merge material lists */
CLAMP(newnu->mat_nr, 0, ob->totcol - 1);
}
- else newnu->mat_nr = 0;
+ else {
+ newnu->mat_nr = 0;
+ }
BLI_addtail(&tempbase, newnu);
- if ( (bezt = newnu->bezt) ) {
+ if ((bezt = newnu->bezt)) {
a = newnu->pntsu;
while (a--) {
mul_m4_v3(cmat, bezt->vec[0]);
@@ -6200,7 +6253,7 @@ int join_curve_exec(bContext *C, wmOperator *UNUSED(op))
}
BKE_nurb_handles_calc(newnu);
}
- if ( (bp = newnu->bp) ) {
+ if ((bp = newnu->bp)) {
a = newnu->pntsu * nu->pntsv;
while (a--) {
mul_m4_v3(cmat, bp->vec);
@@ -6653,14 +6706,18 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf)
if (type & CU_PRIM_PATH)
cu->flag |= CU_PATH | CU_3D;
}
- else DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ else {
+ DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ }
}
else { /* adding surface */
if (obedit == NULL || obedit->type != OB_SURF) {
obedit = ED_object_add_type(C, OB_SURF, loc, rot, TRUE, layer);
newob = 1;
}
- else DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ else {
+ DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ }
}
/* rename here, the undo stack checks name for valid undo pushes */
diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c
index af6b90a9958..63444c5c17e 100644
--- a/source/blender/editors/curve/editfont.c
+++ b/source/blender/editors/curve/editfont.c
@@ -405,7 +405,7 @@ static int paste_file_exec(bContext *C, wmOperator *op)
return retval;
}
-static int paste_file_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int paste_file_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (RNA_struct_property_is_set(op->ptr, "filepath"))
return paste_file_exec(C, op);
@@ -1221,16 +1221,16 @@ static int insert_text_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int insert_text_invoke(bContext *C, wmOperator *op, wmEvent *evt)
+static int insert_text_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
Curve *cu = obedit->data;
EditFont *ef = cu->editfont;
static int accentcode = 0;
- uintptr_t ascii = evt->ascii;
- int alt = evt->alt, shift = evt->shift, ctrl = evt->ctrl;
- int event = evt->type, val = evt->val;
+ uintptr_t ascii = event->ascii;
+ int alt = event->alt, shift = event->shift, ctrl = event->ctrl;
+ int event_type = event->type, event_val = event->val;
wchar_t inserted_text[2] = {0};
if (RNA_struct_property_is_set(op->ptr, "text"))
@@ -1243,26 +1243,26 @@ static int insert_text_invoke(bContext *C, wmOperator *op, wmEvent *evt)
}
/* tab should exit editmode, but we allow it to be typed using modifier keys */
- if (event == TABKEY) {
+ if (event_type == TABKEY) {
if ((alt || ctrl || shift) == 0)
return OPERATOR_PASS_THROUGH;
else
ascii = 9;
}
- if (event == BACKSPACEKEY) {
+ if (event_type == BACKSPACEKEY) {
if (alt && cu->len != 0 && cu->pos > 0)
accentcode = 1;
return OPERATOR_PASS_THROUGH;
}
- if (val && (ascii || evt->utf8_buf[0])) {
+ if (event_val && (ascii || event->utf8_buf[0])) {
/* handle case like TAB (== 9) */
if ( (ascii > 31 && ascii < 254 && ascii != 127) ||
(ascii == 13) ||
(ascii == 10) ||
(ascii == 8) ||
- (evt->utf8_buf[0]))
+ (event->utf8_buf[0]))
{
if (accentcode) {
@@ -1272,8 +1272,8 @@ static int insert_text_invoke(bContext *C, wmOperator *op, wmEvent *evt)
}
accentcode = 0;
}
- else if (evt->utf8_buf[0]) {
- BLI_strncpy_wchar_from_utf8(inserted_text, evt->utf8_buf, 1);
+ else if (event->utf8_buf[0]) {
+ BLI_strncpy_wchar_from_utf8(inserted_text, event->utf8_buf, 1);
ascii = inserted_text[0];
insert_into_textbuf(obedit, ascii);
accentcode = 0;
@@ -1307,7 +1307,7 @@ static int insert_text_invoke(bContext *C, wmOperator *op, wmEvent *evt)
}
/* reset property? */
- if (val == 0)
+ if (event_val == 0)
accentcode = 0;
return OPERATOR_FINISHED;
@@ -1643,7 +1643,7 @@ static int font_open_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int open_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
VFont *vfont = NULL;
char *path;
diff --git a/source/blender/editors/datafiles/SConscript b/source/blender/editors/datafiles/SConscript
index c17ab386fe6..d4e6ed4aff8 100644
--- a/source/blender/editors/datafiles/SConscript
+++ b/source/blender/editors/datafiles/SConscript
@@ -35,75 +35,75 @@ incs = ""
# generated data files
import os
sources.extend((
- os.path.join(env['DATA_SOURCES'], "bfont.pfb.c"),
- os.path.join(env['DATA_SOURCES'], "bfont.ttf.c"),
- os.path.join(env['DATA_SOURCES'], "bmonofont.ttf.c"),
+ os.path.join(env['DATA_SOURCES'], "bfont.pfb.c"),
+ os.path.join(env['DATA_SOURCES'], "bfont.ttf.c"),
+ os.path.join(env['DATA_SOURCES'], "bmonofont.ttf.c"),
- os.path.join(env['DATA_SOURCES'], "splash.png.c"),
- os.path.join(env['DATA_SOURCES'], "blender_icons16.png.c"),
- os.path.join(env['DATA_SOURCES'], "blender_icons32.png.c"),
- os.path.join(env['DATA_SOURCES'], "prvicons.png.c"),
+ os.path.join(env['DATA_SOURCES'], "splash.png.c"),
+ os.path.join(env['DATA_SOURCES'], "blender_icons16.png.c"),
+ os.path.join(env['DATA_SOURCES'], "blender_icons32.png.c"),
+ os.path.join(env['DATA_SOURCES'], "prvicons.png.c"),
- os.path.join(env['DATA_SOURCES'], "startup.blend.c"),
- os.path.join(env['DATA_SOURCES'], "preview.blend.c"),
- os.path.join(env['DATA_SOURCES'], "preview_cycles.blend.c"),
-
- os.path.join(env['DATA_SOURCES'], "add.png.c"),
- os.path.join(env['DATA_SOURCES'], "blob.png.c"),
- os.path.join(env['DATA_SOURCES'], "blur.png.c"),
- os.path.join(env['DATA_SOURCES'], "clay.png.c"),
- os.path.join(env['DATA_SOURCES'], "claystrips.png.c"),
- os.path.join(env['DATA_SOURCES'], "clone.png.c"),
- os.path.join(env['DATA_SOURCES'], "crease.png.c"),
- os.path.join(env['DATA_SOURCES'], "darken.png.c"),
- os.path.join(env['DATA_SOURCES'], "draw.png.c"),
- os.path.join(env['DATA_SOURCES'], "fill.png.c"),
- os.path.join(env['DATA_SOURCES'], "flatten.png.c"),
- os.path.join(env['DATA_SOURCES'], "grab.png.c"),
- os.path.join(env['DATA_SOURCES'], "inflate.png.c"),
- os.path.join(env['DATA_SOURCES'], "layer.png.c"),
- os.path.join(env['DATA_SOURCES'], "lighten.png.c"),
- os.path.join(env['DATA_SOURCES'], "mask.png.c"),
- os.path.join(env['DATA_SOURCES'], "mix.png.c"),
- os.path.join(env['DATA_SOURCES'], "multiply.png.c"),
- os.path.join(env['DATA_SOURCES'], "nudge.png.c"),
- os.path.join(env['DATA_SOURCES'], "pinch.png.c"),
- os.path.join(env['DATA_SOURCES'], "scrape.png.c"),
- os.path.join(env['DATA_SOURCES'], "smear.png.c"),
- os.path.join(env['DATA_SOURCES'], "smooth.png.c"),
- os.path.join(env['DATA_SOURCES'], "snake_hook.png.c"),
- os.path.join(env['DATA_SOURCES'], "soften.png.c"),
- os.path.join(env['DATA_SOURCES'], "subtract.png.c"),
- os.path.join(env['DATA_SOURCES'], "texdraw.png.c"),
- os.path.join(env['DATA_SOURCES'], "thumb.png.c"),
- os.path.join(env['DATA_SOURCES'], "twist.png.c"),
- os.path.join(env['DATA_SOURCES'], "vertexdraw.png.c"),
-
- os.path.join(env['DATA_SOURCES'], "mc01.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc02.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc03.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc04.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc05.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc06.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc07.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc08.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc09.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc10.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc11.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc12.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc13.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc14.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc15.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc16.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc17.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc18.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc19.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc20.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc21.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc22.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc23.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc24.jpg.c"),
+ os.path.join(env['DATA_SOURCES'], "startup.blend.c"),
+ os.path.join(env['DATA_SOURCES'], "preview.blend.c"),
+ os.path.join(env['DATA_SOURCES'], "preview_cycles.blend.c"),
- ))
+ os.path.join(env['DATA_SOURCES'], "add.png.c"),
+ os.path.join(env['DATA_SOURCES'], "blob.png.c"),
+ os.path.join(env['DATA_SOURCES'], "blur.png.c"),
+ os.path.join(env['DATA_SOURCES'], "clay.png.c"),
+ os.path.join(env['DATA_SOURCES'], "claystrips.png.c"),
+ os.path.join(env['DATA_SOURCES'], "clone.png.c"),
+ os.path.join(env['DATA_SOURCES'], "crease.png.c"),
+ os.path.join(env['DATA_SOURCES'], "darken.png.c"),
+ os.path.join(env['DATA_SOURCES'], "draw.png.c"),
+ os.path.join(env['DATA_SOURCES'], "fill.png.c"),
+ os.path.join(env['DATA_SOURCES'], "flatten.png.c"),
+ os.path.join(env['DATA_SOURCES'], "grab.png.c"),
+ os.path.join(env['DATA_SOURCES'], "inflate.png.c"),
+ os.path.join(env['DATA_SOURCES'], "layer.png.c"),
+ os.path.join(env['DATA_SOURCES'], "lighten.png.c"),
+ os.path.join(env['DATA_SOURCES'], "mask.png.c"),
+ os.path.join(env['DATA_SOURCES'], "mix.png.c"),
+ os.path.join(env['DATA_SOURCES'], "multiply.png.c"),
+ os.path.join(env['DATA_SOURCES'], "nudge.png.c"),
+ os.path.join(env['DATA_SOURCES'], "pinch.png.c"),
+ os.path.join(env['DATA_SOURCES'], "scrape.png.c"),
+ os.path.join(env['DATA_SOURCES'], "smear.png.c"),
+ os.path.join(env['DATA_SOURCES'], "smooth.png.c"),
+ os.path.join(env['DATA_SOURCES'], "snake_hook.png.c"),
+ os.path.join(env['DATA_SOURCES'], "soften.png.c"),
+ os.path.join(env['DATA_SOURCES'], "subtract.png.c"),
+ os.path.join(env['DATA_SOURCES'], "texdraw.png.c"),
+ os.path.join(env['DATA_SOURCES'], "thumb.png.c"),
+ os.path.join(env['DATA_SOURCES'], "twist.png.c"),
+ os.path.join(env['DATA_SOURCES'], "vertexdraw.png.c"),
+
+ os.path.join(env['DATA_SOURCES'], "mc01.jpg.c"),
+ os.path.join(env['DATA_SOURCES'], "mc02.jpg.c"),
+ os.path.join(env['DATA_SOURCES'], "mc03.jpg.c"),
+ os.path.join(env['DATA_SOURCES'], "mc04.jpg.c"),
+ os.path.join(env['DATA_SOURCES'], "mc05.jpg.c"),
+ os.path.join(env['DATA_SOURCES'], "mc06.jpg.c"),
+ os.path.join(env['DATA_SOURCES'], "mc07.jpg.c"),
+ os.path.join(env['DATA_SOURCES'], "mc08.jpg.c"),
+ os.path.join(env['DATA_SOURCES'], "mc09.jpg.c"),
+ os.path.join(env['DATA_SOURCES'], "mc10.jpg.c"),
+ os.path.join(env['DATA_SOURCES'], "mc11.jpg.c"),
+ os.path.join(env['DATA_SOURCES'], "mc12.jpg.c"),
+ os.path.join(env['DATA_SOURCES'], "mc13.jpg.c"),
+ os.path.join(env['DATA_SOURCES'], "mc14.jpg.c"),
+ os.path.join(env['DATA_SOURCES'], "mc15.jpg.c"),
+ os.path.join(env['DATA_SOURCES'], "mc16.jpg.c"),
+ os.path.join(env['DATA_SOURCES'], "mc17.jpg.c"),
+ os.path.join(env['DATA_SOURCES'], "mc18.jpg.c"),
+ os.path.join(env['DATA_SOURCES'], "mc19.jpg.c"),
+ os.path.join(env['DATA_SOURCES'], "mc20.jpg.c"),
+ os.path.join(env['DATA_SOURCES'], "mc21.jpg.c"),
+ os.path.join(env['DATA_SOURCES'], "mc22.jpg.c"),
+ os.path.join(env['DATA_SOURCES'], "mc23.jpg.c"),
+ os.path.join(env['DATA_SOURCES'], "mc24.jpg.c"),
+
+ ))
env.BlenderLib ( 'bf_editor_datafiles', sources, Split(incs), [], libtype=['core', 'player'], priority=[235, 30] )
diff --git a/source/blender/editors/gpencil/gpencil_buttons.c b/source/blender/editors/gpencil/gpencil_buttons.c
index 0aa109a0aef..19c1bc34f5c 100644
--- a/source/blender/editors/gpencil/gpencil_buttons.c
+++ b/source/blender/editors/gpencil/gpencil_buttons.c
@@ -86,6 +86,29 @@ static void gp_ui_dellayer_cb(bContext *C, void *gpd, void *gpl)
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
+/* move layer up */
+static void gp_ui_layer_up_cb(bContext *C, void *gpd_v, void *gpl_v)
+{
+ bGPdata *gpd = gpd_v;
+ bGPDlayer *gpl = gpl_v;
+
+ BLI_remlink(&gpd->layers, gpl);
+ BLI_insertlinkbefore(&gpd->layers, gpl->prev, gpl);
+
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+}
+
+/* move layer down */
+static void gp_ui_layer_down_cb(bContext *C, void *gpd_v, void *gpl_v)
+{
+ bGPdata *gpd = gpd_v;
+ bGPDlayer *gpl = gpl_v;
+
+ BLI_remlink(&gpd->layers, gpl);
+ BLI_insertlinkafter(&gpd->layers, gpl->next, gpl);
+
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+}
/* ------- Drawing Code ------- */
@@ -174,6 +197,18 @@ static void gp_drawui_layer(uiLayout *layout, bGPdata *gpd, bGPDlayer *gpl, cons
/* name */
uiItemR(sub, &ptr, "info", 0, "", ICON_NONE);
+ /* move up/down */
+ if (gpl->prev) {
+ but = uiDefIconBut(block, BUT, 0, ICON_TRIA_UP, 0, 0, UI_UNIT_X, UI_UNIT_Y,
+ NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Move layer up"));
+ uiButSetFunc(but, gp_ui_layer_up_cb, gpd, gpl);
+ }
+ if (gpl->next) {
+ but = uiDefIconBut(block, BUT, 0, ICON_TRIA_DOWN, 0, 0, UI_UNIT_X, UI_UNIT_Y,
+ NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Move layer down"));
+ uiButSetFunc(but, gp_ui_layer_down_cb, gpd, gpl);
+ }
+
/* delete 'button' */
uiBlockSetEmboss(block, UI_EMBOSSN);
/* right-align ............................... */
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 46815450bf2..bc68ad8869a 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -277,6 +277,7 @@ static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3]
int mval_prj[2];
float rvec[3], dvec[3];
float mval_f[2];
+ float zfac;
/* Current method just converts each point in screen-coordinates to
* 3D-coordinates using the 3D-cursor as reference. In general, this
@@ -288,12 +289,13 @@ static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3]
*/
gp_get_3d_reference(p, rvec);
+ zfac = ED_view3d_calc_zfac(p->ar->regiondata, rvec, NULL);
/* method taken from editview.c - mouse_cursor() */
/* TODO, use ED_view3d_project_float_global */
if (ED_view3d_project_int_global(p->ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
VECSUB2D(mval_f, mval_prj, mval);
- ED_view3d_win_to_delta(p->ar, mval_f, dvec);
+ ED_view3d_win_to_delta(p->ar, mval_f, dvec, zfac);
sub_v3_v3v3(out, rvec, dvec);
}
else {
@@ -1237,13 +1239,6 @@ static void gp_paint_initstroke(tGPsdata *p, short paintmode)
switch (p->sa->spacetype) {
case SPACE_VIEW3D:
{
- RegionView3D *rv3d = p->ar->regiondata;
- float rvec[3];
-
- /* get reference point for 3d space placement */
- gp_get_3d_reference(p, rvec);
- initgrabz(rv3d, rvec[0], rvec[1], rvec[2]);
-
p->gpd->sbuffer_sflag |= GP_STROKE_3DSPACE;
}
break;
@@ -1551,7 +1546,7 @@ static void gpencil_draw_apply(wmOperator *op, tGPsdata *p)
}
/* handle draw event */
-static void gpencil_draw_apply_event(wmOperator *op, wmEvent *event)
+static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event)
{
tGPsdata *p = op->customdata;
PointerRNA itemptr;
@@ -1689,7 +1684,7 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op)
/* ------------------------------- */
/* start of interactive drawing part of operator */
-static int gpencil_draw_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
tGPsdata *p = NULL;
wmWindow *win = CTX_wm_window(C);
@@ -1800,7 +1795,7 @@ static void gpencil_stroke_end(wmOperator *op)
}
/* events handling during interactive drawing part of operator */
-static int gpencil_draw_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
tGPsdata *p = op->customdata;
int estate = OPERATOR_PASS_THROUGH; /* default exit state - pass through to support MMB view nav, etc. */
diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h
index 31f89063f05..39d1e283f54 100644
--- a/source/blender/editors/include/BIF_glutil.h
+++ b/source/blender/editors/include/BIF_glutil.h
@@ -129,7 +129,7 @@ void glaRasterPosSafe2f(float x, float y, float known_good_x, float known_good_y
void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int format, int type, void *rect);
/**
- * Functions like a limited glDrawPixels, but actually draws the
+ * glaDrawPixelsTex - Functions like a limited glDrawPixels, but actually draws the
* image using textures, which can be tremendously faster on low-end
* cards, and also avoids problems with the raster position being
* clipped when offscreen. The routine respects the glPixelZoom values,
@@ -141,9 +141,17 @@ void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int fo
* 1-to-1 mapping to screen space.
*/
-void glaDrawPixelsTex(float x, float y, int img_w, int img_h, int format, void *rect);
+void glaDrawPixelsTex(float x, float y, int img_w, int img_h, int format, int zoomfilter, void *rect);
-void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, void *rect, float scaleX, float scaleY);
+/**
+ * glaDrawPixelsAuto - Switches between texture or pixel drawing using UserDef.
+ * only RGBA
+ * needs glaDefine2DArea to be set.
+ */
+void glaDrawPixelsAuto(float x, float y, int img_w, int img_h, int format, int zoomfilter, void *rect);
+
+
+void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, int zoomfilter, void *rect, float scaleX, float scaleY);
/* 2D Drawing Assistance */
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index 414d2075bf6..625ef27f4f7 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -298,11 +298,14 @@ typedef enum eAnimFilter_Flags {
#define SEL_MASKLAY(masklay) (masklay->flag & SELECT)
-
/* NLA only */
#define SEL_NLT(nlt) (nlt->flag & NLATRACK_SELECTED)
#define EDITABLE_NLT(nlt) ((nlt->flag & NLATRACK_PROTECTED) == 0)
+
+/* AnimData - NLA mostly... */
+#define SEL_ANIMDATA(adt) (adt->flag & ADT_UI_SELECTED)
+
/* -------------- Channel Defines -------------- */
/* channel heights */
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 30ac360cab6..310b60f13e8 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -61,7 +61,7 @@ typedef struct EditBone {
* normal bones when leaving editmode. */
void *temp; /* Used to store temporary data */
- char name[64]; /* MAX_NAME */
+ char name[64]; /* MAXBONENAME */
float roll; /* Roll along axis. We'll ultimately use the axis/angle method
* for determining the transformation matrix of the bone. The axis
* is tail-head while roll provides the angle. Refer to Graphics
@@ -135,6 +135,7 @@ void ED_armature_validate_active(struct bArmature *arm);
void add_primitive_bone(struct Scene *scene, struct View3D *v3d, struct RegionView3D *rv3d);
struct EditBone *ED_armature_edit_bone_add(struct bArmature *arm, const char *name);
void ED_armature_edit_bone_remove(struct bArmature *arm, EditBone *exBone);
+bool ED_armature_ebone_is_child_recursive(EditBone *ebone_parent, EditBone *ebone_child);
void transform_armature_mirror_update(struct Object *obedit);
void ED_armature_origin_set(struct Scene *scene, struct Object *ob, float cursor[3], int centermode, int around);
diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h
index d66cc49a5d0..66c1798f507 100644
--- a/source/blender/editors/include/ED_curve.h
+++ b/source/blender/editors/include/ED_curve.h
@@ -63,8 +63,6 @@ void load_editNurb(struct Object *obedit);
void make_editNurb(struct Object *obedit);
void free_editNurb(struct Object *obedit);
-void BKE_curve_editNurb_free(struct Curve *cu);
-
int mouse_nurb(struct bContext *C, const int mval[2], int extend, int deselect, int toggle);
struct Nurb *add_nurbs_primitive(struct bContext *C, struct Object *obedit, float mat[4][4], int type, int newob);
diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h
index d45504b3325..b7d9f811349 100644
--- a/source/blender/editors/include/ED_fileselect.h
+++ b/source/blender/editors/include/ED_fileselect.h
@@ -31,10 +31,11 @@
#ifndef __ED_FILESELECT_H__
#define __ED_FILESELECT_H__
-struct SpaceFile;
struct ARegion;
struct FileSelectParams;
+struct SpaceFile;
struct bContext;
+struct wmWindowManager;
#define FILE_LAYOUT_HOR 1
#define FILE_LAYOUT_VER 2
@@ -99,9 +100,9 @@ void ED_fileselect_layout_tilepos(FileLayout *layout, int tile, int *x, int *y);
void ED_operatormacros_file(void);
-void ED_fileselect_clear(struct bContext *C, struct SpaceFile *sfile);
+void ED_fileselect_clear(struct wmWindowManager *wm, struct SpaceFile *sfile);
-void ED_fileselect_exit(struct bContext *C, struct SpaceFile *sfile);
+void ED_fileselect_exit(struct wmWindowManager *wm, struct SpaceFile *sfile);
int ED_file_extension_icon(const char *relname);
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index d3de2593b9d..e704b8f0bf3 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -172,17 +172,10 @@ void em_setup_viewcontext(struct bContext *C, struct ViewContext *vc); /* renam
extern unsigned int bm_vertoffs, bm_solidoffs, bm_wireoffs;
-
/* mesh_ops.c */
void ED_operatortypes_mesh(void);
void ED_operatormacros_mesh(void);
void ED_keymap_mesh(struct wmKeyConfig *keyconf);
-void ED_keymap_mesh(struct wmKeyConfig *keyconf);
-
-
-/* spacetypes.c */
-void ED_spacetypes_init(void);
-
/* editmesh_tools.c (could be moved) */
void EMBM_project_snap_verts(struct bContext *C, struct ARegion *ar, struct BMEditMesh *em);
@@ -193,13 +186,14 @@ void paintface_flush_flags(struct Object *ob);
int paintface_mouse_select(struct bContext *C, struct Object *ob, const int mval[2], int extend, int deselect, int toggle);
int do_paintface_box_select(struct ViewContext *vc, struct rcti *rect, int select, int extend);
void paintface_deselect_all_visible(struct Object *ob, int action, short flush_flags);
-void paintface_select_linked(struct bContext *C, struct Object *ob, int mval[2], int mode);
+void paintface_select_linked(struct bContext *C, struct Object *ob, const int mval[2], int mode);
int paintface_minmax(struct Object *ob, float r_min[3], float r_max[3]);
void paintface_hide(struct Object *ob, const int unselected);
void paintface_reveal(struct Object *ob);
void paintvert_deselect_all_visible(struct Object *ob, int action, short flush_flags);
+void paintvert_select_ungrouped(struct Object *ob, short extend, short flush_flags);
void paintvert_flush_flags(struct Object *ob);
/* mirrtopo */
diff --git a/source/blender/editors/include/ED_numinput.h b/source/blender/editors/include/ED_numinput.h
index 126ea13f0b2..e7d80d96f89 100644
--- a/source/blender/editors/include/ED_numinput.h
+++ b/source/blender/editors/include/ED_numinput.h
@@ -61,7 +61,7 @@ void initNumInput(NumInput *n);
void outputNumInput(NumInput *n, char *str);
short hasNumInput(NumInput *n);
void applyNumInput(NumInput *n, float *vec);
-char handleNumInput(NumInput *n, struct wmEvent *event);
+char handleNumInput(NumInput *n, const struct wmEvent *event);
#define NUM_MODAL_INCREMENT_UP 18
#define NUM_MODAL_INCREMENT_DOWN 19
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index 72208a8e93d..d073eaa5607 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -71,7 +71,6 @@ void ED_region_visible_rect(struct ARegion *ar, struct rcti *rect);
/* spaces */
-void ED_spacetypes_init(void);
void ED_spacetypes_keymap(struct wmKeyConfig *keyconf);
int ED_area_header_switchbutton(const struct bContext *C, struct uiBlock *block, int yco);
int ED_area_header_standardbuttons(const struct bContext *C, struct uiBlock *block, int yco);
diff --git a/source/blender/editors/include/ED_sequencer.h b/source/blender/editors/include/ED_sequencer.h
index 23d173aebdc..21477a72014 100644
--- a/source/blender/editors/include/ED_sequencer.h
+++ b/source/blender/editors/include/ED_sequencer.h
@@ -31,7 +31,7 @@ struct Scene;
struct Sequence;
struct SpaceSeq;
-void ED_sequencer_select_sequence_single(struct Scene *scene, struct Sequence *seq, int deselect_all);
+void ED_sequencer_select_sequence_single(struct Scene *scene, struct Sequence *seq, bool deselect_all);
void ED_sequencer_deselect_all(struct Scene *scene);
int ED_space_sequencer_maskedit_mask_poll(struct bContext *C);
diff --git a/source/blender/editors/include/ED_space_api.h b/source/blender/editors/include/ED_space_api.h
index c8521cb194a..a40cf90f7ad 100644
--- a/source/blender/editors/include/ED_space_api.h
+++ b/source/blender/editors/include/ED_space_api.h
@@ -34,6 +34,8 @@
struct ARegionType;
struct bContext;
+void ED_spacetypes_init(void);
+
/* the pluginnable API for export to editors */
/* calls for registering default spaces */
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index a41aaca15bd..6101d03b946 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -151,7 +151,7 @@ void Transform_Properties(struct wmOperatorType *ot, int flags);
/* view3d manipulators */
-int BIF_do_manipulator(struct bContext *C, struct wmEvent *event, struct wmOperator *op);
+int BIF_do_manipulator(struct bContext *C, const struct wmEvent *event, struct wmOperator *op);
void BIF_draw_manipulator(const struct bContext *C);
/* Snapping */
@@ -177,12 +177,12 @@ typedef enum SnapMode {
#define SNAP_MIN_DISTANCE 30
-int peelObjectsTransForm(struct TransInfo *t, struct ListBase *depth_peels, const float mval[2], SnapMode mode);
-int peelObjectsContext(struct bContext *C, struct ListBase *depth_peels, const float mval[2], SnapMode mode);
-int snapObjectsTransform(struct TransInfo *t, const float mval[2], int *r_dist, float r_loc[3], float r_no[3], SnapMode mode);
-int snapObjectsContext(struct bContext *C, const float mval[2], int *r_dist, float r_loc[3], float r_no[3], SnapMode mode);
-int snapNodesTransform(struct TransInfo *t, const int mval[2], int *r_dist, float r_loc[2], char *r_node_border, SnapMode mode);
-int snapNodesContext(struct bContext *C, const int mval[2], int *r_dist, float r_loc[2], char *r_node_border, SnapMode mode);
+bool peelObjectsTransForm(struct TransInfo *t, struct ListBase *depth_peels, const float mval[2], SnapMode mode);
+bool peelObjectsContext(struct bContext *C, struct ListBase *depth_peels, const float mval[2], SnapMode mode);
+bool snapObjectsTransform(struct TransInfo *t, const float mval[2], int *r_dist, float r_loc[3], float r_no[3], SnapMode mode);
+bool snapObjectsContext(struct bContext *C, const float mval[2], int *r_dist, float r_loc[3], float r_no[3], SnapMode mode);
+bool snapNodesTransform(struct TransInfo *t, const int mval[2], int *r_dist, float r_loc[2], char *r_node_border, SnapMode mode);
+bool snapNodesContext(struct bContext *C, const int mval[2], int *r_dist, float r_loc[2], char *r_node_border, SnapMode mode);
#endif
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index d89d66dd62c..470bbe616cf 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -39,7 +39,6 @@ struct BMVert;
struct BPoint;
struct Base;
struct BezTriple;
-struct BezTriple;
struct BoundBox;
struct EditBone;
struct ImBuf;
@@ -47,7 +46,6 @@ struct MVert;
struct Main;
struct MetaElem;
struct Nurb;
-struct Nurb;
struct Object;
struct RegionView3D;
struct Scene;
@@ -174,52 +172,58 @@ void pose_foreachScreenBone(
/* view3d_project.c */
-void ED_view3d_project_float_v2_m4(const struct ARegion *a, const float co[3], float r_co[2], float mat[4][4]);
-void ED_view3d_project_float_v3_m4(struct ARegion *a, const float co[3], float r_co[3], float mat[4][4]);
+void ED_view3d_project_float_v2_m4(const struct ARegion *ar, const float co[3], float r_co[2], float mat[4][4]);
+void ED_view3d_project_float_v3_m4(const struct ARegion *ar, const float co[3], float r_co[3], float mat[4][4]);
-eV3DProjStatus ED_view3d_project_base(struct ARegion *ar, struct Base *base);
+eV3DProjStatus ED_view3d_project_base(const struct ARegion *ar, struct Base *base);
/* *** short *** */
-eV3DProjStatus ED_view3d_project_short_ex(struct ARegion *ar, float perspmat[4][4], const int is_local,
+eV3DProjStatus ED_view3d_project_short_ex(const struct ARegion *ar, float perspmat[4][4], const bool is_local,
const float co[3], short r_co[2], const eV3DProjTest flag);
-eV3DProjStatus ED_view3d_project_short_global(struct ARegion *ar, const float co[3], short r_co[2], const eV3DProjTest flag);
-eV3DProjStatus ED_view3d_project_short_object(struct ARegion *ar, const float co[3], short r_co[2], const eV3DProjTest flag);
+eV3DProjStatus ED_view3d_project_short_global(const struct ARegion *ar, const float co[3], short r_co[2], const eV3DProjTest flag);
+eV3DProjStatus ED_view3d_project_short_object(const struct ARegion *ar, const float co[3], short r_co[2], const eV3DProjTest flag);
/* *** int *** */
-eV3DProjStatus ED_view3d_project_int_ex(struct ARegion *ar, float perspmat[4][4], const int is_local,
+eV3DProjStatus ED_view3d_project_int_ex(const struct ARegion *ar, float perspmat[4][4], const bool is_local,
const float co[3], int r_co[2], const eV3DProjTest flag);
-eV3DProjStatus ED_view3d_project_int_global(struct ARegion *ar, const float co[3], int r_co[2], const eV3DProjTest flag);
-eV3DProjStatus ED_view3d_project_int_object(struct ARegion *ar, const float co[3], int r_co[2], const eV3DProjTest flag);
+eV3DProjStatus ED_view3d_project_int_global(const struct ARegion *ar, const float co[3], int r_co[2], const eV3DProjTest flag);
+eV3DProjStatus ED_view3d_project_int_object(const struct ARegion *ar, const float co[3], int r_co[2], const eV3DProjTest flag);
/* *** float *** */
-eV3DProjStatus ED_view3d_project_float_ex(struct ARegion *ar, float perspmat[4][4], const int is_local,
- const float co[3], float r_co[2], const eV3DProjTest flag);
-eV3DProjStatus ED_view3d_project_float_global(struct ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag);
-eV3DProjStatus ED_view3d_project_float_object(struct ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag);
-
-int initgrabz(struct RegionView3D *rv3d, float x, float y, float z);
-void ED_view3d_win_to_ray(struct ARegion *ar, struct View3D *v3d, const float mval[2], float ray_start[3], float ray_normal[3]);
-void ED_view3d_global_to_vector(struct RegionView3D *rv3d, const float coord[3], float vec[3]);
-void ED_view3d_win_to_3d(struct ARegion *ar, const float depth_pt[3], const float mval[2], float out[3]);
-void ED_view3d_win_to_delta(struct ARegion *ar, const float mval[2], float out[3]);
-void ED_view3d_win_to_vector(struct ARegion *ar, const float mval[2], float out[3]);
-void ED_view3d_win_to_segment(struct ARegion *ar, struct View3D *v3d, const float mval[2], float ray_start[3], float ray_end[3]);
-int ED_view3d_win_to_segment_clip(struct ARegion *ar, struct View3D *v3d, const float mval[2], float ray_start[3], float ray_end[3]);
-void ED_view3d_ob_project_mat_get(struct RegionView3D *v3d, struct Object *ob, float pmat[4][4]);
+eV3DProjStatus ED_view3d_project_float_ex(const struct ARegion *ar, float perspmat[4][4], const bool is_local,
+ const float co[3], float r_co[2], const eV3DProjTest flag);
+eV3DProjStatus ED_view3d_project_float_global(const struct ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag);
+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);
+void ED_view3d_win_to_ray(const struct ARegion *ar, struct View3D *v3d, const float mval[2], float ray_start[3], float ray_normal[3]);
+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_delta(const struct ARegion *ar, const float mval[2], float out[3], const float zfac);
+void ED_view3d_win_to_vector(const struct ARegion *ar, const float mval[2], float out[3]);
+void ED_view3d_win_to_segment(const struct ARegion *ar, struct View3D *v3d, const float mval[2], float ray_start[3], float ray_end[3]);
+int ED_view3d_win_to_segment_clip(const struct ARegion *ar, struct View3D *v3d, const float mval[2], float ray_start[3], float ray_end[3]);
+void ED_view3d_ob_project_mat_get(const struct RegionView3D *v3d, struct Object *ob, float pmat[4][4]);
void ED_view3d_unproject(struct bglMats *mats, float out[3], const float x, const float y, const float z);
/* end */
-int ED_view3d_clip_range_get(struct View3D *v3d, struct RegionView3D *rv3d, float *clipsta, float *clipend);
-int ED_view3d_viewplane_get(struct View3D *v3d, struct RegionView3D *rv3d, int winxi, int winyi, struct rctf *viewplane, float *clipsta, float *clipend);
-void ED_view3d_calc_camera_border(struct Scene *scene, struct ARegion *ar, struct View3D *v3d, struct RegionView3D *rv3d, struct rctf *viewborder_r, short no_shift);
-void ED_view3d_calc_camera_border_size(struct Scene *scene, struct ARegion *ar, struct View3D *v3d, struct RegionView3D *rv3d, float size_r[2]);
+bool ED_view3d_clip_range_get(struct View3D *v3d, struct RegionView3D *rv3d,
+ float *r_clipsta, float *r_clipend, const bool use_ortho_factor);
+bool ED_view3d_viewplane_get(struct View3D *v3d, struct RegionView3D *rv3d, int winxi, int winyi,
+ struct rctf *r_viewplane, float *r_clipsta, float *r_clipend);
+void ED_view3d_calc_camera_border(struct Scene *scene, struct ARegion *ar,
+ struct View3D *v3d, struct RegionView3D *rv3d,
+ struct rctf *viewborder_r, const bool no_shift);
+void ED_view3d_calc_camera_border_size(struct Scene *scene, struct ARegion *ar,
+ struct View3D *v3d, struct RegionView3D *rv3d,
+ float r_size[2]);
void ED_view3d_clipping_calc(struct BoundBox *bb, float planes[4][4], struct bglMats *mats, const struct rcti *rect);
void ED_view3d_clipping_local(struct RegionView3D *rv3d, float mat[4][4]);
-int ED_view3d_clipping_test(struct RegionView3D *rv3d, const float vec[3], const int is_local);
+int ED_view3d_clipping_test(struct RegionView3D *rv3d, const float co[3], const bool is_local);
void ED_view3d_clipping_set(struct RegionView3D *rv3d);
void ED_view3d_clipping_enable(void);
void ED_view3d_clipping_disable(void);
@@ -255,7 +259,8 @@ short view3d_opengl_select(struct ViewContext *vc, unsigned int *buffer, unsigne
void view3d_set_viewcontext(struct bContext *C, struct ViewContext *vc);
void view3d_operator_needs_opengl(const struct bContext *C);
void view3d_region_operator_needs_opengl(struct wmWindow *win, struct ARegion *ar);
-int view3d_get_view_aligned_coordinate(struct ViewContext *vc, float fp[3], const int mval[2], const short do_fallback);
+bool view3d_get_view_aligned_coordinate(struct ARegion *ar, float fp[3], const int mval[2], const bool do_fallback);
+void view3d_opengl_read_pixels(struct ARegion *ar, int x, int y, int w, int h, int format, int type, void *data);
void view3d_get_transformation(const struct ARegion *ar, struct RegionView3D *rv3d, struct Object *ob, struct bglMats *mats);
/* XXX should move to BLI_math */
@@ -285,7 +290,7 @@ void ED_view3d_offscreen_sky_color_get(struct Scene *scene, float sky_color[3]);
struct Base *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2]);
void ED_view3d_quadview_update(struct ScrArea *sa, struct ARegion *ar, short do_clip);
void ED_view3d_update_viewmat(struct Scene *scene, struct View3D *v3d, struct ARegion *ar, float viewmat[4][4], float winmat[4][4]);
-int ED_view3d_lock(struct RegionView3D *rv3d);
+bool ED_view3d_lock(struct RegionView3D *rv3d);
uint64_t ED_view3d_datamask(struct Scene *scene, struct View3D *v3d);
uint64_t ED_view3d_screen_datamask(struct bScreen *screen);
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index 450d97eb20e..2ac66fb1919 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -87,6 +87,7 @@ enum {
TH_TRANSFORM,
TH_VERTEX,
TH_VERTEX_SELECT,
+ TH_VERTEX_UNREFERENCED,
TH_VERTEX_SIZE,
TH_OUTLINE_WIDTH,
TH_EDGE,
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 2c17a629ed4..4f0d788d733 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -231,7 +231,9 @@ static void ui_text_bounds_block(uiBlock *block, float offset)
nextcol = 1;
col++;
}
- else nextcol = 0;
+ else {
+ nextcol = 0;
+ }
bt->rect.xmin = x1addval;
bt->rect.xmax = bt->rect.xmin + i + block->bounds;
@@ -1461,6 +1463,8 @@ double ui_get_but_val(uiBut *but)
if (but->rnaprop) {
prop = but->rnaprop;
+ BLI_assert(but->rnaindex != -1);
+
switch (RNA_property_type(prop)) {
case PROP_BOOLEAN:
if (RNA_property_array_check(prop))
@@ -1642,6 +1646,9 @@ static double ui_get_but_scale_unit(uiBut *but, double value)
if (unit_type == PROP_UNIT_LENGTH) {
return value * (double)unit->scale_length;
}
+ else if (unit_type == PROP_UNIT_CAMERA) {
+ return value * (double)unit->scale_length;
+ }
else if (unit_type == PROP_UNIT_AREA) {
return value * pow(unit->scale_length, 2);
}
@@ -1674,18 +1681,28 @@ void ui_convert_to_unit_alt_name(uiBut *but, char *str, size_t maxlen)
}
}
-static void ui_get_but_string_unit(uiBut *but, char *str, int len_max, double value, int pad)
+/**
+ * \param float_precision Override the button precision.
+ */
+static void ui_get_but_string_unit(uiBut *but, char *str, int len_max, double value, int pad, int float_precision)
{
UnitSettings *unit = but->block->unit;
int do_split = unit->flag & USER_UNIT_OPT_SPLIT;
int unit_type = uiButGetUnitType(but);
- int precision = but->a2;
+ int precision;
if (unit->scale_length < 0.0001f) unit->scale_length = 1.0f; // XXX do_versions
- /* Sanity checks */
- if (precision > PRECISION_FLOAT_MAX) precision = PRECISION_FLOAT_MAX;
- else if (precision == 0) precision = 2;
+ /* Use precision override? */
+ if (float_precision == -1) {
+ /* Sanity checks */
+ precision = (int)but->a2;
+ if (precision > PRECISION_FLOAT_MAX) precision = PRECISION_FLOAT_MAX;
+ else if (precision == 0) precision = 2;
+ }
+ else {
+ precision = float_precision;
+ }
bUnit_AsString(str, len_max, ui_get_but_scale_unit(but, value), precision,
unit->system, RNA_SUBTYPE_UNIT_VALUE(unit_type), do_split, pad);
@@ -1706,8 +1723,10 @@ static float ui_get_but_step_unit(uiBut *but, float step_default)
}
}
-
-void ui_get_but_string(uiBut *but, char *str, size_t maxlen)
+/**
+ * \param float_precision For number buttons the precission to use or -1 to fallback to the button default.
+ */
+void ui_get_but_string_ex(uiBut *but, char *str, const size_t maxlen, const int float_precision)
{
if (but->rnaprop && ELEM4(but->type, TEX, IDPOIN, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
PropertyType type;
@@ -1779,10 +1798,10 @@ void ui_get_but_string(uiBut *but, char *str, size_t maxlen)
if (ui_is_but_float(but)) {
if (ui_is_but_unit(but)) {
- ui_get_but_string_unit(but, str, maxlen, value, 0);
+ ui_get_but_string_unit(but, str, maxlen, value, 0, float_precision);
}
else {
- const int prec = ui_but_float_precision(but, value);
+ const int prec = (float_precision == -1) ? ui_but_float_precision(but, value) : float_precision;
BLI_snprintf(str, maxlen, "%.*f", prec, value);
}
}
@@ -1790,6 +1809,10 @@ void ui_get_but_string(uiBut *but, char *str, size_t maxlen)
BLI_snprintf(str, maxlen, "%d", (int)value);
}
}
+void ui_get_but_string(uiBut *but, char *str, const size_t maxlen)
+{
+ ui_get_but_string_ex(but, str, maxlen, -1);
+}
#ifdef WITH_PYTHON
@@ -1984,7 +2007,8 @@ static double soft_range_round_down(double value, double max)
return newmax;
}
-void ui_set_but_soft_range(uiBut *but, double value)
+/* note: this could be split up into functions which handle arrays and not */
+static void ui_set_but_soft_range(uiBut *but)
{
/* ideally we would not limit this but practically, its more then
* enough worst case is very long vectors wont use a smart soft-range
@@ -1993,14 +2017,14 @@ void ui_set_but_soft_range(uiBut *but, double value)
if (but->rnaprop) {
const PropertyType type = RNA_property_type(but->rnaprop);
double softmin, softmax /*, step, precision*/;
- double value_min = value;
- double value_max = value;
+ double value_min;
+ double value_max;
/* clamp button range to something reasonable in case
* we get -inf/inf from RNA properties */
if (type == PROP_INT) {
+ const bool is_array = RNA_property_array_check(but->rnaprop);
int imin, imax, istep;
- const int array_len = RNA_property_array_length(&but->rnapoin, but->rnaprop);
RNA_property_int_ui_range(&but->rnapoin, but->rnaprop, &imin, &imax, &istep);
softmin = (imin == INT_MIN) ? -1e4 : imin;
@@ -2008,16 +2032,19 @@ void ui_set_but_soft_range(uiBut *but, double value)
/*step = istep;*/ /*UNUSED*/
/*precision = 1;*/ /*UNUSED*/
- if (array_len >= 2) {
+ if (is_array) {
int value_range[2];
RNA_property_int_get_array_range(&but->rnapoin, but->rnaprop, value_range);
value_min = (double)value_range[0];
value_max = (double)value_range[1];
}
+ else {
+ value_min = value_max = (double)RNA_property_int_get(&but->rnapoin, but->rnaprop);
+ }
}
else if (type == PROP_FLOAT) {
+ const bool is_array = RNA_property_array_check(but->rnaprop);
float fmin, fmax, fstep, fprecision;
- const int array_len = RNA_property_array_length(&but->rnapoin, but->rnaprop);
RNA_property_float_ui_range(&but->rnapoin, but->rnaprop, &fmin, &fmax, &fstep, &fprecision);
softmin = (fmin == -FLT_MAX) ? (float)-1e4 : fmin;
@@ -2025,15 +2052,19 @@ void ui_set_but_soft_range(uiBut *but, double value)
/*step = fstep;*/ /*UNUSED*/
/*precision = fprecision;*/ /*UNUSED*/
- if (array_len >= 2) {
+ if (is_array) {
float value_range[2];
RNA_property_float_get_array_range(&but->rnapoin, but->rnaprop, value_range);
value_min = (double)value_range[0];
value_max = (double)value_range[1];
}
+ else {
+ value_min = value_max = (double)RNA_property_float_get(&but->rnapoin, but->rnaprop);
+ }
}
- else
+ else {
return;
+ }
/* if the value goes out of the soft/max range, adapt the range */
if (value_min + 1e-10 < softmin) {
@@ -2260,8 +2291,7 @@ void ui_check_but(uiBut *but)
/* only update soft range while not editing */
if (but->rnaprop && !(but->editval || but->editstr || but->editvec)) {
- UI_GET_BUT_VALUE_INIT(but, value);
- ui_set_but_soft_range(but, value);
+ ui_set_but_soft_range(but);
}
/* test for min and max, icon sliders, etc */
@@ -2345,7 +2375,7 @@ void ui_check_but(uiBut *but)
/* support length type buttons */
else if (ui_is_but_unit(but)) {
char new_str[sizeof(but->drawstr)];
- ui_get_but_string_unit(but, new_str, sizeof(new_str), value, TRUE);
+ ui_get_but_string_unit(but, new_str, sizeof(new_str), value, TRUE, -1);
BLI_snprintf(but->drawstr, sizeof(but->drawstr), "%s%s", but->str, new_str);
}
else {
@@ -2530,7 +2560,9 @@ static void ui_block_do_align_but(uiBut *first, short nr)
else
flag = UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_LEFT;
}
- else flag = UI_BUT_ALIGN_TOP;
+ else {
+ flag = UI_BUT_ALIGN_TOP;
+ }
}
}
else if (buts_are_horiz(but, next)) {
@@ -2550,7 +2582,9 @@ static void ui_block_do_align_but(uiBut *first, short nr)
if (bt == NULL || bt->alignnr != nr) flag = UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_RIGHT;
}
}
- else flag |= UI_BUT_ALIGN_LEFT;
+ else {
+ flag |= UI_BUT_ALIGN_LEFT;
+ }
}
else {
if (cols == 0) {
@@ -2712,8 +2746,8 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str,
but->retval = retval;
slen = strlen(str);
- if (slen >= UI_MAX_NAME_STR - 1) {
- but->str = MEM_mallocN(slen + 2, "ui_def_but str"); /* why +2 ? */
+ if (slen >= UI_MAX_NAME_STR) {
+ but->str = MEM_mallocN(slen + 1, "ui_def_but str");
}
else {
but->str = but->strdata;
@@ -3016,7 +3050,7 @@ static uiBut *ui_def_but_operator_ptr(uiBlock *block, int type, wmOperatorType *
}
#if 0 /* UNUSED */
-static uiBut *UNUSED_FUNCTION(ui_def_but_operator) (uiBlock * block, int type, const char *opname, int opcontext, const char *str, int x, int y, short width, short height, const char *tip)
+static uiBut *UNUSED_FUNCTION(ui_def_but_operator) (uiBlock *block, int type, const char *opname, int opcontext, const char *str, int x, int y, short width, short height, const char *tip)
{
wmOperatorType *ot = WM_operatortype_find(opname, 0);
if (str == NULL && ot == NULL) str = opname;
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index e19e89af5da..5486e12c6bf 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -97,7 +97,9 @@ void uiDrawBox(int mode, float minx, float miny, float maxx, float maxy, float r
}
glVertex2f(maxx, miny + rad);
}
- else glVertex2f(maxx, miny);
+ else {
+ glVertex2f(maxx, miny);
+ }
/* corner right-top */
if (roundboxtype & UI_CNR_TOP_RIGHT) {
@@ -107,7 +109,9 @@ void uiDrawBox(int mode, float minx, float miny, float maxx, float maxy, float r
}
glVertex2f(maxx - rad, maxy);
}
- else glVertex2f(maxx, maxy);
+ else {
+ glVertex2f(maxx, maxy);
+ }
/* corner left-top */
if (roundboxtype & UI_CNR_TOP_LEFT) {
@@ -117,7 +121,9 @@ void uiDrawBox(int mode, float minx, float miny, float maxx, float maxy, float r
}
glVertex2f(minx, maxy - rad);
}
- else glVertex2f(minx, maxy);
+ else {
+ glVertex2f(minx, maxy);
+ }
/* corner left-bottom */
if (roundboxtype & UI_CNR_BOTTOM_LEFT) {
@@ -127,7 +133,9 @@ void uiDrawBox(int mode, float minx, float miny, float maxx, float maxy, float r
}
glVertex2f(minx + rad, miny);
}
- else glVertex2f(minx, miny);
+ else {
+ glVertex2f(minx, miny);
+ }
glEnd();
}
@@ -381,16 +389,7 @@ void uiRoundRect(float minx, float miny, float maxx, float maxy, float rad)
/* (old, used in outliner) plain antialiased filled box */
void uiRoundBox(float minx, float miny, float maxx, float maxy, float rad)
{
- float color[4];
-
- if (roundboxtype & UI_RB_ALPHA) {
- glGetFloatv(GL_CURRENT_COLOR, color);
- color[3] = 0.5;
- glColor4fv(color);
- glEnable(GL_BLEND);
- }
-
- ui_draw_anti_roundbox(GL_POLYGON, minx, miny, maxx, maxy, rad);
+ ui_draw_anti_roundbox(GL_POLYGON, minx, miny, maxx, maxy, rad, roundboxtype & UI_RB_ALPHA);
}
@@ -454,8 +453,7 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(ar), uiBut *but, uiWidgetColors *UNUSED(w
float facy = (float)h / (float)ibuf->y;
glPixelZoom(facx, facy);
}
- glaDrawPixelsSafe((float)rect->xmin, (float)rect->ymin, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
- //glaDrawPixelsTex((float)rect->xmin, (float)rect->ymin, ibuf->x, ibuf->y, GL_UNSIGNED_BYTE, ibuf->rect);
+ glaDrawPixelsAuto((float)rect->xmin, (float)rect->ymin, ibuf->x, ibuf->y, GL_UNSIGNED_BYTE, GL_NEAREST, ibuf->rect);
glPixelZoom(1.0f, 1.0f);
@@ -1301,8 +1299,10 @@ void ui_draw_but_NORMAL(uiBut *but, uiWidgetColors *wcol, rcti *rect)
glEndList();
}
- else glCallList(displist);
-
+ else {
+ glCallList(displist);
+ }
+
/* restore */
glDisable(GL_LIGHTING);
glDisable(GL_CULL_FACE);
@@ -1602,7 +1602,7 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wc
tmpibuf = BKE_tracking_sample_pattern(scopes->frame_width, scopes->frame_height,
scopes->track_search, scopes->track,
- &scopes->undist_marker, scopes->use_track_mask,
+ &scopes->undist_marker, TRUE, scopes->use_track_mask,
width, height, scopes->track_pos);
if (tmpibuf) {
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index e0d6c293be5..12a6343c7e7 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -235,14 +235,13 @@ void ui_pan_to_scroll(const wmEvent *event, int *type, int *val)
BLI_assert(*type == MOUSEPAN);
/* sign differs, reset */
- if ((dy > 0 && lastdy < 0) || (dy < 0 && lastdy > 0))
+ if ((dy > 0 && lastdy < 0) || (dy < 0 && lastdy > 0)) {
lastdy = dy;
+ }
else {
lastdy += dy;
if (ABS(lastdy) > (int)UI_UNIT_Y) {
- int dy = event->prevy - event->y;
-
if (U.uiflag2 & USER_TRACKPAD_NATURAL)
dy = -dy;
@@ -804,8 +803,6 @@ static void ui_drag_toggle_set(bContext *C, uiDragToggleHandle *drag_info, const
* button we mouse over is X or Y aligned, then lock the mouse to that axis after.
*/
if (drag_info->xy_lock[0] == false && drag_info->xy_lock[1] == false) {
- ARegion *ar = CTX_wm_region(C);
-
/* first store the buttons original coords */
uiBut *but = ui_but_find_mouse_over(ar, xy_input[0], xy_input[1]);
if (but) {
@@ -1402,7 +1399,11 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
/* pass */
}
else if (mode == 'c') {
- ui_get_but_string(but, buf, sizeof(buf));
+ /* Get many decimal places, then strip trailing zeros.
+ * note: too high values start to give strange results (6 or so is ok) */
+ ui_get_but_string_ex(but, buf, sizeof(buf), 6);
+ BLI_str_rstrip_float_zero(buf, '\0');
+
WM_clipboard_text_set(buf, 0);
}
else {
@@ -1984,6 +1985,10 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
data->str = MEM_callocN(sizeof(char) * data->maxlen + 1, "textedit str");
ui_get_but_string(but, data->str, data->maxlen);
+ if (ui_is_but_float(but) && !ui_is_but_unit(but)) {
+ BLI_str_rstrip_float_zero(data->str, '\0');
+ }
+
if (ELEM3(but->type, NUM, NUMABS, NUMSLI)) {
ui_convert_to_unit_alt_name(but, data->str, data->maxlen);
}
@@ -2327,7 +2332,7 @@ static void ui_numedit_begin(uiBut *but, uiHandleButtonData *data)
data->coba = (ColorBand *)but->poin;
but->editcoba = data->coba;
}
- else if (ELEM3(but->type, BUT_NORMAL, HSVCUBE, HSVCIRCLE)) {
+ else if (ELEM4(but->type, BUT_NORMAL, HSVCUBE, HSVCIRCLE, COLOR)) {
ui_get_but_vectorf(but, data->origvec);
copy_v3_v3(data->vec, data->origvec);
but->editvec = data->vec;
@@ -3149,9 +3154,6 @@ static bool ui_numedit_but_SLI(uiBut *but, uiHandleButtonData *data,
BLI_rctf_clamp_pt_v(&but->rect, data->ungrab_mval);
}
#endif
- if (is_horizontal == false) {
- mx_fl = my_fl;
- }
/* done correcting mouse */
@@ -5013,7 +5015,7 @@ static int ui_but_menu(bContext *C, uiBut *but)
uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT);
if (but->rnapoin.data && but->rnaprop) {
- short is_anim = RNA_property_animateable(&but->rnapoin, but->rnaprop);
+ bool is_anim = RNA_property_animateable(&but->rnapoin, but->rnaprop);
/* second slower test, saved people finding keyframe items in menus when its not possible */
if (is_anim)
@@ -6294,7 +6296,7 @@ static void ui_handle_button_activate(bContext *C, ARegion *ar, uiBut *but, uiBu
static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
{
uiHandleButtonData *data = but->active;
- const uiButtonActivateType state_orig = data->state;
+ const uiHandleButtonState state_orig = data->state;
uiBlock *block;
ARegion *ar;
int retval;
@@ -6466,9 +6468,9 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
* This is needed to make sure if a button was active,
* it stays active while the mouse is over it.
* This avoids adding mousemoves, see: [#33466] */
- if (ELEM(state_orig, BUTTON_ACTIVATE, BUTTON_ACTIVATE_OVER)) {
+ if (ELEM(state_orig, BUTTON_STATE_INIT, BUTTON_STATE_HIGHLIGHT)) {
if (ui_but_find_mouse_over(ar, event->x, event->y) == but) {
- button_activate_init(C, ar, but, state_orig);
+ button_activate_init(C, ar, but, BUTTON_ACTIVATE_OVER);
}
}
}
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 086e9dad895..09686d7b416 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -47,6 +47,7 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_fileops_types.h"
#include "DNA_brush_types.h"
#include "DNA_dynamicpaint_types.h"
@@ -703,10 +704,8 @@ static void init_iconfile_list(struct ListBase *list)
{
IconFile *ifile;
struct direntry *dir;
- int restoredir = 1; /* restore to current directory */
int totfile, i, index = 1;
const char *icondir;
- char olddir[FILE_MAX];
list->first = list->last = NULL;
icondir = BLI_get_folder(BLENDER_DATAFILES, "icons");
@@ -714,12 +713,7 @@ static void init_iconfile_list(struct ListBase *list)
if (icondir == NULL)
return;
- /* since BLI_dir_contents changes the current working directory, restore it
- * back to old value afterwards */
- if (!BLI_current_working_dir(olddir, sizeof(olddir)))
- restoredir = 0;
totfile = BLI_dir_contents(icondir, &dir);
- if (restoredir && !chdir(olddir)) {} /* fix warning about checking return value */
for (i = 0; i < totfile; i++) {
if ((dir[i].type & S_IFREG)) {
@@ -766,18 +760,8 @@ static void init_iconfile_list(struct ListBase *list)
}
}
}
-
- /* free temporary direntry structure that's been created by BLI_dir_contents() */
- i = totfile - 1;
-
- for (; i >= 0; i--) {
- MEM_freeN(dir[i].relname);
- MEM_freeN(dir[i].path);
- if (dir[i].string) {
- MEM_freeN(dir[i].string);
- }
- }
- free(dir);
+
+ BLI_free_filelist(dir, totfile);
dir = NULL;
}
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 9093e8f8d30..6065fcfe574 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -394,7 +394,8 @@ extern void ui_set_but_vectorf(uiBut *but, const float vec[3]);
extern void ui_hsvcircle_vals_from_pos(float *val_rad, float *val_dist, const rcti *rect,
const float mx, const float my);
-extern void ui_get_but_string(uiBut *but, char *str, size_t maxlen);
+extern void ui_get_but_string_ex(uiBut *but, char *str, const size_t maxlen, const int float_precision);
+extern void ui_get_but_string(uiBut *but, char *str, const size_t maxlen);
extern void ui_convert_to_unit_alt_name(uiBut *but, char *str, size_t maxlen);
extern int ui_set_but_string(struct bContext *C, uiBut *but, const char *str);
extern int ui_get_but_string_max_length(uiBut *but);
@@ -402,8 +403,6 @@ extern int ui_set_but_string_eval_num(struct bContext *C, uiBut *but, const char
extern void ui_set_but_default(struct bContext *C, short all);
-extern void ui_set_but_soft_range(uiBut *but, double value);
-
extern void ui_check_but(uiBut *but);
extern int ui_is_but_float(uiBut *but);
extern int ui_is_but_bool(uiBut *but);
@@ -523,7 +522,7 @@ extern void ui_button_text_password_hide(char password_str[UI_MAX_DRAW_STR], uiB
/* interface_widgets.c */
void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3);
-void ui_draw_anti_roundbox(int mode, float minx, float miny, float maxx, float maxy, float rad);
+void ui_draw_anti_roundbox(int mode, float minx, float miny, float maxx, float maxy, float rad, bool use_alpha);
void ui_draw_menu_back(struct uiStyle *style, uiBlock *block, rcti *rect);
uiWidgetColors *ui_tooltip_get_theme(void);
void ui_draw_tooltip_background(uiStyle *UNUSED(style), uiBlock * block, rcti * rect);
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index 1e95b4df762..2ca26ae5317 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -1567,7 +1567,7 @@ void uiItemM(uiLayout *layout, bContext *UNUSED(C), const char *menuname, const
}
if (!name) {
- name = IFACE_(mt->label);
+ name = CTX_IFACE_(mt->translation_context, mt->label);
}
if (layout->root->type == UI_LAYOUT_MENU && !icon)
@@ -2369,6 +2369,7 @@ uiLayout *uiLayoutAbsolute(uiLayout *layout, int align)
litem->active = 1;
litem->enabled = 1;
litem->context = layout->context;
+ litem->redalert = layout->redalert;
BLI_addtail(&layout->items, litem);
uiBlockSetCurLayout(layout->root->block, litem);
@@ -2396,6 +2397,7 @@ uiLayout *uiLayoutOverlap(uiLayout *layout)
litem->active = 1;
litem->enabled = 1;
litem->context = layout->context;
+ litem->redalert = layout->redalert;
BLI_addtail(&layout->items, litem);
uiBlockSetCurLayout(layout->root->block, litem);
@@ -2415,6 +2417,7 @@ uiLayout *uiLayoutSplit(uiLayout *layout, float percentage, int align)
split->litem.enabled = 1;
split->litem.context = layout->context;
split->litem.space = layout->root->style->columnspace;
+ split->litem.redalert = layout->redalert;
split->litem.w = layout->w;
split->percentage = percentage;
BLI_addtail(&layout->items, split);
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 3298859ee0c..145deb35667 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -239,7 +239,7 @@ static void eyedropper_color_sample_accum(bContext *C, Eyedropper *eye, int mx,
}
/* main modal status check */
-static int eyedropper_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int eyedropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
Eyedropper *eye = (Eyedropper *)op->customdata;
@@ -285,7 +285,7 @@ static int eyedropper_modal(bContext *C, wmOperator *op, wmEvent *event)
}
/* Modal Operator init */
-static int eyedropper_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int eyedropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
/* init */
if (eyedropper_init(C, op)) {
@@ -853,7 +853,7 @@ static int editsource_exec(bContext *C, wmOperator *op)
ED_region_do_draw(C, ar);
for (BLI_ghashIterator_init(&ghi, ui_editsource_info->hash);
- !BLI_ghashIterator_isDone(&ghi);
+ BLI_ghashIterator_notDone(&ghi);
BLI_ghashIterator_step(&ghi))
{
uiBut *but_key = BLI_ghashIterator_getKey(&ghi);
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index e466c481151..a741ea432a5 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -191,7 +191,7 @@ static void ui_panel_copy_offset(Panel *pa, Panel *papar)
Panel *uiBeginPanel(ScrArea *sa, ARegion *ar, uiBlock *block, PanelType *pt, int *open)
{
Panel *pa, *patab, *palast, *panext;
- char *drawname = pt->label;
+ const char *drawname = CTX_IFACE_(pt->translation_context, pt->label);
char *idname = pt->idname;
char *tabname = pt->idname;
char *hookname = NULL;
@@ -469,7 +469,7 @@ static void ui_draw_aligned_panel_header(uiStyle *style, uiBlock *block, rcti *r
Panel *panel = block->panel;
rcti hrect;
int pnl_icons;
- const char *activename = IFACE_(panel->drawname[0] ? panel->drawname : panel->panelname);
+ const char *activename = panel->drawname[0] ? panel->drawname : panel->panelname;
/* + 0.001f to avoid flirting with float inaccuracy */
if (panel->control & UI_PNL_CLOSE) pnl_icons = (panel->labelofs + 2 * PNL_ICON + 5) / block->aspect + 0.001f;
diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c
index 03c127f33c8..febd1820e5c 100644
--- a/source/blender/editors/interface/interface_regions.c
+++ b/source/blender/editors/interface/interface_regions.c
@@ -663,9 +663,9 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
/* since the text has beens caled already, the size of tooltips is defined now */
/* here we try to figure out the right location */
if (butregion) {
- float ofsx = rect_fl.xmin, ofsy = rect_fl.ymax;
- ui_block_to_window_fl(butregion, but->block, &ofsx, &ofsy);
- BLI_rctf_translate(&rect_fl, ofsx - rect_fl.xmin, ofsy - rect_fl.ymax);
+ float ofsx_fl = rect_fl.xmin, ofsy_fl = rect_fl.ymax;
+ ui_block_to_window_fl(butregion, but->block, &ofsx_fl, &ofsy_fl);
+ BLI_rctf_translate(&rect_fl, ofsx_fl - rect_fl.xmin, ofsy_fl - rect_fl.ymax);
}
BLI_rcti_rctf_copy(&rect_i, &rect_fl);
diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c
index ef24ea951e3..dd4886a7243 100644
--- a/source/blender/editors/interface/interface_style.c
+++ b/source/blender/editors/interface/interface_style.c
@@ -216,7 +216,7 @@ void uiStyleFontDrawRotated(uiFontStyle *fs, rcti *rect, const char *str)
/* rotate counter-clockwise for now (assumes left-to-right language)*/
xofs += height;
yofs = BLF_width(fs->uifont_id, str) + 5;
- angle = 90.0f;
+ angle = (float)M_PI / 2.0f;
/* translate rect to vertical */
txtrect.xmin = rect->xmin - BLI_rcti_size_y(rect);
@@ -330,6 +330,8 @@ void uiStyleInit(void)
{
uiFont *font = U.uifonts.first;
uiStyle *style = U.uistyles.first;
+ int monofont_size = datatoc_bmonofont_ttf_size;
+ unsigned char *monofont_ttf = (unsigned char *)datatoc_bmonofont_ttf;
/* recover from uninitialized dpi */
if (U.dpi == 0)
@@ -400,15 +402,33 @@ void uiStyleInit(void)
ui_style_new(&U.uistyles, "Default Style", UIFONT_DEFAULT);
}
+#ifdef WITH_INTERNATIONAL
+ /* use unicode font for text editor and interactive console */
+ if (U.transopts & USER_DOTRANSLATE) {
+ monofont_ttf = BLF_get_unifont_mono(&monofont_size);
+
+ if (!monofont_ttf) {
+ /* fall back if not found */
+ monofont_size = datatoc_bmonofont_ttf_size;
+ monofont_ttf = (unsigned char *)datatoc_bmonofont_ttf;
+ }
+ }
+
+ /* reload */
+ BLF_unload("monospace");
+ blf_mono_font = -1;
+ blf_mono_font_render = -1;
+#endif
+
/* XXX, this should be moved into a style, but for now best only load the monospaced font once. */
if (blf_mono_font == -1)
- blf_mono_font = BLF_load_mem_unique("monospace", (unsigned char *)datatoc_bmonofont_ttf, datatoc_bmonofont_ttf_size);
+ blf_mono_font = BLF_load_mem_unique("monospace", monofont_ttf, monofont_size);
BLF_size(blf_mono_font, 12 * U.pixelsize, 72);
/* second for rendering else we get threading problems */
if (blf_mono_font_render == -1)
- blf_mono_font_render = BLF_load_mem_unique("monospace", (unsigned char *)datatoc_bmonofont_ttf, datatoc_bmonofont_ttf_size);
+ blf_mono_font_render = BLF_load_mem_unique("monospace", monofont_ttf, monofont_size);
BLF_size(blf_mono_font_render, 12 * U.pixelsize, 72 );
}
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 83540cef9fc..afb44101910 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -281,11 +281,13 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
if (id->flag & LIB_FAKEUSER) id_us_plus(id);
else id_us_min(id);
}
- else return;
+ else {
+ return;
+ }
break;
case UI_ID_LOCAL:
if (id) {
- if (id_make_local(id, 0)) {
+ if (id_make_local(id, false)) {
/* reassign to get get proper updates/notifiers */
idptr = RNA_property_pointer_get(&template->ptr, template->prop);
RNA_property_pointer_set(&template->ptr, template->prop, idptr);
@@ -465,7 +467,7 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str
else {
but = uiDefIconBut(block, BUT, 0, ICON_LIBRARY_DATA_DIRECT, 0, 0, UI_UNIT_X, UI_UNIT_Y,
NULL, 0, 0, 0, 0, TIP_("Direct linked library datablock, click to make local"));
- if (!id_make_local(id, 1 /* test */) || (idfrom && idfrom->lib))
+ if (!id_make_local(id, true /* test */) || (idfrom && idfrom->lib))
uiButSetFlag(but, UI_BUT_DISABLED);
}
@@ -483,7 +485,7 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str
uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ALONE));
if (/* test only */
- (id_copy(id, NULL, 1) == FALSE) ||
+ (id_copy(id, NULL, true) == false) ||
(idfrom && idfrom->lib) ||
(editable == FALSE) ||
/* object in editmode - don't change data */
@@ -676,7 +678,7 @@ void uiTemplateAnyID(uiLayout *layout, PointerRNA *ptr, const char *propname, co
const char *text)
{
PropertyRNA *propID, *propType;
- uiLayout *row;
+ uiLayout *split, *row, *sub;
/* get properties... */
propID = RNA_struct_find_property(ptr, propname);
@@ -692,22 +694,34 @@ void uiTemplateAnyID(uiLayout *layout, PointerRNA *ptr, const char *propname, co
}
/* Start drawing UI Elements using standard defines */
- row = uiLayoutRow(layout, TRUE);
+ split = uiLayoutSplit(layout, 0.33f, FALSE); /* NOTE: split amount here needs to be synced with normal labels */
+
+ /* FIRST PART ................................................ */
+ row = uiLayoutRow(split, FALSE);
/* Label - either use the provided text, or will become "ID-Block:" */
if (text) {
if (text[0])
uiItemL(row, text, ICON_NONE);
}
- else
+ else {
uiItemL(row, IFACE_("ID-Block:"), ICON_NONE);
+ }
+
+ /* SECOND PART ................................................ */
+ row = uiLayoutRow(split, TRUE);
/* ID-Type Selector - just have a menu of icons */
- /* FIXME: the icon-only setting doesn't work when we supply a blank name */
- uiItemFullR(row, ptr, propType, 0, 0, UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
+ sub = uiLayoutRow(row, TRUE); /* HACK: special group just for the enum, otherwise we */
+ uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT); /* we get ugly layout with text included too... */
+
+ uiItemFullR(sub, ptr, propType, 0, 0, UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
/* ID-Block Selector - just use pointer widget... */
- uiItemFullR(row, ptr, propID, 0, 0, 0, "", ICON_NONE);
+ sub = uiLayoutRow(row, TRUE); /* HACK: special group to counteract the effects of the previous */
+ uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_EXPAND); /* enum, which now pushes everything too far right */
+
+ uiItemFullR(sub, ptr, propID, 0, 0, 0, "", ICON_NONE);
}
/********************* RNA Path Builder Template ********************/
@@ -2135,10 +2149,10 @@ static void curvemap_buttons_layout(uiLayout *layout, PointerRNA *ptr, char labe
uiLayoutRow(layout, TRUE);
uiBlockSetNFunc(block, curvemap_buttons_update, MEM_dupallocN(cb), cumap);
- bt = uiDefButF(block, NUM, 0, "X", 0, 2 * UI_UNIT_Y, UI_UNIT_X * 10, UI_UNIT_Y,
- &cmp->x, bounds.xmin, bounds.xmax, 1, 5, "");
- bt = uiDefButF(block, NUM, 0, "Y", 0, 1 * UI_UNIT_Y, UI_UNIT_X * 10, UI_UNIT_Y,
- &cmp->y, bounds.ymin, bounds.ymax, 1, 5, "");
+ uiDefButF(block, NUM, 0, "X", 0, 2 * UI_UNIT_Y, UI_UNIT_X * 10, UI_UNIT_Y,
+ &cmp->x, bounds.xmin, bounds.xmax, 1, 5, "");
+ uiDefButF(block, NUM, 0, "Y", 0, 1 * UI_UNIT_Y, UI_UNIT_X * 10, UI_UNIT_Y,
+ &cmp->y, bounds.ymin, bounds.ymax, 1, 5, "");
}
/* black/white levels */
@@ -2727,7 +2741,7 @@ static void operator_search_cb(const bContext *C, void *UNUSED(arg), const char
{
GHashIterator *iter = WM_operatortype_iter();
- for (; !BLI_ghashIterator_isDone(iter); BLI_ghashIterator_step(iter)) {
+ for (; BLI_ghashIterator_notDone(iter); BLI_ghashIterator_step(iter)) {
wmOperatorType *ot = BLI_ghashIterator_getValue(iter);
if ((ot->flag & OPTYPE_INTERNAL) && (G.debug & G_DEBUG_WM) == 0)
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index dd7b1d0ee06..78b6d2541fd 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -218,13 +218,16 @@ void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y
glDisable(GL_BLEND);
}
-void ui_draw_anti_roundbox(int mode, float minx, float miny, float maxx, float maxy, float rad)
+void ui_draw_anti_roundbox(int mode, float minx, float miny, float maxx, float maxy, float rad, bool use_alpha)
{
float color[4];
int j;
glEnable(GL_BLEND);
glGetFloatv(GL_CURRENT_COLOR, color);
+ if (use_alpha) {
+ color[3] = 0.5f;
+ }
color[3] *= 0.125f;
glColor4fv(color);
@@ -1289,7 +1292,9 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
else if ((but->block->flag & UI_BLOCK_LOOP) && (but->type == BUT)) {
ui_text_clip_left(fstyle, but, rect);
}
- else but->ofs = 0;
+ else {
+ but->ofs = 0;
+ }
/* check for button text label */
if (but->type == ICONTEXTROW) {
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index acea6e133f4..09122737373 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -279,6 +279,8 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
cp = ts->vertex; break;
case TH_VERTEX_SELECT:
cp = ts->vertex_select; break;
+ case TH_VERTEX_UNREFERENCED:
+ cp = ts->vertex_unreferenced; break;
case TH_VERTEX_SIZE:
cp = &ts->vertex_size; break;
case TH_OUTLINE_WIDTH:
@@ -445,7 +447,6 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
case TH_HANDLE_VERTEX_SIZE:
cp = &ts->handle_vertex_size;
break;
-
case TH_DOPESHEET_CHANNELOB:
cp = ts->ds_channel;
break;
@@ -718,6 +719,8 @@ void ui_theme_init_default(void)
/* space view3d */
btheme->tv3d.panelcolors.show_back = FALSE;
btheme->tv3d.panelcolors.show_header = FALSE;
+ rgba_char_args_set_fl(btheme->tv3d.panelcolors.back, 0.45, 0.45, 0.45, 0.5);
+ rgba_char_args_set_fl(btheme->tv3d.panelcolors.header, 0, 0, 0, 0.01);
rgba_char_args_set_fl(btheme->tv3d.back, 0.225, 0.225, 0.225, 1.0);
rgba_char_args_set(btheme->tv3d.text, 0, 0, 0, 255);
rgba_char_args_set(btheme->tv3d.text_hi, 255, 255, 255, 255);
@@ -742,6 +745,7 @@ void ui_theme_init_default(void)
rgba_char_args_set(btheme->tv3d.transform, 0xff, 0xff, 0xff, 255);
rgba_char_args_set(btheme->tv3d.vertex, 0, 0, 0, 255);
rgba_char_args_set(btheme->tv3d.vertex_select, 255, 133, 0, 255);
+ rgba_char_args_set(btheme->tv3d.vertex_unreferenced, 0, 0, 0, 255);
btheme->tv3d.vertex_size = 3;
btheme->tv3d.outline_width = 1;
rgba_char_args_set(btheme->tv3d.edge, 0x0, 0x0, 0x0, 255);
@@ -1376,7 +1380,7 @@ void init_userdef_do_versions(void)
/* signal for derivedmesh to use colorband */
/* run in case this was on and is now off in the user prefs [#28096] */
- vDM_ColorBand_store((U.flag & USER_CUSTOM_RANGE) ? (&U.coba_weight) : NULL);
+ vDM_ColorBand_store((U.flag & USER_CUSTOM_RANGE) ? (&U.coba_weight) : NULL, UI_GetTheme()->tv3d.vertex_unreferenced);
if (bmain->versionfile <= 191) {
strcpy(U.sounddir, "/");
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index ad6428c7e80..8a6de9a549b 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -457,8 +457,12 @@ static void ui_view2d_curRect_validate_resize(View2D *v2d, int resize, int mask_
if (ABS(winx - v2d->oldwinx) > ABS(winy - v2d->oldwiny)) do_y = FALSE;
else do_x = FALSE;
}
- else if (winRatio > 1.0f) do_x = FALSE;
- else do_x = TRUE;
+ else if (winRatio > 1.0f) {
+ do_x = FALSE;
+ }
+ else {
+ do_x = TRUE;
+ }
}
do_cur = do_x;
/* do_win = do_y; */ /* UNUSED */
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index daa78957231..e283bd1351a 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -187,7 +187,7 @@ static int view_pan_exec(bContext *C, wmOperator *op)
}
/* set up modal operator and relevant settings */
-static int view_pan_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int view_pan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
wmWindow *window = CTX_wm_window(C);
v2dViewPanData *vpd;
@@ -231,7 +231,7 @@ static int view_pan_invoke(bContext *C, wmOperator *op, wmEvent *event)
}
/* handle user input - calculations of mouse-movement need to be done here, not in the apply callback! */
-static int view_pan_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int view_pan_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
v2dViewPanData *vpd = op->customdata;
@@ -700,7 +700,7 @@ static int view_zoomin_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int view_zoomin_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int view_zoomin_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
v2dViewZoomData *vzd;
@@ -769,7 +769,7 @@ static int view_zoomout_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int view_zoomout_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int view_zoomout_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
v2dViewZoomData *vzd;
@@ -924,7 +924,7 @@ static int view_zoomdrag_exec(bContext *C, wmOperator *op)
}
/* set up modal operator and relevant settings */
-static int view_zoomdrag_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int view_zoomdrag_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
wmWindow *window = CTX_wm_window(C);
v2dViewZoomData *vzd;
@@ -1005,7 +1005,7 @@ static int view_zoomdrag_invoke(bContext *C, wmOperator *op, wmEvent *event)
}
/* handle user input - calculations of mouse-movement need to be done here, not in the apply callback! */
-static int view_zoomdrag_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int view_zoomdrag_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
v2dViewZoomData *vzd = op->customdata;
View2D *v2d = vzd->v2d;
@@ -1328,7 +1328,7 @@ void UI_view2d_smooth_view(bContext *C, ARegion *ar,
}
/* only meant for timer usage */
-static int view2d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
+static int view2d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
View2D *v2d = &ar->v2d;
@@ -1488,7 +1488,7 @@ static short mouse_in_scroller_handle(int mouse, int sc_min, int sc_max, int sh_
}
/* initialize customdata for scroller manipulation operator */
-static void scroller_activate_init(bContext *C, wmOperator *op, wmEvent *event, short in_scroller)
+static void scroller_activate_init(bContext *C, wmOperator *op, const wmEvent *event, short in_scroller)
{
v2dScrollerMove *vsm;
View2DScrollers *scrollers;
@@ -1637,7 +1637,7 @@ static void scroller_activate_apply(bContext *C, wmOperator *op)
}
/* handle user input for scrollers - calculations of mouse-movement need to be done here, not in the apply callback! */
-static int scroller_activate_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int scroller_activate_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
v2dScrollerMove *vsm = op->customdata;
@@ -1707,7 +1707,7 @@ static int scroller_activate_modal(bContext *C, wmOperator *op, wmEvent *event)
/* a click (or click drag in progress) should have occurred, so check if it happened in scrollbar */
-static int scroller_activate_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int scroller_activate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
View2D *v2d = &ar->v2d;
diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c
index 4908c101a7c..c673e0fb2b0 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -56,7 +56,7 @@
#include "io_collada.h"
-static int wm_collada_export_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int wm_collada_export_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
char filepath[FILE_MAX];
@@ -95,6 +95,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
int triangulate;
int use_object_instantiation;
int sort_by_name;
+ int export_transformation_type;
int second_life;
if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
@@ -115,14 +116,15 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
deform_bones_only = RNA_boolean_get(op->ptr, "deform_bones_only");
include_uv_textures = RNA_boolean_get(op->ptr, "include_uv_textures");
- include_material_textures= RNA_boolean_get(op->ptr, "include_material_textures");
+ include_material_textures = RNA_boolean_get(op->ptr, "include_material_textures");
use_texture_copies = RNA_boolean_get(op->ptr, "use_texture_copies");
active_uv_only = RNA_boolean_get(op->ptr, "active_uv_only");
- triangulate = RNA_boolean_get(op->ptr, "triangulate");
- use_object_instantiation = RNA_boolean_get(op->ptr, "use_object_instantiation");
- sort_by_name = RNA_boolean_get(op->ptr, "sort_by_name");
- second_life = RNA_boolean_get(op->ptr, "second_life");
+ triangulate = RNA_boolean_get(op->ptr, "triangulate");
+ use_object_instantiation = RNA_boolean_get(op->ptr, "use_object_instantiation");
+ sort_by_name = RNA_boolean_get(op->ptr, "sort_by_name");
+ export_transformation_type = RNA_enum_get(op->ptr, "export_transformation_type_selection");
+ second_life = RNA_boolean_get(op->ptr, "second_life");
/* get editmode results */
ED_object_exit_editmode(C, 0); /* 0 = does not exit editmode */
@@ -145,6 +147,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
triangulate,
use_object_instantiation,
sort_by_name,
+ export_transformation_type,
second_life))
{
return OPERATOR_FINISHED;
@@ -224,6 +227,12 @@ static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr)
uiItemR(row, imfptr, "triangulate", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, FALSE);
uiItemR(row, imfptr, "use_object_instantiation", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, FALSE);
+ split = uiLayoutSplit(row, 0.6f, UI_LAYOUT_ALIGN_RIGHT);
+ uiItemL(split, IFACE_("Transformation Type"), ICON_NONE);
+ uiItemR(split, imfptr, "export_transformation_type_selection", 0, "", ICON_NONE);
+
row = uiLayoutRow(box, FALSE);
uiItemR(row, imfptr, "sort_by_name", 0, NULL, ICON_NONE);
@@ -245,6 +254,13 @@ void WM_OT_collada_export(wmOperatorType *ot)
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem prop_bc_export_transformation_type[] = {
+ {BC_TRANSFORMATION_TYPE_MATRIX, "matrix", 0, "Matrix", "Use <matrix> to specify transformations"},
+ {BC_TRANSFORMATION_TYPE_TRANSROTLOC, "transrotloc", 0, "TransRotLoc", "Use <translate>, <rotate>, <scale> to specify transformations"},
+ {BC_TRANSFORMATION_TYPE_BOTH, "both", 0, "Both", "Use <matrix> AND <translate>, <rotate>, <scale> to specify transformations"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
ot->name = "Export COLLADA";
ot->description = "Save a Collada file";
ot->idname = "WM_OT_collada_export";
@@ -308,6 +324,12 @@ void WM_OT_collada_export(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "sort_by_name", 0, "Sort by Object name",
"Sort exported data by Object name");
+ RNA_def_int(ot->srna, "export_transformation_type", 0, INT_MIN, INT_MAX,
+ "Transform", "Transformation type for translation, scale and rotation", INT_MIN, INT_MAX);
+
+ RNA_def_enum(ot->srna, "export_transformation_type_selection", prop_bc_export_transformation_type, 0,
+ "Transform", "Transformation type for translation, scale and rotation");
+
RNA_def_boolean(ot->srna, "second_life", 0, "Export for Second Life",
"Compatibility mode for Second Life");
}
diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c
index 77abe43bba7..33a6aa2d43d 100644
--- a/source/blender/editors/mask/mask_add.c
+++ b/source/blender/editors/mask/mask_add.c
@@ -629,7 +629,7 @@ static int add_vertex_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int add_vertex_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
@@ -703,7 +703,7 @@ static int add_feather_vertex_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
-static int add_feather_vertex_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int add_feather_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c
index 0a996c11f14..ff8e27ac264 100644
--- a/source/blender/editors/mask/mask_ops.c
+++ b/source/blender/editors/mask/mask_ops.c
@@ -438,7 +438,7 @@ static int slide_point_check_initial_feather(MaskSpline *spline)
return TRUE;
}
-static void *slide_point_customdata(bContext *C, wmOperator *op, wmEvent *event)
+static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *event)
{
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
@@ -525,7 +525,7 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, wmEvent *event)
return customdata;
}
-static int slide_point_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int slide_point_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
SlidePointData *slidedata = slide_point_customdata(C, op, event);
@@ -634,7 +634,7 @@ static void free_slide_point_data(SlidePointData *data)
MEM_freeN(data);
}
-static int slide_point_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
SlidePointData *data = (SlidePointData *)op->customdata;
BezTriple *bezt = &data->point->bezt;
diff --git a/source/blender/editors/mask/mask_select.c b/source/blender/editors/mask/mask_select.c
index cd1a47754f8..ccc2fad5f52 100644
--- a/source/blender/editors/mask/mask_select.c
+++ b/source/blender/editors/mask/mask_select.c
@@ -361,7 +361,7 @@ static int select_exec(bContext *C, wmOperator *op)
return OPERATOR_PASS_THROUGH;
}
-static int select_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
@@ -689,7 +689,7 @@ void MASK_OT_select_circle(wmOperatorType *ot)
RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX);
}
-static int mask_select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int mask_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt
index b51d55aaf0e..a76872d6e30 100644
--- a/source/blender/editors/mesh/CMakeLists.txt
+++ b/source/blender/editors/mesh/CMakeLists.txt
@@ -26,6 +26,7 @@ set(INC
../../blenlib
../../blenloader
../../bmesh
+ ../../gpu
../../imbuf
../../makesdna
../../makesrna
@@ -43,6 +44,7 @@ set(SRC
editmesh_add.c
editmesh_bvh.c
editmesh_knife.c
+ editmesh_knife_project.c
editmesh_loopcut.c
editmesh_rip.c
editmesh_select.c
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c
index 7ddf2b54a88..260d01d726a 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.c
@@ -294,7 +294,7 @@ static void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int ind
MEM_freeN(linkflag);
}
-void paintface_select_linked(bContext *UNUSED(C), Object *ob, int UNUSED(mval[2]), int mode)
+void paintface_select_linked(bContext *UNUSED(C), Object *ob, const int UNUSED(mval[2]), int mode)
{
Mesh *me;
unsigned int index = 0;
@@ -525,7 +525,9 @@ int paintface_mouse_select(struct bContext *C, Object *ob, const int mval[2], in
else
mpoly_sel->flag |= ME_FACE_SEL;
}
- else mpoly_sel->flag |= ME_FACE_SEL;
+ else {
+ mpoly_sel->flag |= ME_FACE_SEL;
+ }
/* image window redraw */
@@ -568,7 +570,7 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, int select, int extend)
ibuf = IMB_allocImBuf(sx, sy, 32, IB_rect);
rt = ibuf->rect;
- glReadPixels(rect->xmin + vc->ar->winrct.xmin, rect->ymin + vc->ar->winrct.ymin, sx, sy, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
+ view3d_opengl_read_pixels(vc->ar, rect->xmin, rect->ymin, sx, sy, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
if (ENDIAN_ORDER == B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf);
a = sx * sy;
@@ -710,6 +712,37 @@ void paintvert_deselect_all_visible(Object *ob, int action, short flush_flags)
}
}
+void paintvert_select_ungrouped(Object *ob, short extend, short flush_flags)
+{
+ Mesh *me = BKE_mesh_from_object(ob);
+ MVert *mv;
+ MDeformVert *dv;
+ int a, tot;
+
+ if (me == NULL || me->dvert == NULL) {
+ return;
+ }
+
+ if (!extend) {
+ paintvert_deselect_all_visible(ob, SEL_DESELECT, FALSE);
+ }
+
+ dv = me->dvert;
+ tot = me->totvert;
+
+ for (a = 0, mv = me->mvert; a < tot; a++, mv++, dv++) {
+ if ((mv->flag & ME_HIDE) == 0) {
+ if (dv->dw == NULL) {
+ /* if null weight then not grouped */
+ mv->flag |= SELECT;
+ }
+ }
+ }
+
+ if (flush_flags) {
+ paintvert_flush_flags(ob);
+ }
+}
/* ********************* MESH VERTEX MIRR TOPO LOOKUP *************** */
/* note, this is not the best place for the function to be but moved
diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c
index a356f9fca7f..174715495f6 100644
--- a/source/blender/editors/mesh/editmesh_add.c
+++ b/source/blender/editors/mesh/editmesh_add.c
@@ -32,15 +32,14 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-#include "RNA_define.h"
-#include "RNA_access.h"
-
#include "BLI_math.h"
#include "BKE_context.h"
#include "BKE_library.h"
#include "BKE_tessmesh.h"
+#include "RNA_define.h"
+#include "RNA_access.h"
#include "WM_api.h"
#include "WM_types.h"
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index d7dbe3506b1..b5b6a92cbf5 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -37,6 +37,7 @@
#include "BLI_blenlib.h"
#include "BLI_array.h"
+#include "BLI_linklist.h"
#include "BLI_math.h"
#include "BLI_smallhash.h"
#include "BLI_memarena.h"
@@ -90,7 +91,8 @@ typedef struct KnifeVert {
ListBase faces;
float co[3], cageco[3], sco[3]; /* sco is screen coordinates for cageco */
- short flag, draw, isface, inspace;
+ bool is_face, in_space;
+ bool draw;
} KnifeVert;
typedef struct Ref {
@@ -102,9 +104,9 @@ typedef struct KnifeEdge {
KnifeVert *v1, *v2;
BMFace *basef; /* face to restrict face fill to */
ListBase faces;
- int draw;
- BMEdge *e, *oe; /* non-NULL if this is an original edge */
+ BMEdge *e /* , *e_old */; /* non-NULL if this is an original edge */
+ bool draw;
} KnifeEdge;
typedef struct BMEdgeHit {
@@ -128,7 +130,7 @@ typedef struct KnifePosData {
KnifeVert *vert;
KnifeEdge *edge;
BMFace *bmface;
- int is_space;
+ bool is_space;
float mval[2]; /* mouse screen position (may be non-integral if snapped to something) */
} KnifePosData;
@@ -137,7 +139,8 @@ typedef struct KnifePosData {
typedef struct KnifeTool_OpData {
ARegion *ar; /* region that knifetool was activated in */
void *draw_handle; /* for drawing preview loop */
- ViewContext vc;
+ ViewContext vc; /* note: _don't_ use 'mval', instead use the one we define below */
+ float mval[2]; /* mouse value with snapping applied */
//bContext *C;
Object *ob;
@@ -173,12 +176,15 @@ typedef struct KnifeTool_OpData {
KnifeColors colors;
+ /* run by the UI or not */
+ bool is_interactive;
+
/* operatpr options */
- char cut_through; /* preference, can be modified at runtime (that feature may go) */
- char only_select; /* set on initialization */
- char select_result; /* set on initialization */
+ bool cut_through; /* preference, can be modified at runtime (that feature may go) */
+ bool only_select; /* set on initialization */
+ bool select_result; /* set on initialization */
- short is_ortho;
+ bool is_ortho;
float ortho_extent;
float clipsta, clipend;
@@ -189,8 +195,10 @@ typedef struct KnifeTool_OpData {
MODE_PANNING
} mode;
- int snap_midpoints, prevmode, extend;
- int ignore_edge_snapping, ignore_vert_snapping;
+ int prevmode;
+ bool snap_midpoints, extend;
+ bool ignore_edge_snapping;
+ bool ignore_vert_snapping;
enum {
ANGLE_FREE,
@@ -228,14 +236,16 @@ static void knife_update_header(bContext *C, KnifeTool_OpData *kcd)
ED_area_headerprint(CTX_wm_area(C), header);
}
+#if 0
BLI_INLINE int round_ftoi(float x)
{
return x > 0.0f ? (int)(x + 0.5f) : (int)(x - 0.5f);
}
+#endif
-static void knife_project_v3(KnifeTool_OpData *kcd, const float co[3], float sco[3])
+static void knife_project_v3(const KnifeTool_OpData *kcd, const float co[3], float sco[3])
{
- ED_view3d_project_float_v3_m4(kcd->ar, co, sco, kcd->projmat);
+ ED_view3d_project_float_v3_m4(kcd->ar, co, sco, (float (*)[4])kcd->projmat);
}
static void knife_pos_data_clear(KnifePosData *kpd)
@@ -245,8 +255,7 @@ static void knife_pos_data_clear(KnifePosData *kpd)
kpd->vert = NULL;
kpd->edge = NULL;
kpd->bmface = NULL;
- kpd->mval[0] = 0.0f;
- kpd->mval[1] = 0.0f;
+ zero_v2(kpd->mval);
}
static ListBase *knife_empty_list(KnifeTool_OpData *kcd)
@@ -494,7 +503,7 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd)
if (kcd->prev.edge && kcd->prev.edge == kcd->curr.edge)
return;
- kfe->draw = 1;
+ kfe->draw = true;
if (kcd->prev.vert) {
kfe->v1 = kcd->prev.vert;
@@ -505,9 +514,9 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd)
else {
kfe->v1 = new_knife_vert(kcd, kcd->prev.co, kcd->prev.co);
kfe->v1->draw = kfe->draw = !kcd->prev.is_space;
- kfe->v1->inspace = kcd->prev.is_space;
+ kfe->v1->in_space = kcd->prev.is_space;
kfe->draw = !kcd->prev.is_space;
- kfe->v1->isface = 1;
+ kfe->v1->is_face = true;
if (kfe->v1->draw && kcd->prev.bmface)
knife_append_list(kcd, &kfe->v1->faces, kcd->prev.bmface);
}
@@ -522,13 +531,13 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd)
else {
kfe->v2 = new_knife_vert(kcd, kcd->curr.co, kcd->curr.co);
kfe->v2->draw = !kcd->curr.is_space;
- kfe->v2->isface = 1;
- kfe->v2->inspace = kcd->curr.is_space;
+ kfe->v2->is_face = true;
+ kfe->v2->in_space = kcd->curr.is_space;
if (kfe->v2->draw && kcd->curr.bmface)
knife_append_list(kcd, &kfe->v2->faces, kcd->curr.bmface);
if (kcd->curr.is_space)
- kfe->draw = 0;
+ kfe->draw = false;
kcd->curr.vert = kfe->v2;
}
@@ -632,11 +641,10 @@ static void knife_add_single_cut_through(KnifeTool_OpData *kcd, KnifeVert *v1, K
KnifeEdge *kfenew;
kfenew = new_knife_edge(kcd);
- kfenew->draw = 1;
kfenew->basef = f;
kfenew->v1 = v1;
kfenew->v2 = v2;
- kfenew->draw = 1;
+ kfenew->draw = true;
knife_add_to_vert_edges(kcd, kfenew);
@@ -650,7 +658,7 @@ static void knife_get_vert_faces(KnifeTool_OpData *kcd, KnifeVert *kfv, BMFace *
BMFace *f;
Ref *r;
- if (kfv->isface && facef) {
+ if (kfv->is_face && facef) {
knife_append_list(kcd, lst, facef);
}
else if (kfv->v) {
@@ -689,7 +697,7 @@ static void knife_cut_through(KnifeTool_OpData *kcd)
ListBase firstfaces = {NULL, NULL}, lastfaces = {NULL, NULL};
Ref *r, *r2;
KnifeEdge **splitkfe;
- int i, j, found;
+ int i, j;
if (!kcd->totlinehit) {
/* if no linehits then no interesting back face stuff to do */
@@ -727,15 +735,15 @@ static void knife_cut_through(KnifeTool_OpData *kcd)
/* For each face incident to firstv,
* find the first following linehit (if any) sharing that face and connect */
for (r = firstfaces.first; r; r = r->next) {
+ bool found = false;
f = r->ref;
- found = 0;
for (j = 0, lh2 = kcd->linehits; j < kcd->totlinehit && !found; j++, lh2++) {
kfe2 = lh2->kfe;
for (r2 = kfe2->faces.first; r2; r2 = r2->next) {
if (r2->ref == f) {
v2 = splitkfe[j] ? kfe2->v1 : knife_split_edge(kcd, kfe2, lh2->hit, &splitkfe[j]);
knife_add_single_cut_through(kcd, firstv, v2, f);
- found = 1;
+ found = true;
break;
}
}
@@ -757,8 +765,8 @@ static void knife_cut_through(KnifeTool_OpData *kcd)
/* For each face attached to edge for this linehit,
* find the first following linehit (if any) sharing that face and connect */
for (r = kfe->faces.first; r; r = r->next) {
+ bool found = false;
f = r->ref;
- found = 0;
for (j = i + 1, lh2 = lh + 1; j < kcd->totlinehit && !found; j++, lh2++) {
kfe2 = lh2->kfe;
for (r2 = kfe2->faces.first; r2; r2 = r2->next) {
@@ -766,7 +774,7 @@ static void knife_cut_through(KnifeTool_OpData *kcd)
v1 = splitkfe[i] ? kfe->v1 : knife_split_edge(kcd, kfe, lh->hit, &splitkfe[i]);
v2 = splitkfe[j] ? kfe2->v1 : knife_split_edge(kcd, kfe2, lh2->hit, &splitkfe[j]);
knife_add_single_cut_through(kcd, v1, v2, f);
- found = 1;
+ found = true;
break;
}
}
@@ -890,7 +898,7 @@ static void knife_finish_cut(KnifeTool_OpData *UNUSED(kcd))
}
-static void knifetool_draw_angle_snapping(KnifeTool_OpData *kcd)
+static void knifetool_draw_angle_snapping(const KnifeTool_OpData *kcd)
{
bglMats mats;
double u[3], u1[2], u2[2], v1[3], v2[3], dx, dy;
@@ -1006,7 +1014,7 @@ static void knife_init_colors(KnifeColors *colors)
static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg)
{
View3D *v3d = CTX_wm_view3d(C);
- KnifeTool_OpData *kcd = arg;
+ const KnifeTool_OpData *kcd = arg;
if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
@@ -1062,7 +1070,7 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg)
if (kcd->totlinehit > 0) {
const float vthresh4 = kcd->vthresh / 4.0f;
- const float vthresh4_squared = vthresh4 * vthresh4;
+ const float vthresh4_sq = vthresh4 * vthresh4;
BMEdgeHit *lh;
int i;
@@ -1082,12 +1090,12 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg)
knife_project_v3(kcd, lh->kfe->v2->cageco, sv2);
knife_project_v3(kcd, lh->cagehit, lh->schit);
- if (len_squared_v2v2(lh->schit, sv1) < vthresh4_squared) {
+ if (len_squared_v2v2(lh->schit, sv1) < vthresh4_sq) {
copy_v3_v3(lh->cagehit, lh->kfe->v1->cageco);
glVertex3fv(lh->cagehit);
lh->v = lh->kfe->v1;
}
- else if (len_squared_v2v2(lh->schit, sv2) < vthresh4_squared) {
+ else if (len_squared_v2v2(lh->schit, sv2) < vthresh4_sq) {
copy_v3_v3(lh->cagehit, lh->kfe->v2->cageco);
glVertex3fv(lh->cagehit);
lh->v = lh->kfe->v2;
@@ -1179,7 +1187,7 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree,
/* for comparing distances, error of intersection depends on triangle scale.
* need to scale down before squaring for accurate comparison */
const float depsilon = (FLT_EPSILON / 2.0f) * len_v3_tri_side_max(v1, v2, v3);
- const float depsilon_squared = depsilon * depsilon;
+ const float depsilon_sq = depsilon * depsilon;
copy_v3_v3(cos + 0, v1);
copy_v3_v3(cos + 3, v2);
@@ -1213,14 +1221,14 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree,
interp_v3_v3v3(p, kfe->v1->cageco, kfe->v2->cageco, lambda);
- if (kcd->curr.vert && len_squared_v3v3(kcd->curr.vert->cageco, p) < depsilon_squared) {
+ if (kcd->curr.vert && len_squared_v3v3(kcd->curr.vert->cageco, p) < depsilon_sq) {
continue;
}
- if (kcd->prev.vert && len_squared_v3v3(kcd->prev.vert->cageco, p) < depsilon_squared) {
+ if (kcd->prev.vert && len_squared_v3v3(kcd->prev.vert->cageco, p) < depsilon_sq) {
continue;
}
- if (len_squared_v3v3(kcd->prev.cage, p) < depsilon_squared ||
- len_squared_v3v3(kcd->curr.cage, p) < depsilon_squared)
+ if (len_squared_v3v3(kcd->prev.cage, p) < depsilon_sq ||
+ len_squared_v3v3(kcd->curr.cage, p) < depsilon_sq)
{
continue;
}
@@ -1266,8 +1274,8 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree,
if (!hitf && !BLI_smallhash_haskey(ehash, (intptr_t)kfe)) {
BMEdgeHit hit;
- if (len_squared_v3v3(p, kcd->curr.co) < depsilon_squared ||
- len_squared_v3v3(p, kcd->prev.co) < depsilon_squared)
+ if (len_squared_v3v3(p, kcd->curr.co) < depsilon_sq ||
+ len_squared_v3v3(p, kcd->prev.co) < depsilon_sq)
{
continue;
}
@@ -1381,7 +1389,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
knife_project_v3(kcd, v1, s1);
knife_project_v3(kcd, v2, s2);
- if (len_v2v2(s1, s2) < 1)
+ if (len_squared_v2v2(s1, s2) < 1)
return;
/* unproject screen line */
@@ -1481,7 +1489,7 @@ static void knife_input_ray_segment(KnifeTool_OpData *kcd, const float mval[2],
mul_m4_v3(kcd->ob->imat, r_origin_ofs);
}
-static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd, float co[3], float cageco[3], int *is_space)
+static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd, float co[3], float cageco[3], bool *is_space)
{
BMFace *f;
float dist = KMAXDIST;
@@ -1499,13 +1507,15 @@ static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd, float co[3], float
*is_space = !f;
if (!f) {
- /* try to use backbuffer selection method if ray casting failed */
- f = EDBM_face_find_nearest(&kcd->vc, &dist);
+ if (kcd->is_interactive) {
+ /* try to use backbuffer selection method if ray casting failed */
+ f = EDBM_face_find_nearest(&kcd->vc, &dist);
- /* cheat for now; just put in the origin instead
- * of a true coordinate on the face.
- * This just puts a point 1.0f infront of the view. */
- add_v3_v3v3(co, origin, ray);
+ /* cheat for now; just put in the origin instead
+ * of a true coordinate on the face.
+ * This just puts a point 1.0f infront of the view. */
+ add_v3_v3v3(co, origin, ray);
+ }
}
return f;
@@ -1513,18 +1523,21 @@ static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd, float co[3], float
/* find the 2d screen space density of vertices within a radius. used to scale snapping
* distance for picking edges/verts.*/
-static int knife_sample_screen_density(KnifeTool_OpData *kcd, float radius)
+static int knife_sample_screen_density(KnifeTool_OpData *kcd, const float radius)
{
BMFace *f;
- int is_space;
+ bool is_space;
float co[3], cageco[3], sco[3];
+ BLI_assert(kcd->is_interactive == true);
+
f = knife_find_closest_face(kcd, co, cageco, &is_space);
if (f && !is_space) {
+ const float radius_sq = radius * radius;
ListBase *lst;
Ref *ref;
- float dis;
+ float dis_sq;
int c = 0;
knife_project_v3(kcd, cageco, sco);
@@ -1539,8 +1552,8 @@ static int knife_sample_screen_density(KnifeTool_OpData *kcd, float radius)
knife_project_v3(kcd, kfv->cageco, kfv->sco);
- dis = len_v2v2(kfv->sco, sco);
- if (dis < radius) {
+ dis_sq = len_squared_v2v2(kfv->sco, sco);
+ if (dis_sq < radius_sq) {
if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) {
if (ED_view3d_clipping_test(kcd->vc.rv3d, kfv->cageco, TRUE) == 0) {
c++;
@@ -1563,7 +1576,14 @@ static int knife_sample_screen_density(KnifeTool_OpData *kcd, float radius)
* surrounding mesh (in screen space)*/
static float knife_snap_size(KnifeTool_OpData *kcd, float maxsize)
{
- float density = (float)knife_sample_screen_density(kcd, maxsize * 2.0f);
+ float density;
+
+ if (kcd->is_interactive) {
+ density = (float)knife_sample_screen_density(kcd, maxsize * 2.0f);
+ }
+ else {
+ density = 1.0f;
+ }
if (density < 1.0f)
density = 1.0f;
@@ -1572,7 +1592,7 @@ static float knife_snap_size(KnifeTool_OpData *kcd, float maxsize)
}
/* p is closest point on edge to the mouse cursor */
-static KnifeEdge *knife_find_closest_edge(KnifeTool_OpData *kcd, float p[3], float cagep[3], BMFace **fptr, int *is_space)
+static KnifeEdge *knife_find_closest_edge(KnifeTool_OpData *kcd, float p[3], float cagep[3], BMFace **fptr, bool *is_space)
{
BMFace *f;
float co[3], cageco[3], sco[3], maxdist = knife_snap_size(kcd, kcd->ethresh);
@@ -1668,7 +1688,7 @@ static KnifeEdge *knife_find_closest_edge(KnifeTool_OpData *kcd, float p[3], flo
/* find a vertex near the mouse cursor, if it exists */
static KnifeVert *knife_find_closest_vert(KnifeTool_OpData *kcd, float p[3], float cagep[3], BMFace **fptr,
- int *is_space)
+ bool *is_space)
{
BMFace *f;
float co[3], cageco[3], sco[3], maxdist = knife_snap_size(kcd, kcd->vthresh);
@@ -1684,10 +1704,11 @@ static KnifeVert *knife_find_closest_vert(KnifeTool_OpData *kcd, float p[3], flo
kcd->curr.bmface = f;
if (f) {
+ const float maxdist_sq = maxdist * maxdist;
ListBase *lst;
Ref *ref;
KnifeVert *curv = NULL;
- float dis, curdis = FLT_MAX;
+ float dis_sq, curdis_sq = FLT_MAX;
knife_project_v3(kcd, cageco, sco);
@@ -1701,17 +1722,17 @@ static KnifeVert *knife_find_closest_vert(KnifeTool_OpData *kcd, float p[3], flo
knife_project_v3(kcd, kfv->cageco, kfv->sco);
- dis = len_v2v2(kfv->sco, sco);
- if (dis < curdis && dis < maxdist) {
+ dis_sq = len_squared_v2v2(kfv->sco, sco);
+ if (dis_sq < curdis_sq && dis_sq < maxdist_sq) {
if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) {
if (ED_view3d_clipping_test(kcd->vc.rv3d, kfv->cageco, TRUE) == 0) {
curv = kfv;
- curdis = dis;
+ curdis_sq = dis_sq;
}
}
else {
curv = kfv;
- curdis = dis;
+ curdis_sq = dis_sq;
}
}
}
@@ -1747,7 +1768,7 @@ static KnifeVert *knife_find_closest_vert(KnifeTool_OpData *kcd, float p[3], flo
return NULL;
}
-/* update both kcd->curr.mval and kcd->vc.mval to snap to required angle */
+/* update both kcd->curr.mval and kcd->mval to snap to required angle */
static void knife_snap_angle(KnifeTool_OpData *kcd)
{
float dx, dy;
@@ -1784,16 +1805,14 @@ static void knife_snap_angle(KnifeTool_OpData *kcd)
kcd->curr.mval[0] = kcd->prev.mval[0];
}
- kcd->vc.mval[0] = round_ftoi(kcd->curr.mval[0]);
- kcd->vc.mval[1] = round_ftoi(kcd->curr.mval[1]);
+ copy_v2_v2(kcd->mval, kcd->curr.mval);
}
/* update active knife edge/vert pointers */
static int knife_update_active(KnifeTool_OpData *kcd)
{
knife_pos_data_clear(&kcd->curr);
- kcd->curr.mval[0] = (float)kcd->vc.mval[0];
- kcd->curr.mval[1] = (float)kcd->vc.mval[1];
+ copy_v2_v2(kcd->curr.mval, kcd->mval);
if (kcd->angle_snapping != ANGLE_FREE && kcd->mode == MODE_DRAGGING)
knife_snap_angle(kcd);
@@ -1994,14 +2013,14 @@ static void knifenet_fill_faces(KnifeTool_OpData *kcd)
i++;
if (kfe->e && kfe->v1->v == kfe->e->v1 && kfe->v2->v == kfe->e->v2) {
- kfe->oe = kfe->e;
+ kfe->e_old = kfe->e;
continue;
}
j++;
if (kfe->e) {
- kfe->oe = kfe->e;
+ kfe->e_old = kfe->e;
BMO_elem_flag_enable(bm, kfe->e, DEL);
BMO_elem_flag_disable(bm, kfe->e, BOUNDARY);
@@ -2027,13 +2046,13 @@ static void knifenet_fill_faces(KnifeTool_OpData *kcd)
if (!kfe->v1 || !kfe->v2 || kfe->v1->inspace || kfe->v2->inspace)
continue;
- if (!(kfe->oe && kfe->v1->v == kfe->oe->v1 && kfe->v2->v == kfe->oe->v2))
+ if (!(kfe->e_old && kfe->v1->v == kfe->e_old->v1 && kfe->v2->v == kfe->e_old->v2))
continue;
k++;
BMO_elem_flag_enable(bm, kfe->e, BOUNDARY);
- kfe->oe = kfe->e;
+ kfe->e_old = kfe->e;
for (ref = kfe->faces.first; ref; ref = ref->next) {
f = ref->ref;
@@ -2096,7 +2115,7 @@ static void knifenet_fill_faces(KnifeTool_OpData *kcd)
if (sf_vert->poly_nr > 1 && sf_vert_last->poly_nr > 1) {
ScanFillEdge *sf_edge;
sf_edge = BLI_scanfill_edge_add(&sf_ctx, sf_vert_last, sf_vert);
- if (entry->kfe->oe)
+ if (entry->kfe->e_old)
sf_edge->f = SF_EDGE_BOUNDARY; /* mark as original boundary edge */
BMO_elem_flag_disable(bm, entry->kfe->e->v1, DEL);
@@ -2239,15 +2258,15 @@ static void sort_by_frac_along(ListBase *lst, BMEdge *e)
/* The chain so far goes from an instantiated vertex to kfv (some may be reversed).
* If possible, complete the chain to another instantiated vertex and return 1, else return 0.
* The visited hash says which KnifeVert's have already been tried, not including kfv. */
-static int find_chain_search(KnifeTool_OpData *kcd, KnifeVert *kfv, ListBase *fedges, SmallHash *visited,
- ListBase *chain)
+static bool find_chain_search(KnifeTool_OpData *kcd, KnifeVert *kfv, ListBase *fedges, SmallHash *visited,
+ ListBase *chain)
{
Ref *r;
KnifeEdge *kfe;
KnifeVert *kfv_other;
if (kfv->v)
- return TRUE;
+ return true;
BLI_smallhash_insert(visited, (uintptr_t)kfv, NULL);
/* Try all possible next edges. Could either go through fedges
@@ -2264,22 +2283,22 @@ static int find_chain_search(KnifeTool_OpData *kcd, KnifeVert *kfv, ListBase *fe
if (kfv_other && !BLI_smallhash_haskey(visited, (uintptr_t)kfv_other)) {
knife_append_list(kcd, chain, kfe);
if (find_chain_search(kcd, kfv_other, fedges, visited, chain))
- return TRUE;
+ return true;
BLI_remlink(chain, chain->last);
}
}
- return FALSE;
+ return false;
}
static ListBase *find_chain_from_vertex(KnifeTool_OpData *kcd, KnifeEdge *kfe, BMVert *v, ListBase *fedges)
{
SmallHash visited_, *visited = &visited_;
ListBase *ans;
- int found;
+ bool found;
ans = knife_empty_list(kcd);
knife_append_list(kcd, ans, kfe);
- found = 0;
+ found = false;
BLI_smallhash_init(visited);
if (kfe->v1->v == v) {
BLI_smallhash_insert(visited, (uintptr_t)(kfe->v1), NULL);
@@ -2340,15 +2359,15 @@ static ListBase *find_chain(KnifeTool_OpData *kcd, ListBase *fedges)
/* The hole so far goes from kfvfirst to kfv (some may be reversed).
* If possible, complete the hole back to kfvfirst and return 1, else return 0.
* The visited hash says which KnifeVert's have already been tried, not including kfv or kfvfirst. */
-static int find_hole_search(KnifeTool_OpData *kcd, KnifeVert *kfvfirst, KnifeVert *kfv, ListBase *fedges,
- SmallHash *visited, ListBase *hole)
+static bool find_hole_search(KnifeTool_OpData *kcd, KnifeVert *kfvfirst, KnifeVert *kfv, ListBase *fedges,
+ SmallHash *visited, ListBase *hole)
{
Ref *r;
KnifeEdge *kfe, *kfelast;
KnifeVert *kfv_other;
if (kfv == kfvfirst)
- return TRUE;
+ return true;
BLI_smallhash_insert(visited, (uintptr_t)kfv, NULL);
kfelast = ((Ref *)hole->last)->ref;
@@ -2366,11 +2385,11 @@ static int find_hole_search(KnifeTool_OpData *kcd, KnifeVert *kfvfirst, KnifeVer
if (kfv_other && !BLI_smallhash_haskey(visited, (uintptr_t)kfv_other)) {
knife_append_list(kcd, hole, kfe);
if (find_hole_search(kcd, kfvfirst, kfv_other, fedges, visited, hole))
- return TRUE;
+ return true;
BLI_remlink(hole, hole->last);
}
}
- return FALSE;
+ return false;
}
/* Find a hole (simple cycle with no instantiated vertices).
@@ -2381,10 +2400,10 @@ static ListBase *find_hole(KnifeTool_OpData *kcd, ListBase *fedges)
Ref *r, *ref;
KnifeEdge *kfe;
SmallHash visited_, *visited = &visited_;
- int found;
+ bool found;
ans = NULL;
- found = FALSE;
+ found = false;
for (r = fedges->first; r && !found; r = r->next) {
kfe = r->ref;
@@ -2853,10 +2872,8 @@ static void knife_make_cuts(KnifeTool_OpData *kcd)
#endif
/* called on tool confirmation */
-static void knifetool_finish(wmOperator *op)
+static void knifetool_finish_ex(KnifeTool_OpData *kcd)
{
- KnifeTool_OpData *kcd = op->customdata;
-
#if SCANFILL_CUTS
knifenet_fill_faces(kcd);
#else
@@ -2866,19 +2883,10 @@ static void knifetool_finish(wmOperator *op)
EDBM_mesh_normals_update(kcd->em);
EDBM_update_generic(kcd->em, TRUE, TRUE);
}
-
-/* copied from paint_image.c */
-static int project_knife_view_clip(View3D *v3d, RegionView3D *rv3d, float *clipsta, float *clipend)
+static void knifetool_finish(wmOperator *op)
{
- int orth = ED_view3d_clip_range_get(v3d, rv3d, clipsta, clipend);
-
- if (orth) { /* only needed for ortho */
- float fac = 2.0f / ((*clipend) - (*clipsta));
- *clipsta *= fac;
- *clipend *= fac;
- }
-
- return orth;
+ KnifeTool_OpData *kcd = op->customdata;
+ knifetool_finish_ex(kcd);
}
static void knife_recalc_projmat(KnifeTool_OpData *kcd)
@@ -2887,22 +2895,22 @@ static void knife_recalc_projmat(KnifeTool_OpData *kcd)
ED_view3d_ob_project_mat_get(kcd->ar->regiondata, kcd->ob, kcd->projmat);
//mult_m4_m4m4(kcd->projmat, kcd->vc.rv3d->winmat, kcd->vc.rv3d->viewmat);
- kcd->is_ortho = project_knife_view_clip(kcd->vc.v3d, kcd->vc.rv3d,
- &kcd->clipsta, &kcd->clipend);
+ kcd->is_ortho = ED_view3d_clip_range_get(kcd->vc.v3d, kcd->vc.rv3d,
+ &kcd->clipsta, &kcd->clipend, true);
}
/* called when modal loop selection is done... */
-static void knifetool_exit(bContext *C, wmOperator *op)
+static void knifetool_exit_ex(bContext *C, KnifeTool_OpData *kcd)
{
- KnifeTool_OpData *kcd = op->customdata;
-
if (!kcd)
return;
- WM_cursor_restore(CTX_wm_window(C));
+ if (kcd->is_interactive) {
+ WM_cursor_restore(CTX_wm_window(C));
- /* deactivate the extra drawing stuff in 3D-View */
- ED_region_draw_cb_exit(kcd->ar->type, kcd->draw_handle);
+ /* deactivate the extra drawing stuff in 3D-View */
+ ED_region_draw_cb_exit(kcd->ar->type, kcd->draw_handle);
+ }
/* free the custom data */
BLI_mempool_destroy(kcd->refs);
@@ -2927,6 +2935,11 @@ static void knifetool_exit(bContext *C, wmOperator *op)
/* destroy kcd itself */
MEM_freeN(kcd);
+}
+static void knifetool_exit(bContext *C, wmOperator *op)
+{
+ KnifeTool_OpData *kcd = op->customdata;
+ knifetool_exit_ex(C, kcd);
op->customdata = NULL;
}
@@ -2944,35 +2957,36 @@ static void cage_mapped_verts_callback(void *userData, int index, const float co
}
}
-static void knifetool_update_mval(KnifeTool_OpData *kcd, int mval_i[2])
+static void knifetool_update_mval(KnifeTool_OpData *kcd, const float mval[2])
{
knife_recalc_projmat(kcd);
- kcd->vc.mval[0] = mval_i[0];
- kcd->vc.mval[1] = mval_i[1];
+ copy_v2_v2(kcd->mval, mval);
if (knife_update_active(kcd)) {
ED_region_tag_redraw(kcd->ar);
}
}
+static void knifetool_update_mval_i(KnifeTool_OpData *kcd, const int mval_i[2])
+{
+ float mval[2] = {UNPACK2(mval_i)};
+ knifetool_update_mval(kcd, mval);
+}
+
/* called when modal loop selection gets set up... */
-static int knifetool_init(bContext *C, wmOperator *op, int UNUSED(do_cut))
+static void knifetool_init(bContext *C, KnifeTool_OpData *kcd,
+ const bool only_select, const bool cut_through, const bool is_interactive)
{
- KnifeTool_OpData *kcd;
Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
DerivedMesh *cage, *final;
SmallHash shash;
void *data[3];
- const short only_select = RNA_boolean_get(op->ptr, "only_selected");
-
- /* alloc new customdata */
- kcd = op->customdata = MEM_callocN(sizeof(KnifeTool_OpData), "knifetool Modal Op Data");
/* assign the drawing handle for drawing preview line... */
kcd->ob = obedit;
kcd->ar = CTX_wm_region(C);
- kcd->draw_handle = ED_region_draw_cb_activate(kcd->ar->type, knifetool_draw, kcd, REGION_DRAW_POST_VIEW);
+
em_setup_viewcontext(C, &kcd->vc);
kcd->em = BMEdit_FromObject(kcd->ob);
@@ -2998,7 +3012,7 @@ static int knifetool_init(bContext *C, wmOperator *op, int UNUSED(do_cut))
kcd->vthresh = KMAXDIST - 1;
kcd->ethresh = KMAXDIST;
- kcd->extend = 1;
+ kcd->extend = true;
knife_recalc_projmat(kcd);
@@ -3013,7 +3027,8 @@ static int knifetool_init(bContext *C, wmOperator *op, int UNUSED(do_cut))
kcd->kedgefacemap = BLI_ghash_ptr_new("knife origvertmap");
/* cut all the way through the mesh if use_occlude_geometry button not pushed */
- kcd->cut_through = !RNA_boolean_get(op->ptr, "use_occlude_geometry");
+ kcd->is_interactive = is_interactive;
+ kcd->cut_through = cut_through;
kcd->only_select = only_select;
/* can't usefully select resulting edges in face mode */
@@ -3022,9 +3037,11 @@ static int knifetool_init(bContext *C, wmOperator *op, int UNUSED(do_cut))
knife_pos_data_clear(&kcd->curr);
knife_pos_data_clear(&kcd->prev);
- knife_init_colors(&kcd->colors);
+ if (is_interactive) {
+ kcd->draw_handle = ED_region_draw_cb_activate(kcd->ar->type, knifetool_draw, kcd, REGION_DRAW_POST_VIEW);
- return 1;
+ knife_init_colors(&kcd->colors);
+ }
}
static int knifetool_cancel(bContext *C, wmOperator *op)
@@ -3034,21 +3051,25 @@ static int knifetool_cancel(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
-static int knifetool_invoke(bContext *C, wmOperator *op, wmEvent *evt)
+static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ const bool only_select = RNA_boolean_get(op->ptr, "only_selected");
+ const bool cut_through = !RNA_boolean_get(op->ptr, "use_occlude_geometry");
+
KnifeTool_OpData *kcd;
view3d_operator_needs_opengl(C);
- if (!knifetool_init(C, op, 0))
- return OPERATOR_CANCELLED;
+ /* alloc new customdata */
+ kcd = op->customdata = MEM_callocN(sizeof(KnifeTool_OpData), __func__);
+
+ knifetool_init(C, kcd, only_select, cut_through, true);
/* add a modal handler for this operator - handles loop selection */
WM_cursor_modal(CTX_wm_window(C), BC_KNIFECURSOR);
WM_event_add_modal_handler(C, op);
- kcd = op->customdata;
- knifetool_update_mval(kcd, evt->mval);
+ knifetool_update_mval_i(kcd, event->mval);
knife_update_header(C, kcd);
@@ -3119,11 +3140,11 @@ wmKeyMap *knifetool_modal_keymap(wmKeyConfig *keyconf)
return keymap;
}
-static int knifetool_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
Object *obedit = CTX_data_edit_object(C);
KnifeTool_OpData *kcd = op->customdata;
- int do_refresh = FALSE;
+ bool do_refresh = false;
if (!obedit || obedit->type != OB_MESH || BMEdit_FromObject(obedit) != kcd->em) {
knifetool_exit(C, op);
@@ -3158,7 +3179,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, wmEvent *event)
return OPERATOR_FINISHED;
case KNF_MODAL_MIDPOINT_ON:
- kcd->snap_midpoints = 1;
+ kcd->snap_midpoints = true;
knife_recalc_projmat(kcd);
knife_update_active(kcd);
@@ -3167,7 +3188,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, wmEvent *event)
do_refresh = TRUE;
break;
case KNF_MODAL_MIDPOINT_OFF:
- kcd->snap_midpoints = 0;
+ kcd->snap_midpoints = false;
knife_recalc_projmat(kcd);
knife_update_active(kcd);
@@ -3177,13 +3198,13 @@ static int knifetool_modal(bContext *C, wmOperator *op, wmEvent *event)
break;
case KNF_MODEL_IGNORE_SNAP_ON:
ED_region_tag_redraw(kcd->ar);
- kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = 1;
+ kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = true;
knife_update_header(C, kcd);
do_refresh = TRUE;
break;
case KNF_MODEL_IGNORE_SNAP_OFF:
ED_region_tag_redraw(kcd->ar);
- kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = 0;
+ kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = false;
knife_update_header(C, kcd);
do_refresh = TRUE;
break;
@@ -3241,7 +3262,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, wmEvent *event)
case MOUSEMOVE: /* mouse moved somewhere to select another loop */
if (kcd->mode != MODE_PANNING) {
- knifetool_update_mval(kcd, event->mval);
+ knifetool_update_mval_i(kcd, event->mval);
}
break;
@@ -3251,7 +3272,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, wmEvent *event)
if (do_refresh) {
/* we don't really need to update mval,
* but this happens to be the best way to refresh at the moment */
- knifetool_update_mval(kcd, event->mval);
+ knifetool_update_mval_i(kcd, event->mval);
}
/* keep going until the user confirms */
@@ -3277,3 +3298,229 @@ void MESH_OT_knife_tool(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "use_occlude_geometry", TRUE, "Occlude Geometry", "Only cut the front most geometry");
RNA_def_boolean(ot->srna, "only_selected", FALSE, "Only Selected", "Only cut selected geometry");
}
+
+
+/* -------------------------------------------------------------------- */
+/* Knife tool as a utility function
+ * that can be used for internal slicing operations */
+
+/**
+ * Return a point inside the face.
+ *
+ * tessellation here seems way overkill,
+ * but without this its very hard to know of a point is inside the face
+ */
+static void edvm_mesh_knife_face_point(BMFace *f, float r_cent[3])
+{
+ int tottri = f->len - 2;
+ BMLoop **loops = BLI_array_alloca(loops, f->len);
+ int (*index)[3] = BLI_array_alloca(index, tottri);
+ int j;
+
+ float const *best_co[3] = {NULL};
+ float best_area = -1.0f;
+ bool ok = false;
+
+ tottri = BM_face_calc_tessellation(f, loops, index);
+ BLI_assert(tottri <= f->len - 2);
+
+ for (j = 0; j < tottri; j++) {
+ const float *p1 = loops[index[j][0]]->v->co;
+ const float *p2 = loops[index[j][1]]->v->co;
+ const float *p3 = loops[index[j][2]]->v->co;
+ float area;
+
+ float cross[3];
+ cross_v3_v3v3(cross, p2, p3);
+ area = fabsf(dot_v3v3(p1, cross));
+ if (area > best_area) {
+ best_co[0] = p1;
+ best_co[1] = p2;
+ best_co[2] = p3;
+ best_area = area;
+ ok = true;
+ }
+ }
+
+ if (ok) {
+ mid_v3_v3v3v3(r_cent, best_co[0], best_co[1], best_co[2]);
+ }
+ else {
+ mid_v3_v3v3v3(r_cent, loops[0]->v->co, loops[1]->v->co, loops[2]->v->co);
+ }
+}
+
+static bool edbm_mesh_knife_face_isect(ARegion *ar, LinkNode *polys, BMFace *f, float projmat[4][4])
+{
+ float cent_ss[2];
+ float cent[3];
+
+ edvm_mesh_knife_face_point(f, cent);
+
+ ED_view3d_project_float_v2_m4(ar, cent, cent_ss, projmat);
+
+ /* check */
+ {
+ LinkNode *p = polys;
+ int isect = 0;
+
+ while (p) {
+ const float (*mval_fl)[2] = p->link;
+ const int mval_tot = MEM_allocN_len(mval_fl) / sizeof(*mval_fl);
+ isect += (int)isect_point_poly_v2(cent_ss, mval_fl, mval_tot - 1);
+ p = p->next;
+ }
+
+ if (isect % 2) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * \param use_tag When set, tag all faces inside the polylines.
+ */
+void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag)
+{
+ KnifeTool_OpData *kcd;
+
+ view3d_operator_needs_opengl(C);
+
+ /* init */
+ {
+ const bool only_select = false;
+ const bool cut_through = false;
+ const bool is_interactive = false; /* can enable for testing */
+
+ kcd = MEM_callocN(sizeof(KnifeTool_OpData), __func__);
+
+ knifetool_init(C, kcd, only_select, cut_through, is_interactive);
+
+ kcd->ignore_edge_snapping = true;
+ kcd->ignore_vert_snapping = true;
+
+ if (use_tag) {
+ BM_mesh_elem_hflag_enable_all(kcd->em->bm, BM_EDGE, BM_ELEM_TAG, false);
+ }
+ }
+
+ /* execute */
+ {
+ LinkNode *p = polys;
+
+ knife_recalc_projmat(kcd);
+
+ while (p) {
+ const float (*mval_fl)[2] = p->link;
+ const int mval_tot = MEM_allocN_len(mval_fl) / sizeof(*mval_fl);
+ int i;
+
+ for (i = 0; i < mval_tot; i++) {
+ knifetool_update_mval(kcd, mval_fl[i]);
+ if (i == 0) {
+ knife_start_cut(kcd);
+ kcd->mode = MODE_DRAGGING;
+ }
+ else {
+ knife_add_cut(kcd);
+ }
+ }
+ knife_finish_cut(kcd);
+ kcd->mode = MODE_IDLE;
+ p = p->next;
+ }
+ }
+
+ /* finish */
+ {
+ knifetool_finish_ex(kcd);
+
+ /* tag faces inside! */
+ if (use_tag) {
+ BMesh *bm = kcd->em->bm;
+ float projmat[4][4];
+
+ BMEdge *e;
+ BMIter iter;
+
+ bool keep_search;
+
+ ED_view3d_ob_project_mat_get(kcd->ar->regiondata, kcd->ob, projmat);
+
+ /* use face-loop tag to store if we have intersected */
+#define F_ISECT_IS_UNKNOWN(f) BM_elem_flag_test(BM_FACE_FIRST_LOOP(f), BM_ELEM_TAG)
+#define F_ISECT_SET_UNKNOWN(f) BM_elem_flag_enable(BM_FACE_FIRST_LOOP(f), BM_ELEM_TAG)
+#define F_ISECT_SET_OUTSIDE(f) BM_elem_flag_disable(BM_FACE_FIRST_LOOP(f), BM_ELEM_TAG)
+ {
+ BMFace *f;
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ F_ISECT_SET_UNKNOWN(f);
+ BM_elem_flag_disable(f, BM_ELEM_TAG);
+ }
+ }
+
+ /* tag all faces linked to cut edges */
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ /* check are we tagged?, then we are an original face */
+ if (BM_elem_flag_test(e, BM_ELEM_TAG) == false) {
+ BMFace *f;
+ BMIter fiter;
+ BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
+ if (edbm_mesh_knife_face_isect(kcd->ar, polys, f, projmat)) {
+ BM_elem_flag_enable(f, BM_ELEM_TAG);
+ }
+ }
+ }
+ }
+
+ /* expand tags for faces which are not cut, but are inside the polys */
+ do {
+ BMFace *f;
+ keep_search = false;
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(f, BM_ELEM_TAG) == false && (F_ISECT_IS_UNKNOWN(f))) {
+ /* am I connected to a tagged face via an un-tagged edge (ie, not across a cut) */
+ BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l_iter = l_first;
+ bool found = false;
+
+ do {
+ if (BM_elem_flag_test(l_iter->e, BM_ELEM_TAG) != false) {
+ /* now check if the adjacent faces is tagged */
+ BMLoop *l_radial_iter = l_iter->radial_next;
+ if (l_radial_iter != l_iter) {
+ do {
+ if (BM_elem_flag_test(l_radial_iter->f, BM_ELEM_TAG)) {
+ found = true;
+ }
+ } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter && (found == false));
+ }
+ }
+ } while ((l_iter = l_iter->next) != l_first && (found == false));
+
+ if (found) {
+ if (edbm_mesh_knife_face_isect(kcd->ar, polys, f, projmat)) {
+ BM_elem_flag_enable(f, BM_ELEM_TAG);
+ keep_search = true;
+ }
+ else {
+ /* don't loose time on this face again, set it as outside */
+ F_ISECT_SET_OUTSIDE(f);
+ }
+ }
+ }
+ }
+ } while (keep_search);
+
+#undef F_ISECT_IS_UNKNOWN
+#undef F_ISECT_SET_UNKNOWN
+#undef F_ISECT_SET_OUTSIDE
+
+ }
+
+ knifetool_exit_ex(C, kcd);
+ kcd = NULL;
+ }
+}
diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c
new file mode 100644
index 00000000000..c581ce5a2e8
--- /dev/null
+++ b/source/blender/editors/mesh/editmesh_knife_project.c
@@ -0,0 +1,168 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/mesh/editmesh_knife_project.c
+ * \ingroup edmesh
+ */
+
+#include "DNA_curve_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+#include "BLI_linklist.h"
+#include "BLI_listbase.h"
+
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_context.h"
+#include "BKE_curve.h"
+#include "BKE_cdderivedmesh.h"
+#include "BKE_tessmesh.h"
+#include "BKE_report.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "WM_types.h"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "mesh_intern.h"
+
+
+static LinkNode *knifeproject_poly_from_object(ARegion *ar, Scene *scene, Object *ob, LinkNode *polys)
+{
+ DerivedMesh *dm;
+ bool dm_needsFree;
+
+ if (ob->type == OB_MESH || ob->derivedFinal) {
+ dm = ob->derivedFinal ? ob->derivedFinal : mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
+ dm_needsFree = false;
+ }
+ else if (ELEM3(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {
+ dm = CDDM_from_curve(ob);
+ dm_needsFree = true;
+ }
+ else {
+ dm = NULL;
+ }
+
+ if (dm) {
+ ListBase nurbslist = {NULL, NULL};
+ float projmat[4][4];
+
+ BKE_mesh_to_curve_nurblist(dm, &nurbslist, 0); /* wire */
+ BKE_mesh_to_curve_nurblist(dm, &nurbslist, 1); /* boundary */
+
+ ED_view3d_ob_project_mat_get(ar->regiondata, ob, projmat);
+
+ if (nurbslist.first) {
+ Nurb *nu;
+ for (nu = nurbslist.first; nu; nu = nu->next) {
+ if (nu->bp) {
+ int a;
+ BPoint *bp;
+ bool is_cyclic = (nu->flagu & CU_NURB_CYCLIC) != 0;
+ float (*mval)[2] = MEM_mallocN(sizeof(*mval) * (nu->pntsu + is_cyclic), __func__);
+
+ for (bp = nu->bp, a = 0; a < nu->pntsu; a++, bp++) {
+ ED_view3d_project_float_v3_m4(ar, bp->vec, mval[a], projmat);
+ }
+ if (is_cyclic) {
+ copy_v2_v2(mval[a], mval[0]);
+ }
+
+ BLI_linklist_prepend(&polys, mval);
+ }
+ }
+ }
+
+ BKE_nurbList_free(&nurbslist);
+
+ if (dm_needsFree) {
+ dm->release(dm);
+ }
+ }
+
+
+ return polys;
+}
+
+static int knifeproject_exec(bContext *C, wmOperator *op)
+{
+ ARegion *ar = CTX_wm_region(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BMEdit_FromObject(obedit);
+
+ LinkNode *polys = NULL;
+
+ CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
+ {
+ if (ob != obedit) {
+ polys = knifeproject_poly_from_object(ar, scene, ob, polys);
+ }
+ }
+ CTX_DATA_END;
+
+ if (polys) {
+ EDBM_mesh_knife(C, polys, true);
+
+ /* select only tagged faces */
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
+ BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, BM_ELEM_TAG);
+
+ BM_mesh_select_mode_flush(em->bm);
+
+ BLI_linklist_freeN(polys);
+
+ return OPERATOR_FINISHED;
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "No other selected objects found to use for projection");
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void MESH_OT_knife_project(wmOperatorType *ot)
+{
+ /* description */
+ ot->name = "Knife Project";
+ ot->idname = "MESH_OT_knife_project";
+ ot->description = "Use other objects outlines & boundaries to project knife cuts";
+
+ /* callbacks */
+ ot->exec = knifeproject_exec;
+ ot->poll = ED_operator_editmesh_view3d;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+}
+
diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c
index 83542915ec2..5b9864ca239 100644
--- a/source/blender/editors/mesh/editmesh_loopcut.c
+++ b/source/blender/editors/mesh/editmesh_loopcut.c
@@ -385,7 +385,7 @@ static int ringcut_cancel(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
-static int ringcut_invoke(bContext *C, wmOperator *op, wmEvent *evt)
+static int ringcut_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ScrArea *sa = CTX_wm_area(C);
Object *obedit = CTX_data_edit_object(C);
@@ -405,8 +405,7 @@ static int ringcut_invoke(bContext *C, wmOperator *op, wmEvent *evt)
WM_event_add_modal_handler(C, op);
lcd = op->customdata;
- lcd->vc.mval[0] = evt->mval[0];
- lcd->vc.mval[1] = evt->mval[1];
+ copy_v2_v2_int(lcd->vc.mval, event->mval);
edge = EDBM_edge_find_nearest(&lcd->vc, &dist);
if (edge != lcd->eed) {
@@ -419,7 +418,7 @@ static int ringcut_invoke(bContext *C, wmOperator *op, wmEvent *evt)
return OPERATOR_RUNNING_MODAL;
}
-static int loopcut_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
float smoothness = RNA_float_get(op->ptr, "smoothness");
int cuts = RNA_int_get(op->ptr, "number_cuts");
diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c
index 6cbf5e88cee..8198e088e5a 100644
--- a/source/blender/editors/mesh/editmesh_rip.c
+++ b/source/blender/editors/mesh/editmesh_rip.c
@@ -33,9 +33,6 @@
#include "DNA_object_types.h"
-#include "RNA_define.h"
-#include "RNA_access.h"
-
#include "BLI_math.h"
#include "BLI_array.h"
@@ -43,6 +40,9 @@
#include "BKE_report.h"
#include "BKE_tessmesh.h"
+#include "RNA_define.h"
+#include "RNA_access.h"
+
#include "WM_types.h"
#include "ED_mesh.h"
@@ -499,16 +499,9 @@ static void edbm_tagged_loop_pairs_do_fill_faces(BMesh *bm, UnorderedLoopPair *u
BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter);
}
else {
- if (v_shared == f_verts[0]) {
- BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); l_iter = l_iter->next;
- BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); l_iter = l_iter->next;
- BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, l_iter), l_iter);
- }
- else {
- BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); l_iter = l_iter->next;
- BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); l_iter = l_iter->next;
- BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, l_iter), l_iter);
- }
+ BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); l_iter = l_iter->next;
+ BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); l_iter = l_iter->next;
+ BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, l_iter), l_iter);
}
}
@@ -538,7 +531,7 @@ static int edbm_rip_call_edgesplit(BMEditMesh *em, wmOperator *op)
/**
* This is the main vert ripping function (rip when one vertex is selected)
*/
-static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, wmEvent *event)
+static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *event)
{
const int do_fill = RNA_boolean_get(op->ptr, "use_fill");
UnorderedLoopPair *fill_uloop_pairs = NULL;
@@ -860,7 +853,7 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, wmEvent *event)
/**
* This is the main edge ripping function
*/
-static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, wmEvent *event)
+static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, const wmEvent *event)
{
const int do_fill = RNA_boolean_get(op->ptr, "use_fill");
UnorderedLoopPair *fill_uloop_pairs = NULL;
@@ -988,7 +981,7 @@ static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, wmEvent *event)
}
/* based on mouse cursor position, it defines how is being ripped */
-static int edbm_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int edbm_rip_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BMEdit_FromObject(obedit);
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index 1016c08e1c4..a1c302c6a63 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -66,6 +66,8 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "GPU_extensions.h"
+
#include "mesh_intern.h"
#include "UI_resources.h"
@@ -253,6 +255,9 @@ int EDBM_backbuf_border_mask_init(ViewContext *vc, const int mcords[][2], short
dr = buf->rect;
+ if (vc->rv3d->gpuoffscreen)
+ GPU_offscreen_bind(vc->rv3d->gpuoffscreen);
+
/* draw the mask */
glDisable(GL_DEPTH_TEST);
@@ -270,6 +275,9 @@ int EDBM_backbuf_border_mask_init(ViewContext *vc, const int mcords[][2], short
glFinish(); /* to be sure readpixels sees mask */
+ if (vc->rv3d->gpuoffscreen)
+ GPU_offscreen_unbind(vc->rv3d->gpuoffscreen);
+
/* grab mask */
bufmask = view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
@@ -308,8 +316,10 @@ int EDBM_backbuf_circle_init(ViewContext *vc, short xs, short ys, short rads)
return 0;
}
}
- else if (vc->v3d->drawtype < OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT) == 0) return 0;
-
+ else if (vc->v3d->drawtype < OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT) == 0) {
+ return 0;
+ }
+
xmin = xs - rads; xmax = xs + rads;
ymin = ys - rads; ymax = ys + rads;
buf = view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
@@ -932,7 +942,7 @@ static int edbm_select_mode_exec(bContext *C, wmOperator *op)
}
}
-static int edbm_select_mode_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int edbm_select_mode_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
/* detecting these options based on shift/ctrl here is weak, but it's done
* to make this work when clicking buttons or menus */
@@ -1084,7 +1094,7 @@ void MESH_OT_loop_multi_select(wmOperatorType *ot)
/* ***************** loop select (non modal) ************** */
-static void mouse_mesh_loop(bContext *C, int mval[2], short extend, short deselect, short toggle, short ring)
+static void mouse_mesh_loop(bContext *C, const int mval[2], short extend, short deselect, short toggle, short ring)
{
ViewContext vc;
BMEditMesh *em;
@@ -1171,7 +1181,7 @@ static void mouse_mesh_loop(bContext *C, int mval[2], short extend, short desele
/* Select the face of eed which is the nearest of mouse. */
BMFace *f, *efa = NULL;
BMIter iterf;
- float best_dist = MAXFLOAT;
+ float best_dist = FLT_MAX;
/* We can't be sure this has already been set... */
ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
@@ -1203,7 +1213,7 @@ static void mouse_mesh_loop(bContext *C, int mval[2], short extend, short desele
}
}
-static int edbm_select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int edbm_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
view3d_operator_needs_opengl(C);
@@ -1754,7 +1764,7 @@ static int mouse_mesh_shortest_path_face(ViewContext *vc)
/* ******************* operator for edge and face tag ****************** */
-static int edbm_shortest_path_select_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
+static int edbm_shortest_path_select_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
ViewContext vc;
BMEditMesh *em;
@@ -2252,7 +2262,7 @@ static void linked_limit_default(bContext *C, wmOperator *op)
}
}
-static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Object *obedit = CTX_data_edit_object(C);
ViewContext vc;
@@ -2995,6 +3005,59 @@ void MESH_OT_select_random(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
}
+static int edbm_select_ungrouped_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BMEdit_FromObject(obedit);
+ BMVert *eve;
+ BMIter iter;
+
+ if (!em->selectmode == SCE_SELECT_VERTEX) {
+ BKE_report(op->reports, RPT_ERROR, "Does not work out of vertex selection mode");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (obedit->defbase.first == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No weights/vertex groups on object");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!RNA_boolean_get(op->ptr, "extend")) {
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ }
+
+ BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ MDeformVert *dv = CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT);
+ /* no dv or dv set with no weight */
+ if (dv == NULL || (dv && dv->dw == NULL)) {
+ BM_vert_select_set(em->bm, eve, true);
+ }
+ }
+ }
+
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_ungrouped(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Ungrouped";
+ ot->idname = "MESH_OT_select_ungrouped";
+ ot->description = "Select vertices without a group";
+
+ /* api callbacks */
+ ot->exec = edbm_select_ungrouped_exec;
+ ot->poll = ED_operator_editmesh;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
+}
+
static int edbm_select_next_loop_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *obedit = CTX_data_edit_object(C);
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index c35f942cf33..36a1d30c85e 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -39,10 +39,6 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-#include "RNA_define.h"
-#include "RNA_access.h"
-#include "RNA_enum_types.h"
-
#include "BLI_blenlib.h"
#include "BLI_noise.h"
#include "BLI_math.h"
@@ -59,6 +55,10 @@
#include "BKE_main.h"
#include "BKE_tessmesh.h"
+#include "RNA_define.h"
+#include "RNA_access.h"
+#include "RNA_enum_types.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -77,6 +77,8 @@
#include "mesh_intern.h"
+#define USE_FACE_CREATE_SEL_EXTEND
+
#define MVAL_PIXEL_MARGIN 5.0f
/* allow accumulated normals to form a new direction but don't
@@ -333,10 +335,7 @@ static short edbm_extrude_edge(Object *obedit, BMEditMesh *em, const char hflag,
mult_m4_m4m4(mtx, imtx, obedit->obmat);
}
- for (edge = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, NULL);
- edge;
- edge = BM_iter_step(&iter))
- {
+ BM_ITER_MESH (edge, &iter, bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(edge, hflag) &&
BM_edge_is_boundary(edge) &&
BM_elem_flag_test(edge->l->f, hflag))
@@ -779,7 +778,7 @@ void MESH_OT_select_interior_faces(wmOperatorType *ot)
}
/* *************** add-click-mesh (extrude) operator ************** */
-static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewContext vc;
BMVert *v1;
@@ -863,7 +862,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, wmEvent
copy_v3_v3(min, cent);
mul_m4_v3(vc.obedit->obmat, min); /* view space */
- view3d_get_view_aligned_coordinate(&vc, min, event->mval, TRUE);
+ view3d_get_view_aligned_coordinate(vc.ar, min, event->mval, true);
mul_m4_v3(vc.obedit->imat, min); // back in object space
sub_v3_v3(min, cent);
@@ -912,7 +911,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, wmEvent
BMOIter oiter;
copy_v3_v3(min, curs);
- view3d_get_view_aligned_coordinate(&vc, min, event->mval, FALSE);
+ view3d_get_view_aligned_coordinate(vc.ar, min, event->mval, false);
invert_m4_m4(vc.obedit->imat, vc.obedit->obmat);
mul_m4_v3(vc.obedit->imat, min); // back in object space
@@ -1099,6 +1098,140 @@ static int edbm_add_edge_face__smooth_get(BMesh *bm)
return (vote_on_smooth[0] < vote_on_smooth[1]);
}
+#ifdef USE_FACE_CREATE_SEL_EXTEND
+/**
+ * Function used to get a fixed number of edges linked to a vertex that passes a test function.
+ * This is used so we can request all boundary edges connected to a vertex for eg.
+ */
+static int edbm_add_edge_face_exec__vert_edge_lookup(BMVert *v, BMEdge *e_used, BMEdge **e_arr, const int e_arr_len,
+ bool (* func)(BMEdge *))
+{
+ BMIter iter;
+ BMEdge *e_iter;
+ int i = 0;
+ BM_ITER_ELEM (e_iter, &iter, v, BM_EDGES_OF_VERT) {
+ if (BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN) == false) {
+ if ((e_used == NULL) || (e_used != e_iter)) {
+ if (func(e_iter)) {
+ e_arr[i++] = e_iter;
+ if (i >= e_arr_len) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ return i;
+}
+
+static BMElem *edbm_add_edge_face_exec__tricky_extend_sel(BMesh *bm)
+{
+ BMIter iter;
+ bool found = false;
+
+ if (bm->totvertsel == 1 && bm->totedgesel == 0 && bm->totfacesel == 0) {
+ /* first look for 2 boundary edges */
+ BMVert *v;
+
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ BMEdge *ed_pair[3];
+ if (
+ ((edbm_add_edge_face_exec__vert_edge_lookup(v, NULL, ed_pair, 3, BM_edge_is_wire) == 2) &&
+ (BM_edge_share_face_check(ed_pair[0], ed_pair[1]) == false)) ||
+
+ ((edbm_add_edge_face_exec__vert_edge_lookup(v, NULL, ed_pair, 3, BM_edge_is_boundary) == 2) &&
+ (BM_edge_share_face_check(ed_pair[0], ed_pair[1]) == false))
+ )
+ {
+ BMEdge *e_other = BM_edge_exists(BM_edge_other_vert(ed_pair[0], v),
+ BM_edge_other_vert(ed_pair[1], v));
+ BM_edge_select_set(bm, ed_pair[0], true);
+ BM_edge_select_set(bm, ed_pair[1], true);
+ if (e_other) {
+ BM_edge_select_set(bm, e_other, true);
+ }
+ return (BMElem *)v;
+ }
+ }
+ }
+ else if (bm->totvertsel == 2 && bm->totedgesel == 1 && bm->totfacesel == 0) {
+ /* first look for 2 boundary edges */
+ BMEdge *e;
+
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ BMEdge *ed_pair_v1[2];
+ BMEdge *ed_pair_v2[2];
+ if (
+ ((edbm_add_edge_face_exec__vert_edge_lookup(e->v1, e, ed_pair_v1, 2, BM_edge_is_wire) == 1) &&
+ (edbm_add_edge_face_exec__vert_edge_lookup(e->v2, e, ed_pair_v2, 2, BM_edge_is_wire) == 1) &&
+ (BM_edge_share_face_check(e, ed_pair_v1[0]) == false) &&
+ (BM_edge_share_face_check(e, ed_pair_v2[0]) == false)) ||
+
+ ((edbm_add_edge_face_exec__vert_edge_lookup(e->v1, e, ed_pair_v1, 2, BM_edge_is_boundary) == 1) &&
+ (edbm_add_edge_face_exec__vert_edge_lookup(e->v2, e, ed_pair_v2, 2, BM_edge_is_boundary) == 1) &&
+ (BM_edge_share_face_check(e, ed_pair_v1[0]) == false) &&
+ (BM_edge_share_face_check(e, ed_pair_v2[0]) == false))
+ )
+ {
+ BMVert *v1_other = BM_edge_other_vert(ed_pair_v1[0], e->v1);
+ BMVert *v2_other = BM_edge_other_vert(ed_pair_v2[0], e->v2);
+ BMEdge *e_other = (v1_other != v2_other) ? BM_edge_exists(v1_other, v2_other) : NULL;
+ BM_edge_select_set(bm, ed_pair_v1[0], true);
+ BM_edge_select_set(bm, ed_pair_v2[0], true);
+ if (e_other) {
+ BM_edge_select_set(bm, e_other, true);
+ }
+ return (BMElem *)e;
+ }
+ }
+ }
+
+ return NULL;
+}
+static void edbm_add_edge_face_exec__tricky_finalize_sel(BMesh *bm, BMElem *ele_desel, BMFace *f)
+{
+ /* now we need to find the edge that isnt connected to this element */
+ BM_select_history_clear(bm);
+
+ if (ele_desel->head.htype == BM_VERT) {
+ BMLoop *l = BM_face_vert_share_loop(f, (BMVert *)ele_desel);
+ BLI_assert(f->len == 3);
+ BM_face_select_set(bm, f, false);
+ BM_vert_select_set(bm, (BMVert *)ele_desel, false);
+
+ BM_edge_select_set(bm, l->next->e, true);
+ BM_select_history_store(bm, l->next->e);
+ }
+ else {
+ BMLoop *l = BM_face_edge_share_loop(f, (BMEdge *)ele_desel);
+ BLI_assert(f->len == 4 || f->len == 3);
+ BM_face_select_set(bm, f, false);
+ BM_edge_select_set(bm, (BMEdge *)ele_desel, false);
+ if (f->len == 4) {
+ BM_edge_select_set(bm, l->next->next->e, true);
+ BM_select_history_store(bm, l->next->next->e);
+ }
+ else {
+ BM_vert_select_set(bm, l->next->next->v, true);
+ BM_select_history_store(bm, l->next->next->v);
+ }
+ }
+}
+#endif /* USE_FACE_CREATE_SEL_EXTEND */
+
static int edbm_add_edge_face_exec(bContext *C, wmOperator *op)
{
BMOperator bmop;
@@ -1107,6 +1240,15 @@ static int edbm_add_edge_face_exec(bContext *C, wmOperator *op)
const short use_smooth = edbm_add_edge_face__smooth_get(em->bm);
/* when this is used to dissolve we could avoid this, but checking isnt too slow */
+#ifdef USE_FACE_CREATE_SEL_EXTEND
+ BMElem *ele_desel;
+ BMFace *ele_desel_face;
+
+ /* be extra clever, figure out if a partial selection should be extended so we can create geometry
+ * with single vert or single edge selection */
+ ele_desel = edbm_add_edge_face_exec__tricky_extend_sel(em->bm);
+#endif
+
if (!EDBM_op_init(em, &bmop, op,
"contextual_create geom=%hfev mat_nr=%i use_smooth=%b",
BM_ELEM_SELECT, em->mat_nr, use_smooth))
@@ -1115,8 +1257,22 @@ static int edbm_add_edge_face_exec(bContext *C, wmOperator *op)
}
BMO_op_exec(em->bm, &bmop);
- BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, TRUE);
- BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, TRUE);
+
+#ifdef USE_FACE_CREATE_SEL_EXTEND
+ /* normally we would want to leave the new geometry selected,
+ * but being able to press F many times to add geometry is too useful! */
+ if (ele_desel &&
+ (BMO_slot_buffer_count(bmop.slots_out, "faces.out") == 1) &&
+ (ele_desel_face = BMO_slot_buffer_get_first(bmop.slots_out, "faces.out")))
+ {
+ edbm_add_edge_face_exec__tricky_finalize_sel(em->bm, ele_desel, ele_desel_face);
+ }
+ else
+#endif
+ {
+ BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
+ BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
+ }
if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
return OPERATOR_CANCELLED;
@@ -1355,7 +1511,7 @@ static int edbm_duplicate_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int edbm_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int edbm_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
WM_cursor_wait(1);
edbm_duplicate_exec(C, op);
@@ -2005,12 +2161,22 @@ static int merge_firstlast(BMEditMesh *em, int first, int uvmerge, wmOperator *w
BMVert *mergevert;
BMEditSelection *ese;
+ /* operator could be called directly from shortcut or python,
+ * so do extra check for data here
+ */
+
/* do sanity check in mergemenu in edit.c ?*/
if (first == 0) {
+ if (!em->bm->selected.last || ((BMEditSelection *)em->bm->selected.last)->htype != BM_VERT)
+ return OPERATOR_CANCELLED;
+
ese = em->bm->selected.last;
mergevert = (BMVert *)ese->ele;
}
else {
+ if (!em->bm->selected.first || ((BMEditSelection *)em->bm->selected.first)->htype != BM_VERT)
+ return OPERATOR_CANCELLED;
+
ese = em->bm->selected.first;
mergevert = (BMVert *)ese->ele;
}
@@ -2293,8 +2459,12 @@ static int edbm_select_vertex_path_exec(bContext *C, wmOperator *op)
if (!BM_elem_flag_test(eve, BM_ELEM_SELECT) || BM_elem_flag_test(eve, BM_ELEM_HIDDEN))
continue;
- if (svert == NULL) svert = eve;
- else if (evert == NULL) evert = eve;
+ if (svert == NULL) {
+ svert = eve;
+ }
+ else if (evert == NULL) {
+ evert = eve;
+ }
else {
/* more than two vertices are selected,
* show warning message and cancel operator */
@@ -3225,6 +3395,16 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
Base *base = CTX_data_active_base(C);
BMEditMesh *em = BMEdit_FromObject(base->object);
+ if (type == 0) {
+ if ((em->bm->totvertsel == 0) &&
+ (em->bm->totedgesel == 0) &&
+ (em->bm->totfacesel == 0))
+ {
+ BKE_report(op->reports, RPT_ERROR, "Nothing selected");
+ return OPERATOR_CANCELLED;
+ }
+ }
+
/* editmode separate */
if (type == 0) retval = mesh_separate_selected(bmain, scene, base, em->bm);
else if (type == 1) retval = mesh_separate_material(bmain, scene, base, em->bm);
@@ -3689,7 +3869,7 @@ static int edbm_spin_exec(bContext *C, wmOperator *op)
}
/* get center and axis, in global coords */
-static int edbm_spin_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int edbm_spin_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
@@ -3759,9 +3939,10 @@ static int edbm_screw_exec(bContext *C, wmOperator *op)
/* find two vertices with valence count == 1, more or less is wrong */
v1 = NULL;
v2 = NULL;
- for (eve = BM_iter_new(&iter, em->bm, BM_VERTS_OF_MESH, NULL); eve; eve = BM_iter_step(&iter)) {
+
+ BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
valence = 0;
- for (eed = BM_iter_new(&eiter, em->bm, BM_EDGES_OF_VERT, eve); eed; eed = BM_iter_step(&eiter)) {
+ BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) {
if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
valence++;
}
@@ -3812,7 +3993,7 @@ static int edbm_screw_exec(bContext *C, wmOperator *op)
}
/* get center and axis, in global coords */
-static int edbm_screw_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int edbm_screw_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
@@ -4505,7 +4686,7 @@ static int edbm_sort_elements_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop
int action = RNA_enum_get(ptr, "type");
/* Only show seed for randomize action! */
- if (strcmp(prop_id, "seed") == 0) {
+ if (STREQ(prop_id, "seed")) {
if (action == SRT_RANDOMIZE)
return TRUE;
else
@@ -4513,7 +4694,7 @@ static int edbm_sort_elements_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop
}
/* Hide seed for reverse and randomize actions! */
- if (strcmp(prop_id, "reverse") == 0) {
+ if (STREQ(prop_id, "reverse")) {
if (ELEM(action, SRT_RANDOMIZE, SRT_REVERSE))
return FALSE;
else
@@ -4804,7 +4985,7 @@ static int edbm_bevel_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int edbm_bevel_invoke(bContext *C, wmOperator *op, wmEvent *event)
+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);
@@ -4841,7 +5022,7 @@ static int edbm_bevel_invoke(bContext *C, wmOperator *op, wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
-static float edbm_bevel_mval_factor(wmOperator *op, wmEvent *event)
+static float edbm_bevel_mval_factor(wmOperator *op, const wmEvent *event)
{
BevelData *opdata = op->customdata;
int use_dist = TRUE;
@@ -4880,7 +5061,7 @@ static float edbm_bevel_mval_factor(wmOperator *op, wmEvent *event)
return factor;
}
-static int edbm_bevel_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
BevelData *opdata = op->customdata;
int segments = RNA_int_get(op->ptr, "segments");
@@ -5186,7 +5367,7 @@ static int edbm_inset_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int edbm_inset_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int edbm_inset_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
RegionView3D *rv3d = CTX_wm_region_view3d(C);
InsetData *opdata;
@@ -5216,7 +5397,7 @@ static int edbm_inset_invoke(bContext *C, wmOperator *op, wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
-static int edbm_inset_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int edbm_inset_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
InsetData *opdata = op->customdata;
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index 0c9a5aab537..99f526f95f3 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -36,6 +36,7 @@
#include "DNA_scene_types.h"
#include "DNA_view3d_types.h"
+#include "BLI_utildefines.h"
#include "BLI_path_util.h"
#include "BLI_array.h"
#include "BLI_math.h"
@@ -570,7 +571,7 @@ void MESH_OT_uv_texture_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-static int drop_named_image_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int drop_named_image_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
@@ -884,7 +885,7 @@ void ED_mesh_update(Mesh *mesh, bContext *C, int calc_edges, int calc_tessface)
}
if (calc_edges || ((mesh->totpoly || mesh->totface) && mesh->totedge == 0))
- BKE_mesh_calc_edges(mesh, calc_edges);
+ BKE_mesh_calc_edges(mesh, calc_edges, true);
if (calc_tessface) {
if (tessface_input == FALSE) {
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index fe4917acdac..5dab022dd2f 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -48,6 +48,7 @@ struct wmKeyConfig;
struct wmKeyMap;
struct wmOperator;
struct wmOperatorType;
+struct LinkNode;
/* ******************** editmesh_utils.c */
@@ -77,7 +78,6 @@ int EDBM_op_init(struct BMEditMesh *em, struct BMOperator *bmop,
int EDBM_op_finish(struct BMEditMesh *em, struct BMOperator *bmop,
struct wmOperator *op, const int report);
-void EDBM_flag_disable_all(struct BMEditMesh *em, const char hflag);
void EDBM_stats_update(struct BMEditMesh *em);
/* ******************** editface.c */
@@ -128,6 +128,7 @@ void MESH_OT_select_shortest_path(struct wmOperatorType *ot);
void MESH_OT_select_similar(struct wmOperatorType *ot);
void MESH_OT_select_mode(struct wmOperatorType *ot);
void MESH_OT_select_random(struct wmOperatorType *ot);
+void MESH_OT_select_ungrouped(struct wmOperatorType *ot);
void MESH_OT_loop_multi_select(struct wmOperatorType *ot);
void MESH_OT_mark_seam(struct wmOperatorType *ot);
void MESH_OT_mark_sharp(struct wmOperatorType *ot);
@@ -211,6 +212,8 @@ void MESH_OT_edgering_select(struct wmOperatorType *ot);
void MESH_OT_loopcut(struct wmOperatorType *ot);
void MESH_OT_knife_tool(struct wmOperatorType *ot);
+void MESH_OT_knife_project(wmOperatorType *ot);
+
void MESH_OT_bevel(struct wmOperatorType *ot);
void MESH_OT_bridge_edge_loops(struct wmOperatorType *ot);
@@ -228,4 +231,6 @@ void MESH_OT_navmesh_face_add(struct wmOperatorType *ot);
void MESH_OT_navmesh_reset(struct wmOperatorType *ot);
void MESH_OT_navmesh_clear(struct wmOperatorType *ot);
+void EDBM_mesh_knife(struct bContext *C, struct LinkNode *polys, bool use_tag);
+
#endif /* __MESH_INTERN_H__ */
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index 140681304b2..cf3877a8d93 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -59,6 +59,7 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_select_linked);
WM_operatortype_append(MESH_OT_select_linked_pick);
WM_operatortype_append(MESH_OT_select_random);
+ WM_operatortype_append(MESH_OT_select_ungrouped);
WM_operatortype_append(MESH_OT_hide);
WM_operatortype_append(MESH_OT_reveal);
WM_operatortype_append(MESH_OT_select_face_by_sides);
@@ -155,6 +156,7 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_select_nth);
WM_operatortype_append(MESH_OT_vert_connect);
WM_operatortype_append(MESH_OT_knife_tool);
+ WM_operatortype_append(MESH_OT_knife_project);
WM_operatortype_append(MESH_OT_bevel);
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index 378f6374336..3d4d204299f 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -789,7 +789,9 @@ static intptr_t mesh_octree_find_index(MocNode **bt, MVert *mvert, const float c
return (*bt)->index[a];
}
}
- else return -1;
+ else {
+ return -1;
+ }
}
if ( (*bt)->next)
return mesh_octree_find_index(&(*bt)->next, mvert, co);
diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c
index 6c056df5a38..6781624aec6 100644
--- a/source/blender/editors/metaball/mball_edit.c
+++ b/source/blender/editors/metaball/mball_edit.c
@@ -254,7 +254,7 @@ static int duplicate_metaelems_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-static int duplicate_metaelems_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int duplicate_metaelems_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
int retv = duplicate_metaelems_exec(C, op);
diff --git a/source/blender/editors/metaball/mball_ops.c b/source/blender/editors/metaball/mball_ops.c
index f91d57424a1..8c705aac0d2 100644
--- a/source/blender/editors/metaball/mball_ops.c
+++ b/source/blender/editors/metaball/mball_ops.c
@@ -28,17 +28,17 @@
* \ingroup edmeta
*/
+#include "BLI_utildefines.h"
+
#include "RNA_access.h"
+#include "WM_api.h"
+#include "WM_types.h"
+
#include "ED_mball.h"
#include "ED_screen.h"
#include "ED_object.h"
-#include "BLI_utildefines.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
#include "mball_intern.h"
void ED_operatortypes_metaball(void)
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 997cbb71683..dbb0d55a2b1 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -49,11 +49,13 @@
#include "DNA_vfont_types.h"
#include "DNA_actuator_types.h"
+#include "BLI_utildefines.h"
#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string.h"
-#include "BLI_utildefines.h"
+
+#include "BLF_translation.h"
#include "BKE_anim.h"
#include "BKE_animsys.h"
@@ -662,7 +664,9 @@ static int object_armature_add_exec(bContext *C, wmOperator *op)
ED_object_enter_editmode(C, 0);
newob = 1;
}
- else DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ else {
+ DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ }
if (obedit == NULL) {
BKE_report(op->reports, RPT_ERROR, "Cannot create editmode armature");
@@ -736,7 +740,7 @@ void OBJECT_OT_empty_add(wmOperatorType *ot)
ED_object_add_generic_props(ot, FALSE);
}
-static int empty_drop_named_image_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int empty_drop_named_image_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Base *base = NULL;
Image *ima = NULL;
@@ -872,6 +876,7 @@ void OBJECT_OT_lamp_add(wmOperatorType *ot)
/* properties */
ot->prop = RNA_def_enum(ot->srna, "type", lamp_type_items, 0, "Type", "");
+ RNA_def_property_translation_context(ot->prop, BLF_I18NCONTEXT_ID_LAMP);
ED_object_add_generic_props(ot, FALSE);
}
@@ -1482,7 +1487,7 @@ static int convert_exec(bContext *C, wmOperator *op)
newob = ob;
}
- BKE_mesh_from_curve(scene, newob);
+ BKE_mesh_to_curve(scene, newob);
if (newob->type == OB_CURVE)
BKE_object_free_modifiers(newob); /* after derivedmesh calls! */
diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c
index a680230fb32..dc54207b4e6 100644
--- a/source/blender/editors/object/object_bake.c
+++ b/source/blender/editors/object/object_bake.c
@@ -138,7 +138,9 @@ static int multiresbake_check(bContext *C, wmOperator *op)
}
}
}
- else ok = 0;
+ else {
+ ok = 0;
+ }
if (!ok) {
BKE_report(op->reports, RPT_ERROR, "Multires data baking requires multi-resolution object");
@@ -696,7 +698,7 @@ static void bake_freejob(void *bkv)
}
/* catch esc */
-static int objects_bake_render_modal(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
+static int objects_bake_render_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
/* no running blender, remove handler and pass through */
if (0 == WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C), WM_JOB_TYPE_OBJECT_BAKE_TEXTURE))
@@ -719,7 +721,7 @@ static int is_multires_bake(Scene *scene)
return 0;
}
-static int objects_bake_render_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(_event))
+static int objects_bake_render_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(_event))
{
Scene *scene = CTX_data_scene(C);
int result = OPERATOR_CANCELLED;
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index 1bed7d7dd11..8e2a87c7c64 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -435,7 +435,9 @@ static void test_constraints(Object *owner, bPoseChannel *pchan)
curcon->flag |= CONSTRAINT_DISABLE;
}
}
- else curcon->flag |= CONSTRAINT_DISABLE;
+ else {
+ curcon->flag |= CONSTRAINT_DISABLE;
+ }
}
}
else if (curcon->type == CONSTRAINT_TYPE_CAMERASOLVER) {
@@ -645,7 +647,7 @@ static int stretchto_reset_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int stretchto_reset_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int stretchto_reset_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (edit_constraint_invoke_properties(C, op))
return stretchto_reset_exec(C, op);
@@ -691,7 +693,7 @@ static int limitdistance_reset_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int limitdistance_reset_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int limitdistance_reset_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (edit_constraint_invoke_properties(C, op))
return limitdistance_reset_exec(C, op);
@@ -827,7 +829,7 @@ static int childof_set_inverse_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int childof_set_inverse_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int childof_set_inverse_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (edit_constraint_invoke_properties(C, op))
return childof_set_inverse_exec(C, op);
@@ -874,7 +876,7 @@ static int childof_clear_inverse_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int childof_clear_inverse_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int childof_clear_inverse_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (edit_constraint_invoke_properties(C, op))
return childof_clear_inverse_exec(C, op);
@@ -991,7 +993,7 @@ static int followpath_path_animate_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int followpath_path_animate_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int followpath_path_animate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
/* hook up invoke properties for figuring out which constraint we're dealing with */
if (edit_constraint_invoke_properties(C, op)) {
@@ -1049,7 +1051,7 @@ static int objectsolver_set_inverse_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int objectsolver_set_inverse_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int objectsolver_set_inverse_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (edit_constraint_invoke_properties(C, op))
return objectsolver_set_inverse_exec(C, op);
@@ -1095,7 +1097,7 @@ static int objectsolver_clear_inverse_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int objectsolver_clear_inverse_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int objectsolver_clear_inverse_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (edit_constraint_invoke_properties(C, op))
return objectsolver_clear_inverse_exec(C, op);
@@ -1231,7 +1233,7 @@ static int constraint_move_down_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
-static int constraint_move_down_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int constraint_move_down_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (edit_constraint_invoke_properties(C, op))
return constraint_move_down_exec(C, op);
@@ -1280,7 +1282,7 @@ static int constraint_move_up_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
-static int constraint_move_up_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int constraint_move_up_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (edit_constraint_invoke_properties(C, op))
return constraint_move_up_exec(C, op);
@@ -1848,7 +1850,7 @@ void POSE_OT_constraint_add_with_targets(wmOperatorType *ot)
// TODO: should these be here, or back in editors/armature/poseobject.c again?
/* present menu with options + validation for targets to use */
-static int pose_ik_add_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(evt))
+static int pose_ik_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
bPoseChannel *pchan = BKE_pose_channel_active(ob);
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index b94c9e940dc..ca57ab76c57 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -1012,7 +1012,7 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event)
DAG_relations_tag_update(bmain);
}
-static void UNUSED_FUNCTION(copy_attr_menu) (Main * bmain, Scene * scene, View3D * v3d)
+static void UNUSED_FUNCTION(copy_attr_menu) (Main *bmain, Scene *scene, View3D *v3d)
{
Object *ob;
short event;
@@ -1132,7 +1132,7 @@ void ED_objects_recalculate_paths(bContext *C, Scene *scene)
/* show popup to determine settings */
-static int object_calculate_paths_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int object_calculate_paths_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Object *ob = CTX_data_active_object(C);
@@ -1358,7 +1358,7 @@ void OBJECT_OT_shade_smooth(wmOperatorType *ot)
/* ********************** */
-static void UNUSED_FUNCTION(image_aspect) (Scene * scene, View3D * v3d)
+static void UNUSED_FUNCTION(image_aspect) (Scene *scene, View3D *v3d)
{
/* all selected objects with an image map: scale in image aspect */
Base *base;
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index a302aa65fd0..163a869613b 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -138,6 +138,7 @@ void OBJECT_OT_hook_recenter(struct wmOperatorType *ot);
/* object_lattice.c */
void LATTICE_OT_select_all(struct wmOperatorType *ot);
+void LATTICE_OT_select_ungrouped(struct wmOperatorType *ot);
void LATTICE_OT_make_regular(struct wmOperatorType *ot);
void LATTICE_OT_flip(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_lattice.c b/source/blender/editors/object/object_lattice.c
index c9eae776ac7..053f1ffabd0 100644
--- a/source/blender/editors/object/object_lattice.c
+++ b/source/blender/editors/object/object_lattice.c
@@ -53,6 +53,7 @@
#include "BKE_key.h"
#include "BKE_lattice.h"
#include "BKE_deform.h"
+#include "BKE_report.h"
#include "ED_lattice.h"
#include "ED_object.h"
@@ -255,6 +256,58 @@ void LATTICE_OT_select_all(wmOperatorType *ot)
WM_operator_properties_select_all(ot);
}
+/************************** Select Ungrouped Verts Operator *************************/
+
+static int lattice_select_ungrouped_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt;
+ MDeformVert *dv;
+ BPoint *bp;
+ int a, tot;
+
+ if (obedit->defbase.first == NULL || lt->dvert == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No weights/vertex groups on object");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!RNA_boolean_get(op->ptr, "extend")) {
+ ED_setflagsLatt(obedit, 0);
+ }
+
+ dv = lt->dvert;
+ tot = lt->pntsu * lt->pntsv * lt->pntsw;
+
+ for (a = 0, bp = lt->def; a < tot; a++, bp++, dv++) {
+ if (bp->hide == 0) {
+ if (dv->dw == NULL) {
+ bp->f1 |= SELECT;
+ }
+ }
+ }
+
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void LATTICE_OT_select_ungrouped(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Ungrouped";
+ ot->idname = "LATTICE_OT_select_ungrouped";
+ ot->description = "Select vertices without a group";
+
+ /* api callbacks */
+ ot->exec = lattice_select_ungrouped_exec;
+ ot->poll = ED_operator_editlattice;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
+}
+
/************************** Make Regular Operator *************************/
static int make_regular_poll(bContext *C)
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index 8d29813e2ac..d66620c2ff6 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -892,7 +892,7 @@ static int modifier_remove_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int modifier_remove_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int modifier_remove_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (edit_modifier_invoke_properties(C, op))
return modifier_remove_exec(C, op);
@@ -931,7 +931,7 @@ static int modifier_move_up_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int modifier_move_up_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int modifier_move_up_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (edit_modifier_invoke_properties(C, op))
return modifier_move_up_exec(C, op);
@@ -970,7 +970,7 @@ static int modifier_move_down_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int modifier_move_down_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int modifier_move_down_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (edit_modifier_invoke_properties(C, op))
return modifier_move_down_exec(C, op);
@@ -1012,7 +1012,7 @@ static int modifier_apply_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int modifier_apply_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int modifier_apply_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (edit_modifier_invoke_properties(C, op))
return modifier_apply_exec(C, op);
@@ -1061,7 +1061,7 @@ static int modifier_convert_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int modifier_convert_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int modifier_convert_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (edit_modifier_invoke_properties(C, op))
return modifier_convert_exec(C, op);
@@ -1100,7 +1100,7 @@ static int modifier_copy_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int modifier_copy_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int modifier_copy_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (edit_modifier_invoke_properties(C, op))
return modifier_copy_exec(C, op);
@@ -1149,7 +1149,7 @@ static int multires_higher_levels_delete_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int multires_higher_levels_delete_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int multires_higher_levels_delete_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (edit_modifier_invoke_properties(C, op))
return multires_higher_levels_delete_exec(C, op);
@@ -1199,7 +1199,7 @@ static int multires_subdivide_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int multires_subdivide_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int multires_subdivide_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (edit_modifier_invoke_properties(C, op))
return multires_subdivide_exec(C, op);
@@ -1263,7 +1263,7 @@ static int multires_reshape_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int multires_reshape_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int multires_reshape_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (edit_modifier_invoke_properties(C, op))
return multires_reshape_exec(C, op);
@@ -1314,7 +1314,7 @@ static int multires_external_save_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int multires_external_save_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int multires_external_save_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Object *ob = ED_object_active_context(C);
MultiresModifierData *mmd;
@@ -1410,7 +1410,7 @@ static int multires_base_apply_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int multires_base_apply_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int multires_base_apply_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (edit_modifier_invoke_properties(C, op))
return multires_base_apply_exec(C, op);
@@ -1834,7 +1834,7 @@ static int skin_armature_create_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int skin_armature_create_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int skin_armature_create_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (edit_modifier_invoke_properties(C, op))
return skin_armature_create_exec(C, op);
@@ -1927,7 +1927,7 @@ static int meshdeform_bind_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int meshdeform_bind_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int meshdeform_bind_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (edit_modifier_invoke_properties(C, op))
return meshdeform_bind_exec(C, op);
@@ -1975,7 +1975,7 @@ static int explode_refresh_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int explode_refresh_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int explode_refresh_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (edit_modifier_invoke_properties(C, op))
return explode_refresh_exec(C, op);
@@ -2191,7 +2191,7 @@ static int ocean_bake_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int ocean_bake_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int ocean_bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (edit_modifier_invoke_properties(C, op))
return ocean_bake_exec(C, op);
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index e5aaaffade8..594dfd6e271 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -211,6 +211,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_shape_key_move);
WM_operatortype_append(LATTICE_OT_select_all);
+ WM_operatortype_append(LATTICE_OT_select_ungrouped);
WM_operatortype_append(LATTICE_OT_make_regular);
WM_operatortype_append(LATTICE_OT_flip);
@@ -364,7 +365,7 @@ void ED_keymap_object(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "OBJECT_OT_delete", XKEY, KM_PRESS, KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "use_global", TRUE);
- WM_keymap_add_item(keymap, "OBJECT_OT_delete", DELKEY, KM_PRESS, 0, 0);
+ kmi = WM_keymap_add_item(keymap, "OBJECT_OT_delete", DELKEY, KM_PRESS, 0, 0);
RNA_boolean_set(kmi->ptr, "use_global", FALSE);
kmi = WM_keymap_add_item(keymap, "OBJECT_OT_delete", DELKEY, KM_PRESS, KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "use_global", TRUE);
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index f9dde043607..6039ff6d34b 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -215,7 +215,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
}
}
- if (v4 || !((v1 && v2 == 0 && v3 == 0) || (v1 && v2 && v3)) ) {
+ if (v4 || !((v1 && v2 == 0 && v3 == 0) || (v1 && v2 && v3))) {
BKE_report(op->reports, RPT_ERROR, "Select either 1 or 3 vertices to parent to");
return OPERATOR_CANCELLED;
}
@@ -286,7 +286,7 @@ void OBJECT_OT_vertex_parent_set(wmOperatorType *ot)
/********************** Make Proxy Operator *************************/
/* set the object to proxify */
-static int make_proxy_invoke(bContext *C, wmOperator *op, wmEvent *evt)
+static int make_proxy_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Scene *scene = CTX_data_scene(C);
Object *ob = ED_object_active_context(C);
@@ -299,7 +299,7 @@ static int make_proxy_invoke(bContext *C, wmOperator *op, wmEvent *evt)
if (ob->dup_group && ob->dup_group->id.lib) {
/* gives menu with list of objects in group */
//proxy_group_objects_menu(C, op, ob, ob->dup_group);
- WM_enum_search_invoke(C, op, evt);
+ WM_enum_search_invoke(C, op, event);
return OPERATOR_CANCELLED;
}
@@ -608,8 +608,10 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
cu->flag |= CU_PATH | CU_FOLLOW;
BKE_displist_make_curveTypes(scene, par, 0); /* force creation of path data */
}
- else cu->flag |= CU_FOLLOW;
-
+ else {
+ cu->flag |= CU_FOLLOW;
+ }
+
/* if follow, add F-Curve for ctime (i.e. "eval_time") so that path-follow works */
if (partype == PAR_FOLLOW) {
/* get or create F-Curve */
@@ -797,7 +799,7 @@ static int parent_set_exec(bContext *C, wmOperator *op)
}
-static int parent_set_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
+static int parent_set_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
{
Object *ob = ED_object_active_context(C);
uiPopupMenu *pup = uiPupMenuBegin(C, IFACE_("Set Parent To"), ICON_NONE);
@@ -1227,7 +1229,7 @@ static unsigned int move_to_layer_init(bContext *C, wmOperator *op)
return lay;
}
-static int move_to_layer_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int move_to_layer_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
View3D *v3d = CTX_wm_view3d(C);
if (v3d && v3d->localvd) {
@@ -1541,6 +1543,7 @@ static int make_links_data_exec(bContext *C, wmOperator *op)
DAG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, CTX_wm_view3d(C));
+ WM_event_add_notifier(C, NC_OBJECT, NULL);
return OPERATOR_FINISHED;
}
@@ -1928,11 +1931,11 @@ static void make_local_makelocalmaterial(Material *ma)
AnimData *adt;
int b;
- id_make_local(&ma->id, 0);
+ id_make_local(&ma->id, false);
for (b = 0; b < MAX_MTEX; b++)
if (ma->mtex[b] && ma->mtex[b]->tex)
- id_make_local(&ma->mtex[b]->tex->id, 0);
+ id_make_local(&ma->mtex[b]->tex->id, false);
adt = BKE_animdata_from_id(&ma->id);
if (adt) BKE_animdata_make_local(adt);
@@ -1958,7 +1961,7 @@ static int make_local_exec(bContext *C, wmOperator *op)
int a, b, mode = RNA_enum_get(op->ptr, "type");
if (mode == MAKE_LOCAL_ALL) {
- BKE_library_make_local(bmain, NULL, 0); /* NULL is all libs */
+ BKE_library_make_local(bmain, NULL, false); /* NULL is all libs */
WM_event_add_notifier(C, NC_WINDOW, NULL);
return OPERATOR_FINISHED;
}
@@ -1968,7 +1971,7 @@ static int make_local_exec(bContext *C, wmOperator *op)
CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
{
if (ob->id.lib)
- id_make_local(&ob->id, 0);
+ id_make_local(&ob->id, false);
}
CTX_DATA_END;
@@ -1986,7 +1989,7 @@ static int make_local_exec(bContext *C, wmOperator *op)
id = ob->data;
if (id && (ELEM(mode, MAKE_LOCAL_SELECT_OBDATA, MAKE_LOCAL_SELECT_OBDATA_MATERIAL))) {
- id_make_local(id, 0);
+ id_make_local(id, false);
adt = BKE_animdata_from_id(id);
if (adt) BKE_animdata_make_local(adt);
@@ -2002,7 +2005,7 @@ static int make_local_exec(bContext *C, wmOperator *op)
}
for (psys = ob->particlesystem.first; psys; psys = psys->next)
- id_make_local(&psys->part->id, 0);
+ id_make_local(&psys->part->id, false);
adt = BKE_animdata_from_id(&ob->id);
if (adt) BKE_animdata_make_local(adt);
@@ -2017,7 +2020,7 @@ static int make_local_exec(bContext *C, wmOperator *op)
for (b = 0; b < MAX_MTEX; b++)
if (la->mtex[b] && la->mtex[b]->tex)
- id_make_local(&la->mtex[b]->tex->id, 0);
+ id_make_local(&la->mtex[b]->tex->id, false);
}
else {
for (a = 0; a < ob->totcol; a++) {
@@ -2130,7 +2133,7 @@ void OBJECT_OT_make_single_user(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "animation", 0, "Object Animation", "Make animation data local to each object");
}
-static int drop_named_material_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int drop_named_material_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Base *base = ED_view3d_give_base_under_cursor(C, event->mval);
Material *ma;
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index 3fa6c301fcb..80d494a6a07 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -795,8 +795,8 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
if (centermode == ORIGIN_TO_CURSOR) { /* done */ }
else if (centermode == ORIGIN_TO_CENTER_OF_MASS) { BKE_mesh_center_centroid(me, cent); }
- else if (around == V3D_CENTROID) { BKE_mesh_center_median(me, cent); }
- else { BKE_mesh_center_bounds(me, cent); }
+ else if (around == V3D_CENTROID) { BKE_mesh_center_median(me, cent); }
+ else { BKE_mesh_center_bounds(me, cent); }
negate_v3_v3(cent_neg, cent);
BKE_mesh_translate(me, cent_neg, 1);
@@ -808,9 +808,9 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
Curve *cu = ob->data;
- if (centermode == ORIGIN_TO_CURSOR) { /* done */ }
+ if (centermode == ORIGIN_TO_CURSOR) { /* done */ }
else if (around == V3D_CENTROID) { BKE_curve_center_median(cu, cent); }
- else { BKE_curve_center_bounds(cu, cent); }
+ else { BKE_curve_center_bounds(cu, cent); }
/* don't allow Z change if curve is 2D */
if ((ob->type == OB_CURVE) && !(cu->flag & CU_3D))
@@ -889,9 +889,9 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
else if (ob->type == OB_MBALL) {
MetaBall *mb = ob->data;
- if (centermode == ORIGIN_TO_CURSOR) { /* done */ }
+ if (centermode == ORIGIN_TO_CURSOR) { /* done */ }
else if (around == V3D_CENTROID) { BKE_mball_center_median(mb, cent); }
- else { BKE_mball_center_bounds(mb, cent); }
+ else { BKE_mball_center_bounds(mb, cent); }
negate_v3_v3(cent_neg, cent);
BKE_mball_translate(mb, cent_neg);
@@ -910,9 +910,9 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
else if (ob->type == OB_LATTICE) {
Lattice *lt = ob->data;
- if (centermode == ORIGIN_TO_CURSOR) { /* done */ }
+ if (centermode == ORIGIN_TO_CURSOR) { /* done */ }
else if (around == V3D_CENTROID) { BKE_lattice_center_median(lt, cent); }
- else { BKE_lattice_center_bounds(lt, cent); }
+ else { BKE_lattice_center_bounds(lt, cent); }
negate_v3_v3(cent_neg, cent);
BKE_lattice_translate(lt, cent_neg, 1);
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index ef882b2486b..5abbb7124c0 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -1037,7 +1037,7 @@ static void vgroup_duplicate(Object *ob)
BLI_snprintf(name, sizeof(name), "%s_copy", dg->name);
}
else {
- BLI_snprintf(name, sizeof(name), "%s", dg->name);
+ BLI_strncpy(name, dg->name, sizeof(name));
}
cdg = defgroup_duplicate(dg);
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 31079de275e..329f1f67c4a 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -430,15 +430,6 @@ static int key_test_depth(PEData *data, const float co[3], const int screen_co[2
gluProject(co[0], co[1], co[2], data->mats.modelview, data->mats.projection,
(GLint *)data->mats.viewport, &ux, &uy, &uz);
-#if 0 /* works well but too slow on some systems [#23118] */
- screen_co[0] += (short)data->vc.ar->winrct.xmin;
- screen_co[1] += (short)data->vc.ar->winrct.ymin;
-
- /* PE_set_view3d_data calls this. no need to call here */
- /* view3d_validate_backbuf(&data->vc); */
- glReadPixels(screen_co[0], screen_co[1], 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
-#else /* faster to use depths, these are calculated in PE_set_view3d_data */
-
/* check if screen_co is within bounds because brush_cut uses out of screen coords */
if (screen_co[0] >= 0 && screen_co[0] < vd->w && screen_co[1] >= 0 && screen_co[1] < vd->h) {
BLI_assert(vd && vd->depths);
@@ -447,7 +438,6 @@ static int key_test_depth(PEData *data, const float co[3], const int screen_co[2
}
else
return 0;
-#endif
if ((float)uz - 0.00001f > depth)
return 0;
@@ -1555,7 +1545,7 @@ static int select_linked_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int select_linked_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int select_linked_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
RNA_int_set_array(op->ptr, "location", event->mval);
return select_linked_exec(C, op);
@@ -3476,6 +3466,7 @@ typedef struct BrushEdit {
int first;
int lastmouse[2];
+ float zfac;
/* optional cached view settings to avoid setting on every mousemove */
PEData data;
@@ -3498,7 +3489,6 @@ static int brush_edit_init(bContext *C, wmOperator *op)
INIT_MINMAX(min, max);
PE_minmax(scene, min, max);
mid_v3_v3v3(min, min, max);
- initgrabz(ar->regiondata, min[0], min[1], min[2]);
bedit= MEM_callocN(sizeof(BrushEdit), "BrushEdit");
bedit->first= 1;
@@ -3508,6 +3498,8 @@ static int brush_edit_init(bContext *C, wmOperator *op)
bedit->ob= ob;
bedit->edit= edit;
+ bedit->zfac = ED_view3d_calc_zfac(ar->regiondata, min, NULL);
+
/* cache view depths and settings for re-use */
PE_set_view3d_data(C, &bedit->data);
@@ -3587,7 +3579,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
invert_m4_m4(ob->imat, ob->obmat);
- ED_view3d_win_to_delta(ar, mval_f, vec);
+ ED_view3d_win_to_delta(ar, mval_f, vec, bedit->zfac);
data.dvec= vec;
foreach_mouse_hit_key(&data, brush_comb, selected);
@@ -3757,7 +3749,7 @@ static int brush_edit_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static void brush_edit_apply_event(bContext *C, wmOperator *op, wmEvent *event)
+static void brush_edit_apply_event(bContext *C, wmOperator *op, const wmEvent *event)
{
PointerRNA itemptr;
float mouse[2];
@@ -3774,7 +3766,7 @@ static void brush_edit_apply_event(bContext *C, wmOperator *op, wmEvent *event)
brush_edit_apply(C, op, &itemptr);
}
-static int brush_edit_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int brush_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (!brush_edit_init(C, op))
return OPERATOR_CANCELLED;
@@ -3786,7 +3778,7 @@ static int brush_edit_invoke(bContext *C, wmOperator *op, wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
-static int brush_edit_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int brush_edit_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
switch (event->type) {
case LEFTMOUSE:
diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c
index fc55b2b5915..df723b06259 100644
--- a/source/blender/editors/physics/physics_fluid.c
+++ b/source/blender/editors/physics/physics_fluid.c
@@ -679,18 +679,15 @@ static int fluid_init_filepaths(Object *fsDomain, char *targetDir, char *targetF
if (fileCfg) {
dirExist = 1; fclose(fileCfg);
// remove cfg dummy from directory test
- BLI_delete(targetFile, 0, 0);
+ BLI_delete(targetFile, false, false);
}
if (targetDir[0] == '\0' || (!dirExist)) {
- char blendDir[FILE_MAX];
char blendFile[FILE_MAX];
// invalid dir, reset to current/previous
- BLI_strncpy(blendDir, G.main->name, FILE_MAX);
- BLI_splitdirstring(blendDir, blendFile);
+ BLI_split_file_part(G.main->name, blendFile, sizeof(blendFile));
BLI_replace_extension(blendFile, FILE_MAX, ""); /* strip .blend */
-
BLI_snprintf(newSurfdataPath, FILE_MAX, "//fluidsimdata/%s_%s_", blendFile, fsDomain->id.name);
BLI_snprintf(debugStrBuffer, 256, "fluidsimBake::error - warning resetting output dir to '%s'\n", newSurfdataPath);
@@ -852,9 +849,9 @@ static void fluidsim_delete_until_lastframe(FluidsimSettings *fss, const char *r
curFrame++;
if ((exists = BLI_exists(targetFile))) {
- BLI_delete(targetFile, 0, 0);
- BLI_delete(targetFileVel, 0, 0);
- BLI_delete(previewFile, 0, 0);
+ BLI_delete(targetFile, false, false);
+ BLI_delete(targetFileVel, false, false);
+ BLI_delete(previewFile, false, false);
}
} while (exists);
@@ -1130,7 +1127,7 @@ static int fluidsimBake(bContext *UNUSED(C), ReportList *UNUSED(reports), Object
/***************************** Operators ******************************/
-static int fluid_bake_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int fluid_bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
/* only one bake job at a time */
if (WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C), WM_JOB_TYPE_OBJECT_SIM_FLUID))
diff --git a/source/blender/editors/physics/physics_ops.c b/source/blender/editors/physics/physics_ops.c
index 51a66886c6e..2ede7047b74 100644
--- a/source/blender/editors/physics/physics_ops.c
+++ b/source/blender/editors/physics/physics_ops.c
@@ -27,9 +27,9 @@
* \ingroup edphys
*/
-
#include <stdlib.h>
+#include "BLI_utildefines.h"
#include "RNA_access.h"
@@ -39,8 +39,6 @@
#include "ED_physics.h"
#include "ED_object.h"
-#include "BLI_utildefines.h"
-
#include "physics_intern.h" // own include
diff --git a/source/blender/editors/physics/rigidbody_object.c b/source/blender/editors/physics/rigidbody_object.c
index 6bcdf6e07aa..9c03c6173a5 100644
--- a/source/blender/editors/physics/rigidbody_object.c
+++ b/source/blender/editors/physics/rigidbody_object.c
@@ -44,6 +44,8 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLF_translation.h"
+
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_global.h"
@@ -374,61 +376,61 @@ typedef struct rbMaterialDensityItem {
* 3) http://www.avlandesign.com/density_metal.htm
*/
static rbMaterialDensityItem RB_MATERIAL_DENSITY_TABLE[] = {
- {"Air", 1.0f}, /* not quite; adapted from 1.43 for oxygen for use as default */
- {"Acrylic", 1400.0f},
- {"Asphalt (Crushed)", 721.0f},
- {"Bark", 240.0f},
- {"Beans (Cocoa)", 593.0f},
- {"Beans (Soy)", 721.0f},
- {"Brick (Pressed)", 2400.0f},
- {"Brick (Common)", 2000.0f},
- {"Brick (Soft)", 1600.0f},
- {"Brass", 8216.0f},
- {"Bronze", 8860.0f},
- {"Carbon (Solid)", 2146.0f},
- {"Cardboard", 689.0f},
- {"Cast Iron", 7150.0f},
- //{"Cement", 1442.0f},
- {"Chalk (Solid)", 2499.0f},
- //{"Coffee (Fresh/Roast)", ~500},
- {"Concrete", 2320.0f},
- {"Charcoal", 208.0f},
- {"Cork", 240.0f},
- {"Copper", 8933.0f},
- {"Garbage", 481.0f},
- {"Glass (Broken)", 1940.0f},
- {"Glass (Solid)", 2190.0f},
- {"Gold", 19282.0f},
- {"Granite (Broken)", 1650.0f},
- {"Granite (Solid)", 2691.0f},
- {"Gravel", 2780.0f},
- {"Ice (Crushed)", 593.0f},
- {"Ice (Solid)", 919.0f},
- {"Iron", 7874.0f},
- {"Lead", 11342.0f},
- {"Limestone (Broken)", 1554.0f},
- {"Limestone (Solid)", 2611.0f},
- {"Marble (Broken)", 1570.0f},
- {"Marble (Solid)", 2563.0f},
- {"Paper", 1201.0f},
- {"Peanuts (Shelled)", 641.0f},
- {"Peanuts (Not Shelled)", 272.0f},
- {"Plaster", 849.0f},
- {"Plastic", 1200.0f},
- {"Polystyrene", 1050.0f},
- {"Rubber", 1522.0f},
- {"Silver", 10501.0f},
- {"Steel", 7860.0f},
- {"Stone", 2515.0f},
- {"Stone (Crushed)", 1602.0f},
- {"Timber", 610.0f}
+ {N_("Air"), 1.0f}, /* not quite; adapted from 1.43 for oxygen for use as default */
+ {N_("Acrylic"), 1400.0f},
+ {N_("Asphalt (Crushed)"), 721.0f},
+ {N_("Bark"), 240.0f},
+ {N_("Beans (Cocoa)"), 593.0f},
+ {N_("Beans (Soy)"), 721.0f},
+ {N_("Brick (Pressed)"), 2400.0f},
+ {N_("Brick (Common)"), 2000.0f},
+ {N_("Brick (Soft)"), 1600.0f},
+ {N_("Brass"), 8216.0f},
+ {N_("Bronze"), 8860.0f},
+ {N_("Carbon (Solid)"), 2146.0f},
+ {N_("Cardboard"), 689.0f},
+ {N_("Cast Iron"), 7150.0f},
+ /* {N_("Cement"), 1442.0f}, */
+ {N_("Chalk (Solid)"), 2499.0f},
+ /* {N_("Coffee (Fresh/Roast)"), ~500}, */
+ {N_("Concrete"), 2320.0f},
+ {N_("Charcoal"), 208.0f},
+ {N_("Cork"), 240.0f},
+ {N_("Copper"), 8933.0f},
+ {N_("Garbage"), 481.0f},
+ {N_("Glass (Broken)"), 1940.0f},
+ {N_("Glass (Solid)"), 2190.0f},
+ {N_("Gold"), 19282.0f},
+ {N_("Granite (Broken)"), 1650.0f},
+ {N_("Granite (Solid)"), 2691.0f},
+ {N_("Gravel"), 2780.0f},
+ {N_("Ice (Crushed)"), 593.0f},
+ {N_("Ice (Solid)"), 919.0f},
+ {N_("Iron"), 7874.0f},
+ {N_("Lead"), 11342.0f},
+ {N_("Limestone (Broken)"), 1554.0f},
+ {N_("Limestone (Solid)"), 2611.0f},
+ {N_("Marble (Broken)"), 1570.0f},
+ {N_("Marble (Solid)"), 2563.0f},
+ {N_("Paper"), 1201.0f},
+ {N_("Peanuts (Shelled)"), 641.0f},
+ {N_("Peanuts (Not Shelled)"), 272.0f},
+ {N_("Plaster"), 849.0f},
+ {N_("Plastic"), 1200.0f},
+ {N_("Polystyrene"), 1050.0f},
+ {N_("Rubber"), 1522.0f},
+ {N_("Silver"), 10501.0f},
+ {N_("Steel"), 7860.0f},
+ {N_("Stone"), 2515.0f},
+ {N_("Stone (Crushed)"), 1602.0f},
+ {N_("Timber"), 610.0f}
};
static const int NUM_RB_MATERIAL_PRESETS = sizeof(RB_MATERIAL_DENSITY_TABLE) / sizeof(rbMaterialDensityItem);
/* dynamically generate list of items
* - Although there is a runtime cost, this has a lower maintenance cost
- * in the long run than other two-list solutions...
+ * in the long run than other two-list solutions...
*/
static EnumPropertyItem *rigidbody_materials_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
{
@@ -441,14 +443,16 @@ static EnumPropertyItem *rigidbody_materials_itemf(bContext *UNUSED(C), PointerR
for (i = 0; i < NUM_RB_MATERIAL_PRESETS; i++) {
rbMaterialDensityItem *preset = &RB_MATERIAL_DENSITY_TABLE[i];
- item_tmp.identifier = item_tmp.name = preset->name;
+ item_tmp.identifier = preset->name;
+ item_tmp.name = IFACE_(preset->name);
item_tmp.value = i;
RNA_enum_item_add(&item, &totitem, &item_tmp);
}
/* add special "custom" entry to the end of the list */
{
- item_tmp.identifier = item_tmp.name = "Custom";
+ item_tmp.identifier = "Custom";
+ item_tmp.name = IFACE_("Custom");
item_tmp.value = -1;
RNA_enum_item_add(&item, &totitem, &item_tmp);
}
diff --git a/source/blender/editors/physics/rigidbody_world.c b/source/blender/editors/physics/rigidbody_world.c
index babe32c74b2..b7430cb8a95 100644
--- a/source/blender/editors/physics/rigidbody_world.c
+++ b/source/blender/editors/physics/rigidbody_world.c
@@ -175,7 +175,7 @@ static int rigidbody_world_export_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int rigidbody_world_export_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(evt))
+static int rigidbody_world_export_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (!RNA_struct_property_is_set(op->ptr, "relative_path"))
RNA_boolean_set(op->ptr, "relative_path", (U.flag & USER_RELPATHS));
diff --git a/source/blender/editors/render/SConscript b/source/blender/editors/render/SConscript
index 9d1de2fc700..25af8080d51 100644
--- a/source/blender/editors/render/SConscript
+++ b/source/blender/editors/render/SConscript
@@ -33,7 +33,7 @@ incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
incs += ' ../../gpu'
incs += ' ../../makesrna ../../render/extern/include #/intern/elbeem/extern'
-incs += ' ../../blenloader ../../bmesh'
+incs += ' ../../blenloader ../../bmesh ../../blenfont'
if env['OURPLATFORM'] == 'linux':
cflags='-pthread'
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index deb6eaf2c22..b138bc63a68 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -39,6 +39,8 @@
#include "BLI_rand.h"
#include "BLI_utildefines.h"
+#include "BLF_translation.h"
+
#include "DNA_scene_types.h"
#include "BKE_blender.h"
@@ -281,38 +283,39 @@ static void make_renderinfo_string(RenderStats *rs, Scene *scene, char *str)
megs_peak_memory = (peak_memory) / (1024.0 * 1024.0);
if (scene->lay & 0xFF000000)
- spos += sprintf(spos, "Localview | ");
+ spos += sprintf(spos, IFACE_("Localview | "));
else if (scene->r.scemode & R_SINGLE_LAYER)
- spos += sprintf(spos, "Single Layer | ");
+ spos += sprintf(spos, IFACE_("Single Layer | "));
- spos += sprintf(spos, "Frame:%d ", (scene->r.cfra));
+ spos += sprintf(spos, IFACE_("Frame:%d "), (scene->r.cfra));
if (rs->statstr) {
spos += sprintf(spos, "| %s ", rs->statstr);
}
else {
- if (rs->totvert) spos += sprintf(spos, "Ve:%d ", rs->totvert);
- if (rs->totface) spos += sprintf(spos, "Fa:%d ", rs->totface);
- if (rs->tothalo) spos += sprintf(spos, "Ha:%d ", rs->tothalo);
- if (rs->totstrand) spos += sprintf(spos, "St:%d ", rs->totstrand);
- if (rs->totlamp) spos += sprintf(spos, "La:%d ", rs->totlamp);
+ if (rs->totvert) spos += sprintf(spos, IFACE_("Ve:%d "), rs->totvert);
+ if (rs->totface) spos += sprintf(spos, IFACE_("Fa:%d "), rs->totface);
+ if (rs->tothalo) spos += sprintf(spos, IFACE_("Ha:%d "), rs->tothalo);
+ if (rs->totstrand) spos += sprintf(spos, IFACE_("St:%d "), rs->totstrand);
+ if (rs->totlamp) spos += sprintf(spos, IFACE_("La:%d "), rs->totlamp);
if (rs->mem_peak == 0.0f)
- spos += sprintf(spos, "Mem:%.2fM (%.2fM, peak %.2fM) ", megs_used_memory, mmap_used_memory, megs_peak_memory);
+ spos += sprintf(spos, IFACE_("Mem:%.2fM (%.2fM, Peak %.2fM) "),
+ megs_used_memory, mmap_used_memory, megs_peak_memory);
else
- spos += sprintf(spos, "Mem:%.2fM, Peak: %.2fM ", rs->mem_used, rs->mem_peak);
+ spos += sprintf(spos, IFACE_("Mem:%.2fM, Peak: %.2fM "), rs->mem_used, rs->mem_peak);
if (rs->curfield)
- spos += sprintf(spos, "Field %d ", rs->curfield);
+ spos += sprintf(spos, IFACE_("Field %d "), rs->curfield);
if (rs->curblur)
- spos += sprintf(spos, "Blur %d ", rs->curblur);
+ spos += sprintf(spos, IFACE_("Blur %d "), rs->curblur);
}
BLI_timestr(rs->lastframetime, info_time_str);
- spos += sprintf(spos, "Time:%s ", info_time_str);
+ spos += sprintf(spos, IFACE_("Time:%s "), info_time_str);
if (rs->curfsa)
- spos += sprintf(spos, "| Full Sample %d ", rs->curfsa);
+ spos += sprintf(spos, IFACE_("| Full Sample %d "), rs->curfsa);
if (rs->infostr && rs->infostr[0])
spos += sprintf(spos, "| %s ", rs->infostr);
@@ -462,7 +465,7 @@ static void render_drawlock(void *UNUSED(rjv), int lock)
}
/* catch esc */
-static int screen_render_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int screen_render_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
Scene *scene = (Scene *) op->customdata;
@@ -481,7 +484,7 @@ static int screen_render_modal(bContext *C, wmOperator *op, wmEvent *event)
}
/* using context, starts job */
-static int screen_render_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
/* new render clears all callbacks */
Main *mainp;
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index ea18f2c8fbb..f47d737beca 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.c
@@ -638,7 +638,7 @@ static int screen_opengl_render_anim_step(bContext *C, wmOperator *op)
}
-static int screen_opengl_render_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
OGLRender *oglrender = op->customdata;
int anim = RNA_boolean_get(op->ptr, "animation");
@@ -677,7 +677,7 @@ static int screen_opengl_render_modal(bContext *C, wmOperator *op, wmEvent *even
return OPERATOR_RUNNING_MODAL;
}
-static int screen_opengl_render_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int screen_opengl_render_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
OGLRender *oglrender;
int anim = RNA_boolean_get(op->ptr, "animation");
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index dfc80e4cf51..7802e5460ff 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -110,7 +110,7 @@ ImBuf *get_brush_icon(Brush *brush)
static const int flags = IB_rect | IB_multilayer | IB_metadata;
char path[FILE_MAX];
- char *folder;
+ const char *folder;
if (!(brush->icon_imbuf)) {
if (brush->flag & BRUSH_CUSTOM_ICON) {
@@ -188,8 +188,8 @@ typedef struct IconPreview {
/* *************************** Preview for buttons *********************** */
-static Main *pr_main = NULL;
-static Main *pr_main_cycles = NULL;
+static Main *G_pr_main = NULL;
+static Main *G_pr_main_cycles = NULL;
#ifndef WITH_HEADLESS
static Main *load_main_from_memory(char *blend, int blend_size)
@@ -214,18 +214,18 @@ static Main *load_main_from_memory(char *blend, int blend_size)
void ED_preview_init_dbase(void)
{
#ifndef WITH_HEADLESS
- pr_main = load_main_from_memory(datatoc_preview_blend, datatoc_preview_blend_size);
- pr_main_cycles = load_main_from_memory(datatoc_preview_cycles_blend, datatoc_preview_cycles_blend_size);
+ G_pr_main = load_main_from_memory(datatoc_preview_blend, datatoc_preview_blend_size);
+ G_pr_main_cycles = load_main_from_memory(datatoc_preview_cycles_blend, datatoc_preview_cycles_blend_size);
#endif
}
void ED_preview_free_dbase(void)
{
- if (pr_main)
- free_main(pr_main);
+ if (G_pr_main)
+ free_main(G_pr_main);
- if (pr_main_cycles)
- free_main(pr_main_cycles);
+ if (G_pr_main_cycles)
+ free_main(G_pr_main_cycles);
}
static int preview_mat_has_sss(Material *mat, bNodeTree *ntree)
@@ -425,15 +425,16 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre
if (tex && sp->slot)
mat->mtex[0]->which_output = sp->slot->which_output;
-
+
+ mat->mtex[0]->mapto &= ~MAP_ALPHA;
+ mat->alpha = 1.0f;
+
/* show alpha in this case */
if (tex == NULL || (tex->flag & TEX_PRV_ALPHA)) {
- mat->mtex[0]->mapto |= MAP_ALPHA;
- mat->alpha = 0.0f;
- }
- else {
- mat->mtex[0]->mapto &= ~MAP_ALPHA;
- mat->alpha = 1.0f;
+ if (!(tex && tex->type == TEX_IMAGE && (tex->imaflag & (TEX_USEALPHA | TEX_CALCALPHA)) == 0)) {
+ mat->mtex[0]->mapto |= MAP_ALPHA;
+ mat->alpha = 0.0f;
+ }
}
}
}
@@ -670,8 +671,10 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs
if (first) sizex = sp->sizex / 2;
else sizex = sp->sizex - sp->sizex / 2;
}
- else sizex = sp->sizex;
-
+ else {
+ sizex = sp->sizex;
+ }
+
/* we have to set preview variables first */
sce = preview_get_scene(pr_main);
if (sce) {
@@ -1025,7 +1028,7 @@ static void icon_preview_startjob_all_sizes(void *customdata, short *stop, short
sp->pr_method = PR_ICON_RENDER;
sp->pr_rect = cur_size->rect;
sp->id = ip->id;
- sp->pr_main = pr_main;
+ sp->pr_main = G_pr_main;
common_preview_startjob(sp, stop, do_update, progress);
shader_preview_free(sp);
@@ -1128,9 +1131,9 @@ void ED_preview_shader_job(const bContext *C, void *owner, ID *id, ID *parent, M
/* hardcoded preview .blend for cycles/internal, this should be solved
* once with custom preview .blend path for external engines */
if (BKE_scene_use_new_shading_nodes(scene))
- sp->pr_main = pr_main_cycles;
+ sp->pr_main = G_pr_main_cycles;
else
- sp->pr_main = pr_main;
+ sp->pr_main = G_pr_main;
if (ob && ob->totcol) copy_v4_v4(sp->col, ob->col);
else sp->col[0] = sp->col[1] = sp->col[2] = sp->col[3] = 1.0f;
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index aa1edb1c1b1..decc5b131ae 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -1327,7 +1327,7 @@ static int envmap_save_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int envmap_save_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int envmap_save_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
//Scene *scene= CTX_data_scene(C);
diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c
index 16d7923baff..a467b053443 100644
--- a/source/blender/editors/render/render_update.c
+++ b/source/blender/editors/render/render_update.c
@@ -394,8 +394,6 @@ static void texture_changed(Main *bmain, Tex *tex)
if (dm && totmaterial && material) {
for (a = 0; a < *totmaterial; a++) {
- Material *ma;
-
if (ob->matbits && ob->matbits[a])
ma = ob->mat[a];
else
diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.c
index 8b2ac740e47..186d0d20623 100644
--- a/source/blender/editors/render/render_view.c
+++ b/source/blender/editors/render/render_view.c
@@ -275,7 +275,7 @@ void RENDER_OT_view_cancel(struct wmOperatorType *ot)
/************************* show render viewer *****************/
-static int render_view_show_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
+static int render_view_show_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
wmWindow *wincur = CTX_wm_window(C);
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 1b7cd4a6d20..2d6e8d0ada0 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -67,6 +67,8 @@
#include "screen_intern.h"
+extern void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3); /* xxx temp */
+
/* general area and region code */
static void region_draw_emboss(ARegion *ar, rcti *scirct)
@@ -245,8 +247,6 @@ static void draw_azone_plus(float x1, float y1, float x2, float y2)
static void region_draw_azone_tab_plus(AZone *az)
{
- extern void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3); /* xxx temp */
-
glEnable(GL_BLEND);
/* add code to draw region hidden as 'too small' */
@@ -321,8 +321,6 @@ static void region_draw_azone_tab(AZone *az)
static void region_draw_azone_tria(AZone *az)
{
- extern void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3); /* xxx temp */
-
glEnable(GL_BLEND);
//UI_GetThemeColor3fv(TH_HEADER, col);
glColor4f(0.0f, 0.0f, 0.0f, 0.35f);
@@ -590,7 +588,7 @@ static void area_azone_initialize(bScreen *screen, ScrArea *sa)
BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2);
}
-#define AZONEPAD_EDGE (0.2f * U.widget_unit)
+#define AZONEPAD_EDGE (0.1f * U.widget_unit)
#define AZONEPAD_ICON (0.45f * U.widget_unit)
static void region_azone_edge(AZone *az, ARegion *ar)
{
@@ -599,22 +597,22 @@ static void region_azone_edge(AZone *az, ARegion *ar)
az->x1 = ar->winrct.xmin;
az->y1 = ar->winrct.ymax - AZONEPAD_EDGE;
az->x2 = ar->winrct.xmax;
- az->y2 = ar->winrct.ymax;
+ az->y2 = ar->winrct.ymax + AZONEPAD_EDGE;
break;
case AE_BOTTOM_TO_TOPLEFT:
az->x1 = ar->winrct.xmin;
az->y1 = ar->winrct.ymin + AZONEPAD_EDGE;
az->x2 = ar->winrct.xmax;
- az->y2 = ar->winrct.ymin;
+ az->y2 = ar->winrct.ymin - AZONEPAD_EDGE;
break;
case AE_LEFT_TO_TOPRIGHT:
- az->x1 = ar->winrct.xmin;
+ az->x1 = ar->winrct.xmin - AZONEPAD_EDGE;
az->y1 = ar->winrct.ymin;
az->x2 = ar->winrct.xmin + AZONEPAD_EDGE;
az->y2 = ar->winrct.ymax;
break;
case AE_RIGHT_TO_TOPLEFT:
- az->x1 = ar->winrct.xmax;
+ az->x1 = ar->winrct.xmax + AZONEPAD_EDGE;
az->y1 = ar->winrct.ymin;
az->x2 = ar->winrct.xmax - AZONEPAD_EDGE;
az->y2 = ar->winrct.ymax;
@@ -1071,7 +1069,9 @@ static void region_rect_recursive(wmWindow *win, ScrArea *sa, ARegion *ar, rcti
if (G.debug & G_DEBUG)
printf("region quadsplit failed\n");
}
- else quad = 1;
+ else {
+ quad = 1;
+ }
}
if (quad) {
if (quad == 1) { /* left bottom */
@@ -1746,7 +1746,9 @@ void ED_region_panels(const bContext *C, ARegion *ar, int vertical, const char *
/* uiScalePanels(ar, BLI_rctf_size_x(&v2d->cur));
break; */
}
- else break;
+ else {
+ break;
+ }
}
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index 105c2dc88d1..8501b53afae 100644
--- a/source/blender/editors/screen/glutil.c
+++ b/source/blender/editors/screen/glutil.c
@@ -482,7 +482,7 @@ static int get_cached_work_texture(int *w_r, int *h_r)
return texid;
}
-void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, void *rect, float scaleX, float scaleY)
+void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, int zoomfilter, void *rect, float scaleX, float scaleY)
{
unsigned char *uc_rect = (unsigned char *) rect;
float *f_rect = (float *)rect;
@@ -503,6 +503,7 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format,
/* don't want nasty border artifacts */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, zoomfilter);
#ifdef __APPLE__
/* workaround for os x 10.5/10.6 driver bug: http://lists.apple.com/archives/Mac-opengl/2008/Jul/msg00117.html */
@@ -560,10 +561,10 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format,
glEnable(GL_TEXTURE_2D);
glBegin(GL_QUADS);
glTexCoord2f((float)(0 + offset_left) / tex_w, (float)(0 + offset_bot) / tex_h);
- glVertex2f(rast_x + (float)offset_left * xzoom, rast_y + (float)offset_bot * xzoom);
+ glVertex2f(rast_x + (float)offset_left * xzoom, rast_y + (float)offset_bot * yzoom);
glTexCoord2f((float)(subpart_w - offset_right) / tex_w, (float)(0 + offset_bot) / tex_h);
- glVertex2f(rast_x + (float)(subpart_w - offset_right) * xzoom * scaleX, rast_y + (float)offset_bot * xzoom);
+ glVertex2f(rast_x + (float)(subpart_w - offset_right) * xzoom * scaleX, rast_y + (float)offset_bot * yzoom);
glTexCoord2f((float)(subpart_w - offset_right) / tex_w, (float)(subpart_h - offset_top) / tex_h);
glVertex2f(rast_x + (float)(subpart_w - offset_right) * xzoom * scaleX, rast_y + (float)(subpart_h - offset_top) * yzoom * scaleY);
@@ -585,9 +586,9 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format,
#endif
}
-void glaDrawPixelsTex(float x, float y, int img_w, int img_h, int format, void *rect)
+void glaDrawPixelsTex(float x, float y, int img_w, int img_h, int format, int zoomfilter, void *rect)
{
- glaDrawPixelsTexScaled(x, y, img_w, img_h, format, rect, 1.0f, 1.0f);
+ glaDrawPixelsTexScaled(x, y, img_w, img_h, format, zoomfilter, rect, 1.0f, 1.0f);
}
void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int format, int type, void *rect)
@@ -669,6 +670,22 @@ void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int fo
}
}
+/* uses either DrawPixelsSafe or DrawPixelsTex, based on user defined maximum */
+void glaDrawPixelsAuto(float x, float y, int img_w, int img_h, int format, int zoomfilter, void *rect)
+{
+ if (U.image_gpubuffer_limit) {
+ /* Megapixels, use float math to prevent overflow */
+ float img_size = ((float)img_w * (float)img_h) / (1024.0f * 1024.0f);
+
+ if (U.image_gpubuffer_limit > (int)img_size) {
+ glColor4f(1.0, 1.0, 1.0, 1.0);
+ glaDrawPixelsTex(x, y, img_w, img_h, format, zoomfilter, rect);
+ return;
+ }
+ }
+ glaDrawPixelsSafe(x, y, img_w, img_h, img_w, GL_RGBA, format, rect);
+}
+
/* 2D Drawing Assistance */
void glaDefine2DArea(rcti *screen_rect)
@@ -807,7 +824,9 @@ void bglBegin(int mode)
pointhack = floor(value[0] + 0.5f);
if (pointhack > 4) pointhack = 4;
}
- else glBegin(mode);
+ else {
+ glBegin(mode);
+ }
}
}
@@ -835,7 +854,9 @@ void bglVertex3fv(const float vec[3])
glRasterPos3fv(vec);
glBitmap(pointhack, pointhack, (float)pointhack / 2.0f, (float)pointhack / 2.0f, 0.0, 0.0, Squaredot);
}
- else glVertex3fv(vec);
+ else {
+ glVertex3fv(vec);
+ }
break;
}
}
@@ -848,7 +869,9 @@ void bglVertex3f(float x, float y, float z)
glRasterPos3f(x, y, z);
glBitmap(pointhack, pointhack, (float)pointhack / 2.0f, (float)pointhack / 2.0f, 0.0, 0.0, Squaredot);
}
- else glVertex3f(x, y, z);
+ else {
+ glVertex3f(x, y, z);
+ }
break;
}
}
@@ -861,7 +884,9 @@ void bglVertex2fv(const float vec[2])
glRasterPos2fv(vec);
glBitmap(pointhack, pointhack, (float)pointhack / 2, pointhack / 2, 0.0, 0.0, Squaredot);
}
- else glVertex2fv(vec);
+ else {
+ glVertex2fv(vec);
+ }
break;
}
}
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index 7c22dff1b01..6045bdfebfe 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -194,7 +194,9 @@ void removenotused_scrverts(bScreen *sc)
BLI_remlink(&sc->vertbase, sv);
MEM_freeN(sv);
}
- else sv->flag = 0;
+ else {
+ sv->flag = 0;
+ }
sv = svn;
}
}
@@ -250,7 +252,9 @@ void removenotused_scredges(bScreen *sc)
BLI_remlink(&sc->edgebase, se);
MEM_freeN(se);
}
- else se->flag = 0;
+ else {
+ se->flag = 0;
+ }
se = sen;
}
}
@@ -1133,8 +1137,12 @@ void ED_screens_initialize(wmWindowManager *wm)
void ED_region_exit(bContext *C, ARegion *ar)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
ARegion *prevar = CTX_wm_region(C);
+ if (ar->type && ar->type->exit)
+ ar->type->exit(wm, ar);
+
CTX_wm_region_set(C, ar);
WM_event_remove_handlers(C, &ar->handlers);
if (ar->swinid)
@@ -1153,18 +1161,12 @@ void ED_region_exit(bContext *C, ARegion *ar)
void ED_area_exit(bContext *C, ScrArea *sa)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
ScrArea *prevsa = CTX_wm_area(C);
ARegion *ar;
- if (sa->spacetype == SPACE_FILE) {
- SpaceLink *sl = sa->spacedata.first;
- if (sl && sl->spacetype == SPACE_FILE) {
- ED_fileselect_exit(C, (SpaceFile *)sl);
- }
- }
- else if (sa->spacetype == SPACE_VIEW3D) {
- ED_render_engine_area_exit(sa);
- }
+ if (sa->type && sa->type->exit)
+ sa->type->exit(wm, sa);
CTX_wm_area_set(C, sa);
for (ar = sa->regionbase.first; ar; ar = ar->next)
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index fcd0968d52f..1906a3259a9 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -644,7 +644,7 @@ static void actionzone_apply(bContext *C, wmOperator *op, int type)
wm_event_add(win, &event);
}
-static int actionzone_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int actionzone_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
AZone *az = is_in_area_actionzone(CTX_wm_area(C), &event->x);
sActionzoneData *sad;
@@ -674,7 +674,7 @@ static int actionzone_invoke(bContext *C, wmOperator *op, wmEvent *event)
}
-static int actionzone_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
sActionzoneData *sad = op->customdata;
int deltax, deltay;
@@ -769,7 +769,7 @@ typedef struct sAreaSwapData {
ScrArea *sa1, *sa2;
} sAreaSwapData;
-static int area_swap_init(wmOperator *op, wmEvent *event)
+static int area_swap_init(wmOperator *op, const wmEvent *event)
{
sAreaSwapData *sd = NULL;
sActionzoneData *sad = event->customdata;
@@ -800,7 +800,7 @@ static int area_swap_cancel(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
-static int area_swap_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int area_swap_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (!area_swap_init(op, event))
@@ -814,7 +814,7 @@ static int area_swap_invoke(bContext *C, wmOperator *op, wmEvent *event)
}
-static int area_swap_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int area_swap_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
sActionzoneData *sad = op->customdata;
@@ -866,7 +866,7 @@ static void SCREEN_OT_area_swap(wmOperatorType *ot)
/* *********** Duplicate area as new window operator ****************** */
/* operator callback */
-static int area_dupli_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
wmWindow *newwin, *win;
bScreen *newsc, *sc;
@@ -1100,7 +1100,7 @@ static int area_move_exec(bContext *C, wmOperator *op)
}
/* interaction callback */
-static int area_move_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int area_move_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
RNA_int_set(op->ptr, "x", event->x);
RNA_int_set(op->ptr, "y", event->y);
@@ -1125,7 +1125,7 @@ static int area_move_cancel(bContext *C, wmOperator *op)
}
/* modal callback for while moving edges */
-static int area_move_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int area_move_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
sAreaMoveData *md = op->customdata;
int delta, x, y;
@@ -1382,7 +1382,7 @@ static void area_split_exit(bContext *C, wmOperator *op)
/* UI callback, adds new handler */
-static int area_split_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
sAreaSplitData *sd;
int dir;
@@ -1514,7 +1514,7 @@ static int area_split_cancel(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
-static int area_split_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
sAreaSplitData *sd = (sAreaSplitData *)op->customdata;
float fac;
@@ -1697,7 +1697,7 @@ static int area_max_regionsize(ScrArea *sa, ARegion *scalear, AZEdge edge)
return dist;
}
-static int region_scale_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int region_scale_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
sActionzoneData *sad = event->customdata;
AZone *az;
@@ -1795,7 +1795,7 @@ static void region_scale_toggle_hidden(bContext *C, RegionMoveData *rmd)
region_scale_validate_size(rmd);
}
-static int region_scale_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
RegionMoveData *rmd = op->customdata;
int delta;
@@ -2318,7 +2318,7 @@ static int area_join_exec(bContext *C, wmOperator *op)
}
/* interaction callback */
-static int area_join_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int area_join_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (event->type == EVT_ACTIONZONE_AREA) {
@@ -2374,7 +2374,7 @@ static int area_join_cancel(bContext *C, wmOperator *op)
}
/* modal callback while selecting area (space) that will be removed */
-static int area_join_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
bScreen *sc = CTX_wm_screen(C);
sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
@@ -2490,7 +2490,7 @@ static void SCREEN_OT_area_join(wmOperatorType *ot)
/* ******************************* */
-static int screen_area_options_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int screen_area_options_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
uiPopupMenu *pup;
uiLayout *layout;
@@ -2604,7 +2604,7 @@ static void SCREEN_OT_repeat_last(wmOperatorType *ot)
}
-static int repeat_history_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int repeat_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
wmWindowManager *wm = CTX_wm_manager(C);
wmOperator *lastop;
@@ -2661,7 +2661,7 @@ static void SCREEN_OT_repeat_history(wmOperatorType *ot)
/* ********************** redo operator ***************************** */
-static int redo_last_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
+static int redo_last_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
{
wmOperator *lastop = WM_operator_last_redo(C);
@@ -2958,7 +2958,7 @@ void ED_screens_header_tools_menu_create(bContext *C, uiLayout *layout, void *UN
}
}
-static int header_toolbox_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
+static int header_toolbox_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
{
uiPopupMenu *pup;
uiLayout *layout;
@@ -3071,7 +3071,7 @@ static int match_region_with_redraws(int spacetype, int regiontype, int redraws)
return 0;
}
-static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
+static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
bScreen *screen = CTX_wm_screen(C);
@@ -3421,7 +3421,7 @@ static void SCREEN_OT_back_to_previous(struct wmOperatorType *ot)
/* *********** show user pref window ****** */
-static int userpref_show_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
+static int userpref_show_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
wmWindow *win = CTX_wm_window(C);
rcti rect;
@@ -3696,7 +3696,7 @@ void region_blend_start(bContext *C, ScrArea *sa, ARegion *ar)
}
/* timer runs in win->handlers, so it cannot use context to find area/region */
-static int region_blend_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
+static int region_blend_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
RegionAlphaInfo *rgi;
wmTimer *timer = event->customdata;
@@ -3820,7 +3820,7 @@ static void keymap_modal_set(wmKeyConfig *keyconf)
}
-static int open_file_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event))
+static int open_file_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
{
if (drag->type == WM_DRAG_PATH) {
if (drag->icon == ICON_FILE_BLEND)
diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c
index 9cde62e8302..0fbb4c25e78 100644
--- a/source/blender/editors/screen/screendump.c
+++ b/source/blender/editors/screen/screendump.c
@@ -204,7 +204,7 @@ static int screenshot_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int screenshot_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int screenshot_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (screenshot_data_create(C, op)) {
if (RNA_struct_property_is_set(op->ptr, "filepath"))
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index 5bed31e2e52..0899fb97a2a 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -23,6 +23,7 @@ set(INC
../uvedit
../../blenkernel
../../blenlib
+ ../../blenfont
../../blenloader
../../bmesh
../../gpu
@@ -43,6 +44,7 @@ set(SRC
paint_hide.c
paint_image.c
paint_image_2d.c
+ paint_image_proj.c
paint_mask.c
paint_ops.c
paint_stroke.c
@@ -57,4 +59,8 @@ set(SRC
sculpt_intern.h
)
+if(WITH_INTERNATIONAL)
+ add_definitions(-DWITH_INTERNATIONAL)
+endif()
+
blender_add_lib(bf_editor_sculpt_paint "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/sculpt_paint/SConscript b/source/blender/editors/sculpt_paint/SConscript
index 6767e06f65b..d10666de637 100644
--- a/source/blender/editors/sculpt_paint/SConscript
+++ b/source/blender/editors/sculpt_paint/SConscript
@@ -31,7 +31,7 @@ sources = env.Glob('*.c')
defs = []
-incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
+incs = '../include ../../blenlib ../../blenfont ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
incs += ' ../../render/extern/include'
incs += ' ../../gpu ../../makesrna ../../blenloader ../../bmesh ../uvedit'
@@ -47,4 +47,7 @@ if env['OURPLATFORM'] == 'linuxcross':
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
incs += ' ' + env['BF_PTHREADS_INC']
+if env['WITH_BF_INTERNATIONAL']:
+ defs.append('WITH_INTERNATIONAL')
+
env.BlenderLib ( 'bf_editors_sculpt_paint', sources, Split(incs), defines=defs, libtype=['core'], priority=[40] )
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index ffea5af74a3..8d9cbbbcf11 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -207,14 +207,14 @@ static int load_tex(Brush *br, ViewContext *vc)
x = (float)i / size;
y = (float)j / size;
- x -= 0.5f;
- y -= 0.5f;
-
if (br->mtex.brush_map_mode == MTEX_MAP_MODE_TILED) {
x *= vc->ar->winx / radius;
y *= vc->ar->winy / radius;
}
else {
+ x -= 0.5f;
+ y -= 0.5f;
+
x *= 2;
y *= 2;
}
@@ -345,14 +345,14 @@ static int sculpt_get_brush_geometry(bContext *C, ViewContext *vc,
{
Scene *scene = CTX_data_scene(C);
Paint *paint = paint_get_active_from_context(C);
- float window[2];
+ float mouse[2];
int hit;
- window[0] = x + vc->ar->winrct.xmin;
- window[1] = y + vc->ar->winrct.ymin;
+ mouse[0] = x;
+ mouse[1] = y;
if (vc->obact->sculpt && vc->obact->sculpt->pbvh &&
- sculpt_stroke_get_location(C, location, window))
+ sculpt_stroke_get_location(C, location, mouse))
{
Brush *brush = paint_brush(paint);
*pixel_radius =
@@ -420,8 +420,7 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush,
if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) {
/* brush rotation */
glTranslatef(0.5, 0.5, 0);
- glRotatef((double)RAD2DEGF((brush->flag & BRUSH_RAKE) ?
- ups->last_angle : ups->special_rotation),
+ glRotatef((double)RAD2DEGF(ups->brush_rotation),
0.0, 0.0, 1.0);
glTranslatef(-0.5f, -0.5f, 0);
@@ -434,11 +433,10 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush,
if (ups->draw_anchored) {
const float *aim = ups->anchored_initial_mouse;
- const rcti *win = &vc->ar->winrct;
- quad.xmin = aim[0] - ups->anchored_size - win->xmin;
- quad.ymin = aim[1] - ups->anchored_size - win->ymin;
- quad.xmax = aim[0] + ups->anchored_size - win->xmin;
- quad.ymax = aim[1] + ups->anchored_size - win->ymin;
+ quad.xmin = aim[0] - ups->anchored_size;
+ quad.ymin = aim[1] - ups->anchored_size;
+ quad.xmax = aim[0] + ups->anchored_size;
+ quad.ymax = aim[1] + ups->anchored_size;
}
else {
const int radius = BKE_brush_size_get(vc->scene, brush);
@@ -537,38 +535,22 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
* mouse over too, not just during a stroke */
view3d_set_viewcontext(C, &vc);
+ if (brush->flag & BRUSH_RAKE)
+ /* here, translation contains the mouse coordinates. */
+ paint_calculate_rake_rotation(ups, translation);
+
+ /* draw overlay */
+ paint_draw_alpha_overlay(ups, brush, &vc, x, y);
+
/* TODO: as sculpt and other paint modes are unified, this
* special mode of drawing will go away */
if (vc.obact->sculpt) {
float location[3];
int pixel_radius, hit;
- /* this is probably here so that rake takes into
- * account the brush movements before the stroke
- * starts, but this doesn't really belong in draw code
- * TODO) */
- {
- const float u = 0.5f;
- const float v = 1 - u;
- const float r = 20;
-
- const float dx = ups->last_x - x;
- const float dy = ups->last_y - y;
-
- if (dx * dx + dy * dy >= r * r) {
- ups->last_angle = atan2(dx, dy);
-
- ups->last_x = u * ups->last_x + v * x;
- ups->last_y = u * ups->last_y + v * y;
- }
- }
-
/* test if brush is over the mesh */
hit = sculpt_get_brush_geometry(C, &vc, x, y, &pixel_radius, location);
- /* draw overlay */
- paint_draw_alpha_overlay(ups, brush, &vc, x, y);
-
if (BKE_brush_use_locked_size(scene, brush))
BKE_brush_size_set(scene, brush, pixel_radius);
@@ -590,8 +572,8 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
if (ups->draw_anchored) {
final_radius = ups->anchored_size;
- translation[0] = ups->anchored_initial_mouse[0] - vc.ar->winrct.xmin;
- translation[1] = ups->anchored_initial_mouse[1] - vc.ar->winrct.ymin;
+ translation[0] = ups->anchored_initial_mouse[0];
+ translation[1] = ups->anchored_initial_mouse[1];
}
}
diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c
index d50261a3b98..14eb358f20f 100644
--- a/source/blender/editors/sculpt_paint/paint_hide.c
+++ b/source/blender/editors/sculpt_paint/paint_hide.c
@@ -424,7 +424,7 @@ static int hide_show_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int hide_show_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int hide_show_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
PartialVisArea area = RNA_enum_get(op->ptr, "area");
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index edeb66d9281..144dfa948d0 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -101,298 +101,8 @@
#include "paint_intern.h"
-/* Defines and Structs */
-/* FTOCHAR as inline function */
-BLI_INLINE unsigned char f_to_char(const float val)
-{
- return FTOCHAR(val);
-}
-
-
-#define IMAPAINT_CHAR_TO_FLOAT(c) ((c) / 255.0f)
-
-#define IMAPAINT_FLOAT_RGB_TO_CHAR(c, f) { \
- (c)[0] = f_to_char((f)[0]); \
- (c)[1] = f_to_char((f)[1]); \
- (c)[2] = f_to_char((f)[2]); \
-} (void)0
-#define IMAPAINT_FLOAT_RGBA_TO_CHAR(c, f) { \
- (c)[0] = f_to_char((f)[0]); \
- (c)[1] = f_to_char((f)[1]); \
- (c)[2] = f_to_char((f)[2]); \
- (c)[3] = f_to_char((f)[3]); \
-} (void)0
-#define IMAPAINT_CHAR_RGB_TO_FLOAT(f, c) { \
- (f)[0] = IMAPAINT_CHAR_TO_FLOAT((c)[0]); \
- (f)[1] = IMAPAINT_CHAR_TO_FLOAT((c)[1]); \
- (f)[2] = IMAPAINT_CHAR_TO_FLOAT((c)[2]); \
-} (void)0
-#define IMAPAINT_CHAR_RGBA_TO_FLOAT(f, c) { \
- (f)[0] = IMAPAINT_CHAR_TO_FLOAT((c)[0]); \
- (f)[1] = IMAPAINT_CHAR_TO_FLOAT((c)[1]); \
- (f)[2] = IMAPAINT_CHAR_TO_FLOAT((c)[2]); \
- (f)[3] = IMAPAINT_CHAR_TO_FLOAT((c)[3]); \
-} (void)0
-
-#define IMAPAINT_FLOAT_RGB_COPY(a, b) copy_v3_v3(a, b)
-
#define IMAPAINT_TILE_BITS 6
#define IMAPAINT_TILE_SIZE (1 << IMAPAINT_TILE_BITS)
-#define IMAPAINT_TILE_NUMBER(size) (((size) + IMAPAINT_TILE_SIZE - 1) >> IMAPAINT_TILE_BITS)
-
-static void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short texpaint);
-
-
-typedef struct ImagePaintState {
- SpaceImage *sima;
- View2D *v2d;
- Scene *scene;
- bScreen *screen;
-
- Brush *brush;
- short tool, blend;
- Image *image;
- ImBuf *canvas;
- ImBuf *clonecanvas;
- char *warnpackedfile;
- char *warnmultifile;
-
- /* viewport texture paint only, but _not_ project paint */
- Object *ob;
- int faceindex;
- float uv[2];
- int do_facesel;
-
- DerivedMesh *dm;
- int dm_totface;
- int dm_release;
-
- MFace *dm_mface;
- MTFace *dm_mtface;
-} ImagePaintState;
-
-typedef struct ImagePaintPartialRedraw {
- int x1, y1, x2, y2; /* XXX, could use 'rcti' */
- int enabled;
-} ImagePaintPartialRedraw;
-
-typedef struct ImagePaintRegion {
- int destx, desty;
- int srcx, srcy;
- int width, height;
-} ImagePaintRegion;
-
-/* ProjectionPaint defines */
-
-/* approx the number of buckets to have under the brush,
- * used with the brush size to set the ps->buckets_x and ps->buckets_y value.
- *
- * When 3 - a brush should have ~9 buckets under it at once
- * ...this helps for threading while painting as well as
- * avoiding initializing pixels that wont touch the brush */
-#define PROJ_BUCKET_BRUSH_DIV 4
-
-#define PROJ_BUCKET_RECT_MIN 4
-#define PROJ_BUCKET_RECT_MAX 256
-
-#define PROJ_BOUNDBOX_DIV 8
-#define PROJ_BOUNDBOX_SQUARED (PROJ_BOUNDBOX_DIV * PROJ_BOUNDBOX_DIV)
-
-//#define PROJ_DEBUG_PAINT 1
-//#define PROJ_DEBUG_NOSEAMBLEED 1
-//#define PROJ_DEBUG_PRINT_CLIP 1
-#define PROJ_DEBUG_WINCLIP 1
-
-/* projectFaceSeamFlags options */
-//#define PROJ_FACE_IGNORE (1<<0) /* When the face is hidden, backfacing or occluded */
-//#define PROJ_FACE_INIT (1<<1) /* When we have initialized the faces data */
-#define PROJ_FACE_SEAM1 (1 << 0) /* If this face has a seam on any of its edges */
-#define PROJ_FACE_SEAM2 (1 << 1)
-#define PROJ_FACE_SEAM3 (1 << 2)
-#define PROJ_FACE_SEAM4 (1 << 3)
-
-#define PROJ_FACE_NOSEAM1 (1 << 4)
-#define PROJ_FACE_NOSEAM2 (1 << 5)
-#define PROJ_FACE_NOSEAM3 (1 << 6)
-#define PROJ_FACE_NOSEAM4 (1 << 7)
-
-#define PROJ_SRC_VIEW 1
-#define PROJ_SRC_IMAGE_CAM 2
-#define PROJ_SRC_IMAGE_VIEW 3
-
-#define PROJ_VIEW_DATA_ID "view_data"
-#define PROJ_VIEW_DATA_SIZE (4 * 4 + 4 * 4 + 3) /* viewmat + winmat + clipsta + clipend + is_ortho */
-
-
-/* a slightly scaled down face is used to get fake 3D location for edge pixels in the seams
- * as this number approaches 1.0f the likelihood increases of float precision errors where
- * it is occluded by an adjacent face */
-#define PROJ_FACE_SCALE_SEAM 0.99f
-
-#define PROJ_BUCKET_NULL 0
-#define PROJ_BUCKET_INIT (1 << 0)
-// #define PROJ_BUCKET_CLONE_INIT (1<<1)
-
-/* used for testing doubles, if a point is on a line etc */
-#define PROJ_GEOM_TOLERANCE 0.00075f
-
-/* vert flags */
-#define PROJ_VERT_CULL 1
-
-/* This is mainly a convenience struct used so we can keep an array of images we use
- * Thir imbufs, etc, in 1 array, When using threads this array is copied for each thread
- * because 'partRedrawRect' and 'touch' values would not be thread safe */
-typedef struct ProjPaintImage {
- Image *ima;
- ImBuf *ibuf;
- ImagePaintPartialRedraw *partRedrawRect;
- void **undoRect; /* only used to build undo tiles after painting */
- int touch;
-} ProjPaintImage;
-
-/* Main projection painting struct passed to all projection painting functions */
-typedef struct ProjPaintState {
- View3D *v3d;
- RegionView3D *rv3d;
- ARegion *ar;
- Scene *scene;
- int source; /* PROJ_SRC_**** */
-
- Brush *brush;
- short tool, blend;
- Object *ob;
- /* end similarities with ImagePaintState */
-
- DerivedMesh *dm;
- int dm_totface;
- int dm_totvert;
- int dm_release;
-
- MVert *dm_mvert;
- MFace *dm_mface;
- MTFace *dm_mtface;
- MTFace *dm_mtface_clone; /* other UV map, use for cloning between layers */
- MTFace *dm_mtface_stencil;
-
- /* projection painting only */
- MemArena *arena_mt[BLENDER_MAX_THREADS]; /* for multithreading, the first item is sometimes used for non threaded cases too */
- LinkNode **bucketRect; /* screen sized 2D array, each pixel has a linked list of ProjPixel's */
- LinkNode **bucketFaces; /* bucketRect aligned array linkList of faces overlapping each bucket */
- unsigned char *bucketFlags; /* store if the bucks have been initialized */
-#ifndef PROJ_DEBUG_NOSEAMBLEED
- char *faceSeamFlags; /* store info about faces, if they are initialized etc*/
- float (*faceSeamUVs)[4][2]; /* expanded UVs for faces to use as seams */
- LinkNode **vertFaces; /* Only needed for when seam_bleed_px is enabled, use to find UV seams */
-#endif
- char *vertFlags; /* store options per vert, now only store if the vert is pointing away from the view */
- int buckets_x; /* The size of the bucket grid, the grid span's screenMin/screenMax so you can paint outsize the screen or with 2 brushes at once */
- int buckets_y;
-
- ProjPaintImage *projImages;
-
- int pixel_sizeof; /* result of project_paint_pixel_sizeof(), constant per stroke */
-
- int image_tot; /* size of projectImages array */
-
- float (*screenCoords)[4]; /* verts projected into floating point screen space */
-
- float screenMin[2]; /* 2D bounds for mesh verts on the screen's plane (screenspace) */
- float screenMax[2];
- float screen_width; /* Calculated from screenMin & screenMax */
- float screen_height;
- int winx, winy; /* from the carea or from the projection render */
-
- /* options for projection painting */
- int do_layer_clone;
- int do_layer_stencil;
- int do_layer_stencil_inv;
-
- short do_occlude; /* Use raytraced occlusion? - ortherwise will paint right through to the back*/
- short do_backfacecull; /* ignore faces with normals pointing away, skips a lot of raycasts if your normals are correctly flipped */
- short do_mask_normal; /* mask out pixels based on their normals */
- short do_new_shading_nodes; /* cache BKE_scene_use_new_shading_nodes value */
- float normal_angle; /* what angle to mask at*/
- float normal_angle_inner;
- float normal_angle_range; /* difference between normal_angle and normal_angle_inner, for easy access */
-
- short is_ortho;
- bool do_masking; /* use masking during painting. Some operations such as airbrush may disable */
- short is_texbrush; /* only to avoid running */
-#ifndef PROJ_DEBUG_NOSEAMBLEED
- float seam_bleed_px;
-#endif
- /* clone vars */
- float cloneOffset[2];
-
- float projectMat[4][4]; /* Projection matrix, use for getting screen coords */
- float viewDir[3]; /* View vector, use for do_backfacecull and for ray casting with an ortho viewport */
- float viewPos[3]; /* View location in object relative 3D space, so can compare to verts */
- float clipsta, clipend;
-
- /* reproject vars */
- Image *reproject_image;
- ImBuf *reproject_ibuf;
-
-
- /* threads */
- int thread_tot;
- int bucketMin[2];
- int bucketMax[2];
- int context_bucket_x, context_bucket_y; /* must lock threads while accessing these */
-} ProjPaintState;
-
-typedef union pixelPointer {
- float *f_pt; /* float buffer */
- unsigned int *uint_pt; /* 2 ways to access a char buffer */
- unsigned char *ch_pt;
-} PixelPointer;
-
-typedef union pixelStore {
- unsigned char ch[4];
- unsigned int uint;
- float f[4];
-} PixelStore;
-
-typedef struct ProjPixel {
- float projCoSS[2]; /* the floating point screen projection of this pixel */
- float worldCoSS[3];
- /* Only used when the airbrush is disabled.
- * Store the max mask value to avoid painting over an area with a lower opacity
- * with an advantage that we can avoid touching the pixel at all, if the
- * new mask value is lower then mask_max */
- unsigned short mask_max;
-
- /* for various reasons we may want to mask out painting onto this pixel */
- unsigned short mask;
-
- short x_px, y_px;
-
- PixelStore origColor;
- PixelStore newColor;
- PixelPointer pixel;
-
- short image_index; /* if anyone wants to paint onto more then 32768 images they can bite me */
- unsigned char bb_cell_index;
-} ProjPixel;
-
-typedef struct ProjPixelClone {
- struct ProjPixel __pp;
- PixelStore clonepx;
-} ProjPixelClone;
-
-/* blur, store surrounding colors */
-#define PROJ_PIXEL_SOFTEN_TOT 4
-/* blur picking offset (in screenspace) */
-#define PROJ_PIXEL_SOFTEN_OFS_PX 1.0f
-
-static const float proj_pixel_soften_v2[PROJ_PIXEL_SOFTEN_TOT][2] = {
- {-PROJ_PIXEL_SOFTEN_OFS_PX, 0.0f},
- { 0.0f, -PROJ_PIXEL_SOFTEN_OFS_PX},
- { 0.0f, PROJ_PIXEL_SOFTEN_OFS_PX},
- { PROJ_PIXEL_SOFTEN_OFS_PX, 0.0f},
-};
-
-/* Finish projection painting structs */
typedef struct UndoImageTile {
struct UndoImageTile *next, *prev;
@@ -411,8 +121,21 @@ typedef struct UndoImageTile {
char gen_type;
} UndoImageTile;
+/* this is a static resource for non-globality,
+ * Maybe it should be exposed as part of the
+ * paint operation, but for now just give a public interface */
static ImagePaintPartialRedraw imapaintpartial = {0, 0, 0, 0, 0};
+ImagePaintPartialRedraw *get_imapaintpartial(void)
+{
+ return &imapaintpartial;
+}
+
+void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr)
+{
+ imapaintpartial = *ippr;
+}
+
/* UNDO */
static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, int restore)
@@ -433,7 +156,7 @@ static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, int
tile->y * IMAPAINT_TILE_SIZE, 0, 0, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
}
-static void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile)
+void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile)
{
ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
UndoImageTile *tile;
@@ -472,7 +195,7 @@ static void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int
return tile->rect.pt;
}
-static void image_undo_restore(bContext *C, ListBase *lb)
+void image_undo_restore(bContext *C, ListBase *lb)
{
Main *bmain = CTX_data_main(C);
Image *ima = NULL;
@@ -481,7 +204,7 @@ static void image_undo_restore(bContext *C, ListBase *lb)
tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32,
IB_rectfloat | IB_rect);
-
+
for (tile = lb->first; tile; tile = tile->next) {
short use_float;
@@ -538,7 +261,7 @@ static void image_undo_restore(bContext *C, ListBase *lb)
IMB_freeImBuf(tmpibuf);
}
-static void image_undo_free(ListBase *lb)
+void image_undo_free(ListBase *lb)
{
UndoImageTile *tile;
@@ -546,3839 +269,14 @@ static void image_undo_free(ListBase *lb)
MEM_freeN(tile->rect.pt);
}
-/* get active image for face depending on old/new shading system */
-
-static Image *imapaint_face_image(const ImagePaintState *s, int face_index)
-{
- Image *ima;
-
- if (BKE_scene_use_new_shading_nodes(s->scene)) {
- MFace *mf = &s->dm_mface[face_index];
- ED_object_get_active_image(s->ob, mf->mat_nr + 1, &ima, NULL, NULL);
- }
- else {
- MTFace *tf = &s->dm_mtface[face_index];
- ima = tf->tpage;
- }
-
- return ima;
-}
-
-static Image *project_paint_face_image(const ProjPaintState *ps, MTFace *dm_mtface, int face_index)
-{
- Image *ima;
-
- if (ps->do_new_shading_nodes) { /* cached BKE_scene_use_new_shading_nodes result */
- MFace *mf = ps->dm_mface + face_index;
- ED_object_get_active_image(ps->ob, mf->mat_nr + 1, &ima, NULL, NULL);
- }
- else {
- ima = dm_mtface[face_index].tpage;
- }
-
- return ima;
-}
-
-/* fast projection bucket array lookup, use the safe version for bound checking */
-static int project_bucket_offset(const ProjPaintState *ps, const float projCoSS[2])
-{
- /* If we were not dealing with screenspace 2D coords we could simple do...
- * ps->bucketRect[x + (y*ps->buckets_y)] */
-
- /* please explain?
- * projCoSS[0] - ps->screenMin[0] : zero origin
- * ... / ps->screen_width : range from 0.0 to 1.0
- * ... * ps->buckets_x : use as a bucket index
- *
- * Second multiplication does similar but for vertical offset
- */
- return ( (int)(((projCoSS[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x)) +
- (((int)(((projCoSS[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y)) * ps->buckets_x);
-}
-
-static int project_bucket_offset_safe(const ProjPaintState *ps, const float projCoSS[2])
-{
- int bucket_index = project_bucket_offset(ps, projCoSS);
-
- if (bucket_index < 0 || bucket_index >= ps->buckets_x * ps->buckets_y) {
- return -1;
- }
- else {
- return bucket_index;
- }
-}
-
-/* still use 2D X,Y space but this works for verts transformed by a perspective matrix, using their 4th component as a weight */
-static void barycentric_weights_v2_persp(const float v1[4], const float v2[4], const float v3[4], const float co[2], float w[3])
-{
- float wtot_inv, wtot;
-
- w[0] = area_tri_signed_v2(v2, v3, co) / v1[3];
- w[1] = area_tri_signed_v2(v3, v1, co) / v2[3];
- w[2] = area_tri_signed_v2(v1, v2, co) / v3[3];
- wtot = w[0] + w[1] + w[2];
-
- if (wtot != 0.0f) {
- wtot_inv = 1.0f / wtot;
-
- w[0] = w[0] * wtot_inv;
- w[1] = w[1] * wtot_inv;
- w[2] = w[2] * wtot_inv;
- }
- else /* dummy values for zero area face */
- w[0] = w[1] = w[2] = 1.0f / 3.0f;
-}
-
-static float VecZDepthOrtho(const float pt[2],
- const float v1[3], const float v2[3], const float v3[3],
- float w[3])
-{
- barycentric_weights_v2(v1, v2, v3, pt, w);
- return (v1[2] * w[0]) + (v2[2] * w[1]) + (v3[2] * w[2]);
-}
-
-static float VecZDepthPersp(const float pt[2],
- const float v1[4], const float v2[4], const float v3[4],
- float w[3])
-{
- float wtot_inv, wtot;
- float w_tmp[3];
-
- barycentric_weights_v2_persp(v1, v2, v3, pt, w);
- /* for the depth we need the weights to match what
- * barycentric_weights_v2 would return, in this case its easiest just to
- * undo the 4th axis division and make it unit-sum
- *
- * don't call barycentric_weights_v2() because our callers expect 'w'
- * to be weighted from the perspective */
- w_tmp[0] = w[0] * v1[3];
- w_tmp[1] = w[1] * v2[3];
- w_tmp[2] = w[2] * v3[3];
-
- wtot = w_tmp[0] + w_tmp[1] + w_tmp[2];
-
- if (wtot != 0.0f) {
- wtot_inv = 1.0f / wtot;
-
- w_tmp[0] = w_tmp[0] * wtot_inv;
- w_tmp[1] = w_tmp[1] * wtot_inv;
- w_tmp[2] = w_tmp[2] * wtot_inv;
- }
- else /* dummy values for zero area face */
- w_tmp[0] = w_tmp[1] = w_tmp[2] = 1.0f / 3.0f;
- /* done mimicing barycentric_weights_v2() */
-
- return (v1[2] * w_tmp[0]) + (v2[2] * w_tmp[1]) + (v3[2] * w_tmp[2]);
-}
-
-
-/* Return the top-most face index that the screen space coord 'pt' touches (or -1) */
-static int project_paint_PickFace(const ProjPaintState *ps, float pt[2], float w[3], int *side)
-{
- LinkNode *node;
- float w_tmp[3];
- float *v1, *v2, *v3, *v4;
- int bucket_index;
- int face_index;
- int best_side = -1;
- int best_face_index = -1;
- float z_depth_best = FLT_MAX, z_depth;
- MFace *mf;
-
- bucket_index = project_bucket_offset_safe(ps, pt);
- if (bucket_index == -1)
- return -1;
-
-
-
- /* we could return 0 for 1 face buckets, as long as this function assumes
- * that the point its testing is only every originated from an existing face */
-
- for (node = ps->bucketFaces[bucket_index]; node; node = node->next) {
- face_index = GET_INT_FROM_POINTER(node->link);
- mf = ps->dm_mface + face_index;
-
- v1 = ps->screenCoords[mf->v1];
- v2 = ps->screenCoords[mf->v2];
- v3 = ps->screenCoords[mf->v3];
-
- if (isect_point_tri_v2(pt, v1, v2, v3)) {
- if (ps->is_ortho) z_depth = VecZDepthOrtho(pt, v1, v2, v3, w_tmp);
- else z_depth = VecZDepthPersp(pt, v1, v2, v3, w_tmp);
-
- if (z_depth < z_depth_best) {
- best_face_index = face_index;
- best_side = 0;
- z_depth_best = z_depth;
- copy_v3_v3(w, w_tmp);
- }
- }
- else if (mf->v4) {
- v4 = ps->screenCoords[mf->v4];
-
- if (isect_point_tri_v2(pt, v1, v3, v4)) {
- if (ps->is_ortho) z_depth = VecZDepthOrtho(pt, v1, v3, v4, w_tmp);
- else z_depth = VecZDepthPersp(pt, v1, v3, v4, w_tmp);
-
- if (z_depth < z_depth_best) {
- best_face_index = face_index;
- best_side = 1;
- z_depth_best = z_depth;
- copy_v3_v3(w, w_tmp);
- }
- }
- }
- }
-
- *side = best_side;
- return best_face_index; /* will be -1 or a valid face */
-}
-
-/* Converts a uv coord into a pixel location wrapping if the uv is outside 0-1 range */
-static void uvco_to_wrapped_pxco(float uv[2], int ibuf_x, int ibuf_y, float *x, float *y)
-{
- /* use */
- *x = (float)fmodf(uv[0], 1.0f);
- *y = (float)fmodf(uv[1], 1.0f);
-
- if (*x < 0.0f) *x += 1.0f;
- if (*y < 0.0f) *y += 1.0f;
-
- *x = *x * ibuf_x - 0.5f;
- *y = *y * ibuf_y - 0.5f;
-}
-
-/* Set the top-most face color that the screen space coord 'pt' touches (or return 0 if none touch) */
-static int project_paint_PickColor(const ProjPaintState *ps, float pt[2], float *rgba_fp, unsigned char *rgba, const int interp)
-{
- float w[3], uv[2];
- int side;
- int face_index;
- MTFace *tf;
- Image *ima;
- ImBuf *ibuf;
- int xi, yi;
-
-
- face_index = project_paint_PickFace(ps, pt, w, &side);
-
- if (face_index == -1)
- return 0;
-
- tf = ps->dm_mtface + face_index;
-
- if (side == 0) {
- interp_v2_v2v2v2(uv, tf->uv[0], tf->uv[1], tf->uv[2], w);
- }
- else { /* QUAD */
- interp_v2_v2v2v2(uv, tf->uv[0], tf->uv[2], tf->uv[3], w);
- }
-
- ima = project_paint_face_image(ps, ps->dm_mtface, face_index);
- ibuf = ima->ibufs.first; /* we must have got the imbuf before getting here */
- if (!ibuf) return 0;
-
- if (interp) {
- float x, y;
- uvco_to_wrapped_pxco(uv, ibuf->x, ibuf->y, &x, &y);
-
- if (ibuf->rect_float) {
- if (rgba_fp) {
- bilinear_interpolation_color_wrap(ibuf, NULL, rgba_fp, x, y);
- }
- else {
- float rgba_tmp_f[4];
- bilinear_interpolation_color_wrap(ibuf, NULL, rgba_tmp_f, x, y);
- IMAPAINT_FLOAT_RGBA_TO_CHAR(rgba, rgba_tmp_f);
- }
- }
- else {
- if (rgba) {
- bilinear_interpolation_color_wrap(ibuf, rgba, NULL, x, y);
- }
- else {
- unsigned char rgba_tmp[4];
- bilinear_interpolation_color_wrap(ibuf, rgba_tmp, NULL, x, y);
- IMAPAINT_CHAR_RGBA_TO_FLOAT(rgba_fp, rgba_tmp);
- }
- }
- }
- else {
- //xi = (int)((uv[0]*ibuf->x) + 0.5f);
- //yi = (int)((uv[1]*ibuf->y) + 0.5f);
- //if (xi < 0 || xi >= ibuf->x || yi < 0 || yi >= ibuf->y) return 0;
-
- /* wrap */
- xi = ((int)(uv[0] * ibuf->x)) % ibuf->x;
- if (xi < 0) xi += ibuf->x;
- yi = ((int)(uv[1] * ibuf->y)) % ibuf->y;
- if (yi < 0) yi += ibuf->y;
-
-
- if (rgba) {
- if (ibuf->rect_float) {
- float *rgba_tmp_fp = ibuf->rect_float + (xi + yi * ibuf->x * 4);
- IMAPAINT_FLOAT_RGBA_TO_CHAR(rgba, rgba_tmp_fp);
- }
- else {
- *((unsigned int *)rgba) = *(unsigned int *)(((char *)ibuf->rect) + ((xi + yi * ibuf->x) * 4));
- }
- }
-
- if (rgba_fp) {
- if (ibuf->rect_float) {
- copy_v4_v4(rgba_fp, (ibuf->rect_float + ((xi + yi * ibuf->x) * 4)));
- }
- else {
- char *tmp_ch = ((char *)ibuf->rect) + ((xi + yi * ibuf->x) * 4);
- IMAPAINT_CHAR_RGBA_TO_FLOAT(rgba_fp, tmp_ch);
- }
- }
- }
- return 1;
-}
-
-/* Check if 'pt' is infront of the 3 verts on the Z axis (used for screenspace occlusuion test)
- * return...
- * 0 : no occlusion
- * -1 : no occlusion but 2D intersection is true (avoid testing the other half of a quad)
- * 1 : occluded
- * 2 : occluded with w[3] weights set (need to know in some cases) */
-
-static int project_paint_occlude_ptv(float pt[3], float v1[4], float v2[4], float v3[4], float w[3], int is_ortho)
-{
- /* if all are behind us, return false */
- if (v1[2] > pt[2] && v2[2] > pt[2] && v3[2] > pt[2])
- return 0;
-
- /* do a 2D point in try intersection */
- if (!isect_point_tri_v2(pt, v1, v2, v3))
- return 0; /* we know there is */
-
-
- /* From here on we know there IS an intersection */
- /* if ALL of the verts are infront of us then we know it intersects ? */
- if (v1[2] < pt[2] && v2[2] < pt[2] && v3[2] < pt[2]) {
- return 1;
- }
- else {
- /* we intersect? - find the exact depth at the point of intersection */
- /* Is this point is occluded by another face? */
- if (is_ortho) {
- if (VecZDepthOrtho(pt, v1, v2, v3, w) < pt[2]) return 2;
- }
- else {
- if (VecZDepthPersp(pt, v1, v2, v3, w) < pt[2]) return 2;
- }
- }
- return -1;
-}
-
-
-static int project_paint_occlude_ptv_clip(const ProjPaintState *ps, const MFace *mf,
- float pt[3], float v1[4], float v2[4], float v3[4],
- const int side)
-{
- float w[3], wco[3];
- int ret = project_paint_occlude_ptv(pt, v1, v2, v3, w, ps->is_ortho);
-
- if (ret <= 0)
- return ret;
-
- if (ret == 1) { /* weights not calculated */
- if (ps->is_ortho) barycentric_weights_v2(v1, v2, v3, pt, w);
- else barycentric_weights_v2_persp(v1, v2, v3, pt, w);
- }
-
- /* Test if we're in the clipped area, */
- if (side) interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v3].co, ps->dm_mvert[mf->v4].co, w);
- else interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v2].co, ps->dm_mvert[mf->v3].co, w);
-
- if (!ED_view3d_clipping_test(ps->rv3d, wco, TRUE)) {
- return 1;
- }
-
- return -1;
-}
-
-
-/* Check if a screenspace location is occluded by any other faces
- * check, pixelScreenCo must be in screenspace, its Z-Depth only needs to be used for comparison
- * and doesn't need to be correct in relation to X and Y coords (this is the case in perspective view) */
-static int project_bucket_point_occluded(const ProjPaintState *ps, LinkNode *bucketFace, const int orig_face, float pixelScreenCo[4])
-{
- MFace *mf;
- int face_index;
- int isect_ret;
- float w[3]; /* not needed when clipping */
- const short do_clip = ps->rv3d ? ps->rv3d->rflag & RV3D_CLIPPING : 0;
-
- /* we could return 0 for 1 face buckets, as long as this function assumes
- * that the point its testing is only every originated from an existing face */
-
- for (; bucketFace; bucketFace = bucketFace->next) {
- face_index = GET_INT_FROM_POINTER(bucketFace->link);
-
- if (orig_face != face_index) {
- mf = ps->dm_mface + face_index;
- if (do_clip)
- isect_ret = project_paint_occlude_ptv_clip(ps, mf, pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v2], ps->screenCoords[mf->v3], 0);
- else
- isect_ret = project_paint_occlude_ptv(pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v2], ps->screenCoords[mf->v3], w, ps->is_ortho);
-
- /* Note, if (isect_ret == -1) then we don't want to test the other side of the quad */
- if (isect_ret == 0 && mf->v4) {
- if (do_clip)
- isect_ret = project_paint_occlude_ptv_clip(ps, mf, pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v3], ps->screenCoords[mf->v4], 1);
- else
- isect_ret = project_paint_occlude_ptv(pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v3], ps->screenCoords[mf->v4], w, ps->is_ortho);
- }
- if (isect_ret >= 1) {
- /* TODO - we may want to cache the first hit,
- * it is not possible to swap the face order in the list anymore */
- return 1;
- }
- }
- }
- return 0;
-}
-
-/* basic line intersection, could move to math_geom.c, 2 points with a horiz line
- * 1 for an intersection, 2 if the first point is aligned, 3 if the second point is aligned */
-#define ISECT_TRUE 1
-#define ISECT_TRUE_P1 2
-#define ISECT_TRUE_P2 3
-static int line_isect_y(const float p1[2], const float p2[2], const float y_level, float *x_isect)
-{
- float y_diff;
-
- if (y_level == p1[1]) { /* are we touching the first point? - no interpolation needed */
- *x_isect = p1[0];
- return ISECT_TRUE_P1;
- }
- if (y_level == p2[1]) { /* are we touching the second point? - no interpolation needed */
- *x_isect = p2[0];
- return ISECT_TRUE_P2;
- }
-
- y_diff = fabsf(p1[1] - p2[1]); /* yuck, horizontal line, we cant do much here */
-
- if (y_diff < 0.000001f) {
- *x_isect = (p1[0] + p2[0]) * 0.5f;
- return ISECT_TRUE;
- }
-
- if (p1[1] > y_level && p2[1] < y_level) {
- *x_isect = (p2[0] * (p1[1] - y_level) + p1[0] * (y_level - p2[1])) / y_diff; /*(p1[1]-p2[1]);*/
- return ISECT_TRUE;
- }
- else if (p1[1] < y_level && p2[1] > y_level) {
- *x_isect = (p2[0] * (y_level - p1[1]) + p1[0] * (p2[1] - y_level)) / y_diff; /*(p2[1]-p1[1]);*/
- return ISECT_TRUE;
- }
- else {
- return 0;
- }
-}
-
-static int line_isect_x(const float p1[2], const float p2[2], const float x_level, float *y_isect)
-{
- float x_diff;
-
- if (x_level == p1[0]) { /* are we touching the first point? - no interpolation needed */
- *y_isect = p1[1];
- return ISECT_TRUE_P1;
- }
- if (x_level == p2[0]) { /* are we touching the second point? - no interpolation needed */
- *y_isect = p2[1];
- return ISECT_TRUE_P2;
- }
-
- x_diff = fabsf(p1[0] - p2[0]); /* yuck, horizontal line, we cant do much here */
-
- if (x_diff < 0.000001f) { /* yuck, vertical line, we cant do much here */
- *y_isect = (p1[0] + p2[0]) * 0.5f;
- return ISECT_TRUE;
- }
-
- if (p1[0] > x_level && p2[0] < x_level) {
- *y_isect = (p2[1] * (p1[0] - x_level) + p1[1] * (x_level - p2[0])) / x_diff; /*(p1[0]-p2[0]);*/
- return ISECT_TRUE;
- }
- else if (p1[0] < x_level && p2[0] > x_level) {
- *y_isect = (p2[1] * (x_level - p1[0]) + p1[1] * (p2[0] - x_level)) / x_diff; /*(p2[0]-p1[0]);*/
- return ISECT_TRUE;
- }
- else {
- return 0;
- }
-}
-
-/* simple func use for comparing UV locations to check if there are seams.
- * Its possible this gives incorrect results, when the UVs for 1 face go into the next
- * tile, but do not do this for the adjacent face, it could return a false positive.
- * This is so unlikely that Id not worry about it. */
-#ifndef PROJ_DEBUG_NOSEAMBLEED
-static int cmp_uv(const float vec2a[2], const float vec2b[2])
-{
- /* if the UV's are not between 0.0 and 1.0 */
- float xa = (float)fmodf(vec2a[0], 1.0f);
- float ya = (float)fmodf(vec2a[1], 1.0f);
-
- float xb = (float)fmodf(vec2b[0], 1.0f);
- float yb = (float)fmodf(vec2b[1], 1.0f);
-
- if (xa < 0.0f) xa += 1.0f;
- if (ya < 0.0f) ya += 1.0f;
-
- if (xb < 0.0f) xb += 1.0f;
- if (yb < 0.0f) yb += 1.0f;
-
- return ((fabsf(xa - xb) < PROJ_GEOM_TOLERANCE) && (fabsf(ya - yb) < PROJ_GEOM_TOLERANCE)) ? 1 : 0;
-}
-#endif
-
-/* set min_px and max_px to the image space bounds of the UV coords
- * return zero if there is no area in the returned rectangle */
-#ifndef PROJ_DEBUG_NOSEAMBLEED
-static int pixel_bounds_uv(
- const float uv1[2], const float uv2[2], const float uv3[2], const float uv4[2],
- rcti *bounds_px,
- const int ibuf_x, const int ibuf_y,
- int is_quad
- )
-{
- float min_uv[2], max_uv[2]; /* UV bounds */
-
- INIT_MINMAX2(min_uv, max_uv);
-
- minmax_v2v2_v2(min_uv, max_uv, uv1);
- minmax_v2v2_v2(min_uv, max_uv, uv2);
- minmax_v2v2_v2(min_uv, max_uv, uv3);
- if (is_quad)
- minmax_v2v2_v2(min_uv, max_uv, uv4);
-
- bounds_px->xmin = (int)(ibuf_x * min_uv[0]);
- bounds_px->ymin = (int)(ibuf_y * min_uv[1]);
-
- bounds_px->xmax = (int)(ibuf_x * max_uv[0]) + 1;
- bounds_px->ymax = (int)(ibuf_y * max_uv[1]) + 1;
-
- /*printf("%d %d %d %d\n", min_px[0], min_px[1], max_px[0], max_px[1]);*/
-
- /* face uses no UV area when quantized to pixels? */
- return (bounds_px->xmin == bounds_px->xmax || bounds_px->ymin == bounds_px->ymax) ? 0 : 1;
-}
-#endif
-
-static int pixel_bounds_array(float (*uv)[2], rcti *bounds_px, const int ibuf_x, const int ibuf_y, int tot)
-{
- float min_uv[2], max_uv[2]; /* UV bounds */
-
- if (tot == 0) {
- return 0;
- }
-
- INIT_MINMAX2(min_uv, max_uv);
-
- while (tot--) {
- minmax_v2v2_v2(min_uv, max_uv, (*uv));
- uv++;
- }
-
- bounds_px->xmin = (int)(ibuf_x * min_uv[0]);
- bounds_px->ymin = (int)(ibuf_y * min_uv[1]);
-
- bounds_px->xmax = (int)(ibuf_x * max_uv[0]) + 1;
- bounds_px->ymax = (int)(ibuf_y * max_uv[1]) + 1;
-
- /*printf("%d %d %d %d\n", min_px[0], min_px[1], max_px[0], max_px[1]);*/
-
- /* face uses no UV area when quantized to pixels? */
- return (bounds_px->xmin == bounds_px->xmax || bounds_px->ymin == bounds_px->ymax) ? 0 : 1;
-}
-
-#ifndef PROJ_DEBUG_NOSEAMBLEED
-
-/* This function returns 1 if this face has a seam along the 2 face-vert indices
- * 'orig_i1_fidx' and 'orig_i2_fidx' */
-static int check_seam(const ProjPaintState *ps, const int orig_face, const int orig_i1_fidx, const int orig_i2_fidx, int *other_face, int *orig_fidx)
-{
- LinkNode *node;
- int face_index;
- unsigned int i1, i2;
- int i1_fidx = -1, i2_fidx = -1; /* index in face */
- MFace *mf;
- MTFace *tf;
- const MFace *orig_mf = ps->dm_mface + orig_face;
- const MTFace *orig_tf = ps->dm_mtface + orig_face;
-
- /* vert indices from face vert order indices */
- i1 = (*(&orig_mf->v1 + orig_i1_fidx));
- i2 = (*(&orig_mf->v1 + orig_i2_fidx));
-
- for (node = ps->vertFaces[i1]; node; node = node->next) {
- face_index = GET_INT_FROM_POINTER(node->link);
-
- if (face_index != orig_face) {
- mf = ps->dm_mface + face_index;
- /* could check if the 2 faces images match here,
- * but then there wouldn't be a way to return the opposite face's info */
-
-
- /* We need to know the order of the verts in the adjacent face
- * set the i1_fidx and i2_fidx to (0,1,2,3) */
- if (mf->v1 == i1) i1_fidx = 0;
- else if (mf->v2 == i1) i1_fidx = 1;
- else if (mf->v3 == i1) i1_fidx = 2;
- else if (mf->v4 && mf->v4 == i1) i1_fidx = 3;
-
- if (mf->v1 == i2) i2_fidx = 0;
- else if (mf->v2 == i2) i2_fidx = 1;
- else if (mf->v3 == i2) i2_fidx = 2;
- else if (mf->v4 && mf->v4 == i2) i2_fidx = 3;
-
- /* Only need to check if 'i2_fidx' is valid because we know i1_fidx is the same vert on both faces */
- if (i2_fidx != -1) {
- Image *tpage = project_paint_face_image(ps, ps->dm_mtface, face_index);
- Image *orig_tpage = project_paint_face_image(ps, ps->dm_mtface, orig_face);
-
- /* This IS an adjacent face!, now lets check if the UVs are ok */
- tf = ps->dm_mtface + face_index;
-
- /* set up the other face */
- *other_face = face_index;
- *orig_fidx = (i1_fidx < i2_fidx) ? i1_fidx : i2_fidx;
-
- /* first test if they have the same image */
- if ((orig_tpage == tpage) &&
- cmp_uv(orig_tf->uv[orig_i1_fidx], tf->uv[i1_fidx]) &&
- cmp_uv(orig_tf->uv[orig_i2_fidx], tf->uv[i2_fidx]) )
- {
- // printf("SEAM (NONE)\n");
- return 0;
-
- }
- else {
- // printf("SEAM (UV GAP)\n");
- return 1;
- }
- }
- }
- }
- // printf("SEAM (NO FACE)\n");
- *other_face = -1;
- return 1;
-}
-
-/* Calculate outset UV's, this is not the same as simply scaling the UVs,
- * since the outset coords are a margin that keep an even distance from the original UV's,
- * note that the image aspect is taken into account */
-static void uv_image_outset(float (*orig_uv)[2], float (*outset_uv)[2], const float scaler, const int ibuf_x, const int ibuf_y, const int is_quad)
-{
- float a1, a2, a3, a4 = 0.0f;
- float puv[4][2]; /* pixelspace uv's */
- float no1[2], no2[2], no3[2], no4[2]; /* normals */
- float dir1[2], dir2[2], dir3[2], dir4[2];
- float ibuf_inv[2];
-
- ibuf_inv[0] = 1.0f / (float)ibuf_x;
- ibuf_inv[1] = 1.0f / (float)ibuf_y;
-
- /* make UV's in pixel space so we can */
- puv[0][0] = orig_uv[0][0] * ibuf_x;
- puv[0][1] = orig_uv[0][1] * ibuf_y;
-
- puv[1][0] = orig_uv[1][0] * ibuf_x;
- puv[1][1] = orig_uv[1][1] * ibuf_y;
-
- puv[2][0] = orig_uv[2][0] * ibuf_x;
- puv[2][1] = orig_uv[2][1] * ibuf_y;
-
- if (is_quad) {
- puv[3][0] = orig_uv[3][0] * ibuf_x;
- puv[3][1] = orig_uv[3][1] * ibuf_y;
- }
-
- /* face edge directions */
- sub_v2_v2v2(dir1, puv[1], puv[0]);
- sub_v2_v2v2(dir2, puv[2], puv[1]);
- normalize_v2(dir1);
- normalize_v2(dir2);
-
- if (is_quad) {
- sub_v2_v2v2(dir3, puv[3], puv[2]);
- sub_v2_v2v2(dir4, puv[0], puv[3]);
- normalize_v2(dir3);
- normalize_v2(dir4);
- }
- else {
- sub_v2_v2v2(dir3, puv[0], puv[2]);
- normalize_v2(dir3);
- }
-
- /* TODO - angle_normalized_v2v2(...) * (M_PI/180.0f)
- * This is incorrect. Its already given radians but without it wont work.
- * need to look into a fix - campbell */
- if (is_quad) {
- a1 = shell_angle_to_dist(angle_normalized_v2v2(dir4, dir1) * ((float)M_PI / 180.0f));
- a2 = shell_angle_to_dist(angle_normalized_v2v2(dir1, dir2) * ((float)M_PI / 180.0f));
- a3 = shell_angle_to_dist(angle_normalized_v2v2(dir2, dir3) * ((float)M_PI / 180.0f));
- a4 = shell_angle_to_dist(angle_normalized_v2v2(dir3, dir4) * ((float)M_PI / 180.0f));
- }
- else {
- a1 = shell_angle_to_dist(angle_normalized_v2v2(dir3, dir1) * ((float)M_PI / 180.0f));
- a2 = shell_angle_to_dist(angle_normalized_v2v2(dir1, dir2) * ((float)M_PI / 180.0f));
- a3 = shell_angle_to_dist(angle_normalized_v2v2(dir2, dir3) * ((float)M_PI / 180.0f));
- }
-
- if (is_quad) {
- sub_v2_v2v2(no1, dir4, dir1);
- sub_v2_v2v2(no2, dir1, dir2);
- sub_v2_v2v2(no3, dir2, dir3);
- sub_v2_v2v2(no4, dir3, dir4);
- normalize_v2(no1);
- normalize_v2(no2);
- normalize_v2(no3);
- normalize_v2(no4);
- mul_v2_fl(no1, a1 * scaler);
- mul_v2_fl(no2, a2 * scaler);
- mul_v2_fl(no3, a3 * scaler);
- mul_v2_fl(no4, a4 * scaler);
- add_v2_v2v2(outset_uv[0], puv[0], no1);
- add_v2_v2v2(outset_uv[1], puv[1], no2);
- add_v2_v2v2(outset_uv[2], puv[2], no3);
- add_v2_v2v2(outset_uv[3], puv[3], no4);
- mul_v2_v2(outset_uv[0], ibuf_inv);
- mul_v2_v2(outset_uv[1], ibuf_inv);
- mul_v2_v2(outset_uv[2], ibuf_inv);
- mul_v2_v2(outset_uv[3], ibuf_inv);
- }
- else {
- sub_v2_v2v2(no1, dir3, dir1);
- sub_v2_v2v2(no2, dir1, dir2);
- sub_v2_v2v2(no3, dir2, dir3);
- normalize_v2(no1);
- normalize_v2(no2);
- normalize_v2(no3);
- mul_v2_fl(no1, a1 * scaler);
- mul_v2_fl(no2, a2 * scaler);
- mul_v2_fl(no3, a3 * scaler);
- add_v2_v2v2(outset_uv[0], puv[0], no1);
- add_v2_v2v2(outset_uv[1], puv[1], no2);
- add_v2_v2v2(outset_uv[2], puv[2], no3);
-
- mul_v2_v2(outset_uv[0], ibuf_inv);
- mul_v2_v2(outset_uv[1], ibuf_inv);
- mul_v2_v2(outset_uv[2], ibuf_inv);
- }
-}
-
-/*
- * Be tricky with flags, first 4 bits are PROJ_FACE_SEAM1 to 4, last 4 bits are PROJ_FACE_NOSEAM1 to 4
- * 1<<i - where i is (0-3)
- *
- * If we're multithreadng, make sure threads are locked when this is called
- */
-static void project_face_seams_init(const ProjPaintState *ps, const int face_index, const int is_quad)
-{
- int other_face, other_fidx; /* vars for the other face, we also set its flag */
- int fidx1 = is_quad ? 3 : 2;
- int fidx2 = 0; /* next fidx in the face (0,1,2,3) -> (1,2,3,0) or (0,1,2) -> (1,2,0) for a tri */
-
- do {
- if ((ps->faceSeamFlags[face_index] & (1 << fidx1 | 16 << fidx1)) == 0) {
- if (check_seam(ps, face_index, fidx1, fidx2, &other_face, &other_fidx)) {
- ps->faceSeamFlags[face_index] |= 1 << fidx1;
- if (other_face != -1)
- ps->faceSeamFlags[other_face] |= 1 << other_fidx;
- }
- else {
- ps->faceSeamFlags[face_index] |= 16 << fidx1;
- if (other_face != -1)
- ps->faceSeamFlags[other_face] |= 16 << other_fidx; /* second 4 bits for disabled */
- }
- }
-
- fidx2 = fidx1;
- } while (fidx1--);
-}
-#endif // PROJ_DEBUG_NOSEAMBLEED
-
-
-/* Converts a UV location to a 3D screenspace location
- * Takes a 'uv' and 3 UV coords, and sets the values of pixelScreenCo
- *
- * This is used for finding a pixels location in screenspace for painting */
-static void screen_px_from_ortho(
- float uv[2],
- float v1co[3], float v2co[3], float v3co[3], /* Screenspace coords */
- float uv1co[2], float uv2co[2], float uv3co[2],
- float pixelScreenCo[4],
- float w[3])
-{
- barycentric_weights_v2(uv1co, uv2co, uv3co, uv, w);
- interp_v3_v3v3v3(pixelScreenCo, v1co, v2co, v3co, w);
-}
-
-/* same as screen_px_from_ortho except we need to take into account
- * the perspective W coord for each vert */
-static void screen_px_from_persp(
- float uv[2],
- float v1co[4], float v2co[4], float v3co[4], /* screenspace coords */
- float uv1co[2], float uv2co[2], float uv3co[2],
- float pixelScreenCo[4],
- float w[3])
-{
-
- float wtot_inv, wtot;
- barycentric_weights_v2(uv1co, uv2co, uv3co, uv, w);
-
- /* re-weight from the 4th coord of each screen vert */
- w[0] *= v1co[3];
- w[1] *= v2co[3];
- w[2] *= v3co[3];
-
- wtot = w[0] + w[1] + w[2];
-
- if (wtot > 0.0f) {
- wtot_inv = 1.0f / wtot;
- w[0] *= wtot_inv;
- w[1] *= wtot_inv;
- w[2] *= wtot_inv;
- }
- else {
- w[0] = w[1] = w[2] = 1.0f / 3.0f; /* dummy values for zero area face */
- }
- /* done re-weighting */
-
- interp_v3_v3v3v3(pixelScreenCo, v1co, v2co, v3co, w);
-}
-
-static void project_face_pixel(const MTFace *tf_other, ImBuf *ibuf_other, const float w[3], int side, unsigned char rgba_ub[4], float rgba_f[4])
-{
- float *uvCo1, *uvCo2, *uvCo3;
- float uv_other[2], x, y;
-
- uvCo1 = (float *)tf_other->uv[0];
- if (side == 1) {
- uvCo2 = (float *)tf_other->uv[2];
- uvCo3 = (float *)tf_other->uv[3];
- }
- else {
- uvCo2 = (float *)tf_other->uv[1];
- uvCo3 = (float *)tf_other->uv[2];
- }
-
- interp_v2_v2v2v2(uv_other, uvCo1, uvCo2, uvCo3, (float *)w);
-
- /* use */
- uvco_to_wrapped_pxco(uv_other, ibuf_other->x, ibuf_other->y, &x, &y);
-
-
- if (ibuf_other->rect_float) { /* from float to float */
- bilinear_interpolation_color_wrap(ibuf_other, NULL, rgba_f, x, y);
- }
- else { /* from char to float */
- bilinear_interpolation_color_wrap(ibuf_other, rgba_ub, NULL, x, y);
- }
-
-}
-
-/* run this outside project_paint_uvpixel_init since pixels with mask 0 don't need init */
-static float project_paint_uvpixel_mask(
- const ProjPaintState *ps,
- const int face_index,
- const int side,
- const float w[3])
-{
- float mask;
-
- /* Image Mask */
- if (ps->do_layer_stencil) {
- /* another UV maps image is masking this one's */
- ImBuf *ibuf_other;
- Image *other_tpage = project_paint_face_image(ps, ps->dm_mtface_stencil, face_index);
- const MTFace *tf_other = ps->dm_mtface_stencil + face_index;
-
- if (other_tpage && (ibuf_other = BKE_image_acquire_ibuf(other_tpage, NULL, NULL))) {
- /* BKE_image_acquire_ibuf - TODO - this may be slow */
- unsigned char rgba_ub[4];
- float rgba_f[4];
-
- project_face_pixel(tf_other, ibuf_other, w, side, rgba_ub, rgba_f);
-
- if (ibuf_other->rect_float) { /* from float to float */
- mask = ((rgba_f[0] + rgba_f[1] + rgba_f[2]) / 3.0f) * rgba_f[3];
- }
- else { /* from char to float */
- mask = ((rgba_ub[0] + rgba_ub[1] + rgba_ub[2]) / (256 * 3.0f)) * (rgba_ub[3] / 256.0f);
- }
-
- BKE_image_release_ibuf(other_tpage, ibuf_other, NULL);
-
- if (!ps->do_layer_stencil_inv) /* matching the gimps layer mask black/white rules, white==full opacity */
- mask = (1.0f - mask);
-
- if (mask == 0.0f) {
- return 0.0f;
- }
- }
- else {
- return 0.0f;
- }
- }
- else {
- mask = 1.0f;
- }
-
- /* calculate mask */
- if (ps->do_mask_normal) {
- MFace *mf = &ps->dm_mface[face_index];
- float no[3], angle;
- if (mf->flag & ME_SMOOTH) {
- short *no1, *no2, *no3;
- no1 = ps->dm_mvert[mf->v1].no;
- if (side == 1) {
- no2 = ps->dm_mvert[mf->v3].no;
- no3 = ps->dm_mvert[mf->v4].no;
- }
- else {
- no2 = ps->dm_mvert[mf->v2].no;
- no3 = ps->dm_mvert[mf->v3].no;
- }
-
- no[0] = w[0] * no1[0] + w[1] * no2[0] + w[2] * no3[0];
- no[1] = w[0] * no1[1] + w[1] * no2[1] + w[2] * no3[1];
- no[2] = w[0] * no1[2] + w[1] * no2[2] + w[2] * no3[2];
- normalize_v3(no);
- }
- else {
- /* incase the */
-#if 1
- /* normalizing per pixel isn't optimal, we could cache or check ps->*/
- if (mf->v4)
- normal_quad_v3(no,
- ps->dm_mvert[mf->v1].co,
- ps->dm_mvert[mf->v2].co,
- ps->dm_mvert[mf->v3].co,
- ps->dm_mvert[mf->v4].co);
- else
- normal_tri_v3(no,
- ps->dm_mvert[mf->v1].co,
- ps->dm_mvert[mf->v2].co,
- ps->dm_mvert[mf->v3].co);
-#else
- /* don't use because some modifiers dont have normal data (subsurf for eg) */
- copy_v3_v3(no, (float *)ps->dm->getTessFaceData(ps->dm, face_index, CD_NORMAL));
-#endif
- }
-
- /* now we can use the normal as a mask */
- if (ps->is_ortho) {
- angle = angle_normalized_v3v3((float *)ps->viewDir, no);
- }
- else {
- /* Annoying but for the perspective view we need to get the pixels location in 3D space :/ */
- float viewDirPersp[3];
- float *co1, *co2, *co3;
- co1 = ps->dm_mvert[mf->v1].co;
- if (side == 1) {
- co2 = ps->dm_mvert[mf->v3].co;
- co3 = ps->dm_mvert[mf->v4].co;
- }
- else {
- co2 = ps->dm_mvert[mf->v2].co;
- co3 = ps->dm_mvert[mf->v3].co;
- }
-
- /* Get the direction from the viewPoint to the pixel and normalize */
- viewDirPersp[0] = (ps->viewPos[0] - (w[0] * co1[0] + w[1] * co2[0] + w[2] * co3[0]));
- viewDirPersp[1] = (ps->viewPos[1] - (w[0] * co1[1] + w[1] * co2[1] + w[2] * co3[1]));
- viewDirPersp[2] = (ps->viewPos[2] - (w[0] * co1[2] + w[1] * co2[2] + w[2] * co3[2]));
- normalize_v3(viewDirPersp);
-
- angle = angle_normalized_v3v3(viewDirPersp, no);
- }
-
- if (angle >= ps->normal_angle) {
- return 0.0f; /* outsize the normal limit*/
- }
- else if (angle > ps->normal_angle_inner) {
- mask *= (ps->normal_angle - angle) / ps->normal_angle_range;
- } /* otherwise no mask normal is needed, were within the limit */
- }
-
- /* This only works when the opacity dosnt change while painting, stylus pressure messes with this
- * so don't use it. */
- // if (ps->is_airbrush == 0) mask *= BKE_brush_alpha_get(ps->brush);
-
- return mask;
-}
-
-static int project_paint_pixel_sizeof(const short tool)
-{
- if ((tool == PAINT_TOOL_CLONE) || (tool == PAINT_TOOL_SMEAR)) {
- return sizeof(ProjPixelClone);
- }
- else {
- return sizeof(ProjPixel);
- }
-}
-
-
-/* run this function when we know a bucket's, face's pixel can be initialized,
- * return the ProjPixel which is added to 'ps->bucketRect[bucket_index]' */
-static ProjPixel *project_paint_uvpixel_init(
- const ProjPaintState *ps,
- MemArena *arena,
- const ImBuf *ibuf,
- short x_px, short y_px,
- const float mask,
- const int face_index,
- const int image_index,
- const float pixelScreenCo[4],
- const float world_spaceCo[3],
- const int side,
- const float w[3])
-{
- ProjPixel *projPixel;
-
- /* wrap pixel location */
- x_px = x_px % ibuf->x;
- if (x_px < 0) x_px += ibuf->x;
- y_px = y_px % ibuf->y;
- if (y_px < 0) y_px += ibuf->y;
-
- BLI_assert(ps->pixel_sizeof == project_paint_pixel_sizeof(ps->tool));
- projPixel = (ProjPixel *)BLI_memarena_alloc(arena, ps->pixel_sizeof);
- //memset(projPixel, 0, size);
-
- if (ibuf->rect_float) {
- projPixel->pixel.f_pt = ibuf->rect_float + ((x_px + y_px * ibuf->x) * 4);
- projPixel->origColor.f[0] = projPixel->newColor.f[0] = projPixel->pixel.f_pt[0];
- projPixel->origColor.f[1] = projPixel->newColor.f[1] = projPixel->pixel.f_pt[1];
- projPixel->origColor.f[2] = projPixel->newColor.f[2] = projPixel->pixel.f_pt[2];
- projPixel->origColor.f[3] = projPixel->newColor.f[3] = projPixel->pixel.f_pt[3];
- }
- else {
- projPixel->pixel.ch_pt = ((unsigned char *)ibuf->rect + ((x_px + y_px * ibuf->x) * 4));
- projPixel->origColor.uint = projPixel->newColor.uint = *projPixel->pixel.uint_pt;
- }
-
- /* screenspace unclamped, we could keep its z and w values but don't need them at the moment */
- if (ps->brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) {
- copy_v3_v3(projPixel->worldCoSS, world_spaceCo);
- }
-
- copy_v2_v2(projPixel->projCoSS, pixelScreenCo);
-
- projPixel->x_px = x_px;
- projPixel->y_px = y_px;
-
- projPixel->mask = (unsigned short)(mask * 65535);
- projPixel->mask_max = 0;
-
- /* which bounding box cell are we in?, needed for undo */
- projPixel->bb_cell_index = ((int)(((float)x_px / (float)ibuf->x) * PROJ_BOUNDBOX_DIV)) +
- ((int)(((float)y_px / (float)ibuf->y) * PROJ_BOUNDBOX_DIV)) * PROJ_BOUNDBOX_DIV;
-
- /* done with view3d_project_float inline */
- if (ps->tool == PAINT_TOOL_CLONE) {
- if (ps->dm_mtface_clone) {
- ImBuf *ibuf_other;
- Image *other_tpage = project_paint_face_image(ps, ps->dm_mtface_clone, face_index);
- const MTFace *tf_other = ps->dm_mtface_clone + face_index;
-
- if (other_tpage && (ibuf_other = BKE_image_acquire_ibuf(other_tpage, NULL, NULL))) {
- /* BKE_image_acquire_ibuf - TODO - this may be slow */
-
- if (ibuf->rect_float) {
- if (ibuf_other->rect_float) { /* from float to float */
- project_face_pixel(tf_other, ibuf_other, w, side, NULL, ((ProjPixelClone *)projPixel)->clonepx.f);
- }
- else { /* from char to float */
- unsigned char rgba_ub[4];
- project_face_pixel(tf_other, ibuf_other, w, side, rgba_ub, NULL);
- IMAPAINT_CHAR_RGBA_TO_FLOAT(((ProjPixelClone *)projPixel)->clonepx.f, rgba_ub);
- }
- }
- else {
- if (ibuf_other->rect_float) { /* float to char */
- float rgba[4];
- project_face_pixel(tf_other, ibuf_other, w, side, NULL, rgba);
- IMAPAINT_FLOAT_RGBA_TO_CHAR(((ProjPixelClone *)projPixel)->clonepx.ch, rgba);
- }
- else { /* char to char */
- project_face_pixel(tf_other, ibuf_other, w, side, ((ProjPixelClone *)projPixel)->clonepx.ch, NULL);
- }
- }
-
- BKE_image_release_ibuf(other_tpage, ibuf_other, NULL);
- }
- else {
- if (ibuf->rect_float) {
- ((ProjPixelClone *)projPixel)->clonepx.f[3] = 0;
- }
- else {
- ((ProjPixelClone *)projPixel)->clonepx.ch[3] = 0;
- }
- }
-
- }
- else {
- float co[2];
- sub_v2_v2v2(co, projPixel->projCoSS, (float *)ps->cloneOffset);
-
- /* no need to initialize the bucket, we're only checking buckets faces and for this
- * the faces are already initialized in project_paint_delayed_face_init(...) */
- if (ibuf->rect_float) {
- if (!project_paint_PickColor(ps, co, ((ProjPixelClone *)projPixel)->clonepx.f, NULL, 1)) {
- ((ProjPixelClone *)projPixel)->clonepx.f[3] = 0; /* zero alpha - ignore */
- }
- }
- else {
- if (!project_paint_PickColor(ps, co, NULL, ((ProjPixelClone *)projPixel)->clonepx.ch, 1)) {
- ((ProjPixelClone *)projPixel)->clonepx.ch[3] = 0; /* zero alpha - ignore */
- }
- }
- }
- }
-
-#ifdef PROJ_DEBUG_PAINT
- if (ibuf->rect_float) projPixel->pixel.f_pt[0] = 0;
- else projPixel->pixel.ch_pt[0] = 0;
-#endif
- projPixel->image_index = image_index;
-
- return projPixel;
-}
-
-static int line_clip_rect2f(
- rctf *rect,
- const float l1[2], const float l2[2],
- float l1_clip[2], float l2_clip[2])
-{
- /* first account for horizontal, then vertical lines */
- /* horiz */
- if (fabsf(l1[1] - l2[1]) < PROJ_GEOM_TOLERANCE) {
- /* is the line out of range on its Y axis? */
- if (l1[1] < rect->ymin || l1[1] > rect->ymax) {
- return 0;
- }
- /* line is out of range on its X axis */
- if ((l1[0] < rect->xmin && l2[0] < rect->xmin) || (l1[0] > rect->xmax && l2[0] > rect->xmax)) {
- return 0;
- }
-
-
- if (fabsf(l1[0] - l2[0]) < PROJ_GEOM_TOLERANCE) { /* this is a single point (or close to)*/
- if (BLI_rctf_isect_pt_v(rect, l1)) {
- copy_v2_v2(l1_clip, l1);
- copy_v2_v2(l2_clip, l2);
- return 1;
- }
- else {
- return 0;
- }
- }
-
- copy_v2_v2(l1_clip, l1);
- copy_v2_v2(l2_clip, l2);
- CLAMP(l1_clip[0], rect->xmin, rect->xmax);
- CLAMP(l2_clip[0], rect->xmin, rect->xmax);
- return 1;
- }
- else if (fabsf(l1[0] - l2[0]) < PROJ_GEOM_TOLERANCE) {
- /* is the line out of range on its X axis? */
- if (l1[0] < rect->xmin || l1[0] > rect->xmax) {
- return 0;
- }
-
- /* line is out of range on its Y axis */
- if ((l1[1] < rect->ymin && l2[1] < rect->ymin) || (l1[1] > rect->ymax && l2[1] > rect->ymax)) {
- return 0;
- }
-
- if (fabsf(l1[1] - l2[1]) < PROJ_GEOM_TOLERANCE) { /* this is a single point (or close to)*/
- if (BLI_rctf_isect_pt_v(rect, l1)) {
- copy_v2_v2(l1_clip, l1);
- copy_v2_v2(l2_clip, l2);
- return 1;
- }
- else {
- return 0;
- }
- }
-
- copy_v2_v2(l1_clip, l1);
- copy_v2_v2(l2_clip, l2);
- CLAMP(l1_clip[1], rect->ymin, rect->ymax);
- CLAMP(l2_clip[1], rect->ymin, rect->ymax);
- return 1;
- }
- else {
- float isect;
- short ok1 = 0;
- short ok2 = 0;
-
- /* Done with vertical lines */
-
- /* are either of the points inside the rectangle ? */
- if (BLI_rctf_isect_pt_v(rect, l1)) {
- copy_v2_v2(l1_clip, l1);
- ok1 = 1;
- }
-
- if (BLI_rctf_isect_pt_v(rect, l2)) {
- copy_v2_v2(l2_clip, l2);
- ok2 = 1;
- }
-
- /* line inside rect */
- if (ok1 && ok2) return 1;
-
- /* top/bottom */
- if (line_isect_y(l1, l2, rect->ymin, &isect) && (isect >= rect->xmin) && (isect <= rect->xmax)) {
- if (l1[1] < l2[1]) { /* line 1 is outside */
- l1_clip[0] = isect;
- l1_clip[1] = rect->ymin;
- ok1 = 1;
- }
- else {
- l2_clip[0] = isect;
- l2_clip[1] = rect->ymin;
- ok2 = 2;
- }
- }
-
- if (ok1 && ok2) return 1;
-
- if (line_isect_y(l1, l2, rect->ymax, &isect) && (isect >= rect->xmin) && (isect <= rect->xmax)) {
- if (l1[1] > l2[1]) { /* line 1 is outside */
- l1_clip[0] = isect;
- l1_clip[1] = rect->ymax;
- ok1 = 1;
- }
- else {
- l2_clip[0] = isect;
- l2_clip[1] = rect->ymax;
- ok2 = 2;
- }
- }
-
- if (ok1 && ok2) return 1;
-
- /* left/right */
- if (line_isect_x(l1, l2, rect->xmin, &isect) && (isect >= rect->ymin) && (isect <= rect->ymax)) {
- if (l1[0] < l2[0]) { /* line 1 is outside */
- l1_clip[0] = rect->xmin;
- l1_clip[1] = isect;
- ok1 = 1;
- }
- else {
- l2_clip[0] = rect->xmin;
- l2_clip[1] = isect;
- ok2 = 2;
- }
- }
-
- if (ok1 && ok2) return 1;
-
- if (line_isect_x(l1, l2, rect->xmax, &isect) && (isect >= rect->ymin) && (isect <= rect->ymax)) {
- if (l1[0] > l2[0]) { /* line 1 is outside */
- l1_clip[0] = rect->xmax;
- l1_clip[1] = isect;
- ok1 = 1;
- }
- else {
- l2_clip[0] = rect->xmax;
- l2_clip[1] = isect;
- ok2 = 2;
- }
- }
-
- if (ok1 && ok2) {
- return 1;
- }
- else {
- return 0;
- }
- }
-}
-
-
-
-/* scale the quad & tri about its center
- * scaling by PROJ_FACE_SCALE_SEAM (0.99x) is used for getting fake UV pixel coords that are on the
- * edge of the face but slightly inside it occlusion tests don't return hits on adjacent faces */
-#ifndef PROJ_DEBUG_NOSEAMBLEED
-static void scale_quad(float insetCos[4][3], float *origCos[4], const float inset)
-{
- float cent[3];
- cent[0] = (origCos[0][0] + origCos[1][0] + origCos[2][0] + origCos[3][0]) / 4.0f;
- cent[1] = (origCos[0][1] + origCos[1][1] + origCos[2][1] + origCos[3][1]) / 4.0f;
- cent[2] = (origCos[0][2] + origCos[1][2] + origCos[2][2] + origCos[3][2]) / 4.0f;
-
- sub_v3_v3v3(insetCos[0], origCos[0], cent);
- sub_v3_v3v3(insetCos[1], origCos[1], cent);
- sub_v3_v3v3(insetCos[2], origCos[2], cent);
- sub_v3_v3v3(insetCos[3], origCos[3], cent);
-
- mul_v3_fl(insetCos[0], inset);
- mul_v3_fl(insetCos[1], inset);
- mul_v3_fl(insetCos[2], inset);
- mul_v3_fl(insetCos[3], inset);
-
- add_v3_v3(insetCos[0], cent);
- add_v3_v3(insetCos[1], cent);
- add_v3_v3(insetCos[2], cent);
- add_v3_v3(insetCos[3], cent);
-}
-
-
-static void scale_tri(float insetCos[4][3], float *origCos[4], const float inset)
-{
- float cent[3];
- cent[0] = (origCos[0][0] + origCos[1][0] + origCos[2][0]) / 3.0f;
- cent[1] = (origCos[0][1] + origCos[1][1] + origCos[2][1]) / 3.0f;
- cent[2] = (origCos[0][2] + origCos[1][2] + origCos[2][2]) / 3.0f;
-
- sub_v3_v3v3(insetCos[0], origCos[0], cent);
- sub_v3_v3v3(insetCos[1], origCos[1], cent);
- sub_v3_v3v3(insetCos[2], origCos[2], cent);
-
- mul_v3_fl(insetCos[0], inset);
- mul_v3_fl(insetCos[1], inset);
- mul_v3_fl(insetCos[2], inset);
-
- add_v3_v3(insetCos[0], cent);
- add_v3_v3(insetCos[1], cent);
- add_v3_v3(insetCos[2], cent);
-}
-#endif //PROJ_DEBUG_NOSEAMBLEED
-
-static float len_squared_v2v2_alt(const float *v1, const float v2_1, const float v2_2)
-{
- float x, y;
-
- x = v1[0] - v2_1;
- y = v1[1] - v2_2;
- return x * x + y * y;
-}
-
-/* note, use a squared value so we can use len_squared_v2v2
- * be sure that you have done a bounds check first or this may fail */
-/* only give bucket_bounds as an arg because we need it elsewhere */
-static int project_bucket_isect_circle(const float cent[2], const float radius_squared, rctf *bucket_bounds)
-{
-
- /* Would normally to a simple intersection test, however we know the bounds of these 2 already intersect
- * so we only need to test if the center is inside the vertical or horizontal bounds on either axis,
- * this is even less work then an intersection test
- */
-#if 0
- if (BLI_rctf_isect_pt_v(bucket_bounds, cent))
- return 1;
-#endif
-
- if ((bucket_bounds->xmin <= cent[0] && bucket_bounds->xmax >= cent[0]) ||
- (bucket_bounds->ymin <= cent[1] && bucket_bounds->ymax >= cent[1]))
- {
- return 1;
- }
-
- /* out of bounds left */
- if (cent[0] < bucket_bounds->xmin) {
- /* lower left out of radius test */
- if (cent[1] < bucket_bounds->ymin) {
- return (len_squared_v2v2_alt(cent, bucket_bounds->xmin, bucket_bounds->ymin) < radius_squared) ? 1 : 0;
- }
- /* top left test */
- else if (cent[1] > bucket_bounds->ymax) {
- return (len_squared_v2v2_alt(cent, bucket_bounds->xmin, bucket_bounds->ymax) < radius_squared) ? 1 : 0;
- }
- }
- else if (cent[0] > bucket_bounds->xmax) {
- /* lower right out of radius test */
- if (cent[1] < bucket_bounds->ymin) {
- return (len_squared_v2v2_alt(cent, bucket_bounds->xmax, bucket_bounds->ymin) < radius_squared) ? 1 : 0;
- }
- /* top right test */
- else if (cent[1] > bucket_bounds->ymax) {
- return (len_squared_v2v2_alt(cent, bucket_bounds->xmax, bucket_bounds->ymax) < radius_squared) ? 1 : 0;
- }
- }
-
- return 0;
-}
-
-
-
-/* Note for rect_to_uvspace_ortho() and rect_to_uvspace_persp()
- * in ortho view this function gives good results when bucket_bounds are outside the triangle
- * however in some cases, perspective view will mess up with faces that have minimal screenspace area
- * (viewed from the side)
- *
- * for this reason its not reliable in this case so we'll use the Simple Barycentric'
- * funcs that only account for points inside the triangle.
- * however switching back to this for ortho is always an option */
-
-static void rect_to_uvspace_ortho(
- rctf *bucket_bounds,
- float *v1coSS, float *v2coSS, float *v3coSS,
- float *uv1co, float *uv2co, float *uv3co,
- float bucket_bounds_uv[4][2],
- const int flip)
-{
- float uv[2];
- float w[3];
-
- /* get the UV space bounding box */
- uv[0] = bucket_bounds->xmax;
- uv[1] = bucket_bounds->ymin;
- barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w);
- interp_v2_v2v2v2(bucket_bounds_uv[flip ? 3 : 0], uv1co, uv2co, uv3co, w);
-
- //uv[0] = bucket_bounds->xmax; // set above
- uv[1] = bucket_bounds->ymax;
- barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w);
- interp_v2_v2v2v2(bucket_bounds_uv[flip ? 2 : 1], uv1co, uv2co, uv3co, w);
-
- uv[0] = bucket_bounds->xmin;
- //uv[1] = bucket_bounds->ymax; // set above
- barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w);
- interp_v2_v2v2v2(bucket_bounds_uv[flip ? 1 : 2], uv1co, uv2co, uv3co, w);
-
- //uv[0] = bucket_bounds->xmin; // set above
- uv[1] = bucket_bounds->ymin;
- barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w);
- interp_v2_v2v2v2(bucket_bounds_uv[flip ? 0 : 3], uv1co, uv2co, uv3co, w);
-}
-
-/* same as above but use barycentric_weights_v2_persp */
-static void rect_to_uvspace_persp(
- rctf *bucket_bounds,
- float *v1coSS, float *v2coSS, float *v3coSS,
- float *uv1co, float *uv2co, float *uv3co,
- float bucket_bounds_uv[4][2],
- const int flip
- )
-{
- float uv[2];
- float w[3];
-
- /* get the UV space bounding box */
- uv[0] = bucket_bounds->xmax;
- uv[1] = bucket_bounds->ymin;
- barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w);
- interp_v2_v2v2v2(bucket_bounds_uv[flip ? 3 : 0], uv1co, uv2co, uv3co, w);
-
- //uv[0] = bucket_bounds->xmax; // set above
- uv[1] = bucket_bounds->ymax;
- barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w);
- interp_v2_v2v2v2(bucket_bounds_uv[flip ? 2 : 1], uv1co, uv2co, uv3co, w);
-
- uv[0] = bucket_bounds->xmin;
- //uv[1] = bucket_bounds->ymax; // set above
- barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w);
- interp_v2_v2v2v2(bucket_bounds_uv[flip ? 1 : 2], uv1co, uv2co, uv3co, w);
-
- //uv[0] = bucket_bounds->xmin; // set above
- uv[1] = bucket_bounds->ymin;
- barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w);
- interp_v2_v2v2v2(bucket_bounds_uv[flip ? 0 : 3], uv1co, uv2co, uv3co, w);
-}
-
-/* This works as we need it to but we can save a few steps and not use it */
-
-#if 0
-static float angle_2d_clockwise(const float p1[2], const float p2[2], const float p3[2])
-{
- float v1[2], v2[2];
-
- v1[0] = p1[0] - p2[0]; v1[1] = p1[1] - p2[1];
- v2[0] = p3[0] - p2[0]; v2[1] = p3[1] - p2[1];
-
- return -atan2(v1[0] * v2[1] - v1[1] * v2[0], v1[0] * v2[0] + v1[1] * v2[1]);
-}
-#endif
-
-#define ISECT_1 (1)
-#define ISECT_2 (1 << 1)
-#define ISECT_3 (1 << 2)
-#define ISECT_4 (1 << 3)
-#define ISECT_ALL3 ((1 << 3) - 1)
-#define ISECT_ALL4 ((1 << 4) - 1)
-
-/* limit must be a fraction over 1.0f */
-static int IsectPT2Df_limit(float pt[2], float v1[2], float v2[2], float v3[2], float limit)
-{
- return ((area_tri_v2(pt, v1, v2) + area_tri_v2(pt, v2, v3) + area_tri_v2(pt, v3, v1)) / (area_tri_v2(v1, v2, v3))) < limit;
-}
-
-/* Clip the face by a bucket and set the uv-space bucket_bounds_uv
- * so we have the clipped UV's to do pixel intersection tests with
- * */
-static int float_z_sort_flip(const void *p1, const void *p2)
-{
- return (((float *)p1)[2] < ((float *)p2)[2] ? 1 : -1);
-}
-
-static int float_z_sort(const void *p1, const void *p2)
-{
- return (((float *)p1)[2] < ((float *)p2)[2] ? -1 : 1);
-}
-
-static void project_bucket_clip_face(
- const int is_ortho,
- rctf *bucket_bounds,
- float *v1coSS, float *v2coSS, float *v3coSS,
- float *uv1co, float *uv2co, float *uv3co,
- float bucket_bounds_uv[8][2],
- int *tot)
-{
- int inside_bucket_flag = 0;
- int inside_face_flag = 0;
- const int flip = ((line_point_side_v2(v1coSS, v2coSS, v3coSS) > 0.0f) != (line_point_side_v2(uv1co, uv2co, uv3co) > 0.0f));
-
- float bucket_bounds_ss[4][2];
-
- /* get the UV space bounding box */
- inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v1coSS);
- inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v2coSS) << 1;
- inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v3coSS) << 2;
-
- if (inside_bucket_flag == ISECT_ALL3) {
- /* all screenspace points are inside the bucket bounding box, this means we don't need to clip and can simply return the UVs */
- if (flip) { /* facing the back? */
- copy_v2_v2(bucket_bounds_uv[0], uv3co);
- copy_v2_v2(bucket_bounds_uv[1], uv2co);
- copy_v2_v2(bucket_bounds_uv[2], uv1co);
- }
- else {
- copy_v2_v2(bucket_bounds_uv[0], uv1co);
- copy_v2_v2(bucket_bounds_uv[1], uv2co);
- copy_v2_v2(bucket_bounds_uv[2], uv3co);
- }
-
- *tot = 3;
- return;
- }
-
- /* get the UV space bounding box */
- /* use IsectPT2Df_limit here so we catch points are are touching the tri edge (or a small fraction over) */
- bucket_bounds_ss[0][0] = bucket_bounds->xmax;
- bucket_bounds_ss[0][1] = bucket_bounds->ymin;
- inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[0], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ? ISECT_1 : 0);
-
- bucket_bounds_ss[1][0] = bucket_bounds->xmax;
- bucket_bounds_ss[1][1] = bucket_bounds->ymax;
- inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[1], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ? ISECT_2 : 0);
-
- bucket_bounds_ss[2][0] = bucket_bounds->xmin;
- bucket_bounds_ss[2][1] = bucket_bounds->ymax;
- inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[2], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ? ISECT_3 : 0);
-
- bucket_bounds_ss[3][0] = bucket_bounds->xmin;
- bucket_bounds_ss[3][1] = bucket_bounds->ymin;
- inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[3], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ? ISECT_4 : 0);
-
- if (inside_face_flag == ISECT_ALL4) {
- /* bucket is totally inside the screenspace face, we can safely use weights */
-
- if (is_ortho) rect_to_uvspace_ortho(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, bucket_bounds_uv, flip);
- else rect_to_uvspace_persp(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, bucket_bounds_uv, flip);
-
- *tot = 4;
- return;
- }
- else {
- /* The Complicated Case!
- *
- * The 2 cases above are where the face is inside the bucket or the bucket is inside the face.
- *
- * we need to make a convex polyline from the intersection between the screenspace face
- * and the bucket bounds.
- *
- * There are a number of ways this could be done, currently it just collects all intersecting verts,
- * and line intersections, then sorts them clockwise, this is a lot easier then evaluating the geometry to
- * do a correct clipping on both shapes. */
-
-
- /* add a bunch of points, we know must make up the convex hull which is the clipped rect and triangle */
-
-
-
- /* Maximum possible 6 intersections when using a rectangle and triangle */
- float isectVCosSS[8][3]; /* The 3rd float is used to store angle for qsort(), NOT as a Z location */
- float v1_clipSS[2], v2_clipSS[2];
- float w[3];
-
- /* calc center */
- float cent[2] = {0.0f, 0.0f};
- /*float up[2] = {0.0f, 1.0f};*/
- int i;
- short doubles;
-
- (*tot) = 0;
-
- if (inside_face_flag & ISECT_1) { copy_v2_v2(isectVCosSS[*tot], bucket_bounds_ss[0]); (*tot)++; }
- if (inside_face_flag & ISECT_2) { copy_v2_v2(isectVCosSS[*tot], bucket_bounds_ss[1]); (*tot)++; }
- if (inside_face_flag & ISECT_3) { copy_v2_v2(isectVCosSS[*tot], bucket_bounds_ss[2]); (*tot)++; }
- if (inside_face_flag & ISECT_4) { copy_v2_v2(isectVCosSS[*tot], bucket_bounds_ss[3]); (*tot)++; }
-
- if (inside_bucket_flag & ISECT_1) { copy_v2_v2(isectVCosSS[*tot], v1coSS); (*tot)++; }
- if (inside_bucket_flag & ISECT_2) { copy_v2_v2(isectVCosSS[*tot], v2coSS); (*tot)++; }
- if (inside_bucket_flag & ISECT_3) { copy_v2_v2(isectVCosSS[*tot], v3coSS); (*tot)++; }
-
- if ((inside_bucket_flag & (ISECT_1 | ISECT_2)) != (ISECT_1 | ISECT_2)) {
- if (line_clip_rect2f(bucket_bounds, v1coSS, v2coSS, v1_clipSS, v2_clipSS)) {
- if ((inside_bucket_flag & ISECT_1) == 0) { copy_v2_v2(isectVCosSS[*tot], v1_clipSS); (*tot)++; }
- if ((inside_bucket_flag & ISECT_2) == 0) { copy_v2_v2(isectVCosSS[*tot], v2_clipSS); (*tot)++; }
- }
- }
-
- if ((inside_bucket_flag & (ISECT_2 | ISECT_3)) != (ISECT_2 | ISECT_3)) {
- if (line_clip_rect2f(bucket_bounds, v2coSS, v3coSS, v1_clipSS, v2_clipSS)) {
- if ((inside_bucket_flag & ISECT_2) == 0) { copy_v2_v2(isectVCosSS[*tot], v1_clipSS); (*tot)++; }
- if ((inside_bucket_flag & ISECT_3) == 0) { copy_v2_v2(isectVCosSS[*tot], v2_clipSS); (*tot)++; }
- }
- }
-
- if ((inside_bucket_flag & (ISECT_3 | ISECT_1)) != (ISECT_3 | ISECT_1)) {
- if (line_clip_rect2f(bucket_bounds, v3coSS, v1coSS, v1_clipSS, v2_clipSS)) {
- if ((inside_bucket_flag & ISECT_3) == 0) { copy_v2_v2(isectVCosSS[*tot], v1_clipSS); (*tot)++; }
- if ((inside_bucket_flag & ISECT_1) == 0) { copy_v2_v2(isectVCosSS[*tot], v2_clipSS); (*tot)++; }
- }
- }
-
-
- if ((*tot) < 3) { /* no intersections to speak of */
- *tot = 0;
- return;
- }
-
- /* now we have all points we need, collect their angles and sort them clockwise */
-
- for (i = 0; i < (*tot); i++) {
- cent[0] += isectVCosSS[i][0];
- cent[1] += isectVCosSS[i][1];
- }
- cent[0] = cent[0] / (float)(*tot);
- cent[1] = cent[1] / (float)(*tot);
-
-
-
- /* Collect angles for every point around the center point */
-
-
-#if 0 /* uses a few more cycles then the above loop */
- for (i = 0; i < (*tot); i++) {
- isectVCosSS[i][2] = angle_2d_clockwise(up, cent, isectVCosSS[i]);
- }
-#endif
-
- v1_clipSS[0] = cent[0]; /* Abuse this var for the loop below */
- v1_clipSS[1] = cent[1] + 1.0f;
-
- for (i = 0; i < (*tot); i++) {
- v2_clipSS[0] = isectVCosSS[i][0] - cent[0];
- v2_clipSS[1] = isectVCosSS[i][1] - cent[1];
- isectVCosSS[i][2] = atan2f(v1_clipSS[0] * v2_clipSS[1] - v1_clipSS[1] * v2_clipSS[0], v1_clipSS[0] * v2_clipSS[0] + v1_clipSS[1] * v2_clipSS[1]);
- }
-
- if (flip) qsort(isectVCosSS, *tot, sizeof(float) * 3, float_z_sort_flip);
- else qsort(isectVCosSS, *tot, sizeof(float) * 3, float_z_sort);
-
- /* remove doubles */
- /* first/last check */
- if (fabsf(isectVCosSS[0][0] - isectVCosSS[(*tot) - 1][0]) < PROJ_GEOM_TOLERANCE &&
- fabsf(isectVCosSS[0][1] - isectVCosSS[(*tot) - 1][1]) < PROJ_GEOM_TOLERANCE)
- {
- (*tot)--;
- }
-
- /* its possible there is only a few left after remove doubles */
- if ((*tot) < 3) {
- // printf("removed too many doubles A\n");
- *tot = 0;
- return;
- }
-
- doubles = TRUE;
- while (doubles == TRUE) {
- doubles = FALSE;
- for (i = 1; i < (*tot); i++) {
- if (fabsf(isectVCosSS[i - 1][0] - isectVCosSS[i][0]) < PROJ_GEOM_TOLERANCE &&
- fabsf(isectVCosSS[i - 1][1] - isectVCosSS[i][1]) < PROJ_GEOM_TOLERANCE)
- {
- int j;
- for (j = i + 1; j < (*tot); j++) {
- isectVCosSS[j - 1][0] = isectVCosSS[j][0];
- isectVCosSS[j - 1][1] = isectVCosSS[j][1];
- }
- doubles = TRUE; /* keep looking for more doubles */
- (*tot)--;
- }
- }
- }
-
- /* its possible there is only a few left after remove doubles */
- if ((*tot) < 3) {
- // printf("removed too many doubles B\n");
- *tot = 0;
- return;
- }
-
-
- if (is_ortho) {
- for (i = 0; i < (*tot); i++) {
- barycentric_weights_v2(v1coSS, v2coSS, v3coSS, isectVCosSS[i], w);
- interp_v2_v2v2v2(bucket_bounds_uv[i], uv1co, uv2co, uv3co, w);
- }
- }
- else {
- for (i = 0; i < (*tot); i++) {
- barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, isectVCosSS[i], w);
- interp_v2_v2v2v2(bucket_bounds_uv[i], uv1co, uv2co, uv3co, w);
- }
- }
- }
-
-#ifdef PROJ_DEBUG_PRINT_CLIP
- /* include this at the bottom of the above function to debug the output */
-
- {
- /* If there are ever any problems, */
- float test_uv[4][2];
- int i;
- if (is_ortho) rect_to_uvspace_ortho(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, test_uv, flip);
- else rect_to_uvspace_persp(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, test_uv, flip);
- printf("( [(%f,%f), (%f,%f), (%f,%f), (%f,%f)], ", test_uv[0][0], test_uv[0][1], test_uv[1][0], test_uv[1][1], test_uv[2][0], test_uv[2][1], test_uv[3][0], test_uv[3][1]);
-
- printf(" [(%f,%f), (%f,%f), (%f,%f)], ", uv1co[0], uv1co[1], uv2co[0], uv2co[1], uv3co[0], uv3co[1]);
-
- printf("[");
- for (i = 0; i < (*tot); i++) {
- printf("(%f, %f),", bucket_bounds_uv[i][0], bucket_bounds_uv[i][1]);
- }
- printf("]),\\\n");
- }
-#endif
-}
-
-/*
- * # This script creates faces in a blender scene from printed data above.
- *
- * project_ls = [
- * ...(output from above block)...
- * ]
- *
- * from Blender import Scene, Mesh, Window, sys, Mathutils
- *
- * import bpy
- *
- * V = Mathutils.Vector
- *
- * def main():
- * sce = bpy.data.scenes.active
- *
- * for item in project_ls:
- * bb = item[0]
- * uv = item[1]
- * poly = item[2]
- *
- * me = bpy.data.meshes.new()
- * ob = sce.objects.new(me)
- *
- * me.verts.extend([V(bb[0]).xyz, V(bb[1]).xyz, V(bb[2]).xyz, V(bb[3]).xyz])
- * me.faces.extend([(0,1,2,3),])
- * me.verts.extend([V(uv[0]).xyz, V(uv[1]).xyz, V(uv[2]).xyz])
- * me.faces.extend([(4,5,6),])
- *
- * vs = [V(p).xyz for p in poly]
- * print len(vs)
- * l = len(me.verts)
- * me.verts.extend(vs)
- *
- * i = l
- * while i < len(me.verts):
- * ii = i + 1
- * if ii == len(me.verts):
- * ii = l
- * me.edges.extend([i, ii])
- * i += 1
- *
- * if __name__ == '__main__':
- * main()
- */
-
-
-#undef ISECT_1
-#undef ISECT_2
-#undef ISECT_3
-#undef ISECT_4
-#undef ISECT_ALL3
-#undef ISECT_ALL4
-
-
-/* checks if pt is inside a convex 2D polyline, the polyline must be ordered rotating clockwise
- * otherwise it would have to test for mixed (line_point_side_v2 > 0.0f) cases */
-static int IsectPoly2Df(const float pt[2], float uv[][2], const int tot)
-{
- int i;
- if (line_point_side_v2(uv[tot - 1], uv[0], pt) < 0.0f)
- return 0;
-
- for (i = 1; i < tot; i++) {
- if (line_point_side_v2(uv[i - 1], uv[i], pt) < 0.0f)
- return 0;
-
- }
-
- return 1;
-}
-static int IsectPoly2Df_twoside(const float pt[2], float uv[][2], const int tot)
-{
- int i;
- int side = (line_point_side_v2(uv[tot - 1], uv[0], pt) > 0.0f);
-
- for (i = 1; i < tot; i++) {
- if ((line_point_side_v2(uv[i - 1], uv[i], pt) > 0.0f) != side)
- return 0;
-
- }
-
- return 1;
-}
-
-/* One of the most important function for projection painting, since it selects the pixels to be added into each bucket.
- * initialize pixels from this face where it intersects with the bucket_index, optionally initialize pixels for removing seams */
-static void project_paint_face_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, const int face_index, const int image_index, rctf *bucket_bounds, const ImBuf *ibuf, const short clamp_u, const short clamp_v)
-{
- /* Projection vars, to get the 3D locations into screen space */
- MemArena *arena = ps->arena_mt[thread_index];
- LinkNode **bucketPixelNodes = ps->bucketRect + bucket_index;
- LinkNode *bucketFaceNodes = ps->bucketFaces[bucket_index];
-
- const MFace *mf = ps->dm_mface + face_index;
- const MTFace *tf = ps->dm_mtface + face_index;
-
- /* UV/pixel seeking data */
- int x; /* Image X-Pixel */
- int y; /* Image Y-Pixel */
- float mask;
- float uv[2]; /* Image floating point UV - same as x, y but from 0.0-1.0 */
-
- int side;
- float *v1coSS, *v2coSS, *v3coSS; /* vert co screen-space, these will be assigned to mf->v1,2,3 or mf->v1,3,4 */
-
- float *vCo[4]; /* vertex screenspace coords */
-
- float w[3], wco[3];
-
- float *uv1co, *uv2co, *uv3co; /* for convenience only, these will be assigned to tf->uv[0],1,2 or tf->uv[0],2,3 */
- float pixelScreenCo[4];
- bool do_3d_mapping = ps->brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D;
-
- rcti bounds_px; /* ispace bounds */
- /* vars for getting uvspace bounds */
-
- float tf_uv_pxoffset[4][2]; /* bucket bounds in UV space so we can init pixels only for this face, */
- float xhalfpx, yhalfpx;
- const float ibuf_xf = (float)ibuf->x, ibuf_yf = (float)ibuf->y;
-
- int has_x_isect = 0, has_isect = 0; /* for early loop exit */
-
- int i1, i2, i3;
-
- float uv_clip[8][2];
- int uv_clip_tot;
- const short is_ortho = ps->is_ortho;
- const short do_backfacecull = ps->do_backfacecull;
- const short do_clip = ps->rv3d ? ps->rv3d->rflag & RV3D_CLIPPING : 0;
-
- vCo[0] = ps->dm_mvert[mf->v1].co;
- vCo[1] = ps->dm_mvert[mf->v2].co;
- vCo[2] = ps->dm_mvert[mf->v3].co;
-
-
- /* Use tf_uv_pxoffset instead of tf->uv so we can offset the UV half a pixel
- * this is done so we can avoid offsetting all the pixels by 0.5 which causes
- * problems when wrapping negative coords */
- xhalfpx = (0.5f + (PROJ_GEOM_TOLERANCE / 3.0f)) / ibuf_xf;
- yhalfpx = (0.5f + (PROJ_GEOM_TOLERANCE / 4.0f)) / ibuf_yf;
-
- /* Note about (PROJ_GEOM_TOLERANCE/x) above...
- * Needed to add this offset since UV coords are often quads aligned to pixels.
- * In this case pixels can be exactly between 2 triangles causing nasty
- * artifacts.
- *
- * This workaround can be removed and painting will still work on most cases
- * but since the first thing most people try is painting onto a quad- better make it work.
- */
-
-
-
- tf_uv_pxoffset[0][0] = tf->uv[0][0] - xhalfpx;
- tf_uv_pxoffset[0][1] = tf->uv[0][1] - yhalfpx;
-
- tf_uv_pxoffset[1][0] = tf->uv[1][0] - xhalfpx;
- tf_uv_pxoffset[1][1] = tf->uv[1][1] - yhalfpx;
-
- tf_uv_pxoffset[2][0] = tf->uv[2][0] - xhalfpx;
- tf_uv_pxoffset[2][1] = tf->uv[2][1] - yhalfpx;
-
- if (mf->v4) {
- vCo[3] = ps->dm_mvert[mf->v4].co;
-
- tf_uv_pxoffset[3][0] = tf->uv[3][0] - xhalfpx;
- tf_uv_pxoffset[3][1] = tf->uv[3][1] - yhalfpx;
- side = 1;
- }
- else {
- side = 0;
- }
-
- do {
- if (side == 1) {
- i1 = 0; i2 = 2; i3 = 3;
- }
- else {
- i1 = 0; i2 = 1; i3 = 2;
- }
-
- uv1co = tf_uv_pxoffset[i1]; // was tf->uv[i1];
- uv2co = tf_uv_pxoffset[i2]; // was tf->uv[i2];
- uv3co = tf_uv_pxoffset[i3]; // was tf->uv[i3];
-
- v1coSS = ps->screenCoords[(*(&mf->v1 + i1))];
- v2coSS = ps->screenCoords[(*(&mf->v1 + i2))];
- v3coSS = ps->screenCoords[(*(&mf->v1 + i3))];
-
- /* This funtion gives is a concave polyline in UV space from the clipped quad and tri*/
- project_bucket_clip_face(
- is_ortho, bucket_bounds,
- v1coSS, v2coSS, v3coSS,
- uv1co, uv2co, uv3co,
- uv_clip, &uv_clip_tot
- );
-
- /* sometimes this happens, better just allow for 8 intersectiosn even though there should be max 6 */
-#if 0
- if (uv_clip_tot > 6) {
- printf("this should never happen! %d\n", uv_clip_tot);
- }
-#endif
-
- if (pixel_bounds_array(uv_clip, &bounds_px, ibuf->x, ibuf->y, uv_clip_tot)) {
-
- if (clamp_u) {
- CLAMP(bounds_px.xmin, 0, ibuf->x);
- CLAMP(bounds_px.xmax, 0, ibuf->x);
- }
-
- if (clamp_v) {
- CLAMP(bounds_px.ymin, 0, ibuf->y);
- CLAMP(bounds_px.ymax, 0, ibuf->y);
- }
-
- /* clip face and */
-
- has_isect = 0;
- for (y = bounds_px.ymin; y < bounds_px.ymax; y++) {
- //uv[1] = (((float)y) + 0.5f) / (float)ibuf->y;
- uv[1] = (float)y / ibuf_yf; /* use pixel offset UV coords instead */
-
- has_x_isect = 0;
- for (x = bounds_px.xmin; x < bounds_px.xmax; x++) {
- //uv[0] = (((float)x) + 0.5f) / ibuf->x;
- uv[0] = (float)x / ibuf_xf; /* use pixel offset UV coords instead */
-
- /* Note about IsectPoly2Df_twoside, checking the face or uv flipping doesnt work,
- * could check the poly direction but better to do this */
- if ((do_backfacecull == TRUE && IsectPoly2Df(uv, uv_clip, uv_clip_tot)) ||
- (do_backfacecull == FALSE && IsectPoly2Df_twoside(uv, uv_clip, uv_clip_tot)))
- {
-
- has_x_isect = has_isect = 1;
-
- if (is_ortho) screen_px_from_ortho(uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w);
- else screen_px_from_persp(uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w);
-
- /* a pity we need to get the worldspace pixel location here */
- if (do_clip || do_3d_mapping) {
- interp_v3_v3v3v3(wco, ps->dm_mvert[(*(&mf->v1 + i1))].co, ps->dm_mvert[(*(&mf->v1 + i2))].co, ps->dm_mvert[(*(&mf->v1 + i3))].co, w);
- if (do_clip && ED_view3d_clipping_test(ps->rv3d, wco, TRUE)) {
- continue; /* Watch out that no code below this needs to run */
- }
- }
-
- /* Is this UV visible from the view? - raytrace */
- /* project_paint_PickFace is less complex, use for testing */
- //if (project_paint_PickFace(ps, pixelScreenCo, w, &side) == face_index) {
- if ((ps->do_occlude == FALSE) ||
- !project_bucket_point_occluded(ps, bucketFaceNodes, face_index, pixelScreenCo))
- {
- mask = project_paint_uvpixel_mask(ps, face_index, side, w);
-
- if (mask > 0.0f) {
- BLI_linklist_prepend_arena(
- bucketPixelNodes,
- project_paint_uvpixel_init(ps, arena, ibuf, x, y, mask, face_index,
- image_index, pixelScreenCo, wco, side, w),
- arena
- );
- }
- }
-
- }
-//#if 0
- else if (has_x_isect) {
- /* assuming the face is not a bow-tie - we know we cant intersect again on the X */
- break;
- }
-//#endif
- }
-
-
-#if 0 /* TODO - investigate why this dosnt work sometimes! it should! */
- /* no intersection for this entire row, after some intersection above means we can quit now */
- if (has_x_isect == 0 && has_isect) {
- break;
- }
-#endif
- }
- }
- } while (side--);
-
-
-
-#ifndef PROJ_DEBUG_NOSEAMBLEED
- if (ps->seam_bleed_px > 0.0f) {
- int face_seam_flag;
-
- if (ps->thread_tot > 1)
- BLI_lock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */
-
- face_seam_flag = ps->faceSeamFlags[face_index];
-
- /* are any of our edges un-initialized? */
- if ((face_seam_flag & (PROJ_FACE_SEAM1 | PROJ_FACE_NOSEAM1)) == 0 ||
- (face_seam_flag & (PROJ_FACE_SEAM2 | PROJ_FACE_NOSEAM2)) == 0 ||
- (face_seam_flag & (PROJ_FACE_SEAM3 | PROJ_FACE_NOSEAM3)) == 0 ||
- (face_seam_flag & (PROJ_FACE_SEAM4 | PROJ_FACE_NOSEAM4)) == 0)
- {
- project_face_seams_init(ps, face_index, mf->v4);
- face_seam_flag = ps->faceSeamFlags[face_index];
- //printf("seams - %d %d %d %d\n", flag&PROJ_FACE_SEAM1, flag&PROJ_FACE_SEAM2, flag&PROJ_FACE_SEAM3, flag&PROJ_FACE_SEAM4);
- }
-
- if ((face_seam_flag & (PROJ_FACE_SEAM1 | PROJ_FACE_SEAM2 | PROJ_FACE_SEAM3 | PROJ_FACE_SEAM4)) == 0) {
-
- if (ps->thread_tot > 1)
- BLI_unlock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */
-
- }
- else {
- /* we have a seam - deal with it! */
-
- /* Now create new UV's for the seam face */
- float (*outset_uv)[2] = ps->faceSeamUVs[face_index];
- float insetCos[4][3]; /* inset face coords. NOTE!!! ScreenSace for ortho, Worldspace in prespective view */
-
- float *vCoSS[4]; /* vertex screenspace coords */
-
- float bucket_clip_edges[2][2]; /* store the screenspace coords of the face, clipped by the bucket's screen aligned rectangle */
- float edge_verts_inset_clip[2][3];
- int fidx1, fidx2; /* face edge pairs - loop throuh these ((0,1), (1,2), (2,3), (3,0)) or ((0,1), (1,2), (2,0)) for a tri */
-
- float seam_subsection[4][2];
- float fac1, fac2, ftot;
-
-
- if (outset_uv[0][0] == FLT_MAX) /* first time initialize */
- uv_image_outset(tf_uv_pxoffset, outset_uv, ps->seam_bleed_px, ibuf->x, ibuf->y, mf->v4);
-
- /* ps->faceSeamUVs cant be modified when threading, now this is done we can unlock */
- if (ps->thread_tot > 1)
- BLI_unlock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */
-
- vCoSS[0] = ps->screenCoords[mf->v1];
- vCoSS[1] = ps->screenCoords[mf->v2];
- vCoSS[2] = ps->screenCoords[mf->v3];
- if (mf->v4)
- vCoSS[3] = ps->screenCoords[mf->v4];
-
- /* PROJ_FACE_SCALE_SEAM must be slightly less then 1.0f */
- if (is_ortho) {
- if (mf->v4) scale_quad(insetCos, vCoSS, PROJ_FACE_SCALE_SEAM);
- else scale_tri(insetCos, vCoSS, PROJ_FACE_SCALE_SEAM);
- }
- else {
- if (mf->v4) scale_quad(insetCos, vCo, PROJ_FACE_SCALE_SEAM);
- else scale_tri(insetCos, vCo, PROJ_FACE_SCALE_SEAM);
- }
-
- side = 0; /* for triangles this wont need to change */
-
- for (fidx1 = 0; fidx1 < (mf->v4 ? 4 : 3); fidx1++) {
- if (mf->v4) fidx2 = (fidx1 == 3) ? 0 : fidx1 + 1; /* next fidx in the face (0,1,2,3) -> (1,2,3,0) */
- else fidx2 = (fidx1 == 2) ? 0 : fidx1 + 1; /* next fidx in the face (0,1,2) -> (1,2,0) */
-
- if ((face_seam_flag & (1 << fidx1)) && /* 1<<fidx1 -> PROJ_FACE_SEAM# */
- line_clip_rect2f(bucket_bounds, vCoSS[fidx1], vCoSS[fidx2], bucket_clip_edges[0], bucket_clip_edges[1]))
- {
-
- ftot = len_v2v2(vCoSS[fidx1], vCoSS[fidx2]); /* screenspace edge length */
-
- if (ftot > 0.0f) { /* avoid div by zero */
- if (mf->v4) {
- if (fidx1 == 2 || fidx2 == 2) side = 1;
- else side = 0;
- }
-
- fac1 = len_v2v2(vCoSS[fidx1], bucket_clip_edges[0]) / ftot;
- fac2 = len_v2v2(vCoSS[fidx1], bucket_clip_edges[1]) / ftot;
-
- interp_v2_v2v2(seam_subsection[0], tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2], fac1);
- interp_v2_v2v2(seam_subsection[1], tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2], fac2);
-
- interp_v2_v2v2(seam_subsection[2], outset_uv[fidx1], outset_uv[fidx2], fac2);
- interp_v2_v2v2(seam_subsection[3], outset_uv[fidx1], outset_uv[fidx2], fac1);
-
- /* if the bucket_clip_edges values Z values was kept we could avoid this
- * Inset needs to be added so occlusion tests wont hit adjacent faces */
- interp_v3_v3v3(edge_verts_inset_clip[0], insetCos[fidx1], insetCos[fidx2], fac1);
- interp_v3_v3v3(edge_verts_inset_clip[1], insetCos[fidx1], insetCos[fidx2], fac2);
-
-
- if (pixel_bounds_uv(seam_subsection[0], seam_subsection[1], seam_subsection[2], seam_subsection[3], &bounds_px, ibuf->x, ibuf->y, 1)) {
- /* bounds between the seam rect and the uvspace bucket pixels */
-
- has_isect = 0;
- for (y = bounds_px.ymin; y < bounds_px.ymax; y++) {
- // uv[1] = (((float)y) + 0.5f) / (float)ibuf->y;
- uv[1] = (float)y / ibuf_yf; /* use offset uvs instead */
-
- has_x_isect = 0;
- for (x = bounds_px.xmin; x < bounds_px.xmax; x++) {
- //uv[0] = (((float)x) + 0.5f) / (float)ibuf->x;
- uv[0] = (float)x / ibuf_xf; /* use offset uvs instead */
-
- /* test we're inside uvspace bucket and triangle bounds */
- if (isect_point_quad_v2(uv, seam_subsection[0], seam_subsection[1], seam_subsection[2], seam_subsection[3])) {
- float fac;
-
- /* We need to find the closest point along the face edge,
- * getting the screen_px_from_*** wont work because our actual location
- * is not relevant, since we are outside the face, Use VecLerpf to find
- * our location on the side of the face's UV */
-#if 0
- if (is_ortho) screen_px_from_ortho(ps, uv, v1co, v2co, v3co, uv1co, uv2co, uv3co, pixelScreenCo);
- else screen_px_from_persp(ps, uv, v1co, v2co, v3co, uv1co, uv2co, uv3co, pixelScreenCo);
-#endif
-
- /* Since this is a seam we need to work out where on the line this pixel is */
- //fac = line_point_factor_v2(uv, uv_seam_quad[0], uv_seam_quad[1]);
-
- fac = line_point_factor_v2(uv, seam_subsection[0], seam_subsection[1]);
- if (fac < 0.0f) { copy_v3_v3(pixelScreenCo, edge_verts_inset_clip[0]); }
- else if (fac > 1.0f) { copy_v3_v3(pixelScreenCo, edge_verts_inset_clip[1]); }
- else { interp_v3_v3v3(pixelScreenCo, edge_verts_inset_clip[0], edge_verts_inset_clip[1], fac); }
-
- if (!is_ortho) {
- pixelScreenCo[3] = 1.0f;
- mul_m4_v4((float(*)[4])ps->projectMat, pixelScreenCo); /* cast because of const */
- pixelScreenCo[0] = (float)(ps->winx / 2.0f) + (ps->winx / 2.0f) * pixelScreenCo[0] / pixelScreenCo[3];
- pixelScreenCo[1] = (float)(ps->winy / 2.0f) + (ps->winy / 2.0f) * pixelScreenCo[1] / pixelScreenCo[3];
- pixelScreenCo[2] = pixelScreenCo[2] / pixelScreenCo[3]; /* Use the depth for bucket point occlusion */
- }
-
- if ((ps->do_occlude == FALSE) ||
- !project_bucket_point_occluded(ps, bucketFaceNodes, face_index, pixelScreenCo))
- {
- /* Only bother calculating the weights if we intersect */
- if (ps->do_mask_normal || ps->dm_mtface_clone) {
-#if 1
- /* get the UV on the line since we want to copy the pixels from there for bleeding */
- float uv_close[2];
- float uv_fac = closest_to_line_v2(uv_close, uv, tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2]);
- if (uv_fac < 0.0f) copy_v2_v2(uv_close, tf_uv_pxoffset[fidx1]);
- else if (uv_fac > 1.0f) copy_v2_v2(uv_close, tf_uv_pxoffset[fidx2]);
-
- if (side) {
- barycentric_weights_v2(tf_uv_pxoffset[0], tf_uv_pxoffset[2], tf_uv_pxoffset[3], uv_close, w);
- }
- else {
- barycentric_weights_v2(tf_uv_pxoffset[0], tf_uv_pxoffset[1], tf_uv_pxoffset[2], uv_close, w);
- }
-#else /* this is buggy with quads, don't use for now */
-
- /* Cheat, we know where we are along the edge so work out the weights from that */
- uv_fac = fac1 + (uv_fac * (fac2 - fac1));
-
- w[0] = w[1] = w[2] = 0.0;
- if (side) {
- w[fidx1 ? fidx1 - 1 : 0] = 1.0f - uv_fac;
- w[fidx2 ? fidx2 - 1 : 0] = uv_fac;
- }
- else {
- w[fidx1] = 1.0f - uv_fac;
- w[fidx2] = uv_fac;
- }
-#endif
- }
-
- /* a pity we need to get the worldspace pixel location here */
- if (do_clip || do_3d_mapping) {
- if (side) interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v3].co, ps->dm_mvert[mf->v4].co, w);
- else interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v2].co, ps->dm_mvert[mf->v3].co, w);
-
- if (do_clip && ED_view3d_clipping_test(ps->rv3d, wco, TRUE)) {
- continue; /* Watch out that no code below this needs to run */
- }
- }
-
- mask = project_paint_uvpixel_mask(ps, face_index, side, w);
-
- if (mask > 0.0f) {
- BLI_linklist_prepend_arena(
- bucketPixelNodes,
- project_paint_uvpixel_init(ps, arena, ibuf, x, y, mask, face_index, image_index, pixelScreenCo, wco, side, w),
- arena
- );
- }
-
- }
- }
- else if (has_x_isect) {
- /* assuming the face is not a bow-tie - we know we cant intersect again on the X */
- break;
- }
- }
-
-#if 0 /* TODO - investigate why this dosnt work sometimes! it should! */
- /* no intersection for this entire row, after some intersection above means we can quit now */
- if (has_x_isect == 0 && has_isect) {
- break;
- }
-#endif
- }
- }
- }
- }
- }
- }
- }
-#endif // PROJ_DEBUG_NOSEAMBLEED
-}
-
-
-/* takes floating point screenspace min/max and returns int min/max to be used as indices for ps->bucketRect, ps->bucketFlags */
-static void project_paint_bucket_bounds(const ProjPaintState *ps, const float min[2], const float max[2], int bucketMin[2], int bucketMax[2])
-{
- /* divide by bucketWidth & bucketHeight so the bounds are offset in bucket grid units */
- /* XXX: the offset of 0.5 is always truncated to zero and the offset of 1.5f is always truncated to 1, is this really correct?? - jwilkins */
- bucketMin[0] = (int)((int)(((float)(min[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x) + 0.5f); /* these offsets of 0.5 and 1.5 seem odd but they are correct */
- bucketMin[1] = (int)((int)(((float)(min[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y) + 0.5f);
-
- bucketMax[0] = (int)((int)(((float)(max[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x) + 1.5f);
- bucketMax[1] = (int)((int)(((float)(max[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y) + 1.5f);
-
- /* in case the rect is outside the mesh 2d bounds */
- CLAMP(bucketMin[0], 0, ps->buckets_x);
- CLAMP(bucketMin[1], 0, ps->buckets_y);
-
- CLAMP(bucketMax[0], 0, ps->buckets_x);
- CLAMP(bucketMax[1], 0, ps->buckets_y);
-}
-
-/* set bucket_bounds to a screen space-aligned floating point bound-box */
-static void project_bucket_bounds(const ProjPaintState *ps, const int bucket_x, const int bucket_y, rctf *bucket_bounds)
-{
- bucket_bounds->xmin = ps->screenMin[0] + ((bucket_x) * (ps->screen_width / ps->buckets_x)); /* left */
- bucket_bounds->xmax = ps->screenMin[0] + ((bucket_x + 1) * (ps->screen_width / ps->buckets_x)); /* right */
-
- bucket_bounds->ymin = ps->screenMin[1] + ((bucket_y) * (ps->screen_height / ps->buckets_y)); /* bottom */
- bucket_bounds->ymax = ps->screenMin[1] + ((bucket_y + 1) * (ps->screen_height / ps->buckets_y)); /* top */
-}
-
-/* Fill this bucket with pixels from the faces that intersect it.
- *
- * have bucket_bounds as an argument so we don't need to give bucket_x/y the rect function needs */
-static void project_bucket_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, rctf *bucket_bounds)
-{
- LinkNode *node;
- int face_index, image_index = 0;
- ImBuf *ibuf = NULL;
- Image *tpage_last = NULL, *tpage;
- Image *ima = NULL;
-
- if (ps->image_tot == 1) {
- /* Simple loop, no context switching */
- ibuf = ps->projImages[0].ibuf;
- ima = ps->projImages[0].ima;
-
- for (node = ps->bucketFaces[bucket_index]; node; node = node->next) {
- project_paint_face_init(ps, thread_index, bucket_index, GET_INT_FROM_POINTER(node->link), 0, bucket_bounds, ibuf, ima->tpageflag & IMA_CLAMP_U, ima->tpageflag & IMA_CLAMP_V);
- }
- }
- else {
-
- /* More complicated loop, switch between images */
- for (node = ps->bucketFaces[bucket_index]; node; node = node->next) {
- face_index = GET_INT_FROM_POINTER(node->link);
-
- /* Image context switching */
- tpage = project_paint_face_image(ps, ps->dm_mtface, face_index);
- if (tpage_last != tpage) {
- tpage_last = tpage;
-
- for (image_index = 0; image_index < ps->image_tot; image_index++) {
- if (ps->projImages[image_index].ima == tpage_last) {
- ibuf = ps->projImages[image_index].ibuf;
- ima = ps->projImages[image_index].ima;
- break;
- }
- }
- }
- /* context switching done */
-
- project_paint_face_init(ps, thread_index, bucket_index, face_index, image_index, bucket_bounds, ibuf, ima->tpageflag & IMA_CLAMP_U, ima->tpageflag & IMA_CLAMP_V);
- }
- }
-
- ps->bucketFlags[bucket_index] |= PROJ_BUCKET_INIT;
-}
-
-
-/* We want to know if a bucket and a face overlap in screen-space
- *
- * Note, if this ever returns false positives its not that bad, since a face in the bounding area will have its pixels
- * calculated when it might not be needed later, (at the moment at least)
- * obviously it shouldn't have bugs though */
-
-static int project_bucket_face_isect(ProjPaintState *ps, int bucket_x, int bucket_y, const MFace *mf)
-{
- /* TODO - replace this with a tricker method that uses sideofline for all screenCoords's edges against the closest bucket corner */
- rctf bucket_bounds;
- float p1[2], p2[2], p3[2], p4[2];
- float *v, *v1, *v2, *v3, *v4 = NULL;
- int fidx;
-
- project_bucket_bounds(ps, bucket_x, bucket_y, &bucket_bounds);
-
- /* Is one of the faces verts in the bucket bounds? */
-
- fidx = mf->v4 ? 3 : 2;
- do {
- v = ps->screenCoords[(*(&mf->v1 + fidx))];
- if (BLI_rctf_isect_pt_v(&bucket_bounds, v)) {
- return 1;
- }
- } while (fidx--);
-
- v1 = ps->screenCoords[mf->v1];
- v2 = ps->screenCoords[mf->v2];
- v3 = ps->screenCoords[mf->v3];
- if (mf->v4) {
- v4 = ps->screenCoords[mf->v4];
- }
-
- p1[0] = bucket_bounds.xmin; p1[1] = bucket_bounds.ymin;
- p2[0] = bucket_bounds.xmin; p2[1] = bucket_bounds.ymax;
- p3[0] = bucket_bounds.xmax; p3[1] = bucket_bounds.ymax;
- p4[0] = bucket_bounds.xmax; p4[1] = bucket_bounds.ymin;
-
- if (mf->v4) {
- if (isect_point_quad_v2(p1, v1, v2, v3, v4) ||
- isect_point_quad_v2(p2, v1, v2, v3, v4) ||
- isect_point_quad_v2(p3, v1, v2, v3, v4) ||
- isect_point_quad_v2(p4, v1, v2, v3, v4) ||
-
- /* we can avoid testing v3,v1 because another intersection MUST exist if this intersects */
- (isect_line_line_v2(p1, p2, v1, v2) || isect_line_line_v2(p1, p2, v2, v3) || isect_line_line_v2(p1, p2, v3, v4)) ||
- (isect_line_line_v2(p2, p3, v1, v2) || isect_line_line_v2(p2, p3, v2, v3) || isect_line_line_v2(p2, p3, v3, v4)) ||
- (isect_line_line_v2(p3, p4, v1, v2) || isect_line_line_v2(p3, p4, v2, v3) || isect_line_line_v2(p3, p4, v3, v4)) ||
- (isect_line_line_v2(p4, p1, v1, v2) || isect_line_line_v2(p4, p1, v2, v3) || isect_line_line_v2(p4, p1, v3, v4)))
- {
- return 1;
- }
- }
- else {
- if (isect_point_tri_v2(p1, v1, v2, v3) ||
- isect_point_tri_v2(p2, v1, v2, v3) ||
- isect_point_tri_v2(p3, v1, v2, v3) ||
- isect_point_tri_v2(p4, v1, v2, v3) ||
- /* we can avoid testing v3,v1 because another intersection MUST exist if this intersects */
- (isect_line_line_v2(p1, p2, v1, v2) || isect_line_line_v2(p1, p2, v2, v3)) ||
- (isect_line_line_v2(p2, p3, v1, v2) || isect_line_line_v2(p2, p3, v2, v3)) ||
- (isect_line_line_v2(p3, p4, v1, v2) || isect_line_line_v2(p3, p4, v2, v3)) ||
- (isect_line_line_v2(p4, p1, v1, v2) || isect_line_line_v2(p4, p1, v2, v3)))
- {
- return 1;
- }
- }
-
- return 0;
-}
-
-/* Add faces to the bucket but don't initialize its pixels
- * TODO - when painting occluded, sort the faces on their min-Z and only add faces that faces that are not occluded */
-static void project_paint_delayed_face_init(ProjPaintState *ps, const MFace *mf, const int face_index)
-{
- float min[2], max[2], *vCoSS;
- int bucketMin[2], bucketMax[2]; /* for ps->bucketRect indexing */
- int fidx, bucket_x, bucket_y;
- int has_x_isect = -1, has_isect = 0; /* for early loop exit */
- MemArena *arena = ps->arena_mt[0]; /* just use the first thread arena since threading has not started yet */
-
- INIT_MINMAX2(min, max);
-
- fidx = mf->v4 ? 3 : 2;
- do {
- vCoSS = ps->screenCoords[*(&mf->v1 + fidx)];
- minmax_v2v2_v2(min, max, vCoSS);
- } while (fidx--);
-
- project_paint_bucket_bounds(ps, min, max, bucketMin, bucketMax);
-
- for (bucket_y = bucketMin[1]; bucket_y < bucketMax[1]; bucket_y++) {
- has_x_isect = 0;
- for (bucket_x = bucketMin[0]; bucket_x < bucketMax[0]; bucket_x++) {
- if (project_bucket_face_isect(ps, bucket_x, bucket_y, mf)) {
- int bucket_index = bucket_x + (bucket_y * ps->buckets_x);
- BLI_linklist_prepend_arena(
- &ps->bucketFaces[bucket_index],
- SET_INT_IN_POINTER(face_index), /* cast to a pointer to shut up the compiler */
- arena
- );
-
- has_x_isect = has_isect = 1;
- }
- else if (has_x_isect) {
- /* assuming the face is not a bow-tie - we know we cant intersect again on the X */
- break;
- }
- }
-
- /* no intersection for this entire row, after some intersection above means we can quit now */
- if (has_x_isect == 0 && has_isect) {
- break;
- }
- }
-
-#ifndef PROJ_DEBUG_NOSEAMBLEED
- if (ps->seam_bleed_px > 0.0f) {
- if (!mf->v4) {
- ps->faceSeamFlags[face_index] |= PROJ_FACE_NOSEAM4; /* so this wont show up as an untagged edge */
- }
- **ps->faceSeamUVs[face_index] = FLT_MAX; /* set as uninitialized */
- }
-#endif
-}
-
-static int project_paint_view_clip(View3D *v3d, RegionView3D *rv3d, float *clipsta, float *clipend)
-{
- int orth = ED_view3d_clip_range_get(v3d, rv3d, clipsta, clipend);
-
- if (orth) { /* only needed for ortho */
- float fac = 2.0f / ((*clipend) - (*clipsta));
- *clipsta *= fac;
- *clipend *= fac;
- }
-
- return orth;
-}
-
-/* run once per stroke before projection painting */
-static void project_paint_begin(ProjPaintState *ps)
-{
- /* Viewport vars */
- float mat[3][3];
-
- float no[3];
-
- float *projScreenCo; /* Note, we could have 4D vectors are only needed for */
- float projMargin;
-
- /* Image Vars - keep track of images we have used */
- LinkNode *image_LinkList = NULL;
- LinkNode *node;
-
- ProjPaintImage *projIma;
- Image *tpage_last = NULL, *tpage;
-
- /* Face vars */
- MFace *mf;
- MTFace *tf;
-
- int a, i; /* generic looping vars */
- int image_index = -1, face_index;
- MVert *mv;
-
- MemArena *arena; /* at the moment this is just ps->arena_mt[0], but use this to show were not multithreading */
-
- const int diameter = 2 * BKE_brush_size_get(ps->scene, ps->brush);
-
- /* ---- end defines ---- */
-
- if (ps->source == PROJ_SRC_VIEW)
- ED_view3d_clipping_local(ps->rv3d, ps->ob->obmat); /* faster clipping lookups */
-
- /* paint onto the derived mesh */
-
- /* Workaround for subsurf selection, try the display mesh first */
- if (ps->source == PROJ_SRC_IMAGE_CAM) {
- /* using render mesh, assume only camera was rendered from */
- ps->dm = mesh_create_derived_render(ps->scene, ps->ob, ps->scene->customdata_mask | CD_MASK_MTFACE);
- ps->dm_release = TRUE;
- }
- else if (ps->ob->derivedFinal && CustomData_has_layer(&ps->ob->derivedFinal->faceData, CD_MTFACE)) {
- ps->dm = ps->ob->derivedFinal;
- ps->dm_release = FALSE;
- }
- else {
- ps->dm = mesh_get_derived_final(ps->scene, ps->ob, ps->scene->customdata_mask | CD_MASK_MTFACE);
- ps->dm_release = TRUE;
- }
-
- if (!CustomData_has_layer(&ps->dm->faceData, CD_MTFACE) ) {
-
- if (ps->dm_release)
- ps->dm->release(ps->dm);
-
- ps->dm = NULL;
- return;
- }
-
- ps->dm_mvert = ps->dm->getVertArray(ps->dm);
- ps->dm_mface = ps->dm->getTessFaceArray(ps->dm);
- ps->dm_mtface = ps->dm->getTessFaceDataArray(ps->dm, CD_MTFACE);
-
- ps->dm_totvert = ps->dm->getNumVerts(ps->dm);
- ps->dm_totface = ps->dm->getNumTessFaces(ps->dm);
-
- /* use clone mtface? */
-
-
- /* Note, use the original mesh for getting the clone and mask layer index
- * this avoids re-generating the derived mesh just to get the new index */
- if (ps->do_layer_clone) {
- //int layer_num = CustomData_get_clone_layer(&ps->dm->faceData, CD_MTFACE);
- int layer_num = CustomData_get_clone_layer(&((Mesh *)ps->ob->data)->fdata, CD_MTFACE);
- if (layer_num != -1)
- ps->dm_mtface_clone = CustomData_get_layer_n(&ps->dm->faceData, CD_MTFACE, layer_num);
-
- if (ps->dm_mtface_clone == NULL || ps->dm_mtface_clone == ps->dm_mtface) {
- ps->do_layer_clone = FALSE;
- ps->dm_mtface_clone = NULL;
- printf("ACK!\n");
- }
- }
-
- if (ps->do_layer_stencil) {
- //int layer_num = CustomData_get_stencil_layer(&ps->dm->faceData, CD_MTFACE);
- int layer_num = CustomData_get_stencil_layer(&((Mesh *)ps->ob->data)->fdata, CD_MTFACE);
- if (layer_num != -1)
- ps->dm_mtface_stencil = CustomData_get_layer_n(&ps->dm->faceData, CD_MTFACE, layer_num);
-
- if (ps->dm_mtface_stencil == NULL || ps->dm_mtface_stencil == ps->dm_mtface) {
- ps->do_layer_stencil = FALSE;
- ps->dm_mtface_stencil = NULL;
- }
- }
-
- /* when using subsurf or multires, mface arrays are thrown away, we need to keep a copy */
- if (ps->dm->type != DM_TYPE_CDDM) {
- ps->dm_mvert = MEM_dupallocN(ps->dm_mvert);
- ps->dm_mface = MEM_dupallocN(ps->dm_mface);
- /* looks like these are ok for now.*/
-#if 0
- ps->dm_mtface = MEM_dupallocN(ps->dm_mtface);
- ps->dm_mtface_clone = MEM_dupallocN(ps->dm_mtface_clone);
- ps->dm_mtface_stencil = MEM_dupallocN(ps->dm_mtface_stencil);
-#endif
- }
-
- ps->viewDir[0] = 0.0f;
- ps->viewDir[1] = 0.0f;
- ps->viewDir[2] = 1.0f;
-
- {
- float viewmat[4][4];
- float viewinv[4][4];
-
- invert_m4_m4(ps->ob->imat, ps->ob->obmat);
-
- if (ps->source == PROJ_SRC_VIEW) {
- /* normal drawing */
- ps->winx = ps->ar->winx;
- ps->winy = ps->ar->winy;
-
- copy_m4_m4(viewmat, ps->rv3d->viewmat);
- copy_m4_m4(viewinv, ps->rv3d->viewinv);
-
- ED_view3d_ob_project_mat_get(ps->rv3d, ps->ob, ps->projectMat);
-
- ps->is_ortho = project_paint_view_clip(ps->v3d, ps->rv3d, &ps->clipsta, &ps->clipend);
- }
- else {
- /* re-projection */
- float winmat[4][4];
- float vmat[4][4];
-
- ps->winx = ps->reproject_ibuf->x;
- ps->winy = ps->reproject_ibuf->y;
-
- if (ps->source == PROJ_SRC_IMAGE_VIEW) {
- /* image stores camera data, tricky */
- IDProperty *idgroup = IDP_GetProperties(&ps->reproject_image->id, 0);
- IDProperty *view_data = IDP_GetPropertyFromGroup(idgroup, PROJ_VIEW_DATA_ID);
-
- float *array = (float *)IDP_Array(view_data);
-
- /* use image array, written when creating image */
- memcpy(winmat, array, sizeof(winmat)); array += sizeof(winmat) / sizeof(float);
- memcpy(viewmat, array, sizeof(viewmat)); array += sizeof(viewmat) / sizeof(float);
- ps->clipsta = array[0];
- ps->clipend = array[1];
- ps->is_ortho = array[2] ? 1 : 0;
-
- invert_m4_m4(viewinv, viewmat);
- }
- else if (ps->source == PROJ_SRC_IMAGE_CAM) {
- Object *cam_ob = ps->scene->camera;
- CameraParams params;
-
- /* viewmat & viewinv */
- copy_m4_m4(viewinv, cam_ob->obmat);
- normalize_m4(viewinv);
- invert_m4_m4(viewmat, viewinv);
-
- /* window matrix, clipping and ortho */
- BKE_camera_params_init(&params);
- BKE_camera_params_from_object(&params, cam_ob);
- BKE_camera_params_compute_viewplane(&params, ps->winx, ps->winy, 1.0f, 1.0f);
- BKE_camera_params_compute_matrix(&params);
-
- copy_m4_m4(winmat, params.winmat);
- ps->clipsta = params.clipsta;
- ps->clipend = params.clipend;
- ps->is_ortho = params.is_ortho;
- }
-
- /* same as #ED_view3d_ob_project_mat_get */
- mult_m4_m4m4(vmat, viewmat, ps->ob->obmat);
- mult_m4_m4m4(ps->projectMat, winmat, vmat);
- }
-
-
- /* viewDir - object relative */
- invert_m4_m4(ps->ob->imat, ps->ob->obmat);
- copy_m3_m4(mat, viewinv);
- mul_m3_v3(mat, ps->viewDir);
- copy_m3_m4(mat, ps->ob->imat);
- mul_m3_v3(mat, ps->viewDir);
- normalize_v3(ps->viewDir);
-
- /* viewPos - object relative */
- copy_v3_v3(ps->viewPos, viewinv[3]);
- copy_m3_m4(mat, ps->ob->imat);
- mul_m3_v3(mat, ps->viewPos);
- add_v3_v3(ps->viewPos, ps->ob->imat[3]);
- }
-
- /* calculate vert screen coords
- * run this early so we can calculate the x/y resolution of our bucket rect */
- INIT_MINMAX2(ps->screenMin, ps->screenMax);
-
- ps->screenCoords = MEM_mallocN(sizeof(float) * ps->dm_totvert * 4, "ProjectPaint ScreenVerts");
- projScreenCo = *ps->screenCoords;
-
- if (ps->is_ortho) {
- for (a = 0, mv = ps->dm_mvert; a < ps->dm_totvert; a++, mv++, projScreenCo += 4) {
- mul_v3_m4v3(projScreenCo, ps->projectMat, mv->co);
-
- /* screen space, not clamped */
- projScreenCo[0] = (float)(ps->winx / 2.0f) + (ps->winx / 2.0f) * projScreenCo[0];
- projScreenCo[1] = (float)(ps->winy / 2.0f) + (ps->winy / 2.0f) * projScreenCo[1];
- minmax_v2v2_v2(ps->screenMin, ps->screenMax, projScreenCo);
- }
- }
- else {
- for (a = 0, mv = ps->dm_mvert; a < ps->dm_totvert; a++, mv++, projScreenCo += 4) {
- copy_v3_v3(projScreenCo, mv->co);
- projScreenCo[3] = 1.0f;
-
- mul_m4_v4(ps->projectMat, projScreenCo);
-
- if (projScreenCo[3] > ps->clipsta) {
- /* screen space, not clamped */
- projScreenCo[0] = (float)(ps->winx / 2.0f) + (ps->winx / 2.0f) * projScreenCo[0] / projScreenCo[3];
- projScreenCo[1] = (float)(ps->winy / 2.0f) + (ps->winy / 2.0f) * projScreenCo[1] / projScreenCo[3];
- projScreenCo[2] = projScreenCo[2] / projScreenCo[3]; /* Use the depth for bucket point occlusion */
- minmax_v2v2_v2(ps->screenMin, ps->screenMax, projScreenCo);
- }
- else {
- /* TODO - deal with cases where 1 side of a face goes behind the view ?
- *
- * After some research this is actually very tricky, only option is to
- * clip the derived mesh before painting, which is a Pain */
- projScreenCo[0] = FLT_MAX;
- }
- }
- }
-
- /* If this border is not added we get artifacts for faces that
- * have a parallel edge and at the bounds of the the 2D projected verts eg
- * - a single screen aligned quad */
- projMargin = (ps->screenMax[0] - ps->screenMin[0]) * 0.000001f;
- ps->screenMax[0] += projMargin;
- ps->screenMin[0] -= projMargin;
- projMargin = (ps->screenMax[1] - ps->screenMin[1]) * 0.000001f;
- ps->screenMax[1] += projMargin;
- ps->screenMin[1] -= projMargin;
-
- if (ps->source == PROJ_SRC_VIEW) {
-#ifdef PROJ_DEBUG_WINCLIP
- CLAMP(ps->screenMin[0], (float)(-diameter), (float)(ps->winx + diameter));
- CLAMP(ps->screenMax[0], (float)(-diameter), (float)(ps->winx + diameter));
-
- CLAMP(ps->screenMin[1], (float)(-diameter), (float)(ps->winy + diameter));
- CLAMP(ps->screenMax[1], (float)(-diameter), (float)(ps->winy + diameter));
-#endif
- }
- else { /* re-projection, use bounds */
- ps->screenMin[0] = 0;
- ps->screenMax[0] = (float)(ps->winx);
-
- ps->screenMin[1] = 0;
- ps->screenMax[1] = (float)(ps->winy);
- }
-
- /* only for convenience */
- ps->screen_width = ps->screenMax[0] - ps->screenMin[0];
- ps->screen_height = ps->screenMax[1] - ps->screenMin[1];
-
- ps->buckets_x = (int)(ps->screen_width / (((float)diameter) / PROJ_BUCKET_BRUSH_DIV));
- ps->buckets_y = (int)(ps->screen_height / (((float)diameter) / PROJ_BUCKET_BRUSH_DIV));
-
- /* printf("\tscreenspace bucket division x:%d y:%d\n", ps->buckets_x, ps->buckets_y); */
-
- /* really high values could cause problems since it has to allocate a few
- * (ps->buckets_x*ps->buckets_y) sized arrays */
- CLAMP(ps->buckets_x, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX);
- CLAMP(ps->buckets_y, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX);
-
- ps->bucketRect = (LinkNode **)MEM_callocN(sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y, "paint-bucketRect");
- ps->bucketFaces = (LinkNode **)MEM_callocN(sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y, "paint-bucketFaces");
-
- ps->bucketFlags = (unsigned char *)MEM_callocN(sizeof(char) * ps->buckets_x * ps->buckets_y, "paint-bucketFaces");
-#ifndef PROJ_DEBUG_NOSEAMBLEED
- if (ps->seam_bleed_px > 0.0f) {
- ps->vertFaces = (LinkNode **)MEM_callocN(sizeof(LinkNode *) * ps->dm_totvert, "paint-vertFaces");
- ps->faceSeamFlags = (char *)MEM_callocN(sizeof(char) * ps->dm_totface, "paint-faceSeamFlags");
- ps->faceSeamUVs = MEM_mallocN(sizeof(float) * ps->dm_totface * 8, "paint-faceSeamUVs");
- }
-#endif
-
- /* Thread stuff
- *
- * very small brushes run a lot slower multithreaded since the advantage with
- * threads is being able to fill in multiple buckets at once.
- * Only use threads for bigger brushes. */
-
- if (ps->scene->r.mode & R_FIXED_THREADS) {
- ps->thread_tot = ps->scene->r.threads;
- }
- else {
- ps->thread_tot = BLI_system_thread_count();
- }
- for (a = 0; a < ps->thread_tot; a++) {
- ps->arena_mt[a] = BLI_memarena_new(1 << 16, "project paint arena");
- }
-
- arena = ps->arena_mt[0];
-
- if (ps->do_backfacecull && ps->do_mask_normal) {
- float viewDirPersp[3];
-
- ps->vertFlags = MEM_callocN(sizeof(char) * ps->dm_totvert, "paint-vertFlags");
-
- for (a = 0, mv = ps->dm_mvert; a < ps->dm_totvert; a++, mv++) {
- normal_short_to_float_v3(no, mv->no);
-
- if (ps->is_ortho) {
- if (angle_normalized_v3v3(ps->viewDir, no) >= ps->normal_angle) { /* 1 vert of this face is towards us */
- ps->vertFlags[a] |= PROJ_VERT_CULL;
- }
- }
- else {
- sub_v3_v3v3(viewDirPersp, ps->viewPos, mv->co);
- normalize_v3(viewDirPersp);
- if (angle_normalized_v3v3(viewDirPersp, no) >= ps->normal_angle) { /* 1 vert of this face is towards us */
- ps->vertFlags[a] |= PROJ_VERT_CULL;
- }
- }
- }
- }
-
-
- for (face_index = 0, tf = ps->dm_mtface, mf = ps->dm_mface; face_index < ps->dm_totface; mf++, tf++, face_index++) {
-
-#ifndef PROJ_DEBUG_NOSEAMBLEED
- /* add face user if we have bleed enabled, set the UV seam flags later */
- /* annoying but we need to add all faces even ones we never use elsewhere */
- if (ps->seam_bleed_px > 0.0f) {
- BLI_linklist_prepend_arena(&ps->vertFaces[mf->v1], SET_INT_IN_POINTER(face_index), arena);
- BLI_linklist_prepend_arena(&ps->vertFaces[mf->v2], SET_INT_IN_POINTER(face_index), arena);
- BLI_linklist_prepend_arena(&ps->vertFaces[mf->v3], SET_INT_IN_POINTER(face_index), arena);
- if (mf->v4) {
- BLI_linklist_prepend_arena(&ps->vertFaces[mf->v4], SET_INT_IN_POINTER(face_index), arena);
- }
- }
-#endif
-
- tpage = project_paint_face_image(ps, ps->dm_mtface, face_index);
-
- if (tpage && ((((Mesh *)ps->ob->data)->editflag & ME_EDIT_PAINT_FACE_SEL) == 0 || mf->flag & ME_FACE_SEL)) {
-
- float *v1coSS, *v2coSS, *v3coSS, *v4coSS = NULL;
-
- v1coSS = ps->screenCoords[mf->v1];
- v2coSS = ps->screenCoords[mf->v2];
- v3coSS = ps->screenCoords[mf->v3];
- if (mf->v4) {
- v4coSS = ps->screenCoords[mf->v4];
- }
-
-
- if (!ps->is_ortho) {
- if (v1coSS[0] == FLT_MAX ||
- v2coSS[0] == FLT_MAX ||
- v3coSS[0] == FLT_MAX ||
- (mf->v4 && v4coSS[0] == FLT_MAX))
- {
- continue;
- }
- }
-
-#ifdef PROJ_DEBUG_WINCLIP
- /* ignore faces outside the view */
- if (
- (v1coSS[0] < ps->screenMin[0] &&
- v2coSS[0] < ps->screenMin[0] &&
- v3coSS[0] < ps->screenMin[0] &&
- (mf->v4 && v4coSS[0] < ps->screenMin[0])) ||
-
- (v1coSS[0] > ps->screenMax[0] &&
- v2coSS[0] > ps->screenMax[0] &&
- v3coSS[0] > ps->screenMax[0] &&
- (mf->v4 && v4coSS[0] > ps->screenMax[0])) ||
-
- (v1coSS[1] < ps->screenMin[1] &&
- v2coSS[1] < ps->screenMin[1] &&
- v3coSS[1] < ps->screenMin[1] &&
- (mf->v4 && v4coSS[1] < ps->screenMin[1])) ||
-
- (v1coSS[1] > ps->screenMax[1] &&
- v2coSS[1] > ps->screenMax[1] &&
- v3coSS[1] > ps->screenMax[1] &&
- (mf->v4 && v4coSS[1] > ps->screenMax[1]))
- )
- {
- continue;
- }
-
-#endif //PROJ_DEBUG_WINCLIP
-
-
- if (ps->do_backfacecull) {
- if (ps->do_mask_normal) {
- /* Since we are interpolating the normals of faces, we want to make
- * sure all the verts are pointing away from the view,
- * not just the face */
- if ((ps->vertFlags[mf->v1] & PROJ_VERT_CULL) &&
- (ps->vertFlags[mf->v2] & PROJ_VERT_CULL) &&
- (ps->vertFlags[mf->v3] & PROJ_VERT_CULL) &&
- (mf->v4 == 0 || ps->vertFlags[mf->v4] & PROJ_VERT_CULL)
- )
- {
- continue;
- }
- }
- else {
- if (line_point_side_v2(v1coSS, v2coSS, v3coSS) < 0.0f) {
- continue;
- }
-
- }
- }
-
- if (tpage_last != tpage) {
-
- image_index = BLI_linklist_index(image_LinkList, tpage);
-
- if (image_index == -1 && BKE_image_has_ibuf(tpage, NULL)) { /* MemArena dosnt have an append func */
- BLI_linklist_append(&image_LinkList, tpage);
- image_index = ps->image_tot;
- ps->image_tot++;
- }
-
- tpage_last = tpage;
- }
-
- if (image_index != -1) {
- /* Initialize the faces screen pixels */
- /* Add this to a list to initialize later */
- project_paint_delayed_face_init(ps, mf, face_index);
- }
- }
- }
-
- /* build an array of images we use*/
- projIma = ps->projImages = (ProjPaintImage *)BLI_memarena_alloc(arena, sizeof(ProjPaintImage) * ps->image_tot);
-
- for (node = image_LinkList, i = 0; node; node = node->next, i++, projIma++) {
- projIma->ima = node->link;
- projIma->touch = 0;
- projIma->ibuf = BKE_image_acquire_ibuf(projIma->ima, NULL, NULL);
- projIma->partRedrawRect = BLI_memarena_alloc(arena, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
- memset(projIma->partRedrawRect, 0, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
- }
-
- /* we have built the array, discard the linked list */
- BLI_linklist_free(image_LinkList, NULL);
-}
-
-static void project_paint_begin_clone(ProjPaintState *ps, int mouse[2])
-{
- /* setup clone offset */
- if (ps->tool == PAINT_TOOL_CLONE) {
- float projCo[4];
- copy_v3_v3(projCo, give_cursor(ps->scene, ps->v3d));
- mul_m4_v3(ps->ob->imat, projCo);
-
- projCo[3] = 1.0f;
- mul_m4_v4(ps->projectMat, projCo);
- ps->cloneOffset[0] = mouse[0] - ((float)(ps->winx / 2.0f) + (ps->winx / 2.0f) * projCo[0] / projCo[3]);
- ps->cloneOffset[1] = mouse[1] - ((float)(ps->winy / 2.0f) + (ps->winy / 2.0f) * projCo[1] / projCo[3]);
- }
-}
-
-static void project_paint_end(ProjPaintState *ps)
-{
- int a;
- ProjPaintImage *projIma;
-
- /* build undo data from original pixel colors */
- if (U.uiflag & USER_GLOBALUNDO) {
- ProjPixel *projPixel;
- ImBuf *tmpibuf = NULL, *tmpibuf_float = NULL;
- LinkNode *pixel_node;
- void *tilerect;
- MemArena *arena = ps->arena_mt[0]; /* threaded arena re-used for non threaded case */
-
- int bucket_tot = (ps->buckets_x * ps->buckets_y); /* we could get an X/Y but easier to loop through all possible buckets */
- int bucket_index;
- int tile_index;
- int x_round, y_round;
- int x_tile, y_tile;
- int is_float = -1;
-
- /* context */
- ProjPaintImage *last_projIma;
- int last_image_index = -1;
- int last_tile_width = 0;
-
- for (a = 0, last_projIma = ps->projImages; a < ps->image_tot; a++, last_projIma++) {
- int size = sizeof(void **) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->x) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->y);
- last_projIma->undoRect = (void **) BLI_memarena_alloc(arena, size);
- memset(last_projIma->undoRect, 0, size);
- last_projIma->ibuf->userflags |= IB_BITMAPDIRTY;
- }
-
- for (bucket_index = 0; bucket_index < bucket_tot; bucket_index++) {
- /* loop through all pixels */
- for (pixel_node = ps->bucketRect[bucket_index]; pixel_node; pixel_node = pixel_node->next) {
-
- /* ok we have a pixel, was it modified? */
- projPixel = (ProjPixel *)pixel_node->link;
-
- if (last_image_index != projPixel->image_index) {
- /* set the context */
- last_image_index = projPixel->image_index;
- last_projIma = ps->projImages + last_image_index;
- last_tile_width = IMAPAINT_TILE_NUMBER(last_projIma->ibuf->x);
- is_float = last_projIma->ibuf->rect_float ? 1 : 0;
- }
-
-
- if ((is_float == 0 && projPixel->origColor.uint != *projPixel->pixel.uint_pt) ||
- (is_float == 1 &&
- (projPixel->origColor.f[0] != projPixel->pixel.f_pt[0] ||
- projPixel->origColor.f[1] != projPixel->pixel.f_pt[1] ||
- projPixel->origColor.f[2] != projPixel->pixel.f_pt[2] ||
- projPixel->origColor.f[3] != projPixel->pixel.f_pt[3]))
- )
- {
-
- x_tile = projPixel->x_px >> IMAPAINT_TILE_BITS;
- y_tile = projPixel->y_px >> IMAPAINT_TILE_BITS;
-
- x_round = x_tile * IMAPAINT_TILE_SIZE;
- y_round = y_tile * IMAPAINT_TILE_SIZE;
-
- tile_index = x_tile + y_tile * last_tile_width;
-
- if (last_projIma->undoRect[tile_index] == NULL) {
- /* add the undo tile from the modified image, then write the original colors back into it */
- tilerect = last_projIma->undoRect[tile_index] = image_undo_push_tile(last_projIma->ima, last_projIma->ibuf, is_float ? (&tmpibuf_float) : (&tmpibuf), x_tile, y_tile);
- }
- else {
- tilerect = last_projIma->undoRect[tile_index];
- }
-
- /* This is a BIT ODD, but overwrite the undo tiles image info with this pixels original color
- * because allocating the tiles along the way slows down painting */
-
- if (is_float) {
- float *rgba_fp = (float *)tilerect + (((projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE)) * 4;
- copy_v4_v4(rgba_fp, projPixel->origColor.f);
- }
- else {
- ((unsigned int *)tilerect)[(projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE] = projPixel->origColor.uint;
- }
- }
- }
- }
-
- if (tmpibuf) IMB_freeImBuf(tmpibuf);
- if (tmpibuf_float) IMB_freeImBuf(tmpibuf_float);
- }
- /* done calculating undo data */
-
- /* dereference used image buffers */
- for (a = 0, projIma = ps->projImages; a < ps->image_tot; a++, projIma++) {
- BKE_image_release_ibuf(projIma->ima, projIma->ibuf, NULL);
- }
-
- BKE_image_release_ibuf(ps->reproject_image, ps->reproject_ibuf, NULL);
-
- MEM_freeN(ps->screenCoords);
- MEM_freeN(ps->bucketRect);
- MEM_freeN(ps->bucketFaces);
- MEM_freeN(ps->bucketFlags);
-
-#ifndef PROJ_DEBUG_NOSEAMBLEED
- if (ps->seam_bleed_px > 0.0f) {
- MEM_freeN(ps->vertFaces);
- MEM_freeN(ps->faceSeamFlags);
- MEM_freeN(ps->faceSeamUVs);
- }
-#endif
-
- if (ps->vertFlags) MEM_freeN(ps->vertFlags);
-
- for (a = 0; a < ps->thread_tot; a++) {
- BLI_memarena_free(ps->arena_mt[a]);
- }
-
- /* copy for subsurf/multires, so throw away */
- if (ps->dm->type != DM_TYPE_CDDM) {
- if (ps->dm_mvert) MEM_freeN(ps->dm_mvert);
- if (ps->dm_mface) MEM_freeN(ps->dm_mface);
- /* looks like these don't need copying */
-#if 0
- if (ps->dm_mtface) MEM_freeN(ps->dm_mtface);
- if (ps->dm_mtface_clone) MEM_freeN(ps->dm_mtface_clone);
- if (ps->dm_mtface_stencil) MEM_freeN(ps->dm_mtface_stencil);
-#endif
- }
-
- if (ps->dm_release)
- ps->dm->release(ps->dm);
-}
-
-/* 1 = an undo, -1 is a redo. */
-static void partial_redraw_array_init(ImagePaintPartialRedraw *pr)
-{
- int tot = PROJ_BOUNDBOX_SQUARED;
- while (tot--) {
- pr->x1 = 10000000;
- pr->y1 = 10000000;
-
- pr->x2 = -1;
- pr->y2 = -1;
-
- pr->enabled = 1;
-
- pr++;
- }
-}
-
-
-static int partial_redraw_array_merge(ImagePaintPartialRedraw *pr, ImagePaintPartialRedraw *pr_other, int tot)
-{
- int touch = 0;
- while (tot--) {
- pr->x1 = min_ii(pr->x1, pr_other->x1);
- pr->y1 = min_ii(pr->y1, pr_other->y1);
-
- pr->x2 = max_ii(pr->x2, pr_other->x2);
- pr->y2 = max_ii(pr->y2, pr_other->y2);
-
- if (pr->x2 != -1)
- touch = 1;
-
- pr++; pr_other++;
- }
-
- return touch;
-}
-
-/* Loop over all images on this mesh and update any we have touched */
-static int project_image_refresh_tagged(ProjPaintState *ps)
-{
- ImagePaintPartialRedraw *pr;
- ProjPaintImage *projIma;
- int a, i;
- int redraw = 0;
-
-
- for (a = 0, projIma = ps->projImages; a < ps->image_tot; a++, projIma++) {
- if (projIma->touch) {
- /* look over each bound cell */
- for (i = 0; i < PROJ_BOUNDBOX_SQUARED; i++) {
- pr = &(projIma->partRedrawRect[i]);
- if (pr->x2 != -1) { /* TODO - use 'enabled' ? */
- imapaintpartial = *pr;
- imapaint_image_update(NULL, projIma->ima, projIma->ibuf, 1); /*last 1 is for texpaint*/
- redraw = 1;
- }
- }
-
- projIma->touch = 0; /* clear for reuse */
- }
- }
-
- return redraw;
-}
-
-/* run this per painting onto each mouse location */
-static int project_bucket_iter_init(ProjPaintState *ps, const float mval_f[2])
-{
- if (ps->source == PROJ_SRC_VIEW) {
- float min_brush[2], max_brush[2];
- const float radius = (float)BKE_brush_size_get(ps->scene, ps->brush);
-
- /* so we don't have a bucket bounds that is way too small to paint into */
- // if (radius < 1.0f) radius = 1.0f; // this doesn't work yet :/
-
- min_brush[0] = mval_f[0] - radius;
- min_brush[1] = mval_f[1] - radius;
-
- max_brush[0] = mval_f[0] + radius;
- max_brush[1] = mval_f[1] + radius;
-
- /* offset to make this a valid bucket index */
- project_paint_bucket_bounds(ps, min_brush, max_brush, ps->bucketMin, ps->bucketMax);
-
- /* mouse outside the model areas? */
- if (ps->bucketMin[0] == ps->bucketMax[0] || ps->bucketMin[1] == ps->bucketMax[1]) {
- return 0;
- }
-
- ps->context_bucket_x = ps->bucketMin[0];
- ps->context_bucket_y = ps->bucketMin[1];
- }
- else { /* reproject: PROJ_SRC_* */
- ps->bucketMin[0] = 0;
- ps->bucketMin[1] = 0;
-
- ps->bucketMax[0] = ps->buckets_x;
- ps->bucketMax[1] = ps->buckets_y;
-
- ps->context_bucket_x = 0;
- ps->context_bucket_y = 0;
- }
- return 1;
-}
-
-
-static int project_bucket_iter_next(ProjPaintState *ps, int *bucket_index, rctf *bucket_bounds, const float mval[2])
-{
- const int diameter = 2 * BKE_brush_size_get(ps->scene, ps->brush);
-
- if (ps->thread_tot > 1)
- BLI_lock_thread(LOCK_CUSTOM1);
-
- //printf("%d %d\n", ps->context_bucket_x, ps->context_bucket_y);
-
- for (; ps->context_bucket_y < ps->bucketMax[1]; ps->context_bucket_y++) {
- for (; ps->context_bucket_x < ps->bucketMax[0]; ps->context_bucket_x++) {
-
- /* use bucket_bounds for project_bucket_isect_circle and project_bucket_init*/
- project_bucket_bounds(ps, ps->context_bucket_x, ps->context_bucket_y, bucket_bounds);
-
- if ((ps->source != PROJ_SRC_VIEW) ||
- project_bucket_isect_circle(mval, (float)(diameter * diameter), bucket_bounds))
- {
- *bucket_index = ps->context_bucket_x + (ps->context_bucket_y * ps->buckets_x);
- ps->context_bucket_x++;
-
- if (ps->thread_tot > 1)
- BLI_unlock_thread(LOCK_CUSTOM1);
-
- return 1;
- }
- }
- ps->context_bucket_x = ps->bucketMin[0];
- }
-
- if (ps->thread_tot > 1)
- BLI_unlock_thread(LOCK_CUSTOM1);
- return 0;
-}
-
-/* Each thread gets one of these, also used as an argument to pass to project_paint_op */
-typedef struct ProjectHandle {
- /* args */
- ProjPaintState *ps;
- float prevmval[2];
- float mval[2];
-
- /* annoying but we need to have image bounds per thread, then merge into ps->projectPartialRedraws */
- ProjPaintImage *projImages; /* array of partial redraws */
-
- /* thread settings */
- int thread_index;
-
- struct ImagePool *pool;
-} ProjectHandle;
-
-static void blend_color_mix(unsigned char cp[4], const unsigned char cp1[4], const unsigned char cp2[4], const int fac)
-{
- /* this and other blending modes previously used >>8 instead of /255. both
- * are not equivalent (>>8 is /256), and the former results in rounding
- * errors that can turn colors black fast after repeated blending */
- const int mfac = 255 - fac;
-
- cp[0] = (mfac * cp1[0] + fac * cp2[0]) / 255;
- cp[1] = (mfac * cp1[1] + fac * cp2[1]) / 255;
- cp[2] = (mfac * cp1[2] + fac * cp2[2]) / 255;
- cp[3] = (mfac * cp1[3] + fac * cp2[3]) / 255;
-}
-
-static void blend_color_mix_float(float cp[4], const float cp1[4], const float cp2[4], const float fac)
-{
- const float mfac = 1.0f - fac;
- cp[0] = mfac * cp1[0] + fac * cp2[0];
- cp[1] = mfac * cp1[1] + fac * cp2[1];
- cp[2] = mfac * cp1[2] + fac * cp2[2];
- cp[3] = mfac * cp1[3] + fac * cp2[3];
-}
-
-static void blend_color_mix_accum(unsigned char cp[4], const unsigned char cp1[4], const unsigned char cp2[4], const int fac)
-{
- /* this and other blending modes previously used >>8 instead of /255. both
- * are not equivalent (>>8 is /256), and the former results in rounding
- * errors that can turn colors black fast after repeated blending */
- const int mfac = 255 - fac;
- const int alpha = cp1[3] + ((fac * cp2[3]) / 255);
-
- cp[0] = (mfac * cp1[0] + fac * cp2[0]) / 255;
- cp[1] = (mfac * cp1[1] + fac * cp2[1]) / 255;
- cp[2] = (mfac * cp1[2] + fac * cp2[2]) / 255;
- cp[3] = alpha > 255 ? 255 : alpha;
-}
-static void blend_color_mix_accum_float(float cp[4], const float cp1[4], const unsigned char cp2[4], const float fac)
-{
- const float mfac = 1.0f - fac;
- const float alpha = cp1[3] + (fac * (cp2[3] / 255.0f));
-
- cp[0] = (mfac * cp1[0] + (fac * (cp2[0] / 255.0f)));
- cp[1] = (mfac * cp1[1] + (fac * (cp2[1] / 255.0f)));
- cp[2] = (mfac * cp1[2] + (fac * (cp2[2] / 255.0f)));
- cp[3] = alpha > 1.0f ? 1.0f : alpha;
-}
-
-
-static void do_projectpaint_clone(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask)
-{
- if (ps->do_masking && mask < 1.0f) {
- projPixel->newColor.uint = IMB_blend_color(projPixel->newColor.uint, ((ProjPixelClone *)projPixel)->clonepx.uint, (int)(alpha * 255), ps->blend);
- blend_color_mix(projPixel->pixel.ch_pt, projPixel->origColor.ch, projPixel->newColor.ch, (int)(mask * 255));
- }
- else {
- *projPixel->pixel.uint_pt = IMB_blend_color(*projPixel->pixel.uint_pt, ((ProjPixelClone *)projPixel)->clonepx.uint, (int)(alpha * mask * 255), ps->blend);
- }
-}
-
-static void do_projectpaint_clone_f(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask)
-{
- if (ps->do_masking && mask < 1.0f) {
- IMB_blend_color_float(projPixel->newColor.f, projPixel->newColor.f, ((ProjPixelClone *)projPixel)->clonepx.f, alpha, ps->blend);
- blend_color_mix_float(projPixel->pixel.f_pt, projPixel->origColor.f, projPixel->newColor.f, mask);
- }
- else {
- IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, ((ProjPixelClone *)projPixel)->clonepx.f, alpha * mask, ps->blend);
- }
-}
-
-/* do_projectpaint_smear*
- *
- * note, mask is used to modify the alpha here, this is not correct since it allows
- * accumulation of color greater then 'projPixel->mask' however in the case of smear its not
- * really that important to be correct as it is with clone and painting
- */
-static void do_projectpaint_smear(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask, MemArena *smearArena, LinkNode **smearPixels, float co[2])
-{
- unsigned char rgba_ub[4];
-
- if (project_paint_PickColor(ps, co, NULL, rgba_ub, 1) == 0)
- return;
- /* ((ProjPixelClone *)projPixel)->clonepx.uint = IMB_blend_color(*projPixel->pixel.uint_pt, *((unsigned int *)rgba_ub), (int)(alpha*mask*255), ps->blend); */
- blend_color_mix(((ProjPixelClone *)projPixel)->clonepx.ch, projPixel->pixel.ch_pt, rgba_ub, (int)(alpha * mask * 255));
- BLI_linklist_prepend_arena(smearPixels, (void *)projPixel, smearArena);
-}
-
-static void do_projectpaint_smear_f(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask, MemArena *smearArena, LinkNode **smearPixels_f, float co[2])
-{
- float rgba[4];
-
- if (project_paint_PickColor(ps, co, rgba, NULL, 1) == 0)
- return;
-
- /* (ProjPixelClone *)projPixel)->clonepx.uint = IMB_blend_color(*((unsigned int *)rgba_smear), *((unsigned int *)rgba_ub), (int)(alpha*mask*255), ps->blend); */
- blend_color_mix_float(((ProjPixelClone *)projPixel)->clonepx.f, projPixel->pixel.f_pt, rgba, alpha * mask);
- BLI_linklist_prepend_arena(smearPixels_f, (void *)projPixel, smearArena);
-}
-
-/* do_projectpaint_soften for float & byte
- */
-static float inv_pow2(float f)
-{
- f = 1.0f - f;
- f = f * f;
- return 1.0f - f;
-}
-
-static void do_projectpaint_soften_f(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask, MemArena *softenArena, LinkNode **softenPixels)
-{
- unsigned int accum_tot = 0;
- unsigned int i;
-
- float *rgba = projPixel->newColor.f;
-
- /* sigh, alpha values tend to need to be a _lot_ stronger with blur */
- mask = inv_pow2(mask);
- alpha = inv_pow2(alpha);
-
- /* rather then painting, accumulate surrounding colors */
- zero_v4(rgba);
-
- for (i = 0; i < PROJ_PIXEL_SOFTEN_TOT; i++) {
- float co_ofs[2];
- float rgba_tmp[4];
- sub_v2_v2v2(co_ofs, projPixel->projCoSS, proj_pixel_soften_v2[i]);
- if (project_paint_PickColor(ps, co_ofs, rgba_tmp, NULL, TRUE)) {
- add_v4_v4(rgba, rgba_tmp);
- accum_tot++;
- }
- }
-
- if (LIKELY(accum_tot != 0)) {
- mul_v4_fl(rgba, 1.0f / (float)accum_tot);
- blend_color_mix_float(rgba, projPixel->pixel.f_pt, rgba, alpha);
- if (mask < 1.0f) blend_color_mix_float(rgba, projPixel->origColor.f, rgba, mask);
- BLI_linklist_prepend_arena(softenPixels, (void *)projPixel, softenArena);
- }
-}
-
-static void do_projectpaint_soften(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask, MemArena *softenArena, LinkNode **softenPixels)
-{
- unsigned int accum_tot = 0;
- unsigned int i;
-
- float rgba[4]; /* convert to byte after */
-
- /* sigh, alpha values tend to need to be a _lot_ stronger with blur */
- mask = inv_pow2(mask);
- alpha = inv_pow2(alpha);
-
- /* rather then painting, accumulate surrounding colors */
- zero_v4(rgba);
-
- for (i = 0; i < PROJ_PIXEL_SOFTEN_TOT; i++) {
- float co_ofs[2];
- float rgba_tmp[4];
- sub_v2_v2v2(co_ofs, projPixel->projCoSS, proj_pixel_soften_v2[i]);
- if (project_paint_PickColor(ps, co_ofs, rgba_tmp, NULL, TRUE)) {
- add_v4_v4(rgba, rgba_tmp);
- accum_tot++;
- }
- }
-
- if (LIKELY(accum_tot != 0)) {
- unsigned char *rgba_ub = projPixel->newColor.ch;
-
- mul_v4_fl(rgba, 1.0f / (float)accum_tot);
- IMAPAINT_FLOAT_RGBA_TO_CHAR(rgba_ub, rgba);
-
- blend_color_mix(rgba_ub, projPixel->pixel.ch_pt, rgba_ub, (int)(alpha * 255));
- if (mask != 1.0f) blend_color_mix(rgba_ub, projPixel->origColor.ch, rgba_ub, (int)(mask * 255));
- BLI_linklist_prepend_arena(softenPixels, (void *)projPixel, softenArena);
- }
-}
-
-BLI_INLINE void rgba_float_to_uchar__mul_v3(unsigned char rgba_ub[4], const float rgba[4], const float rgb[3])
-{
- rgba_ub[0] = f_to_char(rgba[0] * rgb[0]);
- rgba_ub[1] = f_to_char(rgba[1] * rgb[1]);
- rgba_ub[2] = f_to_char(rgba[2] * rgb[2]);
- rgba_ub[3] = f_to_char(rgba[3]);
-}
-
-static void do_projectpaint_draw(ProjPaintState *ps, ProjPixel *projPixel, const float rgba[4], float alpha, float mask)
-{
- unsigned char rgba_ub[4];
-
- if (ps->is_texbrush) {
- rgba_float_to_uchar__mul_v3(rgba_ub, rgba, ps->brush->rgb);
- }
- else {
- IMAPAINT_FLOAT_RGB_TO_CHAR(rgba_ub, ps->brush->rgb);
- rgba_ub[3] = 255;
- }
-
- if (ps->do_masking && mask < 1.0f) {
- projPixel->newColor.uint = IMB_blend_color(projPixel->newColor.uint, *((unsigned int *)rgba_ub), (int)(alpha * 255), ps->blend);
- blend_color_mix(projPixel->pixel.ch_pt, projPixel->origColor.ch, projPixel->newColor.ch, (int)(mask * 255));
- }
- else {
- *projPixel->pixel.uint_pt = IMB_blend_color(*projPixel->pixel.uint_pt, *((unsigned int *)rgba_ub), (int)(alpha * mask * 255), ps->blend);
- }
-}
-
-static void do_projectpaint_draw_f(ProjPaintState *ps, ProjPixel *projPixel, float rgba[4], float alpha, float mask, int use_color_correction)
-{
- if (ps->is_texbrush) {
- /* rgba already holds a texture result here from higher level function */
- if (use_color_correction) {
- float rgba_br[3];
- srgb_to_linearrgb_v3_v3(rgba_br, ps->brush->rgb);
- mul_v3_v3(rgba, rgba_br);
- }
- else {
- mul_v3_v3(rgba, ps->brush->rgb);
- }
- }
- else {
- if (use_color_correction) {
- srgb_to_linearrgb_v3_v3(rgba, ps->brush->rgb);
- }
- else {
- copy_v3_v3(rgba, ps->brush->rgb);
- }
- rgba[3] = 1.0;
- }
-
- if (ps->do_masking && mask < 1.0f) {
- IMB_blend_color_float(projPixel->newColor.f, projPixel->newColor.f, rgba, alpha, ps->blend);
- blend_color_mix_float(projPixel->pixel.f_pt, projPixel->origColor.f, projPixel->newColor.f, mask);
- }
- else {
- IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, rgba, alpha * mask, ps->blend);
- }
-}
-
-
-
-/* run this for single and multithreaded painting */
-static void *do_projectpaint_thread(void *ph_v)
-{
- /* First unpack args from the struct */
- ProjPaintState *ps = ((ProjectHandle *)ph_v)->ps;
- ProjPaintImage *projImages = ((ProjectHandle *)ph_v)->projImages;
- const float *lastpos = ((ProjectHandle *)ph_v)->prevmval;
- const float *pos = ((ProjectHandle *)ph_v)->mval;
- const int thread_index = ((ProjectHandle *)ph_v)->thread_index;
- struct ImagePool *pool = ((ProjectHandle *)ph_v)->pool;
- /* Done with args from ProjectHandle */
-
- LinkNode *node;
- ProjPixel *projPixel;
- Brush *brush = ps->brush;
-
- int last_index = -1;
- ProjPaintImage *last_projIma = NULL;
- ImagePaintPartialRedraw *last_partial_redraw_cell;
-
- float rgba[4], alpha, dist_nosqrt, dist;
-
- float falloff;
- int bucket_index;
- int is_floatbuf = 0;
- int use_color_correction = FALSE;
- const short tool = ps->tool;
- rctf bucket_bounds;
-
- /* for smear only */
- float pos_ofs[2] = {0};
- float co[2];
- float mask = 1.0f; /* airbrush wont use mask */
- unsigned short mask_short;
- const float radius = (float)BKE_brush_size_get(ps->scene, brush);
- const float radius_squared = radius * radius; /* avoid a square root with every dist comparison */
-
- short lock_alpha = ELEM(brush->blend, IMB_BLEND_ERASE_ALPHA, IMB_BLEND_ADD_ALPHA) ? 0 : brush->flag & BRUSH_LOCK_ALPHA;
-
- LinkNode *smearPixels = NULL;
- LinkNode *smearPixels_f = NULL;
- MemArena *smearArena = NULL; /* mem arena for this brush projection only */
-
- LinkNode *softenPixels = NULL;
- LinkNode *softenPixels_f = NULL;
- MemArena *softenArena = NULL; /* mem arena for this brush projection only */
-
- if (tool == PAINT_TOOL_SMEAR) {
- pos_ofs[0] = pos[0] - lastpos[0];
- pos_ofs[1] = pos[1] - lastpos[1];
-
- smearArena = BLI_memarena_new(1 << 16, "paint smear arena");
- }
- else if (tool == PAINT_TOOL_SOFTEN) {
- softenArena = BLI_memarena_new(1 << 16, "paint soften arena");
- }
-
- /* printf("brush bounds %d %d %d %d\n", bucketMin[0], bucketMin[1], bucketMax[0], bucketMax[1]); */
-
- while (project_bucket_iter_next(ps, &bucket_index, &bucket_bounds, pos)) {
-
- /* Check this bucket and its faces are initialized */
- if (ps->bucketFlags[bucket_index] == PROJ_BUCKET_NULL) {
- /* No pixels initialized */
- project_bucket_init(ps, thread_index, bucket_index, &bucket_bounds);
- }
-
- if (ps->source != PROJ_SRC_VIEW) {
-
- /* Re-Projection, simple, no brushes! */
-
- for (node = ps->bucketRect[bucket_index]; node; node = node->next) {
- projPixel = (ProjPixel *)node->link;
-
- /* copy of code below */
- if (last_index != projPixel->image_index) {
- last_index = projPixel->image_index;
- last_projIma = projImages + last_index;
-
- last_projIma->touch = 1;
- is_floatbuf = last_projIma->ibuf->rect_float ? 1 : 0;
- use_color_correction = TRUE;
- }
- /* end copy */
-
- if (is_floatbuf) {
- /* re-project buffer is assumed byte - TODO, allow float */
- bicubic_interpolation_color(ps->reproject_ibuf, projPixel->newColor.ch, NULL,
- projPixel->projCoSS[0], projPixel->projCoSS[1]);
- if (projPixel->newColor.ch[3]) {
- mask = ((float)projPixel->mask) / 65535.0f;
- blend_color_mix_accum_float(projPixel->pixel.f_pt, projPixel->origColor.f,
- projPixel->newColor.ch, (mask * (projPixel->newColor.ch[3] / 255.0f)));
- }
- }
- else {
- /* re-project buffer is assumed byte - TODO, allow float */
- bicubic_interpolation_color(ps->reproject_ibuf, projPixel->newColor.ch, NULL,
- projPixel->projCoSS[0], projPixel->projCoSS[1]);
- if (projPixel->newColor.ch[3]) {
- mask = ((float)projPixel->mask) / 65535.0f;
- blend_color_mix_accum(projPixel->pixel.ch_pt, projPixel->origColor.ch,
- projPixel->newColor.ch, (int)(mask * projPixel->newColor.ch[3]));
- }
- }
- }
- }
- else {
- /* Normal brush painting */
-
- for (node = ps->bucketRect[bucket_index]; node; node = node->next) {
-
- projPixel = (ProjPixel *)node->link;
-
- dist_nosqrt = len_squared_v2v2(projPixel->projCoSS, pos);
-
- /*if (dist < radius) {*/ /* correct but uses a sqrtf */
- if (dist_nosqrt <= radius_squared) {
- float samplecos[3];
- dist = sqrtf(dist_nosqrt);
-
- falloff = BKE_brush_curve_strength_clamp(ps->brush, dist, radius);
-
- if (ps->is_texbrush) {
- MTex *mtex = &brush->mtex;
- if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
- sub_v2_v2v2(samplecos, projPixel->projCoSS, pos);
- }
- /* taking 3d copy to account for 3D mapping too. It gets concatenated during sampling */
- else if (mtex->brush_map_mode == MTEX_MAP_MODE_3D)
- copy_v3_v3(samplecos, projPixel->worldCoSS);
- else
- copy_v3_v3(samplecos, projPixel->projCoSS);
- }
-
- if (falloff > 0.0f) {
- if (ps->is_texbrush) {
- /* note, for clone and smear, we only use the alpha, could be a special function */
- BKE_brush_sample_tex(ps->scene, brush, samplecos, rgba, thread_index, pool);
- alpha = rgba[3];
- }
- else {
- alpha = 1.0f;
- }
-
- if (!ps->do_masking) {
- /* for an aurbrush there is no real mask, so just multiply the alpha by it */
- alpha *= falloff * BKE_brush_alpha_get(ps->scene, brush);
- mask = ((float)projPixel->mask) / 65535.0f;
- }
- else {
- /* This brush dosnt accumulate so add some curve to the brushes falloff */
- falloff = 1.0f - falloff;
- falloff = 1.0f - (falloff * falloff);
-
- mask_short = (unsigned short)(projPixel->mask * (BKE_brush_alpha_get(ps->scene, brush) * falloff));
- if (mask_short > projPixel->mask_max) {
- mask = ((float)mask_short) / 65535.0f;
- projPixel->mask_max = mask_short;
- }
- else {
- /*mask = ((float)projPixel->mask_max)/65535.0f;*/
-
- /* Go onto the next pixel */
- continue;
- }
- }
-
- if (alpha > 0.0f) {
-
- /* copy of code above */
- if (last_index != projPixel->image_index) {
- last_index = projPixel->image_index;
- last_projIma = projImages + last_index;
-
- last_projIma->touch = 1;
- is_floatbuf = last_projIma->ibuf->rect_float ? 1 : 0;
- use_color_correction = TRUE;
- }
- /* end copy */
-
- last_partial_redraw_cell = last_projIma->partRedrawRect + projPixel->bb_cell_index;
- last_partial_redraw_cell->x1 = min_ii(last_partial_redraw_cell->x1, (int)projPixel->x_px);
- last_partial_redraw_cell->y1 = min_ii(last_partial_redraw_cell->y1, (int)projPixel->y_px);
-
- last_partial_redraw_cell->x2 = max_ii(last_partial_redraw_cell->x2, (int)projPixel->x_px + 1);
- last_partial_redraw_cell->y2 = max_ii(last_partial_redraw_cell->y2, (int)projPixel->y_px + 1);
-
-
- switch (tool) {
- case PAINT_TOOL_CLONE:
- if (is_floatbuf) {
- if (((ProjPixelClone *)projPixel)->clonepx.f[3]) {
- do_projectpaint_clone_f(ps, projPixel, alpha, mask); /* rgba isn't used for cloning, only alpha */
- }
- }
- else {
- if (((ProjPixelClone *)projPixel)->clonepx.ch[3]) {
- do_projectpaint_clone(ps, projPixel, alpha, mask); /* rgba isn't used for cloning, only alpha */
- }
- }
- break;
- case PAINT_TOOL_SMEAR:
- sub_v2_v2v2(co, projPixel->projCoSS, pos_ofs);
-
- if (is_floatbuf) do_projectpaint_smear_f(ps, projPixel, alpha, mask, smearArena, &smearPixels_f, co);
- else do_projectpaint_smear(ps, projPixel, alpha, mask, smearArena, &smearPixels, co);
- break;
- case PAINT_TOOL_SOFTEN:
- if (is_floatbuf) do_projectpaint_soften_f(ps, projPixel, alpha, mask, softenArena, &softenPixels_f);
- else do_projectpaint_soften(ps, projPixel, alpha, mask, softenArena, &softenPixels);
- break;
- default:
- if (is_floatbuf) do_projectpaint_draw_f(ps, projPixel, rgba, alpha, mask, use_color_correction);
- else do_projectpaint_draw(ps, projPixel, rgba, alpha, mask);
- break;
- }
- }
-
- if (lock_alpha) {
- if (is_floatbuf) projPixel->pixel.f_pt[3] = projPixel->origColor.f[3];
- else projPixel->pixel.ch_pt[3] = projPixel->origColor.ch[3];
- }
-
- /* done painting */
- }
- }
- }
- }
- }
-
-
- if (tool == PAINT_TOOL_SMEAR) {
-
- for (node = smearPixels; node; node = node->next) { /* this wont run for a float image */
- projPixel = node->link;
- *projPixel->pixel.uint_pt = ((ProjPixelClone *)projPixel)->clonepx.uint;
- }
-
- for (node = smearPixels_f; node; node = node->next) {
- projPixel = node->link;
- copy_v4_v4(projPixel->pixel.f_pt, ((ProjPixelClone *)projPixel)->clonepx.f);
- }
-
- BLI_memarena_free(smearArena);
- }
- else if (tool == PAINT_TOOL_SOFTEN) {
-
- for (node = softenPixels; node; node = node->next) { /* this wont run for a float image */
- projPixel = node->link;
- *projPixel->pixel.uint_pt = projPixel->newColor.uint;
- }
-
- for (node = softenPixels_f; node; node = node->next) {
- projPixel = node->link;
- copy_v4_v4(projPixel->pixel.f_pt, projPixel->newColor.f);
- }
-
- BLI_memarena_free(softenArena);
- }
-
- return NULL;
-}
-
-static int project_paint_op(void *state, ImBuf *UNUSED(ibufb), const float lastpos[2], const float pos[2])
-{
- /* First unpack args from the struct */
- ProjPaintState *ps = (ProjPaintState *)state;
- int touch_any = 0;
-
- ProjectHandle handles[BLENDER_MAX_THREADS];
- ListBase threads;
- int a, i;
-
- struct ImagePool *pool;
-
- if (!project_bucket_iter_init(ps, pos)) {
- return 0;
- }
-
- if (ps->thread_tot > 1)
- BLI_init_threads(&threads, do_projectpaint_thread, ps->thread_tot);
-
- pool = BKE_image_pool_new();
-
- /* get the threads running */
- for (a = 0; a < ps->thread_tot; a++) {
-
- /* set defaults in handles */
- //memset(&handles[a], 0, sizeof(BakeShade));
-
- handles[a].ps = ps;
- copy_v2_v2(handles[a].mval, pos);
- copy_v2_v2(handles[a].prevmval, lastpos);
-
- /* thread specific */
- handles[a].thread_index = a;
-
- handles[a].projImages = (ProjPaintImage *)BLI_memarena_alloc(ps->arena_mt[a], ps->image_tot * sizeof(ProjPaintImage));
-
- memcpy(handles[a].projImages, ps->projImages, ps->image_tot * sizeof(ProjPaintImage));
-
- /* image bounds */
- for (i = 0; i < ps->image_tot; i++) {
- handles[a].projImages[i].partRedrawRect = (ImagePaintPartialRedraw *)BLI_memarena_alloc(ps->arena_mt[a], sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
- memcpy(handles[a].projImages[i].partRedrawRect, ps->projImages[i].partRedrawRect, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
- }
-
- handles[a].pool = pool;
-
- if (ps->thread_tot > 1)
- BLI_insert_thread(&threads, &handles[a]);
- }
-
- if (ps->thread_tot > 1) /* wait for everything to be done */
- BLI_end_threads(&threads);
- else
- do_projectpaint_thread(&handles[0]);
-
-
- BKE_image_pool_free(pool);
-
- /* move threaded bounds back into ps->projectPartialRedraws */
- for (i = 0; i < ps->image_tot; i++) {
- int touch = 0;
- for (a = 0; a < ps->thread_tot; a++) {
- touch |= partial_redraw_array_merge(ps->projImages[i].partRedrawRect, handles[a].projImages[i].partRedrawRect, PROJ_BOUNDBOX_SQUARED);
- }
-
- if (touch) {
- ps->projImages[i].touch = 1;
- touch_any = 1;
- }
- }
-
- return touch_any;
-}
-
-
-static int project_paint_sub_stroke(ProjPaintState *ps, BrushPainter *painter, const int UNUSED(prevmval_i[2]), const int mval_i[2], double time, float pressure)
-{
-
- /* Use mouse coords as floats for projection painting */
- float pos[2];
-
- pos[0] = (float)(mval_i[0]);
- pos[1] = (float)(mval_i[1]);
-
- // we may want to use this later
- // BKE_brush_painter_require_imbuf(painter, ((ibuf->rect_float) ? 1 : 0), 0, 0);
-
- if (BKE_brush_painter_paint(painter, project_paint_op, pos, time, pressure, ps, 0)) {
- return 1;
- }
- else return 0;
-}
-
-
-static int project_paint_stroke(ProjPaintState *ps, BrushPainter *painter, const int prevmval_i[2], const int mval_i[2], double time, float pressure)
-{
- int a, redraw;
-
- for (a = 0; a < ps->image_tot; a++)
- partial_redraw_array_init(ps->projImages[a].partRedrawRect);
-
- redraw = project_paint_sub_stroke(ps, painter, prevmval_i, mval_i, time, pressure);
-
- if (project_image_refresh_tagged(ps))
- return redraw;
-
- return 0;
-}
-
/* Imagepaint Partial Redraw & Dirty Region */
-static void imapaint_clear_partial_redraw(void)
+void imapaint_clear_partial_redraw(void)
{
memset(&imapaintpartial, 0, sizeof(imapaintpartial));
}
-static void imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h)
+void imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h)
{
ImBuf *tmpibuf = NULL;
int srcx = 0, srcy = 0, origx;
@@ -4417,7 +315,7 @@ static void imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w,
IMB_freeImBuf(tmpibuf);
}
-static void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short texpaint)
+void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short texpaint)
{
if (imapaintpartial.x1 != imapaintpartial.x2 &&
imapaintpartial.y1 != imapaintpartial.y2)
@@ -4438,447 +336,6 @@ static void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, s
}
}
-/* Image Paint Operations */
-
-/* keep these functions in sync */
-static void imapaint_ibuf_rgb_get(ImBuf *ibuf, int x, int y, const short is_torus, float r_rgb[3])
-{
- if (is_torus) {
- x %= ibuf->x;
- if (x < 0) x += ibuf->x;
- y %= ibuf->y;
- if (y < 0) y += ibuf->y;
- }
-
- if (ibuf->rect_float) {
- float *rrgbf = ibuf->rect_float + (ibuf->x * y + x) * 4;
- IMAPAINT_FLOAT_RGB_COPY(r_rgb, rrgbf);
- }
- else {
- char *rrgb = (char *)ibuf->rect + (ibuf->x * y + x) * 4;
- IMAPAINT_CHAR_RGB_TO_FLOAT(r_rgb, rrgb);
- }
-}
-static void imapaint_ibuf_rgb_set(ImBuf *ibuf, int x, int y, const short is_torus, const float rgb[3])
-{
- if (is_torus) {
- x %= ibuf->x;
- if (x < 0) x += ibuf->x;
- y %= ibuf->y;
- if (y < 0) y += ibuf->y;
- }
-
- if (ibuf->rect_float) {
- float *rrgbf = ibuf->rect_float + (ibuf->x * y + x) * 4;
- IMAPAINT_FLOAT_RGB_COPY(rrgbf, rgb);
- }
- else {
- char *rrgb = (char *)ibuf->rect + (ibuf->x * y + x) * 4;
- IMAPAINT_FLOAT_RGB_TO_CHAR(rrgb, rgb);
- }
-}
-
-static int imapaint_ibuf_add_if(ImBuf *ibuf, unsigned int x, unsigned int y, float *outrgb, short torus)
-{
- float inrgb[3];
-
- // XXX: signed unsigned mismatch
- if ((x >= (unsigned int)(ibuf->x)) || (y >= (unsigned int)(ibuf->y))) {
- if (torus) imapaint_ibuf_rgb_get(ibuf, x, y, 1, inrgb);
- else return 0;
- }
- else {
- imapaint_ibuf_rgb_get(ibuf, x, y, 0, inrgb);
- }
-
- outrgb[0] += inrgb[0];
- outrgb[1] += inrgb[1];
- outrgb[2] += inrgb[2];
-
- return 1;
-}
-
-static void imapaint_lift_soften(ImBuf *ibuf, ImBuf *ibufb, int *pos, const short is_torus)
-{
- int x, y, count, xi, yi, xo, yo;
- int out_off[2], in_off[2], dim[2];
- float outrgb[3];
-
- dim[0] = ibufb->x;
- dim[1] = ibufb->y;
- in_off[0] = pos[0];
- in_off[1] = pos[1];
- out_off[0] = out_off[1] = 0;
-
- if (!is_torus) {
- IMB_rectclip(ibuf, ibufb, &in_off[0], &in_off[1], &out_off[0],
- &out_off[1], &dim[0], &dim[1]);
-
- if ((dim[0] == 0) || (dim[1] == 0))
- return;
- }
-
- for (y = 0; y < dim[1]; y++) {
- for (x = 0; x < dim[0]; x++) {
- /* get input pixel */
- xi = in_off[0] + x;
- yi = in_off[1] + y;
-
- count = 1;
- imapaint_ibuf_rgb_get(ibuf, xi, yi, is_torus, outrgb);
-
- count += imapaint_ibuf_add_if(ibuf, xi - 1, yi - 1, outrgb, is_torus);
- count += imapaint_ibuf_add_if(ibuf, xi - 1, yi, outrgb, is_torus);
- count += imapaint_ibuf_add_if(ibuf, xi - 1, yi + 1, outrgb, is_torus);
-
- count += imapaint_ibuf_add_if(ibuf, xi, yi - 1, outrgb, is_torus);
- count += imapaint_ibuf_add_if(ibuf, xi, yi + 1, outrgb, is_torus);
-
- count += imapaint_ibuf_add_if(ibuf, xi + 1, yi - 1, outrgb, is_torus);
- count += imapaint_ibuf_add_if(ibuf, xi + 1, yi, outrgb, is_torus);
- count += imapaint_ibuf_add_if(ibuf, xi + 1, yi + 1, outrgb, is_torus);
-
- mul_v3_fl(outrgb, 1.0f / (float)count);
-
- /* write into brush buffer */
- xo = out_off[0] + x;
- yo = out_off[1] + y;
- imapaint_ibuf_rgb_set(ibufb, xo, yo, 0, outrgb);
- }
- }
-}
-
-static void imapaint_set_region(ImagePaintRegion *region, int destx, int desty, int srcx, int srcy, int width, int height)
-{
- region->destx = destx;
- region->desty = desty;
- region->srcx = srcx;
- region->srcy = srcy;
- region->width = width;
- region->height = height;
-}
-
-static int imapaint_torus_split_region(ImagePaintRegion region[4], ImBuf *dbuf, ImBuf *sbuf)
-{
- int destx = region->destx;
- int desty = region->desty;
- int srcx = region->srcx;
- int srcy = region->srcy;
- int width = region->width;
- int height = region->height;
- int origw, origh, w, h, tot = 0;
-
- /* convert destination and source coordinates to be within image */
- destx = destx % dbuf->x;
- if (destx < 0) destx += dbuf->x;
- desty = desty % dbuf->y;
- if (desty < 0) desty += dbuf->y;
- srcx = srcx % sbuf->x;
- if (srcx < 0) srcx += sbuf->x;
- srcy = srcy % sbuf->y;
- if (srcy < 0) srcy += sbuf->y;
-
- /* clip width of blending area to destination imbuf, to avoid writing the
- * same pixel twice */
- origw = w = (width > dbuf->x) ? dbuf->x : width;
- origh = h = (height > dbuf->y) ? dbuf->y : height;
-
- /* clip within image */
- IMB_rectclip(dbuf, sbuf, &destx, &desty, &srcx, &srcy, &w, &h);
- imapaint_set_region(&region[tot++], destx, desty, srcx, srcy, w, h);
-
- /* do 3 other rects if needed */
- if (w < origw)
- imapaint_set_region(&region[tot++], (destx + w) % dbuf->x, desty, (srcx + w) % sbuf->x, srcy, origw - w, h);
- if (h < origh)
- imapaint_set_region(&region[tot++], destx, (desty + h) % dbuf->y, srcx, (srcy + h) % sbuf->y, w, origh - h);
- if ((w < origw) && (h < origh))
- imapaint_set_region(&region[tot++], (destx + w) % dbuf->x, (desty + h) % dbuf->y, (srcx + w) % sbuf->x, (srcy + h) % sbuf->y, origw - w, origh - h);
-
- return tot;
-}
-
-static void imapaint_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos)
-{
- ImagePaintRegion region[4];
- int a, tot;
-
- imapaint_set_region(region, 0, 0, pos[0], pos[1], ibufb->x, ibufb->y);
- tot = imapaint_torus_split_region(region, ibufb, ibuf);
-
- for (a = 0; a < tot; a++)
- IMB_rectblend(ibufb, ibuf, region[a].destx, region[a].desty,
- region[a].srcx, region[a].srcy,
- region[a].width, region[a].height, IMB_BLEND_COPY_RGB);
-}
-
-static ImBuf *imapaint_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos)
-{
- /* note: allocImbuf returns zero'd memory, so regions outside image will
- * have zero alpha, and hence not be blended onto the image */
- int w = ibufb->x, h = ibufb->y, destx = 0, desty = 0, srcx = pos[0], srcy = pos[1];
- ImBuf *clonebuf = IMB_allocImBuf(w, h, ibufb->planes, ibufb->flags);
-
- IMB_rectclip(clonebuf, ibuf, &destx, &desty, &srcx, &srcy, &w, &h);
- IMB_rectblend(clonebuf, ibuf, destx, desty, srcx, srcy, w, h,
- IMB_BLEND_COPY_RGB);
- IMB_rectblend(clonebuf, ibufb, destx, desty, destx, desty, w, h,
- IMB_BLEND_COPY_ALPHA);
-
- return clonebuf;
-}
-
-static void imapaint_convert_brushco(ImBuf *ibufb, const float pos[2], int ipos[2])
-{
- ipos[0] = (int)floorf((pos[0] - ibufb->x / 2) + 1.0f);
- ipos[1] = (int)floorf((pos[1] - ibufb->y / 2) + 1.0f);
-}
-
-/* dosnt run for projection painting
- * only the old style painting in the 3d view */
-static int imapaint_paint_op(void *state, ImBuf *ibufb, const float lastpos[2], const float pos[2])
-{
- ImagePaintState *s = ((ImagePaintState *)state);
- ImBuf *clonebuf = NULL, *frombuf;
- ImagePaintRegion region[4];
- short torus = s->brush->flag & BRUSH_TORUS;
- short blend = s->blend;
- float *offset = s->brush->clone.offset;
- float liftpos[2];
- int bpos[2], blastpos[2], bliftpos[2];
- int a, tot;
-
- imapaint_convert_brushco(ibufb, pos, bpos);
-
- /* lift from canvas */
- if (s->tool == PAINT_TOOL_SOFTEN) {
- imapaint_lift_soften(s->canvas, ibufb, bpos, torus);
- }
- else if (s->tool == PAINT_TOOL_SMEAR) {
- if (lastpos[0] == pos[0] && lastpos[1] == pos[1])
- return 0;
-
- imapaint_convert_brushco(ibufb, lastpos, blastpos);
- imapaint_lift_smear(s->canvas, ibufb, blastpos);
- }
- else if (s->tool == PAINT_TOOL_CLONE && s->clonecanvas) {
- liftpos[0] = pos[0] - offset[0] * s->canvas->x;
- liftpos[1] = pos[1] - offset[1] * s->canvas->y;
-
- imapaint_convert_brushco(ibufb, liftpos, bliftpos);
- clonebuf = imapaint_lift_clone(s->clonecanvas, ibufb, bliftpos);
- }
-
- frombuf = (clonebuf) ? clonebuf : ibufb;
-
- if (torus) {
- imapaint_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y);
- tot = imapaint_torus_split_region(region, s->canvas, frombuf);
- }
- else {
- imapaint_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y);
- tot = 1;
- }
-
- /* blend into canvas */
- for (a = 0; a < tot; a++) {
- imapaint_dirty_region(s->image, s->canvas,
- region[a].destx, region[a].desty,
- region[a].width, region[a].height);
-
- IMB_rectblend(s->canvas, frombuf,
- region[a].destx, region[a].desty,
- region[a].srcx, region[a].srcy,
- region[a].width, region[a].height, blend);
- }
-
- if (clonebuf) IMB_freeImBuf(clonebuf);
-
- return 1;
-}
-
-/* 3D TexturePaint */
-
-static int texpaint_break_stroke(float *prevuv, float *fwuv, float *bkuv, float *uv)
-{
- float d1[2], d2[2];
- float mismatch = len_v2v2(fwuv, uv);
- float len1 = len_v2v2(prevuv, fwuv);
- float len2 = len_v2v2(bkuv, uv);
-
- sub_v2_v2v2(d1, fwuv, prevuv);
- sub_v2_v2v2(d2, uv, bkuv);
-
- return ((dot_v2v2(d1, d2) < 0.0f) || (mismatch > MAX2(len1, len2) * 2));
-}
-
-/* ImagePaint Common */
-
-static int imapaint_canvas_set(ImagePaintState *s, Image *ima)
-{
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, s->sima ? &s->sima->iuser : NULL, NULL);
-
- /* verify that we can paint and set canvas */
- if (ima == NULL) {
- return 0;
- }
- else if (ima->packedfile && ima->rr) {
- s->warnpackedfile = ima->id.name + 2;
- return 0;
- }
- else if (ibuf && ibuf->channels != 4) {
- s->warnmultifile = ima->id.name + 2;
- return 0;
- }
- else if (!ibuf || !(ibuf->rect || ibuf->rect_float))
- return 0;
-
- s->image = ima;
- s->canvas = ibuf;
-
- /* set clone canvas */
- if (s->tool == PAINT_TOOL_CLONE) {
- ima = s->brush->clone.image;
- ibuf = BKE_image_acquire_ibuf(ima, s->sima ? &s->sima->iuser : NULL, NULL);
-
- if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
- BKE_image_release_ibuf(s->image, s->canvas, NULL);
- return 0;
- }
-
- s->clonecanvas = ibuf;
-
- /* temporarily add float rect for cloning */
- if (s->canvas->rect_float && !s->clonecanvas->rect_float) {
- IMB_float_from_rect(s->clonecanvas);
- }
- else if (!s->canvas->rect_float && !s->clonecanvas->rect)
- IMB_rect_from_float(s->clonecanvas);
- }
-
- return 1;
-}
-
-static void imapaint_canvas_free(ImagePaintState *s)
-{
- BKE_image_release_ibuf(s->image, s->canvas, NULL);
- BKE_image_release_ibuf(s->brush->clone.image, s->clonecanvas, NULL);
-}
-
-static int imapaint_paint_sub_stroke(ImagePaintState *s, BrushPainter *painter, Image *image, short texpaint, float *uv, double time, int update, float pressure)
-{
- ImBuf *ibuf = BKE_image_acquire_ibuf(image, s->sima ? &s->sima->iuser : NULL, NULL);
- float pos[2];
- int is_data;
-
- if (!ibuf)
- return 0;
-
- is_data = ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA;
-
- pos[0] = uv[0] * ibuf->x;
- pos[1] = uv[1] * ibuf->y;
-
- BKE_brush_painter_require_imbuf(painter, ((ibuf->rect_float) ? 1 : 0), 0, 0);
-
- /* OCIO_TODO: float buffers are now always linear, so always use color correction
- * this should probably be changed when texture painting color space is supported
- */
- if (BKE_brush_painter_paint(painter, imapaint_paint_op, pos, time, pressure, s, is_data == FALSE)) {
- if (update)
- imapaint_image_update(s->sima, image, ibuf, texpaint);
- BKE_image_release_ibuf(image, ibuf, NULL);
- return 1;
- }
- else {
- BKE_image_release_ibuf(image, ibuf, NULL);
- return 0;
- }
-}
-
-static int imapaint_paint_stroke(ViewContext *vc, ImagePaintState *s, BrushPainter *painter, short texpaint, const int prevmval[2], const int mval[2], double time, float pressure)
-{
- Image *newimage = NULL;
- float fwuv[2], bkuv[2], newuv[2];
- unsigned int newfaceindex;
- int breakstroke = 0, redraw = 0;
-
- if (texpaint) {
- /* pick new face and image */
- if (imapaint_pick_face(vc, mval, &newfaceindex, s->dm_totface) &&
- ((s->do_facesel == FALSE) || (s->dm_mface[newfaceindex].flag & ME_FACE_SEL)))
- {
- ImBuf *ibuf;
-
- newimage = imapaint_face_image(s, newfaceindex);
- ibuf = BKE_image_acquire_ibuf(newimage, s->sima ? &s->sima->iuser : NULL, NULL);
-
- if (ibuf && ibuf->rect)
- imapaint_pick_uv(s->scene, s->ob, newfaceindex, mval, newuv);
- else {
- newimage = NULL;
- newuv[0] = newuv[1] = 0.0f;
- }
-
- BKE_image_release_ibuf(newimage, ibuf, NULL);
- }
- else
- newuv[0] = newuv[1] = 0.0f;
-
- /* see if stroke is broken, and if so finish painting in old position */
- if (s->image) {
- imapaint_pick_uv(s->scene, s->ob, s->faceindex, mval, fwuv);
- imapaint_pick_uv(s->scene, s->ob, newfaceindex, prevmval, bkuv);
-
- if (newimage == s->image)
- breakstroke = texpaint_break_stroke(s->uv, fwuv, bkuv, newuv);
- else
- breakstroke = 1;
- }
- else
- fwuv[0] = fwuv[1] = 0.0f;
-
- if (breakstroke) {
- imapaint_pick_uv(s->scene, s->ob, s->faceindex, mval, fwuv);
- redraw |= imapaint_paint_sub_stroke(s, painter, s->image, texpaint,
- fwuv, time, 1, pressure);
- imapaint_clear_partial_redraw();
- BKE_brush_painter_break_stroke(painter);
- }
-
- /* set new canvas */
- if (newimage && (newimage != s->image))
- if (!imapaint_canvas_set(s, newimage))
- newimage = NULL;
-
- /* paint in new image */
- if (newimage) {
- if (breakstroke)
- redraw |= imapaint_paint_sub_stroke(s, painter, newimage,
- texpaint, bkuv, time, 0, pressure);
- redraw |= imapaint_paint_sub_stroke(s, painter, newimage, texpaint,
- newuv, time, 1, pressure);
- }
-
- /* update state */
- s->image = newimage;
- s->faceindex = newfaceindex;
- s->uv[0] = newuv[0];
- s->uv[1] = newuv[1];
- }
- else {
- UI_view2d_region_to_view(s->v2d, mval[0], mval[1], &newuv[0], &newuv[1]);
- redraw |= imapaint_paint_sub_stroke(s, painter, s->image, texpaint, newuv,
- time, 1, pressure);
- }
-
- if (redraw)
- imapaint_clear_partial_redraw();
-
- return redraw;
-}
-
/************************ image paint poll ************************/
static Brush *image_paint_brush(bContext *C)
@@ -4889,16 +346,6 @@ static Brush *image_paint_brush(bContext *C)
return paint_brush(&settings->imapaint.paint);
}
-static Brush *uv_sculpt_brush(bContext *C)
-{
- Scene *scene = CTX_data_scene(C);
- ToolSettings *settings = scene->toolsettings;
-
- if (!settings->uvsculpt)
- return NULL;
- return paint_brush(&settings->uvsculpt->paint);
-}
-
static int image_paint_poll(bContext *C)
{
Object *obact = CTX_data_active_object(C);
@@ -4924,38 +371,6 @@ static int image_paint_poll(bContext *C)
return 0;
}
-static int uv_sculpt_brush_poll(bContext *C)
-{
- BMEditMesh *em;
- int ret;
- Object *obedit = CTX_data_edit_object(C);
- SpaceImage *sima = CTX_wm_space_image(C);
- Scene *scene = CTX_data_scene(C);
- ToolSettings *toolsettings = scene->toolsettings;
-
- if (!uv_sculpt_brush(C) || !obedit || obedit->type != OB_MESH)
- return 0;
-
- em = BMEdit_FromObject(obedit);
- ret = EDBM_mtexpoly_check(em);
-
- if (ret && sima) {
- ARegion *ar = CTX_wm_region(C);
- if ((toolsettings->use_uv_sculpt) && ar->regiontype == RGN_TYPE_WINDOW)
- return 1;
- }
-
- return 0;
-}
-
-static int image_paint_3d_poll(bContext *C)
-{
- if (CTX_wm_region_view3d(C))
- return image_paint_poll(C);
-
- return 0;
-}
-
static int image_paint_2d_clone_poll(bContext *C)
{
Brush *brush = image_paint_brush(C);
@@ -4969,339 +384,173 @@ static int image_paint_2d_clone_poll(bContext *C)
}
/************************ paint operator ************************/
-
-typedef enum PaintMode {
+typedef enum TexPaintMode {
PAINT_MODE_2D,
- PAINT_MODE_3D,
PAINT_MODE_3D_PROJECT
-} PaintMode;
+} TexPaintMode;
typedef struct PaintOperation {
- PaintMode mode;
+ TexPaintMode mode;
- BrushPainter *painter;
- ImagePaintState s;
- ProjPaintState ps;
+ void *custom_paint;
- int first;
int prevmouse[2];
- int orig_brush_size;
double starttime;
ViewContext vc;
wmTimer *timer;
-
- short restore_projection;
} PaintOperation;
-static void paint_redraw(bContext *C, ImagePaintState *s, int texpaint, int final)
+void paint_brush_init_tex(Brush *brush)
{
- if (final) {
- if (s->image && !(texpaint || (s->sima && s->sima->lock)))
- GPU_free_image(s->image);
-
- /* compositor listener deals with updating */
- WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, s->image);
- }
- else {
- if (!s->sima || !s->sima->lock)
- ED_region_tag_redraw(CTX_wm_region(C));
- else
- WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, s->image);
+ /* init mtex nodes */
+ if (brush) {
+ MTex *mtex = &brush->mtex;
+ if (mtex->tex && mtex->tex->nodetree)
+ ntreeTexBeginExecTree(mtex->tex->nodetree, 1); /* has internal flag to detect it only does it once */
}
}
-/* initialize project paint settings from context */
-static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps)
+void paint_brush_exit_tex(Brush *brush)
{
- Scene *scene = CTX_data_scene(C);
- ToolSettings *settings = scene->toolsettings;
-
- /* brush */
- ps->brush = paint_brush(&settings->imapaint.paint);
- if (ps->brush) {
- Brush *brush = ps->brush;
- ps->tool = brush->imagepaint_tool;
- ps->blend = brush->blend;
-
- /* disable for 3d mapping also because painting on mirrored mesh can create "stripes" */
- ps->do_masking = (brush->flag & BRUSH_AIRBRUSH || brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW ||
- brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) ? false : true;
- ps->is_texbrush = (brush->mtex.tex) ? 1 : 0;
- }
- else {
- /* brush may be NULL*/
- ps->do_masking = false;
- ps->is_texbrush = false;
+ if (brush) {
+ MTex *mtex = &brush->mtex;
+ if (mtex->tex && mtex->tex->nodetree)
+ ntreeTexEndExecTree(mtex->tex->nodetree->execdata, 1);
}
+}
- /* sizeof(ProjPixel), since we alloc this a _lot_ */
- ps->pixel_sizeof = project_paint_pixel_sizeof(ps->tool);
- BLI_assert(ps->pixel_sizeof >= sizeof(ProjPixel));
-
- /* these can be NULL */
- ps->v3d = CTX_wm_view3d(C);
- ps->rv3d = CTX_wm_region_view3d(C);
- ps->ar = CTX_wm_region(C);
-
- ps->scene = scene;
- ps->ob = ob; /* allow override of active object */
-
- /* setup projection painting data */
- ps->do_backfacecull = (settings->imapaint.flag & IMAGEPAINT_PROJECT_BACKFACE) ? 0 : 1;
- ps->do_occlude = (settings->imapaint.flag & IMAGEPAINT_PROJECT_XRAY) ? 0 : 1;
- ps->do_mask_normal = (settings->imapaint.flag & IMAGEPAINT_PROJECT_FLAT) ? 0 : 1;
- ps->do_new_shading_nodes = BKE_scene_use_new_shading_nodes(scene); /* only cache the value */
-
- if (ps->tool == PAINT_TOOL_CLONE)
- ps->do_layer_clone = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE);
-
- ps->do_layer_stencil = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL) ? 1 : 0;
- ps->do_layer_stencil_inv = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) ? 1 : 0;
-
-
-#ifndef PROJ_DEBUG_NOSEAMBLEED
- ps->seam_bleed_px = settings->imapaint.seam_bleed; /* pixel num to bleed */
-#endif
- if (ps->do_mask_normal) {
- ps->normal_angle_inner = settings->imapaint.normal_angle;
- ps->normal_angle = (ps->normal_angle_inner + 90.0f) * 0.5f;
+static void paint_redraw(const bContext *C, PaintOperation *pop, int final)
+{
+ if (pop->mode == PAINT_MODE_2D) {
+ paint_2d_redraw(C, pop->custom_paint, final);
}
else {
- ps->normal_angle_inner = ps->normal_angle = settings->imapaint.normal_angle;
- }
-
- ps->normal_angle_inner *= (float)(M_PI_2 / 90);
- ps->normal_angle *= (float)(M_PI_2 / 90);
- ps->normal_angle_range = ps->normal_angle - ps->normal_angle_inner;
-
- if (ps->normal_angle_range <= 0.0f)
- ps->do_mask_normal = FALSE; /* no need to do blending */
-}
-
-static void paint_brush_init_tex(Brush *brush)
-{
- /* init mtex nodes */
- if (brush) {
- MTex *mtex = &brush->mtex;
- if (mtex->tex && mtex->tex->nodetree)
- ntreeTexBeginExecTree(mtex->tex->nodetree, 1); /* has internal flag to detect it only does it once */
+ if (final) {
+ /* compositor listener deals with updating */
+ WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, NULL);
+ }
+ else {
+ ED_region_tag_redraw(CTX_wm_region(C));
+ }
}
-
}
-static int texture_paint_init(bContext *C, wmOperator *op)
+static PaintOperation * texture_paint_init(bContext *C, wmOperator *op, const wmEvent *event)
{
Scene *scene = CTX_data_scene(C);
ToolSettings *settings = scene->toolsettings;
- Brush *brush = paint_brush(&settings->imapaint.paint);
PaintOperation *pop = MEM_callocN(sizeof(PaintOperation), "PaintOperation"); /* caller frees */
+ int mode = RNA_enum_get(op->ptr, "mode");
+ view3d_set_viewcontext(C, &pop->vc);
+
+ /* TODO Should avoid putting this here. Instead, last position should be requested
+ * from stroke system. */
+ pop->prevmouse[0] = event->mval[0];
+ pop->prevmouse[1] = event->mval[1];
- pop->first = 1;
- op->customdata = pop;
/* initialize from context */
if (CTX_wm_region_view3d(C)) {
- pop->mode = PAINT_MODE_3D;
-
- if (!(settings->imapaint.flag & IMAGEPAINT_PROJECT_DISABLE))
- pop->mode = PAINT_MODE_3D_PROJECT;
- else
- view3d_set_viewcontext(C, &pop->vc);
+ pop->mode = PAINT_MODE_3D_PROJECT;
+ pop->custom_paint = paint_proj_new_stroke(C, OBACT, pop->prevmouse, mode);
}
else {
- pop->s.sima = CTX_wm_space_image(C);
- pop->s.v2d = &CTX_wm_region(C)->v2d;
+ pop->mode = PAINT_MODE_2D;
+ pop->custom_paint = paint_2d_new_stroke(C, op);
}
- pop->s.scene = scene;
- pop->s.screen = CTX_wm_screen(C);
-
- pop->s.brush = brush;
- pop->s.tool = brush->imagepaint_tool;
- if (pop->mode == PAINT_MODE_3D && (pop->s.tool == PAINT_TOOL_CLONE))
- pop->s.tool = PAINT_TOOL_DRAW;
- pop->s.blend = brush->blend;
- pop->orig_brush_size = BKE_brush_size_get(scene, brush);
-
- if (pop->mode != PAINT_MODE_2D) {
- Object *ob = OBACT;
- Mesh *me = BKE_mesh_from_object(ob);
-
- if (!me) {
- return 0;
- }
-
- pop->s.ob = ob;
- pop->s.do_facesel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
-
- /* for non prohect paint we need */
- /* fill in derived mesh */
- if (ob->derivedFinal && CustomData_has_layer(&ob->derivedFinal->faceData, CD_MTFACE)) {
- pop->s.dm = ob->derivedFinal;
- pop->s.dm_release = FALSE;
- }
- else {
- pop->s.dm = mesh_get_derived_final(pop->s.scene, ob, pop->s.scene->customdata_mask | CD_MASK_MTFACE);
- pop->s.dm_release = TRUE;
- }
-
- if (!CustomData_has_layer(&pop->s.dm->faceData, CD_MTFACE)) {
-
- if (pop->s.dm_release)
- pop->s.dm->release(pop->s.dm);
-
- pop->s.dm = NULL;
- return 0;
- }
-
- pop->s.dm_mface = pop->s.dm->getTessFaceArray(pop->s.dm);
- pop->s.dm_mtface = pop->s.dm->getTessFaceDataArray(pop->s.dm, CD_MTFACE);
- pop->s.dm_totface = pop->s.dm->getNumTessFaces(pop->s.dm);
- }
- else {
- pop->s.image = pop->s.sima->image;
-
- if (!imapaint_canvas_set(&pop->s, pop->s.image)) {
- if (pop->s.warnmultifile)
- BKE_report(op->reports, RPT_WARNING, "Image requires 4 color channels to paint");
- if (pop->s.warnpackedfile)
- BKE_report(op->reports, RPT_WARNING, "Packed MultiLayer files cannot be painted");
-
- return 0;
- }
+ if (!pop->custom_paint) {
+ MEM_freeN(pop);
+ return NULL;
}
- /* note, if we have no UVs on the derived mesh, then we must return here */
- if (pop->mode == PAINT_MODE_3D_PROJECT) {
-
- /* initialize all data from the context */
- project_state_init(C, OBACT, &pop->ps);
-
- /* needed so multiple threads don't try to initialize the brush at once (can leak memory) */
- curvemapping_initialize(pop->ps.brush->curve);
-
- paint_brush_init_tex(pop->ps.brush);
-
- pop->ps.source = PROJ_SRC_VIEW;
-
- if (pop->ps.ob == NULL || !(pop->ps.ob->lay & pop->ps.v3d->lay))
- return 0;
-
- /* Don't allow brush size below 2 */
- if (BKE_brush_size_get(scene, brush) < 2)
- BKE_brush_size_set(scene, brush, 2);
-
- /* allocate and initialize spatial data structures */
- project_paint_begin(&pop->ps);
-
- if (pop->ps.dm == NULL)
- return 0;
- }
- else {
- paint_brush_init_tex(pop->s.brush);
- }
-
settings->imapaint.flag |= IMAGEPAINT_DRAWING;
undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name,
image_undo_restore, image_undo_free);
- /* create painter */
- pop->painter = BKE_brush_painter_new(scene, pop->s.brush);
-
{
UnifiedPaintSettings *ups = &settings->unified_paint_settings;
ups->draw_pressure = true;
}
- return 1;
+ return pop;
}
-static void paint_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
+static void paint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
{
- PaintOperation *pop = op->customdata;
- float time, mousef[2];
+ PaintOperation *pop = paint_stroke_mode_data(stroke);
+ Scene *scene = CTX_data_scene(C);
+ Brush *brush = paint_brush(&scene->toolsettings->imapaint.paint);
+
+ /* initial brush values. Maybe it should be considered moving these to stroke system */
+ float startsize = BKE_brush_size_get(scene, brush);
+ float startalpha = BKE_brush_alpha_get(scene, brush);
+
+ float mousef[2];
float pressure;
- int mouse[2], redraw;
+ int mouse[2], redraw, eraser;
RNA_float_get_array(itemptr, "mouse", mousef);
mouse[0] = (int)(mousef[0]);
mouse[1] = (int)(mousef[1]);
- time = RNA_float_get(itemptr, "time");
pressure = RNA_float_get(itemptr, "pressure");
+ eraser = RNA_boolean_get(itemptr, "pen_flip");
- if (pop->first)
- project_paint_begin_clone(&pop->ps, mouse);
-
- if (pop->mode == PAINT_MODE_3D)
- view3d_operator_needs_opengl(C);
+ if (BKE_brush_use_alpha_pressure(scene, brush))
+ BKE_brush_alpha_set(scene, brush, max_ff(0.0f, startalpha * pressure));
+ if (BKE_brush_use_size_pressure(scene, brush))
+ BKE_brush_size_set(scene, brush, max_ff(1.0f, startsize * pressure));
if (pop->mode == PAINT_MODE_3D_PROJECT) {
- redraw = project_paint_stroke(&pop->ps, pop->painter, pop->prevmouse, mouse, time, pressure);
- pop->prevmouse[0] = mouse[0];
- pop->prevmouse[1] = mouse[1];
-
+ redraw = paint_proj_stroke(C, pop->custom_paint, pop->prevmouse, mouse);
}
else {
- redraw = imapaint_paint_stroke(&pop->vc, &pop->s, pop->painter, pop->mode == PAINT_MODE_3D, pop->prevmouse, mouse, time, pressure);
- pop->prevmouse[0] = mouse[0];
- pop->prevmouse[1] = mouse[1];
+ redraw = paint_2d_stroke(pop->custom_paint, pop->prevmouse, mouse, eraser);
}
- if (redraw)
- paint_redraw(C, &pop->s, pop->mode == PAINT_MODE_3D, 0);
+ pop->prevmouse[0] = mouse[0];
+ pop->prevmouse[1] = mouse[1];
- pop->first = 0;
-}
+ /* restore brush values */
+ BKE_brush_alpha_set(scene, brush, startalpha);
+ BKE_brush_size_set(scene, brush, startsize);
+
+
+ if (redraw)
+ paint_redraw(C, pop, 0);
-static void paint_brush_exit_tex(Brush *brush)
-{
- if (brush) {
- MTex *mtex = &brush->mtex;
- if (mtex->tex && mtex->tex->nodetree)
- ntreeTexEndExecTree(mtex->tex->nodetree->execdata, 1);
- }
}
-static void paint_exit(bContext *C, wmOperator *op)
+static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke)
{
Scene *scene = CTX_data_scene(C);
ToolSettings *settings = scene->toolsettings;
- PaintOperation *pop = op->customdata;
+ PaintOperation *pop = paint_stroke_mode_data(stroke);
+
+ paint_redraw(C, pop, 1);
if (pop->timer)
WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), pop->timer);
- if (pop->restore_projection)
- settings->imapaint.flag &= ~IMAGEPAINT_PROJECT_DISABLE;
-
settings->imapaint.flag &= ~IMAGEPAINT_DRAWING;
- imapaint_canvas_free(&pop->s);
- BKE_brush_painter_free(pop->painter);
if (pop->mode == PAINT_MODE_3D_PROJECT) {
- BKE_brush_size_set(scene, pop->ps.brush, pop->orig_brush_size);
- paint_brush_exit_tex(pop->ps.brush);
-
- project_paint_end(&pop->ps);
+ paint_proj_stroke_done(pop->custom_paint);
}
else {
- paint_brush_exit_tex(pop->s.brush);
-
- /* non projection 3d paint, could move into own function of more needs adding */
- if (pop->s.dm_release)
- pop->s.dm->release(pop->s.dm);
+ paint_2d_stroke_done(pop->custom_paint);
}
-
- paint_redraw(C, &pop->s, pop->mode == PAINT_MODE_3D, 1);
+
undo_paint_push_end(UNDO_PAINT_IMAGE);
-
+
+ /* duplicate warning, see texpaint_init
if (pop->s.warnmultifile)
BKE_reportf(op->reports, RPT_WARNING, "Image requires 4 color channels to paint: %s", pop->s.warnmultifile);
if (pop->s.warnpackedfile)
BKE_reportf(op->reports, RPT_WARNING, "Packed MultiLayer files cannot be painted: %s", pop->s.warnpackedfile);
-
+ */
MEM_freeN(pop);
{
@@ -5310,159 +559,69 @@ static void paint_exit(bContext *C, wmOperator *op)
}
}
-static int paint_exec(bContext *C, wmOperator *op)
+static int paint_stroke_test_start(bContext *UNUSED(C), wmOperator *UNUSED(op), const float UNUSED(mouse[2]))
{
- if (!texture_paint_init(C, op)) {
- MEM_freeN(op->customdata);
- return OPERATOR_CANCELLED;
- }
-
- RNA_BEGIN (op->ptr, itemptr, "stroke")
- {
- paint_apply(C, op, &itemptr);
- }
- RNA_END;
-
- paint_exit(C, op);
-
- return OPERATOR_FINISHED;
+ return true;
}
-static void paint_apply_event(bContext *C, wmOperator *op, wmEvent *event)
-{
- const Scene *scene = CTX_data_scene(C);
- PaintOperation *pop = op->customdata;
- PointerRNA itemptr;
- float pressure, mousef[2];
- double time;
- int tablet;
-
- time = PIL_check_seconds_timer();
-
- tablet = 0;
- pop->s.blend = pop->s.brush->blend;
-
- if (event->tablet_data) {
- wmTabletData *wmtab = event->tablet_data;
-
- tablet = (wmtab->Active != EVT_TABLET_NONE);
- pressure = wmtab->Pressure;
- if (wmtab->Active == EVT_TABLET_ERASER)
- pop->s.blend = IMB_BLEND_ERASE_ALPHA;
- }
- else {
- BLI_assert(fabsf(WM_cursor_pressure(CTX_wm_window(C))) == 1.0f);
- pressure = 1.0f;
- }
-
- if (pop->first) {
- pop->prevmouse[0] = event->mval[0];
- pop->prevmouse[1] = event->mval[1];
- pop->starttime = time;
-
- /* special exception here for too high pressure values on first touch in
- * windows for some tablets, then we just skip first touch .. */
- if (tablet && (pressure >= 0.99f) && ((pop->s.brush->flag & BRUSH_SPACING_PRESSURE) || BKE_brush_use_alpha_pressure(scene, pop->s.brush) || BKE_brush_use_size_pressure(scene, pop->s.brush)))
- return;
-
- /* This can be removed once fixed properly in
- * BKE_brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, double time, float pressure, void *user)
- * at zero pressure we should do nothing 1/2^12 is 0.0002 which is the sensitivity of the most sensitive pen tablet available */
- if (tablet && (pressure < 0.0002f) && ((pop->s.brush->flag & BRUSH_SPACING_PRESSURE) || BKE_brush_use_alpha_pressure(scene, pop->s.brush) || BKE_brush_use_size_pressure(scene, pop->s.brush)))
- return;
-
- }
-
- /* fill in stroke */
- RNA_collection_add(op->ptr, "stroke", &itemptr);
-
- mousef[0] = (float)(event->mval[0]);
- mousef[1] = (float)(event->mval[1]);
- RNA_float_set_array(&itemptr, "mouse", mousef);
- RNA_float_set(&itemptr, "time", (float)(time - pop->starttime));
- RNA_float_set(&itemptr, "pressure", pressure);
-
- /* apply */
- paint_apply(C, op, &itemptr);
-
- {
- UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
- ups->pressure_value = pressure;
- }
-}
-static int paint_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int paint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
PaintOperation *pop;
+ struct PaintStroke *stroke;
+ int retval;
- if (!texture_paint_init(C, op)) {
- MEM_freeN(op->customdata);
+ if (!(pop = texture_paint_init(C, op, event))) {
return OPERATOR_CANCELLED;
}
- paint_apply_event(C, op, event);
-
- pop = op->customdata;
+ stroke = op->customdata = paint_stroke_new(C, NULL, paint_stroke_test_start,
+ paint_stroke_update_step,
+ paint_stroke_done, event->type);
+ paint_stroke_set_mode_data(stroke, pop);
+ /* add modal handler */
WM_event_add_modal_handler(C, op);
- if (pop->s.brush->flag & BRUSH_AIRBRUSH)
- pop->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
+ retval = op->type->modal(C, op, event);
+ OPERATOR_RETVAL_CHECK(retval);
+ BLI_assert(retval == OPERATOR_RUNNING_MODAL);
return OPERATOR_RUNNING_MODAL;
}
-static int paint_modal(bContext *C, wmOperator *op, wmEvent *event)
-{
- PaintOperation *pop = op->customdata;
-
- switch (event->type) {
- case LEFTMOUSE:
- case MIDDLEMOUSE:
- case RIGHTMOUSE: // XXX hardcoded
- paint_exit(C, op);
- return OPERATOR_FINISHED;
- case MOUSEMOVE:
- case INBETWEEN_MOUSEMOVE:
- paint_apply_event(C, op, event);
- break;
- case TIMER:
- if (event->customdata == pop->timer)
- paint_apply_event(C, op, event);
- break;
- }
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-static int paint_cancel(bContext *C, wmOperator *op)
-{
- paint_exit(C, op);
-
- return OPERATOR_CANCELLED;
-}
void PAINT_OT_image_paint(wmOperatorType *ot)
{
+ static EnumPropertyItem stroke_mode_items[] = {
+ {BRUSH_STROKE_NORMAL, "NORMAL", 0, "Normal", "Apply brush normally"},
+ {BRUSH_STROKE_INVERT, "INVERT", 0, "Invert", "Invert action of brush for duration of stroke"},
+ {0}
+ };
+
/* identifiers */
ot->name = "Image Paint";
ot->idname = "PAINT_OT_image_paint";
ot->description = "Paint a stroke into the image";
-
+
/* api callbacks */
- ot->exec = paint_exec;
ot->invoke = paint_invoke;
- ot->modal = paint_modal;
- ot->cancel = paint_cancel;
+ ot->modal = paint_stroke_modal;
+ /* ot->exec = paint_exec; <-- needs stroke property */
ot->poll = image_paint_poll;
+ ot->cancel = paint_stroke_cancel;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_BLOCKING;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ RNA_def_enum(ot->srna, "mode", stroke_mode_items, BRUSH_STROKE_NORMAL,
+ "Paint Stroke Mode",
+ "Action taken when a paint stroke is made");
- /* properties */
RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
}
-static int get_imapaint_zoom(bContext *C, float *zoomx, float *zoomy)
+
+int get_imapaint_zoom(bContext *C, float *zoomx, float *zoomy)
{
RegionView3D *rv3d = CTX_wm_region_view3d(C);
@@ -5484,7 +643,7 @@ static int get_imapaint_zoom(bContext *C, float *zoomx, float *zoomy)
/************************ cursor drawing *******************************/
-static void brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customdata))
+void brush_drawcursor_texpaint_uvsculpt(bContext *C, int x, int y, void *UNUSED(customdata))
{
#define PX_SIZE_FADE_MAX 12.0f
#define PX_SIZE_FADE_MIN 4.0f
@@ -5560,7 +719,8 @@ static void toggle_paint_cursor(bContext *C, int enable)
settings->imapaint.paintcursor = NULL;
}
else if (enable)
- settings->imapaint.paintcursor = WM_paint_cursor_activate(wm, image_paint_poll, brush_drawcursor, NULL);
+ settings->imapaint.paintcursor =
+ WM_paint_cursor_activate(wm, image_paint_poll, brush_drawcursor_texpaint_uvsculpt, NULL);
}
/* enable the paint cursor if it isn't already.
@@ -5587,32 +747,11 @@ void ED_space_image_paint_update(wmWindowManager *wm, ToolSettings *settings)
if (!imapaint->paintcursor) {
imapaint->paintcursor =
WM_paint_cursor_activate(wm, image_paint_poll,
- brush_drawcursor, NULL);
+ brush_drawcursor_texpaint_uvsculpt, NULL);
}
}
}
-
-void ED_space_image_uv_sculpt_update(wmWindowManager *wm, ToolSettings *settings)
-{
- if (settings->use_uv_sculpt) {
- if (!settings->uvsculpt) {
- settings->uvsculpt = MEM_callocN(sizeof(*settings->uvsculpt), "UV Smooth paint");
- settings->uv_sculpt_tool = UV_SCULPT_TOOL_GRAB;
- settings->uv_sculpt_settings = UV_SCULPT_LOCK_BORDERS | UV_SCULPT_ALL_ISLANDS;
- settings->uv_relax_method = UV_SCULPT_TOOL_RELAX_LAPLACIAN;
- }
-
- BKE_paint_init(&settings->uvsculpt->paint, PAINT_CURSOR_SCULPT);
-
- WM_paint_cursor_activate(wm, uv_sculpt_brush_poll,
- brush_drawcursor, NULL);
- }
- else {
- if (settings->uvsculpt)
- settings->uvsculpt->paint.flags &= ~PAINT_SHOW_BRUSH;
- }
-}
/************************ grab clone operator ************************/
typedef struct GrabClone {
@@ -5637,7 +776,7 @@ static int grab_clone_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int grab_clone_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int grab_clone_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Brush *brush = image_paint_brush(C);
GrabClone *cmv;
@@ -5653,7 +792,7 @@ static int grab_clone_invoke(bContext *C, wmOperator *op, wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
-static int grab_clone_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int grab_clone_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
Brush *brush = image_paint_brush(C);
ARegion *ar = CTX_wm_region(C);
@@ -5728,7 +867,7 @@ static int sample_color_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int sample_color_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
RNA_int_set_array(op->ptr, "location", event->mval);
sample_color_exec(C, op);
@@ -5738,7 +877,7 @@ static int sample_color_invoke(bContext *C, wmOperator *op, wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
-static int sample_color_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int sample_color_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
switch (event->type) {
case LEFTMOUSE:
@@ -5793,57 +932,6 @@ void PAINT_OT_sample_color(wmOperatorType *ot)
RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location", "Cursor location in region coordinates", 0, 16384);
}
-/******************** set clone cursor operator ********************/
-
-static int set_clone_cursor_exec(bContext *C, wmOperator *op)
-{
- Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
- float *cursor = give_cursor(scene, v3d);
-
- RNA_float_get_array(op->ptr, "location", cursor);
-
- ED_area_tag_redraw(CTX_wm_area(C));
-
- return OPERATOR_FINISHED;
-}
-
-static int set_clone_cursor_invoke(bContext *C, wmOperator *op, wmEvent *event)
-{
- Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
- ARegion *ar = CTX_wm_region(C);
- float location[3];
-
- view3d_operator_needs_opengl(C);
-
- if (!ED_view3d_autodist(scene, ar, v3d, event->mval, location))
- return OPERATOR_CANCELLED;
-
- RNA_float_set_array(op->ptr, "location", location);
-
- return set_clone_cursor_exec(C, op);
-}
-
-void PAINT_OT_clone_cursor_set(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Set Clone Cursor";
- ot->idname = "PAINT_OT_clone_cursor_set";
- ot->description = "Set the location of the clone cursor";
-
- /* api callbacks */
- ot->exec = set_clone_cursor_exec;
- ot->invoke = set_clone_cursor_invoke;
- ot->poll = image_paint_3d_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_float_vector(ot->srna, "location", 3, NULL, -FLT_MAX, FLT_MAX, "Location", "Cursor location in world space coordinates", -10000.0f, 10000.0f);
-}
-
/******************** texture paint toggle operator ********************/
static int texture_paint_toggle_poll(bContext *C)
@@ -5937,11 +1025,6 @@ int image_texture_paint_poll(bContext *C)
return (texture_paint_poll(C) || image_paint_poll(C));
}
-int uv_sculpt_poll(bContext *C)
-{
- return uv_sculpt_brush_poll(C);
-}
-
int facemask_paint_poll(bContext *C)
{
return paint_facesel_test(CTX_data_active_object(C));
@@ -5956,201 +1039,4 @@ int mask_paint_poll(bContext *C)
{
return paint_facesel_test(CTX_data_active_object(C)) || paint_vertsel_test(CTX_data_active_object(C));
}
-/* use project paint to re-apply an image */
-static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
-{
- Image *image = BLI_findlink(&CTX_data_main(C)->image, RNA_enum_get(op->ptr, "image"));
- Scene *scene = CTX_data_scene(C);
- ProjPaintState ps = {NULL};
- int orig_brush_size;
- IDProperty *idgroup;
- IDProperty *view_data = NULL;
-
- project_state_init(C, OBACT, &ps);
-
- if (ps.ob == NULL || ps.ob->type != OB_MESH) {
- BKE_report(op->reports, RPT_ERROR, "No active mesh object");
- return OPERATOR_CANCELLED;
- }
-
- if (image == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Image could not be found");
- return OPERATOR_CANCELLED;
- }
-
- ps.reproject_image = image;
- ps.reproject_ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
-
- if (ps.reproject_ibuf == NULL || ps.reproject_ibuf->rect == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Image data could not be found");
- return OPERATOR_CANCELLED;
- }
-
- idgroup = IDP_GetProperties(&image->id, 0);
-
- if (idgroup) {
- view_data = IDP_GetPropertyTypeFromGroup(idgroup, PROJ_VIEW_DATA_ID, IDP_ARRAY);
-
- /* type check to make sure its ok */
- if (view_data->len != PROJ_VIEW_DATA_SIZE || view_data->subtype != IDP_FLOAT) {
- BKE_report(op->reports, RPT_ERROR, "Image project data invalid");
- return OPERATOR_CANCELLED;
- }
- }
-
- if (view_data) {
- /* image has stored view projection info */
- ps.source = PROJ_SRC_IMAGE_VIEW;
- }
- else {
- ps.source = PROJ_SRC_IMAGE_CAM;
-
- if (scene->camera == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No active camera set");
- return OPERATOR_CANCELLED;
- }
- }
-
- /* override */
- ps.is_texbrush = 0;
- ps.do_masking = false;
- orig_brush_size = BKE_brush_size_get(scene, ps.brush);
- BKE_brush_size_set(scene, ps.brush, 32); /* cover the whole image */
-
- ps.tool = PAINT_TOOL_DRAW; /* so pixels are initialized with minimal info */
-
- scene->toolsettings->imapaint.flag |= IMAGEPAINT_DRAWING;
-
- undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name,
- image_undo_restore, image_undo_free);
-
- /* allocate and initialize spatial data structures */
- project_paint_begin(&ps);
-
- if (ps.dm == NULL) {
- BKE_brush_size_set(scene, ps.brush, orig_brush_size);
- return OPERATOR_CANCELLED;
- }
- else {
- float pos[2] = {0.0, 0.0};
- float lastpos[2] = {0.0, 0.0};
- int a;
-
- for (a = 0; a < ps.image_tot; a++)
- partial_redraw_array_init(ps.projImages[a].partRedrawRect);
-
- project_paint_op(&ps, NULL, lastpos, pos);
-
- project_image_refresh_tagged(&ps);
-
- for (a = 0; a < ps.image_tot; a++) {
- GPU_free_image(ps.projImages[a].ima);
- WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ps.projImages[a].ima);
- }
- }
-
- project_paint_end(&ps);
-
- scene->toolsettings->imapaint.flag &= ~IMAGEPAINT_DRAWING;
- BKE_brush_size_set(scene, ps.brush, orig_brush_size);
-
- return OPERATOR_FINISHED;
-}
-
-void PAINT_OT_project_image(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Project Image";
- ot->idname = "PAINT_OT_project_image";
- ot->description = "Project an edited render from the active camera back onto the object";
-
- /* api callbacks */
- ot->invoke = WM_enum_search_invoke;
- ot->exec = texture_paint_camera_project_exec;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- prop = RNA_def_enum(ot->srna, "image", DummyRNA_NULL_items, 0, "Image", "");
- RNA_def_enum_funcs(prop, RNA_image_itemf);
- ot->prop = prop;
-}
-
-static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
-{
- Image *image;
- ImBuf *ibuf;
- char filename[FILE_MAX];
-
- Scene *scene = CTX_data_scene(C);
- ToolSettings *settings = scene->toolsettings;
- int w = settings->imapaint.screen_grab_size[0];
- int h = settings->imapaint.screen_grab_size[1];
- int maxsize;
- char err_out[256] = "unknown";
-
- RNA_string_get(op->ptr, "filepath", filename);
-
- glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize);
- if (w > maxsize) w = maxsize;
- if (h > maxsize) h = maxsize;
-
- ibuf = ED_view3d_draw_offscreen_imbuf(CTX_data_scene(C), CTX_wm_view3d(C), CTX_wm_region(C), w, h, IB_rect, FALSE, R_ALPHAPREMUL, err_out);
- if (!ibuf) {
- /* Mostly happens when OpenGL offscreen buffer was failed to create, */
- /* but could be other reasons. Should be handled in the future. nazgul */
- BKE_reportf(op->reports, RPT_ERROR, "Failed to create OpenGL off-screen buffer: %s", err_out);
- return OPERATOR_CANCELLED;
- }
-
- image = BKE_image_add_from_imbuf(ibuf);
-
- if (image) {
- /* now for the trickyness. store the view projection here!
- * re-projection will reuse this */
- View3D *v3d = CTX_wm_view3d(C);
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
-
- IDPropertyTemplate val;
- IDProperty *idgroup = IDP_GetProperties(&image->id, 1);
- IDProperty *view_data;
- int orth;
- float *array;
-
- val.array.len = PROJ_VIEW_DATA_SIZE;
- val.array.type = IDP_FLOAT;
- view_data = IDP_New(IDP_ARRAY, &val, PROJ_VIEW_DATA_ID);
-
- array = (float *)IDP_Array(view_data);
- memcpy(array, rv3d->winmat, sizeof(rv3d->winmat)); array += sizeof(rv3d->winmat) / sizeof(float);
- memcpy(array, rv3d->viewmat, sizeof(rv3d->viewmat)); array += sizeof(rv3d->viewmat) / sizeof(float);
- orth = project_paint_view_clip(v3d, rv3d, &array[0], &array[1]);
- array[2] = orth ? 1.0f : 0.0f; /* using float for a bool is dodgy but since its an extra member in the array... easier then adding a single bool prop */
-
- IDP_AddToGroup(idgroup, view_data);
-
- rename_id(&image->id, "image_view");
- }
-
- return OPERATOR_FINISHED;
-}
-
-void PAINT_OT_image_from_view(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Image from View";
- ot->idname = "PAINT_OT_image_from_view";
- ot->description = "Make an image from the current 3D view for re-projection";
-
- /* api callbacks */
- ot->exec = texture_paint_image_from_view_exec;
- ot->poll = ED_operator_region_view3d_active;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER;
-
- RNA_def_string_file_name(ot->srna, "filepath", "", FILE_MAX, "File Path", "Name of the file");
-}
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index 84250853f38..ed1b25d1b4e 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -35,17 +35,56 @@
#include "DNA_brush_types.h"
#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+#include "DNA_object_types.h"
+#include "BLI_math.h"
+
+#include "BKE_context.h"
#include "BKE_brush.h"
+#include "BKE_main.h"
+#include "BKE_image.h"
+#include "BKE_paint.h"
+#include "BKE_report.h"
-#include "BLI_math.h"
+#include "ED_screen.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
+#include "IMB_colormanagement.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "UI_view2d.h"
#include "RE_shader_ext.h"
- /* Brush Painting for 2D image editor */
+#include "GPU_draw.h"
+
+#include "paint_intern.h"
+
+/* Brush Painting for 2D image editor */
+
+/* Defines and Structs */
+/* FTOCHAR as inline function */
+BLI_INLINE unsigned char f_to_char(const float val)
+{
+ return FTOCHAR(val);
+}
+#define IMAPAINT_FLOAT_RGB_TO_CHAR(c, f) { \
+ (c)[0] = f_to_char((f)[0]); \
+ (c)[1] = f_to_char((f)[1]); \
+ (c)[2] = f_to_char((f)[2]); \
+} (void)0
+
+#define IMAPAINT_CHAR_RGB_TO_FLOAT(f, c) { \
+ (f)[0] = IMAPAINT_CHAR_TO_FLOAT((c)[0]); \
+ (f)[1] = IMAPAINT_CHAR_TO_FLOAT((c)[1]); \
+ (f)[2] = IMAPAINT_CHAR_TO_FLOAT((c)[2]); \
+} (void)0
+
+#define IMAPAINT_FLOAT_RGB_COPY(a, b) copy_v3_v3(a, b)
typedef struct BrushPainterCache {
short enabled;
@@ -57,38 +96,55 @@ typedef struct BrushPainterCache {
int lastsize;
float lastalpha;
float lastjitter;
+ float last_rotation;
ImBuf *ibuf;
ImBuf *texibuf;
ImBuf *maskibuf;
} BrushPainterCache;
-struct BrushPainter {
+typedef struct BrushPainter {
Scene *scene;
Brush *brush;
- float lastmousepos[2]; /* mouse position of last paint call */
-
- float accumdistance; /* accumulated distance of brush since last paint op */
float lastpaintpos[2]; /* position of last paint op */
float startpaintpos[2]; /* position of first paint */
- double accumtime; /* accumulated time since last paint op (airbrush) */
- double lasttime; /* time of last update */
-
- float lastpressure;
-
short firsttouch; /* first paint op */
- float startsize;
- float startalpha;
- float startjitter;
- float startspacing;
-
BrushPainterCache cache;
-};
+} BrushPainter;
+
+typedef struct ImagePaintRegion {
+ int destx, desty;
+ int srcx, srcy;
+ int width, height;
+} ImagePaintRegion;
+
+typedef struct ImagePaintState {
+ BrushPainter *painter;
+ SpaceImage *sima;
+ View2D *v2d;
+ Scene *scene;
+ bScreen *screen;
-BrushPainter *BKE_brush_painter_new(Scene *scene, Brush *brush)
+ Brush *brush;
+ short tool, blend;
+ Image *image;
+ ImBuf *canvas;
+ ImBuf *clonecanvas;
+ char *warnpackedfile;
+ char *warnmultifile;
+
+ /* viewport texture paint only, but _not_ project paint */
+ Object *ob;
+ int faceindex;
+ float uv[2];
+ int do_facesel;
+} ImagePaintState;
+
+
+static BrushPainter *brush_painter_2d_new(Scene *scene, Brush *brush)
{
BrushPainter *painter = MEM_callocN(sizeof(BrushPainter), "BrushPainter");
@@ -97,29 +153,11 @@ BrushPainter *BKE_brush_painter_new(Scene *scene, Brush *brush)
painter->firsttouch = 1;
painter->cache.lastsize = -1; /* force ibuf create in refresh */
- painter->startsize = BKE_brush_size_get(scene, brush);
- painter->startalpha = BKE_brush_alpha_get(scene, brush);
- painter->startjitter = brush->jitter;
- painter->startspacing = brush->spacing;
-
return painter;
}
-static void brush_pressure_apply(BrushPainter *painter, Brush *brush, float pressure)
-{
- if (BKE_brush_use_alpha_pressure(painter->scene, brush))
- BKE_brush_alpha_set(painter->scene, brush, max_ff(0.0f, painter->startalpha * pressure));
- if (BKE_brush_use_size_pressure(painter->scene, brush))
- BKE_brush_size_set(painter->scene, brush, max_ff(1.0f, painter->startsize * pressure));
- if (brush->flag & BRUSH_JITTER_PRESSURE)
- brush->jitter = max_ff(0.0f, painter->startjitter * pressure);
- if (brush->flag & BRUSH_SPACING_PRESSURE)
- brush->spacing = max_ff(1.0f, painter->startspacing * (1.5f - pressure));
-}
-
-
-void BKE_brush_painter_require_imbuf(BrushPainter *painter, short flt, short texonly, int size)
+static void brush_painter_2d_require_imbuf(BrushPainter *painter, short flt, short texonly, int size)
{
if ((painter->cache.flt != flt) || (painter->cache.size != size) ||
((painter->cache.texonly != texonly) && texonly))
@@ -142,22 +180,15 @@ void BKE_brush_painter_require_imbuf(BrushPainter *painter, short flt, short tex
painter->cache.enabled = 1;
}
-void BKE_brush_painter_free(BrushPainter *painter)
+static void brush_painter_2d_free(BrushPainter *painter)
{
- Brush *brush = painter->brush;
-
- BKE_brush_size_set(painter->scene, brush, painter->startsize);
- BKE_brush_alpha_set(painter->scene, brush, painter->startalpha);
- brush->jitter = painter->startjitter;
- brush->spacing = painter->startspacing;
-
if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf);
if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf);
if (painter->cache.maskibuf) IMB_freeImBuf(painter->cache.maskibuf);
MEM_freeN(painter);
}
-static void brush_painter_do_partial(BrushPainter *painter, ImBuf *oldtexibuf,
+static void brush_painter_2d_do_partial(BrushPainter *painter, ImBuf *oldtexibuf,
int x, int y, int w, int h, int xt, int yt,
const float pos[2])
{
@@ -204,7 +235,7 @@ static void brush_painter_do_partial(BrushPainter *painter, ImBuf *oldtexibuf,
xy[0] = x + xoff;
xy[1] = y + yoff;
- BKE_brush_sample_tex_2D(scene, brush, xy, tf, 0);
+ BKE_brush_sample_tex_2D(scene, brush, xy, tf, NULL);
}
bf[0] = tf[0] * mf[0];
@@ -235,7 +266,7 @@ static void brush_painter_do_partial(BrushPainter *painter, ImBuf *oldtexibuf,
xy[0] = x + xoff;
xy[1] = y + yoff;
- BKE_brush_sample_tex_2D(scene, brush, xy, rgba, 0);
+ BKE_brush_sample_tex_2D(scene, brush, xy, rgba, NULL);
rgba_float_to_uchar(t, rgba);
}
@@ -248,7 +279,7 @@ static void brush_painter_do_partial(BrushPainter *painter, ImBuf *oldtexibuf,
}
}
-static void brush_painter_tiled_tex_partial_update(BrushPainter *painter, const float pos[2])
+static void brush_painter_2d_tiled_tex_partial_update(BrushPainter *painter, const float pos[2])
{
const Scene *scene = painter->scene;
Brush *brush = painter->brush;
@@ -286,25 +317,26 @@ static void brush_painter_tiled_tex_partial_update(BrushPainter *painter, const
/* blend existing texture in new position */
if ((x1 < x2) && (y1 < y2))
- brush_painter_do_partial(painter, oldtexibuf, x1, y1, x2, y2, srcx, srcy, pos);
+ brush_painter_2d_do_partial(painter, oldtexibuf, x1, y1, x2, y2, srcx, srcy, pos);
if (oldtexibuf)
IMB_freeImBuf(oldtexibuf);
/* sample texture in new areas */
if ((0 < x1) && (0 < ibuf->y))
- brush_painter_do_partial(painter, NULL, 0, 0, x1, ibuf->y, 0, 0, pos);
+ brush_painter_2d_do_partial(painter, NULL, 0, 0, x1, ibuf->y, 0, 0, pos);
if ((x2 < ibuf->x) && (0 < ibuf->y))
- brush_painter_do_partial(painter, NULL, x2, 0, ibuf->x, ibuf->y, 0, 0, pos);
+ brush_painter_2d_do_partial(painter, NULL, x2, 0, ibuf->x, ibuf->y, 0, 0, pos);
if ((x1 < x2) && (0 < y1))
- brush_painter_do_partial(painter, NULL, x1, 0, x2, y1, 0, 0, pos);
+ brush_painter_2d_do_partial(painter, NULL, x1, 0, x2, y1, 0, 0, pos);
if ((x1 < x2) && (y2 < ibuf->y))
- brush_painter_do_partial(painter, NULL, x1, y2, x2, ibuf->y, 0, 0, pos);
+ brush_painter_2d_do_partial(painter, NULL, x1, y2, x2, ibuf->y, 0, 0, pos);
}
-static void brush_painter_refresh_cache(BrushPainter *painter, const float pos[2], int use_color_correction)
+static void brush_painter_2d_refresh_cache(BrushPainter *painter, const float pos[2], int use_color_correction)
{
const Scene *scene = painter->scene;
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
Brush *brush = painter->brush;
BrushPainterCache *cache = &painter->cache;
MTex *mtex = &brush->mtex;
@@ -313,10 +345,16 @@ static void brush_painter_refresh_cache(BrushPainter *painter, const float pos[2
const int diameter = 2 * BKE_brush_size_get(scene, brush);
const float alpha = BKE_brush_alpha_get(scene, brush);
const bool do_tiled = ELEM(brush->mtex.brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_3D);
+ float rotation = -mtex->rot;
+
+ if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
+ rotation += ups->brush_rotation;
+ }
if (diameter != cache->lastsize ||
alpha != cache->lastalpha ||
- brush->jitter != cache->lastjitter)
+ brush->jitter != cache->lastjitter ||
+ rotation != cache->last_rotation)
{
if (cache->ibuf) {
IMB_freeImBuf(cache->ibuf);
@@ -332,7 +370,7 @@ static void brush_painter_refresh_cache(BrushPainter *painter, const float pos[2
if (do_tiled) {
BKE_brush_imbuf_new(scene, brush, flt, 3, size, &cache->maskibuf, use_color_correction);
- brush_painter_tiled_tex_partial_update(painter, pos);
+ brush_painter_2d_tiled_tex_partial_update(painter, pos);
}
else
BKE_brush_imbuf_new(scene, brush, flt, 2, size, &cache->ibuf, use_color_correction);
@@ -340,221 +378,447 @@ static void brush_painter_refresh_cache(BrushPainter *painter, const float pos[2
cache->lastsize = diameter;
cache->lastalpha = alpha;
cache->lastjitter = brush->jitter;
+ cache->last_rotation = rotation;
}
else if (do_tiled && mtex && mtex->tex) {
int dx = (int)painter->lastpaintpos[0] - (int)pos[0];
int dy = (int)painter->lastpaintpos[1] - (int)pos[1];
if ((dx != 0) || (dy != 0))
- brush_painter_tiled_tex_partial_update(painter, pos);
+ brush_painter_2d_tiled_tex_partial_update(painter, pos);
}
}
-void BKE_brush_painter_break_stroke(BrushPainter *painter)
+/* keep these functions in sync */
+static void paint_2d_ibuf_rgb_get(ImBuf *ibuf, int x, int y, const short is_torus, float r_rgb[3])
{
- painter->firsttouch = 1;
+ if (is_torus) {
+ x %= ibuf->x;
+ if (x < 0) x += ibuf->x;
+ y %= ibuf->y;
+ if (y < 0) y += ibuf->y;
+ }
+
+ if (ibuf->rect_float) {
+ float *rrgbf = ibuf->rect_float + (ibuf->x * y + x) * 4;
+ IMAPAINT_FLOAT_RGB_COPY(r_rgb, rrgbf);
+ }
+ else {
+ char *rrgb = (char *)ibuf->rect + (ibuf->x * y + x) * 4;
+ IMAPAINT_CHAR_RGB_TO_FLOAT(r_rgb, rrgb);
+ }
}
+static void paint_2d_ibuf_rgb_set(ImBuf *ibuf, int x, int y, const short is_torus, const float rgb[3])
+{
+ if (is_torus) {
+ x %= ibuf->x;
+ if (x < 0) x += ibuf->x;
+ y %= ibuf->y;
+ if (y < 0) y += ibuf->y;
+ }
+ if (ibuf->rect_float) {
+ float *rrgbf = ibuf->rect_float + (ibuf->x * y + x) * 4;
+ IMAPAINT_FLOAT_RGB_COPY(rrgbf, rgb);
+ }
+ else {
+ char *rrgb = (char *)ibuf->rect + (ibuf->x * y + x) * 4;
+ IMAPAINT_FLOAT_RGB_TO_CHAR(rrgb, rgb);
+ }
+}
-int BKE_brush_painter_paint(BrushPainter *painter, BrushFunc func, const float pos[2], double time, float pressure,
- void *user, int use_color_correction)
+static int paint_2d_ibuf_add_if(ImBuf *ibuf, unsigned int x, unsigned int y, float *outrgb, short torus)
{
- Scene *scene = painter->scene;
- Brush *brush = painter->brush;
- int totpaintops = 0;
+ float inrgb[3];
- if (pressure == 0.0f) {
- if (painter->lastpressure) // XXX - hack, operator misses
- pressure = painter->lastpressure;
- else
- pressure = 1.0f; /* zero pressure == not using tablet */
- }
- if (painter->firsttouch) {
- /* paint exactly once on first touch */
- painter->startpaintpos[0] = pos[0];
- painter->startpaintpos[1] = pos[1];
-
- brush_pressure_apply(painter, brush, pressure);
- if (painter->cache.enabled)
- brush_painter_refresh_cache(painter, pos, use_color_correction);
- totpaintops += func(user, painter->cache.ibuf, pos, pos);
-
- painter->lasttime = time;
- painter->firsttouch = 0;
- painter->lastpaintpos[0] = pos[0];
- painter->lastpaintpos[1] = pos[1];
- }
-#if 0
- else if (painter->brush->flag & BRUSH_AIRBRUSH) {
- float spacing, step, paintpos[2], dmousepos[2], len;
- double starttime, curtime = time;
-
- /* compute brush spacing adapted to brush size */
- spacing = brush->rate; //radius*brush->spacing * 0.01f;
-
- /* setup starting time, direction vector and accumulated time */
- starttime = painter->accumtime;
- sub_v2_v2v2(dmousepos, pos, painter->lastmousepos);
- len = normalize_v2(dmousepos);
- painter->accumtime += curtime - painter->lasttime;
-
- /* do paint op over unpainted time distance */
- while (painter->accumtime >= spacing) {
- step = (spacing - starttime) * len;
- paintpos[0] = painter->lastmousepos[0] + dmousepos[0] * step;
- paintpos[1] = painter->lastmousepos[1] + dmousepos[1] * step;
-
- if (painter->cache.enabled)
- brush_painter_refresh_cache(painter);
- totpaintops += func(user, painter->cache.ibuf,
- painter->lastpaintpos, paintpos);
-
- painter->lastpaintpos[0] = paintpos[0];
- painter->lastpaintpos[1] = paintpos[1];
- painter->accumtime -= spacing;
- starttime -= spacing;
- }
-
- painter->lasttime = curtime;
+ // XXX: signed unsigned mismatch
+ if ((x >= (unsigned int)(ibuf->x)) || (y >= (unsigned int)(ibuf->y))) {
+ if (torus) paint_2d_ibuf_rgb_get(ibuf, x, y, 1, inrgb);
+ else return 0;
}
-#endif
else {
- float startdistance, spacing, step, paintpos[2], dmousepos[2], finalpos[2];
- float t, len, press;
- const int radius = BKE_brush_size_get(scene, brush);
-
- /* compute brush spacing adapted to brush radius, spacing may depend
- * on pressure, so update it */
- brush_pressure_apply(painter, brush, painter->lastpressure);
- spacing = max_ff(1.0f, radius) * brush->spacing * 0.01f;
-
- /* setup starting distance, direction vector and accumulated distance */
- startdistance = painter->accumdistance;
- sub_v2_v2v2(dmousepos, pos, painter->lastmousepos);
- len = normalize_v2(dmousepos);
- painter->accumdistance += len;
-
- if (brush->flag & BRUSH_SPACE) {
- /* do paint op over unpainted distance */
- while ((len > 0.0f) && (painter->accumdistance >= spacing)) {
- step = spacing - startdistance;
- paintpos[0] = painter->lastmousepos[0] + dmousepos[0] * step;
- paintpos[1] = painter->lastmousepos[1] + dmousepos[1] * step;
-
- t = step / len;
- press = (1.0f - t) * painter->lastpressure + t * pressure;
- brush_pressure_apply(painter, brush, press);
- spacing = max_ff(1.0f, radius) * brush->spacing * 0.01f;
-
- BKE_brush_jitter_pos(scene, brush, paintpos, finalpos);
-
- if (painter->cache.enabled)
- brush_painter_refresh_cache(painter, finalpos, use_color_correction);
-
- totpaintops +=
- func(user, painter->cache.ibuf, painter->lastpaintpos, finalpos);
-
- painter->lastpaintpos[0] = paintpos[0];
- painter->lastpaintpos[1] = paintpos[1];
- painter->accumdistance -= spacing;
- startdistance -= spacing;
- }
- }
- else {
- BKE_brush_jitter_pos(scene, brush, pos, finalpos);
+ paint_2d_ibuf_rgb_get(ibuf, x, y, 0, inrgb);
+ }
- if (painter->cache.enabled)
- brush_painter_refresh_cache(painter, finalpos, use_color_correction);
+ outrgb[0] += inrgb[0];
+ outrgb[1] += inrgb[1];
+ outrgb[2] += inrgb[2];
- totpaintops += func(user, painter->cache.ibuf, pos, finalpos);
+ return 1;
+}
- painter->lastpaintpos[0] = pos[0];
- painter->lastpaintpos[1] = pos[1];
- painter->accumdistance = 0;
- }
+static void paint_2d_lift_soften(ImBuf *ibuf, ImBuf *ibufb, int *pos, const short is_torus)
+{
+ int x, y, count, xi, yi, xo, yo;
+ int out_off[2], in_off[2], dim[2];
+ float outrgb[3];
+
+ dim[0] = ibufb->x;
+ dim[1] = ibufb->y;
+ in_off[0] = pos[0];
+ in_off[1] = pos[1];
+ out_off[0] = out_off[1] = 0;
+
+ if (!is_torus) {
+ IMB_rectclip(ibuf, ibufb, &in_off[0], &in_off[1], &out_off[0],
+ &out_off[1], &dim[0], &dim[1]);
+
+ if ((dim[0] == 0) || (dim[1] == 0))
+ return;
+ }
- /* do airbrush paint ops, based on the number of paint ops left over
- * from regular painting. this is a temporary solution until we have
- * accurate time stamps for mouse move events */
- if (brush->flag & BRUSH_AIRBRUSH) {
- double curtime = time;
- double painttime = brush->rate * totpaintops;
+ for (y = 0; y < dim[1]; y++) {
+ for (x = 0; x < dim[0]; x++) {
+ /* get input pixel */
+ xi = in_off[0] + x;
+ yi = in_off[1] + y;
- painter->accumtime += curtime - painter->lasttime;
- if (painter->accumtime <= painttime)
- painter->accumtime = 0.0;
- else
- painter->accumtime -= painttime;
+ count = 1;
+ paint_2d_ibuf_rgb_get(ibuf, xi, yi, is_torus, outrgb);
- while (painter->accumtime >= (double)brush->rate) {
- brush_pressure_apply(painter, brush, pressure);
+ count += paint_2d_ibuf_add_if(ibuf, xi - 1, yi - 1, outrgb, is_torus);
+ count += paint_2d_ibuf_add_if(ibuf, xi - 1, yi, outrgb, is_torus);
+ count += paint_2d_ibuf_add_if(ibuf, xi - 1, yi + 1, outrgb, is_torus);
- BKE_brush_jitter_pos(scene, brush, pos, finalpos);
+ count += paint_2d_ibuf_add_if(ibuf, xi, yi - 1, outrgb, is_torus);
+ count += paint_2d_ibuf_add_if(ibuf, xi, yi + 1, outrgb, is_torus);
- if (painter->cache.enabled)
- brush_painter_refresh_cache(painter, finalpos, use_color_correction);
+ count += paint_2d_ibuf_add_if(ibuf, xi + 1, yi - 1, outrgb, is_torus);
+ count += paint_2d_ibuf_add_if(ibuf, xi + 1, yi, outrgb, is_torus);
+ count += paint_2d_ibuf_add_if(ibuf, xi + 1, yi + 1, outrgb, is_torus);
- totpaintops +=
- func(user, painter->cache.ibuf, painter->lastmousepos, finalpos);
- painter->accumtime -= (double)brush->rate;
- }
+ mul_v3_fl(outrgb, 1.0f / (float)count);
- painter->lasttime = curtime;
+ /* write into brush buffer */
+ xo = out_off[0] + x;
+ yo = out_off[1] + y;
+ paint_2d_ibuf_rgb_set(ibufb, xo, yo, 0, outrgb);
}
}
+}
- painter->lastmousepos[0] = pos[0];
- painter->lastmousepos[1] = pos[1];
- painter->lastpressure = pressure;
+static void paint_2d_set_region(ImagePaintRegion *region, int destx, int desty, int srcx, int srcy, int width, int height)
+{
+ region->destx = destx;
+ region->desty = desty;
+ region->srcx = srcx;
+ region->srcy = srcy;
+ region->width = width;
+ region->height = height;
+}
+
+static int paint_2d_torus_split_region(ImagePaintRegion region[4], ImBuf *dbuf, ImBuf *sbuf)
+{
+ int destx = region->destx;
+ int desty = region->desty;
+ int srcx = region->srcx;
+ int srcy = region->srcy;
+ int width = region->width;
+ int height = region->height;
+ int origw, origh, w, h, tot = 0;
+
+ /* convert destination and source coordinates to be within image */
+ destx = destx % dbuf->x;
+ if (destx < 0) destx += dbuf->x;
+ desty = desty % dbuf->y;
+ if (desty < 0) desty += dbuf->y;
+ srcx = srcx % sbuf->x;
+ if (srcx < 0) srcx += sbuf->x;
+ srcy = srcy % sbuf->y;
+ if (srcy < 0) srcy += sbuf->y;
+
+ /* clip width of blending area to destination imbuf, to avoid writing the
+ * same pixel twice */
+ origw = w = (width > dbuf->x) ? dbuf->x : width;
+ origh = h = (height > dbuf->y) ? dbuf->y : height;
+
+ /* clip within image */
+ IMB_rectclip(dbuf, sbuf, &destx, &desty, &srcx, &srcy, &w, &h);
+ paint_2d_set_region(&region[tot++], destx, desty, srcx, srcy, w, h);
+
+ /* do 3 other rects if needed */
+ if (w < origw)
+ paint_2d_set_region(&region[tot++], (destx + w) % dbuf->x, desty, (srcx + w) % sbuf->x, srcy, origw - w, h);
+ if (h < origh)
+ paint_2d_set_region(&region[tot++], destx, (desty + h) % dbuf->y, srcx, (srcy + h) % sbuf->y, w, origh - h);
+ if ((w < origw) && (h < origh))
+ paint_2d_set_region(&region[tot++], (destx + w) % dbuf->x, (desty + h) % dbuf->y, (srcx + w) % sbuf->x, (srcy + h) % sbuf->y, origw - w, origh - h);
+
+ return tot;
+}
- BKE_brush_alpha_set(scene, brush, painter->startalpha);
- BKE_brush_size_set(scene, brush, painter->startsize);
- brush->jitter = painter->startjitter;
- brush->spacing = painter->startspacing;
+static void paint_2d_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos)
+{
+ ImagePaintRegion region[4];
+ int a, tot;
+
+ paint_2d_set_region(region, 0, 0, pos[0], pos[1], ibufb->x, ibufb->y);
+ tot = paint_2d_torus_split_region(region, ibufb, ibuf);
+
+ for (a = 0; a < tot; a++)
+ IMB_rectblend(ibufb, ibuf, region[a].destx, region[a].desty,
+ region[a].srcx, region[a].srcy,
+ region[a].width, region[a].height, IMB_BLEND_COPY_RGB);
+}
- return totpaintops;
+static ImBuf *paint_2d_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos)
+{
+ /* note: allocImbuf returns zero'd memory, so regions outside image will
+ * have zero alpha, and hence not be blended onto the image */
+ int w = ibufb->x, h = ibufb->y, destx = 0, desty = 0, srcx = pos[0], srcy = pos[1];
+ ImBuf *clonebuf = IMB_allocImBuf(w, h, ibufb->planes, ibufb->flags);
+
+ IMB_rectclip(clonebuf, ibuf, &destx, &desty, &srcx, &srcy, &w, &h);
+ IMB_rectblend(clonebuf, ibuf, destx, desty, srcx, srcy, w, h,
+ IMB_BLEND_COPY_RGB);
+ IMB_rectblend(clonebuf, ibufb, destx, desty, destx, desty, w, h,
+ IMB_BLEND_COPY_ALPHA);
+
+ return clonebuf;
}
+static void paint_2d_convert_brushco(ImBuf *ibufb, const float pos[2], int ipos[2])
+{
+ ipos[0] = (int)floorf((pos[0] - ibufb->x / 2) + 1.0f);
+ ipos[1] = (int)floorf((pos[1] - ibufb->y / 2) + 1.0f);
+}
-/* TODO: should probably be unified with BrushPainter stuff? */
-unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side)
+static int paint_2d_op(void *state, ImBuf *ibufb, const float lastpos[2], const float pos[2])
{
- unsigned int *texcache = NULL;
- MTex *mtex = &br->mtex;
- TexResult texres = {0};
- int hasrgb, ix, iy;
- int side = half_side * 2;
-
- if (mtex->tex) {
- float x, y, step = 2.0 / side, co[3];
-
- texcache = MEM_callocN(sizeof(int) * side * side, "Brush texture cache");
-
- /*do normalized cannonical view coords for texture*/
- for (y = -1.0, iy = 0; iy < side; iy++, y += step) {
- for (x = -1.0, ix = 0; ix < side; ix++, x += step) {
- co[0] = x;
- co[1] = y;
- co[2] = 0.0f;
-
- /* This is copied from displace modifier code */
- hasrgb = multitex_ext(mtex->tex, co, NULL, NULL, 0, &texres, NULL);
-
- /* if the texture gave an RGB value, we assume it didn't give a valid
- * intensity, so calculate one (formula from do_material_tex).
- * if the texture didn't give an RGB value, copy the intensity across
- */
- if (hasrgb & TEX_RGB)
- texres.tin = rgb_to_grayscale(&texres.tr);
-
- ((char *)texcache)[(iy * side + ix) * 4] =
- ((char *)texcache)[(iy * side + ix) * 4 + 1] =
- ((char *)texcache)[(iy * side + ix) * 4 + 2] =
- ((char *)texcache)[(iy * side + ix) * 4 + 3] = (char)(texres.tin * 255.0f);
- }
+ ImagePaintState *s = ((ImagePaintState *)state);
+ ImBuf *clonebuf = NULL, *frombuf;
+ ImagePaintRegion region[4];
+ short torus = s->brush->flag & BRUSH_TORUS;
+ short blend = s->blend;
+ float *offset = s->brush->clone.offset;
+ float liftpos[2];
+ int bpos[2], blastpos[2], bliftpos[2];
+ int a, tot;
+
+ paint_2d_convert_brushco(ibufb, pos, bpos);
+
+ /* lift from canvas */
+ if (s->tool == PAINT_TOOL_SOFTEN) {
+ paint_2d_lift_soften(s->canvas, ibufb, bpos, torus);
+ }
+ else if (s->tool == PAINT_TOOL_SMEAR) {
+ if (lastpos[0] == pos[0] && lastpos[1] == pos[1])
+ return 0;
+
+ paint_2d_convert_brushco(ibufb, lastpos, blastpos);
+ paint_2d_lift_smear(s->canvas, ibufb, blastpos);
+ }
+ else if (s->tool == PAINT_TOOL_CLONE && s->clonecanvas) {
+ liftpos[0] = pos[0] - offset[0] * s->canvas->x;
+ liftpos[1] = pos[1] - offset[1] * s->canvas->y;
+
+ paint_2d_convert_brushco(ibufb, liftpos, bliftpos);
+ clonebuf = paint_2d_lift_clone(s->clonecanvas, ibufb, bliftpos);
+ }
+
+ frombuf = (clonebuf) ? clonebuf : ibufb;
+
+ if (torus) {
+ paint_2d_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y);
+ tot = paint_2d_torus_split_region(region, s->canvas, frombuf);
+ }
+ else {
+ paint_2d_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y);
+ tot = 1;
+ }
+
+ /* blend into canvas */
+ for (a = 0; a < tot; a++) {
+ imapaint_dirty_region(s->image, s->canvas,
+ region[a].destx, region[a].desty,
+ region[a].width, region[a].height);
+
+ IMB_rectblend(s->canvas, frombuf,
+ region[a].destx, region[a].desty,
+ region[a].srcx, region[a].srcy,
+ region[a].width, region[a].height, blend);
+ }
+
+ if (clonebuf) IMB_freeImBuf(clonebuf);
+
+ return 1;
+}
+
+
+static int paint_2d_canvas_set(ImagePaintState *s, Image *ima)
+{
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, s->sima ? &s->sima->iuser : NULL, NULL);
+
+ /* verify that we can paint and set canvas */
+ if (ima == NULL) {
+ return 0;
+ }
+ else if (ima->packedfile && ima->rr) {
+ s->warnpackedfile = ima->id.name + 2;
+ return 0;
+ }
+ else if (ibuf && ibuf->channels != 4) {
+ s->warnmultifile = ima->id.name + 2;
+ return 0;
+ }
+ else if (!ibuf || !(ibuf->rect || ibuf->rect_float))
+ return 0;
+
+ s->image = ima;
+ s->canvas = ibuf;
+
+ /* set clone canvas */
+ if (s->tool == PAINT_TOOL_CLONE) {
+ ima = s->brush->clone.image;
+ ibuf = BKE_image_acquire_ibuf(ima, s->sima ? &s->sima->iuser : NULL, NULL);
+
+ if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) {
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ BKE_image_release_ibuf(s->image, s->canvas, NULL);
+ return 0;
+ }
+
+ s->clonecanvas = ibuf;
+
+ /* temporarily add float rect for cloning */
+ if (s->canvas->rect_float && !s->clonecanvas->rect_float) {
+ IMB_float_from_rect(s->clonecanvas);
}
+ else if (!s->canvas->rect_float && !s->clonecanvas->rect)
+ IMB_rect_from_float(s->clonecanvas);
}
- return texcache;
+ return 1;
}
+static void paint_2d_canvas_free(ImagePaintState *s)
+{
+ BKE_image_release_ibuf(s->image, s->canvas, NULL);
+ BKE_image_release_ibuf(s->brush->clone.image, s->clonecanvas, NULL);
+}
+
+int paint_2d_stroke(void *ps, const int prev_mval[2], const int mval[2], int eraser)
+{
+ float newuv[2], olduv[2];
+ int redraw = 0;
+ ImagePaintState *s = ps;
+ BrushPainter *painter = s->painter;
+ ImBuf *ibuf = BKE_image_acquire_ibuf(s->image, s->sima ? &s->sima->iuser : NULL, NULL);
+ const bool is_data = (ibuf && ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA);
+
+ if (!ibuf)
+ return 0;
+
+ s->blend = s->brush->blend;
+ if (eraser)
+ s->blend = IMB_BLEND_ERASE_ALPHA;
+
+ UI_view2d_region_to_view(s->v2d, mval[0], mval[1], &newuv[0], &newuv[1]);
+ UI_view2d_region_to_view(s->v2d, prev_mval[0], prev_mval[1], &olduv[0], &olduv[1]);
+
+ newuv[0] *= ibuf->x;
+ newuv[1] *= ibuf->y;
+
+ olduv[0] *= ibuf->x;
+ olduv[1] *= ibuf->y;
+
+ if (painter->firsttouch) {
+ /* paint exactly once on first touch */
+ painter->startpaintpos[0] = newuv[0];
+ painter->startpaintpos[1] = newuv[1];
+
+ painter->firsttouch = 0;
+ copy_v2_v2(painter->lastpaintpos, newuv);
+ }
+ else {
+ copy_v2_v2(painter->lastpaintpos, olduv);
+ }
+ /* OCIO_TODO: float buffers are now always linear, so always use color correction
+ * this should probably be changed when texture painting color space is supported
+ */
+ brush_painter_2d_require_imbuf(painter, ((ibuf->rect_float) ? 1 : 0), 0, 0);
+
+ if (painter->cache.enabled)
+ brush_painter_2d_refresh_cache(painter, newuv, is_data == false);
+
+ if (paint_2d_op(s, painter->cache.ibuf, olduv, newuv)) {
+ imapaint_image_update(s->sima, s->image, ibuf, false);
+ BKE_image_release_ibuf(s->image, ibuf, NULL);
+ redraw |= 1;
+ }
+ else {
+ BKE_image_release_ibuf(s->image, ibuf, NULL);
+ }
+
+ if (redraw)
+ imapaint_clear_partial_redraw();
+
+ return redraw;
+}
+
+void *paint_2d_new_stroke(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *settings = scene->toolsettings;
+ Brush *brush = paint_brush(&settings->imapaint.paint);
+
+ ImagePaintState *s = MEM_callocN(sizeof(ImagePaintState), "ImagePaintState");
+
+ s->sima = CTX_wm_space_image(C);
+ s->v2d = &CTX_wm_region(C)->v2d;
+ s->scene = scene;
+ s->screen = CTX_wm_screen(C);
+
+ s->brush = brush;
+ s->tool = brush->imagepaint_tool;
+ s->blend = brush->blend;
+
+ s->image = s->sima->image;
+
+ if (!paint_2d_canvas_set(s, s->image)) {
+ if (s->warnmultifile)
+ BKE_report(op->reports, RPT_WARNING, "Image requires 4 color channels to paint");
+ if (s->warnpackedfile)
+ BKE_report(op->reports, RPT_WARNING, "Packed MultiLayer files cannot be painted");
+
+ MEM_freeN(s);
+ return NULL;
+ }
+
+ paint_brush_init_tex(s->brush);
+
+ /* create painter */
+ s->painter = brush_painter_2d_new(scene, s->brush);
+
+ return s;
+}
+
+void paint_2d_redraw (const bContext *C, void *ps, int final)
+{
+ ImagePaintState *s = ps;
+
+ if (final) {
+ if (s->image && !(s->sima && s->sima->lock))
+ GPU_free_image(s->image);
+
+ /* compositor listener deals with updating */
+ WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, s->image);
+ }
+ else {
+ if (!s->sima || !s->sima->lock)
+ ED_region_tag_redraw(CTX_wm_region(C));
+ else
+ WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, s->image);
+ }
+}
+
+void paint_2d_stroke_done(void *ps)
+{
+ ImagePaintState *s = ps;
+
+ paint_2d_canvas_free(s);
+ brush_painter_2d_free(s->painter);
+ paint_brush_exit_tex(s->brush);
+
+ MEM_freeN(s);
+}
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
new file mode 100644
index 00000000000..96916236279
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -0,0 +1,4465 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: some of this file.
+ *
+ * Contributor(s): Jens Ole Wund (bjornmose), Campbell Barton (ideasman42)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/sculpt_paint/paint_image_proj.c
+ * \ingroup edsculpt
+ * \brief Functions to paint images in 2D and 3D.
+ */
+
+#include <float.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#ifdef WIN32
+# include "BLI_winstuff.h"
+#endif
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_linklist.h"
+#include "BLI_memarena.h"
+#include "BLI_threads.h"
+#include "BLI_utildefines.h"
+
+#include "PIL_time.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_camera.h"
+#include "BKE_context.h"
+#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_idprop.h"
+#include "BKE_brush.h"
+#include "BKE_image.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_colortools.h"
+
+#include "BKE_tessmesh.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "UI_view2d.h"
+
+#include "ED_image.h"
+#include "ED_screen.h"
+#include "ED_sculpt.h"
+#include "ED_uvedit.h"
+#include "ED_view3d.h"
+#include "ED_mesh.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "GPU_draw.h"
+
+#include "IMB_colormanagement.h"
+
+#include "paint_intern.h"
+
+/* Defines and Structs */
+/* FTOCHAR as inline function */
+BLI_INLINE unsigned char f_to_char(const float val)
+{
+ return FTOCHAR(val);
+}
+
+#define IMAPAINT_FLOAT_RGBA_TO_CHAR(c, f) { \
+ (c)[0] = f_to_char((f)[0]); \
+ (c)[1] = f_to_char((f)[1]); \
+ (c)[2] = f_to_char((f)[2]); \
+ (c)[3] = f_to_char((f)[3]); \
+} (void)0
+
+#define IMAPAINT_CHAR_RGBA_TO_FLOAT(f, c) { \
+ (f)[0] = IMAPAINT_CHAR_TO_FLOAT((c)[0]); \
+ (f)[1] = IMAPAINT_CHAR_TO_FLOAT((c)[1]); \
+ (f)[2] = IMAPAINT_CHAR_TO_FLOAT((c)[2]); \
+ (f)[3] = IMAPAINT_CHAR_TO_FLOAT((c)[3]); \
+} (void)0
+
+#define IMAPAINT_FLOAT_RGB_TO_CHAR(c, f) { \
+ (c)[0] = f_to_char((f)[0]); \
+ (c)[1] = f_to_char((f)[1]); \
+ (c)[2] = f_to_char((f)[2]); \
+} (void)0
+
+/* ProjectionPaint defines */
+
+/* approx the number of buckets to have under the brush,
+ * used with the brush size to set the ps->buckets_x and ps->buckets_y value.
+ *
+ * When 3 - a brush should have ~9 buckets under it at once
+ * ...this helps for threading while painting as well as
+ * avoiding initializing pixels that wont touch the brush */
+#define PROJ_BUCKET_BRUSH_DIV 4
+
+#define PROJ_BUCKET_RECT_MIN 4
+#define PROJ_BUCKET_RECT_MAX 256
+
+#define PROJ_BOUNDBOX_DIV 8
+#define PROJ_BOUNDBOX_SQUARED (PROJ_BOUNDBOX_DIV * PROJ_BOUNDBOX_DIV)
+
+//#define PROJ_DEBUG_PAINT 1
+//#define PROJ_DEBUG_NOSEAMBLEED 1
+//#define PROJ_DEBUG_PRINT_CLIP 1
+#define PROJ_DEBUG_WINCLIP 1
+
+/* projectFaceSeamFlags options */
+//#define PROJ_FACE_IGNORE (1<<0) /* When the face is hidden, backfacing or occluded */
+//#define PROJ_FACE_INIT (1<<1) /* When we have initialized the faces data */
+#define PROJ_FACE_SEAM1 (1 << 0) /* If this face has a seam on any of its edges */
+#define PROJ_FACE_SEAM2 (1 << 1)
+#define PROJ_FACE_SEAM3 (1 << 2)
+#define PROJ_FACE_SEAM4 (1 << 3)
+
+#define PROJ_FACE_NOSEAM1 (1 << 4)
+#define PROJ_FACE_NOSEAM2 (1 << 5)
+#define PROJ_FACE_NOSEAM3 (1 << 6)
+#define PROJ_FACE_NOSEAM4 (1 << 7)
+
+#define PROJ_SRC_VIEW 1
+#define PROJ_SRC_IMAGE_CAM 2
+#define PROJ_SRC_IMAGE_VIEW 3
+
+#define PROJ_VIEW_DATA_ID "view_data"
+#define PROJ_VIEW_DATA_SIZE (4 * 4 + 4 * 4 + 3) /* viewmat + winmat + clipsta + clipend + is_ortho */
+
+
+/* a slightly scaled down face is used to get fake 3D location for edge pixels in the seams
+ * as this number approaches 1.0f the likelihood increases of float precision errors where
+ * it is occluded by an adjacent face */
+#define PROJ_FACE_SCALE_SEAM 0.99f
+
+#define PROJ_BUCKET_NULL 0
+#define PROJ_BUCKET_INIT (1 << 0)
+// #define PROJ_BUCKET_CLONE_INIT (1<<1)
+
+/* used for testing doubles, if a point is on a line etc */
+#define PROJ_GEOM_TOLERANCE 0.00075f
+
+/* vert flags */
+#define PROJ_VERT_CULL 1
+
+/* This is mainly a convenience struct used so we can keep an array of images we use
+ * Thir imbufs, etc, in 1 array, When using threads this array is copied for each thread
+ * because 'partRedrawRect' and 'touch' values would not be thread safe */
+typedef struct ProjPaintImage {
+ Image *ima;
+ ImBuf *ibuf;
+ ImagePaintPartialRedraw *partRedrawRect;
+ void **undoRect; /* only used to build undo tiles after painting */
+ int touch;
+} ProjPaintImage;
+
+/* Main projection painting struct passed to all projection painting functions */
+typedef struct ProjPaintState {
+ View3D *v3d;
+ RegionView3D *rv3d;
+ ARegion *ar;
+ Scene *scene;
+ int source; /* PROJ_SRC_**** */
+
+ Brush *brush;
+ short tool, blend, mode;
+ int orig_brush_size;
+ Object *ob;
+ /* end similarities with ImagePaintState */
+
+ DerivedMesh *dm;
+ int dm_totface;
+ int dm_totvert;
+ int dm_release;
+
+ MVert *dm_mvert;
+ MFace *dm_mface;
+ MTFace *dm_mtface;
+ MTFace *dm_mtface_clone; /* other UV map, use for cloning between layers */
+ MTFace *dm_mtface_stencil;
+
+ /* projection painting only */
+ MemArena *arena_mt[BLENDER_MAX_THREADS]; /* for multithreading, the first item is sometimes used for non threaded cases too */
+ LinkNode **bucketRect; /* screen sized 2D array, each pixel has a linked list of ProjPixel's */
+ LinkNode **bucketFaces; /* bucketRect aligned array linkList of faces overlapping each bucket */
+ unsigned char *bucketFlags; /* store if the bucks have been initialized */
+#ifndef PROJ_DEBUG_NOSEAMBLEED
+ char *faceSeamFlags; /* store info about faces, if they are initialized etc*/
+ float (*faceSeamUVs)[4][2]; /* expanded UVs for faces to use as seams */
+ LinkNode **vertFaces; /* Only needed for when seam_bleed_px is enabled, use to find UV seams */
+#endif
+ char *vertFlags; /* store options per vert, now only store if the vert is pointing away from the view */
+ int buckets_x; /* The size of the bucket grid, the grid span's screenMin/screenMax so you can paint outsize the screen or with 2 brushes at once */
+ int buckets_y;
+
+ ProjPaintImage *projImages;
+
+ int pixel_sizeof; /* result of project_paint_pixel_sizeof(), constant per stroke */
+
+ int image_tot; /* size of projectImages array */
+
+ float (*screenCoords)[4]; /* verts projected into floating point screen space */
+
+ float screenMin[2]; /* 2D bounds for mesh verts on the screen's plane (screenspace) */
+ float screenMax[2];
+ float screen_width; /* Calculated from screenMin & screenMax */
+ float screen_height;
+ int winx, winy; /* from the carea or from the projection render */
+
+ /* options for projection painting */
+ int do_layer_clone;
+ int do_layer_stencil;
+ int do_layer_stencil_inv;
+
+ short do_occlude; /* Use raytraced occlusion? - ortherwise will paint right through to the back*/
+ short do_backfacecull; /* ignore faces with normals pointing away, skips a lot of raycasts if your normals are correctly flipped */
+ short do_mask_normal; /* mask out pixels based on their normals */
+ short do_new_shading_nodes; /* cache BKE_scene_use_new_shading_nodes value */
+ float normal_angle; /* what angle to mask at*/
+ float normal_angle_inner;
+ float normal_angle_range; /* difference between normal_angle and normal_angle_inner, for easy access */
+
+ short is_ortho;
+ bool do_masking; /* use masking during painting. Some operations such as airbrush may disable */
+ short is_texbrush; /* only to avoid running */
+#ifndef PROJ_DEBUG_NOSEAMBLEED
+ float seam_bleed_px;
+#endif
+ /* clone vars */
+ float cloneOffset[2];
+
+ float projectMat[4][4]; /* Projection matrix, use for getting screen coords */
+ float viewDir[3]; /* View vector, use for do_backfacecull and for ray casting with an ortho viewport */
+ float viewPos[3]; /* View location in object relative 3D space, so can compare to verts */
+ float clipsta, clipend;
+
+ /* reproject vars */
+ Image *reproject_image;
+ ImBuf *reproject_ibuf;
+
+
+ /* threads */
+ int thread_tot;
+ int bucketMin[2];
+ int bucketMax[2];
+ int context_bucket_x, context_bucket_y; /* must lock threads while accessing these */
+} ProjPaintState;
+
+typedef union pixelPointer {
+ float *f_pt; /* float buffer */
+ unsigned int *uint_pt; /* 2 ways to access a char buffer */
+ unsigned char *ch_pt;
+} PixelPointer;
+
+typedef union pixelStore {
+ unsigned char ch[4];
+ unsigned int uint;
+ float f[4];
+} PixelStore;
+
+typedef struct ProjPixel {
+ float projCoSS[2]; /* the floating point screen projection of this pixel */
+ float worldCoSS[3];
+ /* Only used when the airbrush is disabled.
+ * Store the max mask value to avoid painting over an area with a lower opacity
+ * with an advantage that we can avoid touching the pixel at all, if the
+ * new mask value is lower then mask_max */
+ unsigned short mask_max;
+
+ /* for various reasons we may want to mask out painting onto this pixel */
+ unsigned short mask;
+
+ short x_px, y_px;
+
+ PixelStore origColor;
+ PixelStore newColor;
+ PixelPointer pixel;
+
+ short image_index; /* if anyone wants to paint onto more then 32768 images they can bite me */
+ unsigned char bb_cell_index;
+} ProjPixel;
+
+typedef struct ProjPixelClone {
+ struct ProjPixel __pp;
+ PixelStore clonepx;
+} ProjPixelClone;
+
+/* blur, store surrounding colors */
+#define PROJ_PIXEL_SOFTEN_TOT 4
+/* blur picking offset (in screenspace) */
+#define PROJ_PIXEL_SOFTEN_OFS_PX 1.0f
+
+static const float proj_pixel_soften_v2[PROJ_PIXEL_SOFTEN_TOT][2] = {
+ {-PROJ_PIXEL_SOFTEN_OFS_PX, 0.0f},
+ { 0.0f, -PROJ_PIXEL_SOFTEN_OFS_PX},
+ { 0.0f, PROJ_PIXEL_SOFTEN_OFS_PX},
+ { PROJ_PIXEL_SOFTEN_OFS_PX, 0.0f},
+};
+
+/* Finish projection painting structs */
+
+static Image *project_paint_face_image(const ProjPaintState *ps, MTFace *dm_mtface, int face_index)
+{
+ Image *ima;
+
+ if (ps->do_new_shading_nodes) { /* cached BKE_scene_use_new_shading_nodes result */
+ MFace *mf = ps->dm_mface + face_index;
+ ED_object_get_active_image(ps->ob, mf->mat_nr + 1, &ima, NULL, NULL);
+ }
+ else {
+ ima = dm_mtface[face_index].tpage;
+ }
+
+ return ima;
+}
+
+/* fast projection bucket array lookup, use the safe version for bound checking */
+static int project_bucket_offset(const ProjPaintState *ps, const float projCoSS[2])
+{
+ /* If we were not dealing with screenspace 2D coords we could simple do...
+ * ps->bucketRect[x + (y*ps->buckets_y)] */
+
+ /* please explain?
+ * projCoSS[0] - ps->screenMin[0] : zero origin
+ * ... / ps->screen_width : range from 0.0 to 1.0
+ * ... * ps->buckets_x : use as a bucket index
+ *
+ * Second multiplication does similar but for vertical offset
+ */
+ return ( (int)(((projCoSS[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x)) +
+ (((int)(((projCoSS[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y)) * ps->buckets_x);
+}
+
+static int project_bucket_offset_safe(const ProjPaintState *ps, const float projCoSS[2])
+{
+ int bucket_index = project_bucket_offset(ps, projCoSS);
+
+ if (bucket_index < 0 || bucket_index >= ps->buckets_x * ps->buckets_y) {
+ return -1;
+ }
+ else {
+ return bucket_index;
+ }
+}
+
+/* still use 2D X,Y space but this works for verts transformed by a perspective matrix, using their 4th component as a weight */
+static void barycentric_weights_v2_persp(const float v1[4], const float v2[4], const float v3[4], const float co[2], float w[3])
+{
+ float wtot_inv, wtot;
+
+ w[0] = area_tri_signed_v2(v2, v3, co) / v1[3];
+ w[1] = area_tri_signed_v2(v3, v1, co) / v2[3];
+ w[2] = area_tri_signed_v2(v1, v2, co) / v3[3];
+ wtot = w[0] + w[1] + w[2];
+
+ if (wtot != 0.0f) {
+ wtot_inv = 1.0f / wtot;
+
+ w[0] = w[0] * wtot_inv;
+ w[1] = w[1] * wtot_inv;
+ w[2] = w[2] * wtot_inv;
+ }
+ else /* dummy values for zero area face */
+ w[0] = w[1] = w[2] = 1.0f / 3.0f;
+}
+
+static float VecZDepthOrtho(const float pt[2],
+ const float v1[3], const float v2[3], const float v3[3],
+ float w[3])
+{
+ barycentric_weights_v2(v1, v2, v3, pt, w);
+ return (v1[2] * w[0]) + (v2[2] * w[1]) + (v3[2] * w[2]);
+}
+
+static float VecZDepthPersp(const float pt[2],
+ const float v1[4], const float v2[4], const float v3[4],
+ float w[3])
+{
+ float wtot_inv, wtot;
+ float w_tmp[3];
+
+ barycentric_weights_v2_persp(v1, v2, v3, pt, w);
+ /* for the depth we need the weights to match what
+ * barycentric_weights_v2 would return, in this case its easiest just to
+ * undo the 4th axis division and make it unit-sum
+ *
+ * don't call barycentric_weights_v2() because our callers expect 'w'
+ * to be weighted from the perspective */
+ w_tmp[0] = w[0] * v1[3];
+ w_tmp[1] = w[1] * v2[3];
+ w_tmp[2] = w[2] * v3[3];
+
+ wtot = w_tmp[0] + w_tmp[1] + w_tmp[2];
+
+ if (wtot != 0.0f) {
+ wtot_inv = 1.0f / wtot;
+
+ w_tmp[0] = w_tmp[0] * wtot_inv;
+ w_tmp[1] = w_tmp[1] * wtot_inv;
+ w_tmp[2] = w_tmp[2] * wtot_inv;
+ }
+ else /* dummy values for zero area face */
+ w_tmp[0] = w_tmp[1] = w_tmp[2] = 1.0f / 3.0f;
+ /* done mimicing barycentric_weights_v2() */
+
+ return (v1[2] * w_tmp[0]) + (v2[2] * w_tmp[1]) + (v3[2] * w_tmp[2]);
+}
+
+
+/* Return the top-most face index that the screen space coord 'pt' touches (or -1) */
+static int project_paint_PickFace(const ProjPaintState *ps, const float pt[2], float w[3], int *side)
+{
+ LinkNode *node;
+ float w_tmp[3];
+ float *v1, *v2, *v3, *v4;
+ int bucket_index;
+ int face_index;
+ int best_side = -1;
+ int best_face_index = -1;
+ float z_depth_best = FLT_MAX, z_depth;
+ MFace *mf;
+
+ bucket_index = project_bucket_offset_safe(ps, pt);
+ if (bucket_index == -1)
+ return -1;
+
+
+
+ /* we could return 0 for 1 face buckets, as long as this function assumes
+ * that the point its testing is only every originated from an existing face */
+
+ for (node = ps->bucketFaces[bucket_index]; node; node = node->next) {
+ face_index = GET_INT_FROM_POINTER(node->link);
+ mf = ps->dm_mface + face_index;
+
+ v1 = ps->screenCoords[mf->v1];
+ v2 = ps->screenCoords[mf->v2];
+ v3 = ps->screenCoords[mf->v3];
+
+ if (isect_point_tri_v2(pt, v1, v2, v3)) {
+ if (ps->is_ortho) z_depth = VecZDepthOrtho(pt, v1, v2, v3, w_tmp);
+ else z_depth = VecZDepthPersp(pt, v1, v2, v3, w_tmp);
+
+ if (z_depth < z_depth_best) {
+ best_face_index = face_index;
+ best_side = 0;
+ z_depth_best = z_depth;
+ copy_v3_v3(w, w_tmp);
+ }
+ }
+ else if (mf->v4) {
+ v4 = ps->screenCoords[mf->v4];
+
+ if (isect_point_tri_v2(pt, v1, v3, v4)) {
+ if (ps->is_ortho) z_depth = VecZDepthOrtho(pt, v1, v3, v4, w_tmp);
+ else z_depth = VecZDepthPersp(pt, v1, v3, v4, w_tmp);
+
+ if (z_depth < z_depth_best) {
+ best_face_index = face_index;
+ best_side = 1;
+ z_depth_best = z_depth;
+ copy_v3_v3(w, w_tmp);
+ }
+ }
+ }
+ }
+
+ *side = best_side;
+ return best_face_index; /* will be -1 or a valid face */
+}
+
+/* Converts a uv coord into a pixel location wrapping if the uv is outside 0-1 range */
+static void uvco_to_wrapped_pxco(float uv[2], int ibuf_x, int ibuf_y, float *x, float *y)
+{
+ /* use */
+ *x = (float)fmodf(uv[0], 1.0f);
+ *y = (float)fmodf(uv[1], 1.0f);
+
+ if (*x < 0.0f) *x += 1.0f;
+ if (*y < 0.0f) *y += 1.0f;
+
+ *x = *x * ibuf_x - 0.5f;
+ *y = *y * ibuf_y - 0.5f;
+}
+
+/* Set the top-most face color that the screen space coord 'pt' touches (or return 0 if none touch) */
+static int project_paint_PickColor(const ProjPaintState *ps, const float pt[2],
+ float *rgba_fp, unsigned char *rgba, const int interp)
+{
+ float w[3], uv[2];
+ int side;
+ int face_index;
+ MTFace *tf;
+ Image *ima;
+ ImBuf *ibuf;
+ int xi, yi;
+
+
+ face_index = project_paint_PickFace(ps, pt, w, &side);
+
+ if (face_index == -1)
+ return 0;
+
+ tf = ps->dm_mtface + face_index;
+
+ if (side == 0) {
+ interp_v2_v2v2v2(uv, tf->uv[0], tf->uv[1], tf->uv[2], w);
+ }
+ else { /* QUAD */
+ interp_v2_v2v2v2(uv, tf->uv[0], tf->uv[2], tf->uv[3], w);
+ }
+
+ ima = project_paint_face_image(ps, ps->dm_mtface, face_index);
+ ibuf = ima->ibufs.first; /* we must have got the imbuf before getting here */
+ if (!ibuf) return 0;
+
+ if (interp) {
+ float x, y;
+ uvco_to_wrapped_pxco(uv, ibuf->x, ibuf->y, &x, &y);
+
+ if (ibuf->rect_float) {
+ if (rgba_fp) {
+ bilinear_interpolation_color_wrap(ibuf, NULL, rgba_fp, x, y);
+ }
+ else {
+ float rgba_tmp_f[4];
+ bilinear_interpolation_color_wrap(ibuf, NULL, rgba_tmp_f, x, y);
+ IMAPAINT_FLOAT_RGBA_TO_CHAR(rgba, rgba_tmp_f);
+ }
+ }
+ else {
+ if (rgba) {
+ bilinear_interpolation_color_wrap(ibuf, rgba, NULL, x, y);
+ }
+ else {
+ unsigned char rgba_tmp[4];
+ bilinear_interpolation_color_wrap(ibuf, rgba_tmp, NULL, x, y);
+ IMAPAINT_CHAR_RGBA_TO_FLOAT(rgba_fp, rgba_tmp);
+ }
+ }
+ }
+ else {
+ //xi = (int)((uv[0]*ibuf->x) + 0.5f);
+ //yi = (int)((uv[1]*ibuf->y) + 0.5f);
+ //if (xi < 0 || xi >= ibuf->x || yi < 0 || yi >= ibuf->y) return 0;
+
+ /* wrap */
+ xi = ((int)(uv[0] * ibuf->x)) % ibuf->x;
+ if (xi < 0) xi += ibuf->x;
+ yi = ((int)(uv[1] * ibuf->y)) % ibuf->y;
+ if (yi < 0) yi += ibuf->y;
+
+
+ if (rgba) {
+ if (ibuf->rect_float) {
+ float *rgba_tmp_fp = ibuf->rect_float + (xi + yi * ibuf->x * 4);
+ IMAPAINT_FLOAT_RGBA_TO_CHAR(rgba, rgba_tmp_fp);
+ }
+ else {
+ *((unsigned int *)rgba) = *(unsigned int *)(((char *)ibuf->rect) + ((xi + yi * ibuf->x) * 4));
+ }
+ }
+
+ if (rgba_fp) {
+ if (ibuf->rect_float) {
+ copy_v4_v4(rgba_fp, (ibuf->rect_float + ((xi + yi * ibuf->x) * 4)));
+ }
+ else {
+ char *tmp_ch = ((char *)ibuf->rect) + ((xi + yi * ibuf->x) * 4);
+ IMAPAINT_CHAR_RGBA_TO_FLOAT(rgba_fp, tmp_ch);
+ }
+ }
+ }
+ return 1;
+}
+
+/* Check if 'pt' is infront of the 3 verts on the Z axis (used for screenspace occlusuion test)
+ * return...
+ * 0 : no occlusion
+ * -1 : no occlusion but 2D intersection is true (avoid testing the other half of a quad)
+ * 1 : occluded
+ * 2 : occluded with w[3] weights set (need to know in some cases) */
+
+static int project_paint_occlude_ptv(float pt[3], float v1[4], float v2[4], float v3[4], float w[3], int is_ortho)
+{
+ /* if all are behind us, return false */
+ if (v1[2] > pt[2] && v2[2] > pt[2] && v3[2] > pt[2])
+ return 0;
+
+ /* do a 2D point in try intersection */
+ if (!isect_point_tri_v2(pt, v1, v2, v3))
+ return 0; /* we know there is */
+
+
+ /* From here on we know there IS an intersection */
+ /* if ALL of the verts are infront of us then we know it intersects ? */
+ if (v1[2] < pt[2] && v2[2] < pt[2] && v3[2] < pt[2]) {
+ return 1;
+ }
+ else {
+ /* we intersect? - find the exact depth at the point of intersection */
+ /* Is this point is occluded by another face? */
+ if (is_ortho) {
+ if (VecZDepthOrtho(pt, v1, v2, v3, w) < pt[2]) return 2;
+ }
+ else {
+ if (VecZDepthPersp(pt, v1, v2, v3, w) < pt[2]) return 2;
+ }
+ }
+ return -1;
+}
+
+
+static int project_paint_occlude_ptv_clip(const ProjPaintState *ps, const MFace *mf,
+ float pt[3], float v1[4], float v2[4], float v3[4],
+ const int side)
+{
+ float w[3], wco[3];
+ int ret = project_paint_occlude_ptv(pt, v1, v2, v3, w, ps->is_ortho);
+
+ if (ret <= 0)
+ return ret;
+
+ if (ret == 1) { /* weights not calculated */
+ if (ps->is_ortho) barycentric_weights_v2(v1, v2, v3, pt, w);
+ else barycentric_weights_v2_persp(v1, v2, v3, pt, w);
+ }
+
+ /* Test if we're in the clipped area, */
+ if (side) interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v3].co, ps->dm_mvert[mf->v4].co, w);
+ else interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v2].co, ps->dm_mvert[mf->v3].co, w);
+
+ if (!ED_view3d_clipping_test(ps->rv3d, wco, TRUE)) {
+ return 1;
+ }
+
+ return -1;
+}
+
+
+/* Check if a screenspace location is occluded by any other faces
+ * check, pixelScreenCo must be in screenspace, its Z-Depth only needs to be used for comparison
+ * and doesn't need to be correct in relation to X and Y coords (this is the case in perspective view) */
+static int project_bucket_point_occluded(const ProjPaintState *ps, LinkNode *bucketFace, const int orig_face, float pixelScreenCo[4])
+{
+ MFace *mf;
+ int face_index;
+ int isect_ret;
+ float w[3]; /* not needed when clipping */
+ const short do_clip = ps->rv3d ? ps->rv3d->rflag & RV3D_CLIPPING : 0;
+
+ /* we could return 0 for 1 face buckets, as long as this function assumes
+ * that the point its testing is only every originated from an existing face */
+
+ for (; bucketFace; bucketFace = bucketFace->next) {
+ face_index = GET_INT_FROM_POINTER(bucketFace->link);
+
+ if (orig_face != face_index) {
+ mf = ps->dm_mface + face_index;
+ if (do_clip)
+ isect_ret = project_paint_occlude_ptv_clip(ps, mf, pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v2], ps->screenCoords[mf->v3], 0);
+ else
+ isect_ret = project_paint_occlude_ptv(pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v2], ps->screenCoords[mf->v3], w, ps->is_ortho);
+
+ /* Note, if (isect_ret == -1) then we don't want to test the other side of the quad */
+ if (isect_ret == 0 && mf->v4) {
+ if (do_clip)
+ isect_ret = project_paint_occlude_ptv_clip(ps, mf, pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v3], ps->screenCoords[mf->v4], 1);
+ else
+ isect_ret = project_paint_occlude_ptv(pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v3], ps->screenCoords[mf->v4], w, ps->is_ortho);
+ }
+ if (isect_ret >= 1) {
+ /* TODO - we may want to cache the first hit,
+ * it is not possible to swap the face order in the list anymore */
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+/* basic line intersection, could move to math_geom.c, 2 points with a horiz line
+ * 1 for an intersection, 2 if the first point is aligned, 3 if the second point is aligned */
+#define ISECT_TRUE 1
+#define ISECT_TRUE_P1 2
+#define ISECT_TRUE_P2 3
+static int line_isect_y(const float p1[2], const float p2[2], const float y_level, float *x_isect)
+{
+ float y_diff;
+
+ if (y_level == p1[1]) { /* are we touching the first point? - no interpolation needed */
+ *x_isect = p1[0];
+ return ISECT_TRUE_P1;
+ }
+ if (y_level == p2[1]) { /* are we touching the second point? - no interpolation needed */
+ *x_isect = p2[0];
+ return ISECT_TRUE_P2;
+ }
+
+ y_diff = fabsf(p1[1] - p2[1]); /* yuck, horizontal line, we cant do much here */
+
+ if (y_diff < 0.000001f) {
+ *x_isect = (p1[0] + p2[0]) * 0.5f;
+ return ISECT_TRUE;
+ }
+
+ if (p1[1] > y_level && p2[1] < y_level) {
+ *x_isect = (p2[0] * (p1[1] - y_level) + p1[0] * (y_level - p2[1])) / y_diff; /*(p1[1]-p2[1]);*/
+ return ISECT_TRUE;
+ }
+ else if (p1[1] < y_level && p2[1] > y_level) {
+ *x_isect = (p2[0] * (y_level - p1[1]) + p1[0] * (p2[1] - y_level)) / y_diff; /*(p2[1]-p1[1]);*/
+ return ISECT_TRUE;
+ }
+ else {
+ return 0;
+ }
+}
+
+static int line_isect_x(const float p1[2], const float p2[2], const float x_level, float *y_isect)
+{
+ float x_diff;
+
+ if (x_level == p1[0]) { /* are we touching the first point? - no interpolation needed */
+ *y_isect = p1[1];
+ return ISECT_TRUE_P1;
+ }
+ if (x_level == p2[0]) { /* are we touching the second point? - no interpolation needed */
+ *y_isect = p2[1];
+ return ISECT_TRUE_P2;
+ }
+
+ x_diff = fabsf(p1[0] - p2[0]); /* yuck, horizontal line, we cant do much here */
+
+ if (x_diff < 0.000001f) { /* yuck, vertical line, we cant do much here */
+ *y_isect = (p1[0] + p2[0]) * 0.5f;
+ return ISECT_TRUE;
+ }
+
+ if (p1[0] > x_level && p2[0] < x_level) {
+ *y_isect = (p2[1] * (p1[0] - x_level) + p1[1] * (x_level - p2[0])) / x_diff; /*(p1[0]-p2[0]);*/
+ return ISECT_TRUE;
+ }
+ else if (p1[0] < x_level && p2[0] > x_level) {
+ *y_isect = (p2[1] * (x_level - p1[0]) + p1[1] * (p2[0] - x_level)) / x_diff; /*(p2[0]-p1[0]);*/
+ return ISECT_TRUE;
+ }
+ else {
+ return 0;
+ }
+}
+
+/* simple func use for comparing UV locations to check if there are seams.
+ * Its possible this gives incorrect results, when the UVs for 1 face go into the next
+ * tile, but do not do this for the adjacent face, it could return a false positive.
+ * This is so unlikely that Id not worry about it. */
+#ifndef PROJ_DEBUG_NOSEAMBLEED
+static int cmp_uv(const float vec2a[2], const float vec2b[2])
+{
+ /* if the UV's are not between 0.0 and 1.0 */
+ float xa = (float)fmodf(vec2a[0], 1.0f);
+ float ya = (float)fmodf(vec2a[1], 1.0f);
+
+ float xb = (float)fmodf(vec2b[0], 1.0f);
+ float yb = (float)fmodf(vec2b[1], 1.0f);
+
+ if (xa < 0.0f) xa += 1.0f;
+ if (ya < 0.0f) ya += 1.0f;
+
+ if (xb < 0.0f) xb += 1.0f;
+ if (yb < 0.0f) yb += 1.0f;
+
+ return ((fabsf(xa - xb) < PROJ_GEOM_TOLERANCE) && (fabsf(ya - yb) < PROJ_GEOM_TOLERANCE)) ? 1 : 0;
+}
+#endif
+
+/* set min_px and max_px to the image space bounds of the UV coords
+ * return zero if there is no area in the returned rectangle */
+#ifndef PROJ_DEBUG_NOSEAMBLEED
+static int pixel_bounds_uv(
+ const float uv1[2], const float uv2[2], const float uv3[2], const float uv4[2],
+ rcti *bounds_px,
+ const int ibuf_x, const int ibuf_y,
+ int is_quad
+ )
+{
+ float min_uv[2], max_uv[2]; /* UV bounds */
+
+ INIT_MINMAX2(min_uv, max_uv);
+
+ minmax_v2v2_v2(min_uv, max_uv, uv1);
+ minmax_v2v2_v2(min_uv, max_uv, uv2);
+ minmax_v2v2_v2(min_uv, max_uv, uv3);
+ if (is_quad)
+ minmax_v2v2_v2(min_uv, max_uv, uv4);
+
+ bounds_px->xmin = (int)(ibuf_x * min_uv[0]);
+ bounds_px->ymin = (int)(ibuf_y * min_uv[1]);
+
+ bounds_px->xmax = (int)(ibuf_x * max_uv[0]) + 1;
+ bounds_px->ymax = (int)(ibuf_y * max_uv[1]) + 1;
+
+ /*printf("%d %d %d %d\n", min_px[0], min_px[1], max_px[0], max_px[1]);*/
+
+ /* face uses no UV area when quantized to pixels? */
+ return (bounds_px->xmin == bounds_px->xmax || bounds_px->ymin == bounds_px->ymax) ? 0 : 1;
+}
+#endif
+
+static int pixel_bounds_array(float (*uv)[2], rcti *bounds_px, const int ibuf_x, const int ibuf_y, int tot)
+{
+ float min_uv[2], max_uv[2]; /* UV bounds */
+
+ if (tot == 0) {
+ return 0;
+ }
+
+ INIT_MINMAX2(min_uv, max_uv);
+
+ while (tot--) {
+ minmax_v2v2_v2(min_uv, max_uv, (*uv));
+ uv++;
+ }
+
+ bounds_px->xmin = (int)(ibuf_x * min_uv[0]);
+ bounds_px->ymin = (int)(ibuf_y * min_uv[1]);
+
+ bounds_px->xmax = (int)(ibuf_x * max_uv[0]) + 1;
+ bounds_px->ymax = (int)(ibuf_y * max_uv[1]) + 1;
+
+ /*printf("%d %d %d %d\n", min_px[0], min_px[1], max_px[0], max_px[1]);*/
+
+ /* face uses no UV area when quantized to pixels? */
+ return (bounds_px->xmin == bounds_px->xmax || bounds_px->ymin == bounds_px->ymax) ? 0 : 1;
+}
+
+#ifndef PROJ_DEBUG_NOSEAMBLEED
+
+/* This function returns 1 if this face has a seam along the 2 face-vert indices
+ * 'orig_i1_fidx' and 'orig_i2_fidx' */
+static int check_seam(const ProjPaintState *ps, const int orig_face, const int orig_i1_fidx, const int orig_i2_fidx, int *other_face, int *orig_fidx)
+{
+ LinkNode *node;
+ int face_index;
+ unsigned int i1, i2;
+ int i1_fidx = -1, i2_fidx = -1; /* index in face */
+ MFace *mf;
+ MTFace *tf;
+ const MFace *orig_mf = ps->dm_mface + orig_face;
+ const MTFace *orig_tf = ps->dm_mtface + orig_face;
+
+ /* vert indices from face vert order indices */
+ i1 = (*(&orig_mf->v1 + orig_i1_fidx));
+ i2 = (*(&orig_mf->v1 + orig_i2_fidx));
+
+ for (node = ps->vertFaces[i1]; node; node = node->next) {
+ face_index = GET_INT_FROM_POINTER(node->link);
+
+ if (face_index != orig_face) {
+ mf = ps->dm_mface + face_index;
+ /* could check if the 2 faces images match here,
+ * but then there wouldn't be a way to return the opposite face's info */
+
+
+ /* We need to know the order of the verts in the adjacent face
+ * set the i1_fidx and i2_fidx to (0,1,2,3) */
+ if (mf->v1 == i1) i1_fidx = 0;
+ else if (mf->v2 == i1) i1_fidx = 1;
+ else if (mf->v3 == i1) i1_fidx = 2;
+ else if (mf->v4 && mf->v4 == i1) i1_fidx = 3;
+
+ if (mf->v1 == i2) i2_fidx = 0;
+ else if (mf->v2 == i2) i2_fidx = 1;
+ else if (mf->v3 == i2) i2_fidx = 2;
+ else if (mf->v4 && mf->v4 == i2) i2_fidx = 3;
+
+ /* Only need to check if 'i2_fidx' is valid because we know i1_fidx is the same vert on both faces */
+ if (i2_fidx != -1) {
+ Image *tpage = project_paint_face_image(ps, ps->dm_mtface, face_index);
+ Image *orig_tpage = project_paint_face_image(ps, ps->dm_mtface, orig_face);
+
+ /* This IS an adjacent face!, now lets check if the UVs are ok */
+ tf = ps->dm_mtface + face_index;
+
+ /* set up the other face */
+ *other_face = face_index;
+ *orig_fidx = (i1_fidx < i2_fidx) ? i1_fidx : i2_fidx;
+
+ /* first test if they have the same image */
+ if ((orig_tpage == tpage) &&
+ cmp_uv(orig_tf->uv[orig_i1_fidx], tf->uv[i1_fidx]) &&
+ cmp_uv(orig_tf->uv[orig_i2_fidx], tf->uv[i2_fidx]) )
+ {
+ // printf("SEAM (NONE)\n");
+ return 0;
+
+ }
+ else {
+ // printf("SEAM (UV GAP)\n");
+ return 1;
+ }
+ }
+ }
+ }
+ // printf("SEAM (NO FACE)\n");
+ *other_face = -1;
+ return 1;
+}
+
+/* Calculate outset UV's, this is not the same as simply scaling the UVs,
+ * since the outset coords are a margin that keep an even distance from the original UV's,
+ * note that the image aspect is taken into account */
+static void uv_image_outset(float (*orig_uv)[2], float (*outset_uv)[2], const float scaler,
+ const int ibuf_x, const int ibuf_y, const int is_quad)
+{
+ float a1, a2, a3, a4 = 0.0f;
+ float puv[4][2]; /* pixelspace uv's */
+ float no1[2], no2[2], no3[2], no4[2]; /* normals */
+ float dir1[2], dir2[2], dir3[2], dir4[2];
+ float ibuf_inv[2];
+
+ ibuf_inv[0] = 1.0f / (float)ibuf_x;
+ ibuf_inv[1] = 1.0f / (float)ibuf_y;
+
+ /* make UV's in pixel space so we can */
+ puv[0][0] = orig_uv[0][0] * ibuf_x;
+ puv[0][1] = orig_uv[0][1] * ibuf_y;
+
+ puv[1][0] = orig_uv[1][0] * ibuf_x;
+ puv[1][1] = orig_uv[1][1] * ibuf_y;
+
+ puv[2][0] = orig_uv[2][0] * ibuf_x;
+ puv[2][1] = orig_uv[2][1] * ibuf_y;
+
+ if (is_quad) {
+ puv[3][0] = orig_uv[3][0] * ibuf_x;
+ puv[3][1] = orig_uv[3][1] * ibuf_y;
+ }
+
+ /* face edge directions */
+ sub_v2_v2v2(dir1, puv[1], puv[0]);
+ sub_v2_v2v2(dir2, puv[2], puv[1]);
+ normalize_v2(dir1);
+ normalize_v2(dir2);
+
+ if (is_quad) {
+ sub_v2_v2v2(dir3, puv[3], puv[2]);
+ sub_v2_v2v2(dir4, puv[0], puv[3]);
+ normalize_v2(dir3);
+ normalize_v2(dir4);
+ }
+ else {
+ sub_v2_v2v2(dir3, puv[0], puv[2]);
+ normalize_v2(dir3);
+ }
+
+ /* TODO - angle_normalized_v2v2(...) * (M_PI/180.0f)
+ * This is incorrect. Its already given radians but without it wont work.
+ * need to look into a fix - campbell */
+ if (is_quad) {
+ a1 = shell_angle_to_dist(angle_normalized_v2v2(dir4, dir1) * ((float)M_PI / 180.0f));
+ a2 = shell_angle_to_dist(angle_normalized_v2v2(dir1, dir2) * ((float)M_PI / 180.0f));
+ a3 = shell_angle_to_dist(angle_normalized_v2v2(dir2, dir3) * ((float)M_PI / 180.0f));
+ a4 = shell_angle_to_dist(angle_normalized_v2v2(dir3, dir4) * ((float)M_PI / 180.0f));
+ }
+ else {
+ a1 = shell_angle_to_dist(angle_normalized_v2v2(dir3, dir1) * ((float)M_PI / 180.0f));
+ a2 = shell_angle_to_dist(angle_normalized_v2v2(dir1, dir2) * ((float)M_PI / 180.0f));
+ a3 = shell_angle_to_dist(angle_normalized_v2v2(dir2, dir3) * ((float)M_PI / 180.0f));
+ }
+
+ if (is_quad) {
+ sub_v2_v2v2(no1, dir4, dir1);
+ sub_v2_v2v2(no2, dir1, dir2);
+ sub_v2_v2v2(no3, dir2, dir3);
+ sub_v2_v2v2(no4, dir3, dir4);
+ normalize_v2(no1);
+ normalize_v2(no2);
+ normalize_v2(no3);
+ normalize_v2(no4);
+ mul_v2_fl(no1, a1 * scaler);
+ mul_v2_fl(no2, a2 * scaler);
+ mul_v2_fl(no3, a3 * scaler);
+ mul_v2_fl(no4, a4 * scaler);
+ add_v2_v2v2(outset_uv[0], puv[0], no1);
+ add_v2_v2v2(outset_uv[1], puv[1], no2);
+ add_v2_v2v2(outset_uv[2], puv[2], no3);
+ add_v2_v2v2(outset_uv[3], puv[3], no4);
+ mul_v2_v2(outset_uv[0], ibuf_inv);
+ mul_v2_v2(outset_uv[1], ibuf_inv);
+ mul_v2_v2(outset_uv[2], ibuf_inv);
+ mul_v2_v2(outset_uv[3], ibuf_inv);
+ }
+ else {
+ sub_v2_v2v2(no1, dir3, dir1);
+ sub_v2_v2v2(no2, dir1, dir2);
+ sub_v2_v2v2(no3, dir2, dir3);
+ normalize_v2(no1);
+ normalize_v2(no2);
+ normalize_v2(no3);
+ mul_v2_fl(no1, a1 * scaler);
+ mul_v2_fl(no2, a2 * scaler);
+ mul_v2_fl(no3, a3 * scaler);
+ add_v2_v2v2(outset_uv[0], puv[0], no1);
+ add_v2_v2v2(outset_uv[1], puv[1], no2);
+ add_v2_v2v2(outset_uv[2], puv[2], no3);
+
+ mul_v2_v2(outset_uv[0], ibuf_inv);
+ mul_v2_v2(outset_uv[1], ibuf_inv);
+ mul_v2_v2(outset_uv[2], ibuf_inv);
+ }
+}
+
+/*
+ * Be tricky with flags, first 4 bits are PROJ_FACE_SEAM1 to 4, last 4 bits are PROJ_FACE_NOSEAM1 to 4
+ * 1<<i - where i is (0-3)
+ *
+ * If we're multithreadng, make sure threads are locked when this is called
+ */
+static void project_face_seams_init(const ProjPaintState *ps, const int face_index, const int is_quad)
+{
+ int other_face, other_fidx; /* vars for the other face, we also set its flag */
+ int fidx1 = is_quad ? 3 : 2;
+ int fidx2 = 0; /* next fidx in the face (0,1,2,3) -> (1,2,3,0) or (0,1,2) -> (1,2,0) for a tri */
+
+ do {
+ if ((ps->faceSeamFlags[face_index] & (1 << fidx1 | 16 << fidx1)) == 0) {
+ if (check_seam(ps, face_index, fidx1, fidx2, &other_face, &other_fidx)) {
+ ps->faceSeamFlags[face_index] |= 1 << fidx1;
+ if (other_face != -1)
+ ps->faceSeamFlags[other_face] |= 1 << other_fidx;
+ }
+ else {
+ ps->faceSeamFlags[face_index] |= 16 << fidx1;
+ if (other_face != -1)
+ ps->faceSeamFlags[other_face] |= 16 << other_fidx; /* second 4 bits for disabled */
+ }
+ }
+
+ fidx2 = fidx1;
+ } while (fidx1--);
+}
+#endif // PROJ_DEBUG_NOSEAMBLEED
+
+
+/* Converts a UV location to a 3D screenspace location
+ * Takes a 'uv' and 3 UV coords, and sets the values of pixelScreenCo
+ *
+ * This is used for finding a pixels location in screenspace for painting */
+static void screen_px_from_ortho(
+ float uv[2],
+ float v1co[3], float v2co[3], float v3co[3], /* Screenspace coords */
+ float uv1co[2], float uv2co[2], float uv3co[2],
+ float pixelScreenCo[4],
+ float w[3])
+{
+ barycentric_weights_v2(uv1co, uv2co, uv3co, uv, w);
+ interp_v3_v3v3v3(pixelScreenCo, v1co, v2co, v3co, w);
+}
+
+/* same as screen_px_from_ortho except we need to take into account
+ * the perspective W coord for each vert */
+static void screen_px_from_persp(
+ float uv[2],
+ float v1co[4], float v2co[4], float v3co[4], /* screenspace coords */
+ float uv1co[2], float uv2co[2], float uv3co[2],
+ float pixelScreenCo[4],
+ float w[3])
+{
+
+ float wtot_inv, wtot;
+ barycentric_weights_v2(uv1co, uv2co, uv3co, uv, w);
+
+ /* re-weight from the 4th coord of each screen vert */
+ w[0] *= v1co[3];
+ w[1] *= v2co[3];
+ w[2] *= v3co[3];
+
+ wtot = w[0] + w[1] + w[2];
+
+ if (wtot > 0.0f) {
+ wtot_inv = 1.0f / wtot;
+ w[0] *= wtot_inv;
+ w[1] *= wtot_inv;
+ w[2] *= wtot_inv;
+ }
+ else {
+ w[0] = w[1] = w[2] = 1.0f / 3.0f; /* dummy values for zero area face */
+ }
+ /* done re-weighting */
+
+ interp_v3_v3v3v3(pixelScreenCo, v1co, v2co, v3co, w);
+}
+
+static void project_face_pixel(const MTFace *tf_other, ImBuf *ibuf_other, const float w[3],
+ int side, unsigned char rgba_ub[4], float rgba_f[4])
+{
+ float *uvCo1, *uvCo2, *uvCo3;
+ float uv_other[2], x, y;
+
+ uvCo1 = (float *)tf_other->uv[0];
+ if (side == 1) {
+ uvCo2 = (float *)tf_other->uv[2];
+ uvCo3 = (float *)tf_other->uv[3];
+ }
+ else {
+ uvCo2 = (float *)tf_other->uv[1];
+ uvCo3 = (float *)tf_other->uv[2];
+ }
+
+ interp_v2_v2v2v2(uv_other, uvCo1, uvCo2, uvCo3, (float *)w);
+
+ /* use */
+ uvco_to_wrapped_pxco(uv_other, ibuf_other->x, ibuf_other->y, &x, &y);
+
+
+ if (ibuf_other->rect_float) { /* from float to float */
+ bilinear_interpolation_color_wrap(ibuf_other, NULL, rgba_f, x, y);
+ }
+ else { /* from char to float */
+ bilinear_interpolation_color_wrap(ibuf_other, rgba_ub, NULL, x, y);
+ }
+
+}
+
+/* run this outside project_paint_uvpixel_init since pixels with mask 0 don't need init */
+static float project_paint_uvpixel_mask(
+ const ProjPaintState *ps,
+ const int face_index,
+ const int side,
+ const float w[3])
+{
+ float mask;
+
+ /* Image Mask */
+ if (ps->do_layer_stencil) {
+ /* another UV maps image is masking this one's */
+ ImBuf *ibuf_other;
+ Image *other_tpage = project_paint_face_image(ps, ps->dm_mtface_stencil, face_index);
+ const MTFace *tf_other = ps->dm_mtface_stencil + face_index;
+
+ if (other_tpage && (ibuf_other = BKE_image_acquire_ibuf(other_tpage, NULL, NULL))) {
+ /* BKE_image_acquire_ibuf - TODO - this may be slow */
+ unsigned char rgba_ub[4];
+ float rgba_f[4];
+
+ project_face_pixel(tf_other, ibuf_other, w, side, rgba_ub, rgba_f);
+
+ if (ibuf_other->rect_float) { /* from float to float */
+ mask = ((rgba_f[0] + rgba_f[1] + rgba_f[2]) / 3.0f) * rgba_f[3];
+ }
+ else { /* from char to float */
+ mask = ((rgba_ub[0] + rgba_ub[1] + rgba_ub[2]) / (256 * 3.0f)) * (rgba_ub[3] / 256.0f);
+ }
+
+ BKE_image_release_ibuf(other_tpage, ibuf_other, NULL);
+
+ if (!ps->do_layer_stencil_inv) /* matching the gimps layer mask black/white rules, white==full opacity */
+ mask = (1.0f - mask);
+
+ if (mask == 0.0f) {
+ return 0.0f;
+ }
+ }
+ else {
+ return 0.0f;
+ }
+ }
+ else {
+ mask = 1.0f;
+ }
+
+ /* calculate mask */
+ if (ps->do_mask_normal) {
+ MFace *mf = &ps->dm_mface[face_index];
+ float no[3], angle;
+ if (mf->flag & ME_SMOOTH) {
+ short *no1, *no2, *no3;
+ no1 = ps->dm_mvert[mf->v1].no;
+ if (side == 1) {
+ no2 = ps->dm_mvert[mf->v3].no;
+ no3 = ps->dm_mvert[mf->v4].no;
+ }
+ else {
+ no2 = ps->dm_mvert[mf->v2].no;
+ no3 = ps->dm_mvert[mf->v3].no;
+ }
+
+ no[0] = w[0] * no1[0] + w[1] * no2[0] + w[2] * no3[0];
+ no[1] = w[0] * no1[1] + w[1] * no2[1] + w[2] * no3[1];
+ no[2] = w[0] * no1[2] + w[1] * no2[2] + w[2] * no3[2];
+ normalize_v3(no);
+ }
+ else {
+ /* incase the */
+#if 1
+ /* normalizing per pixel isn't optimal, we could cache or check ps->*/
+ if (mf->v4)
+ normal_quad_v3(no,
+ ps->dm_mvert[mf->v1].co,
+ ps->dm_mvert[mf->v2].co,
+ ps->dm_mvert[mf->v3].co,
+ ps->dm_mvert[mf->v4].co);
+ else
+ normal_tri_v3(no,
+ ps->dm_mvert[mf->v1].co,
+ ps->dm_mvert[mf->v2].co,
+ ps->dm_mvert[mf->v3].co);
+#else
+ /* don't use because some modifiers dont have normal data (subsurf for eg) */
+ copy_v3_v3(no, (float *)ps->dm->getTessFaceData(ps->dm, face_index, CD_NORMAL));
+#endif
+ }
+
+ /* now we can use the normal as a mask */
+ if (ps->is_ortho) {
+ angle = angle_normalized_v3v3((float *)ps->viewDir, no);
+ }
+ else {
+ /* Annoying but for the perspective view we need to get the pixels location in 3D space :/ */
+ float viewDirPersp[3];
+ float *co1, *co2, *co3;
+ co1 = ps->dm_mvert[mf->v1].co;
+ if (side == 1) {
+ co2 = ps->dm_mvert[mf->v3].co;
+ co3 = ps->dm_mvert[mf->v4].co;
+ }
+ else {
+ co2 = ps->dm_mvert[mf->v2].co;
+ co3 = ps->dm_mvert[mf->v3].co;
+ }
+
+ /* Get the direction from the viewPoint to the pixel and normalize */
+ viewDirPersp[0] = (ps->viewPos[0] - (w[0] * co1[0] + w[1] * co2[0] + w[2] * co3[0]));
+ viewDirPersp[1] = (ps->viewPos[1] - (w[0] * co1[1] + w[1] * co2[1] + w[2] * co3[1]));
+ viewDirPersp[2] = (ps->viewPos[2] - (w[0] * co1[2] + w[1] * co2[2] + w[2] * co3[2]));
+ normalize_v3(viewDirPersp);
+
+ angle = angle_normalized_v3v3(viewDirPersp, no);
+ }
+
+ if (angle >= ps->normal_angle) {
+ return 0.0f; /* outsize the normal limit*/
+ }
+ else if (angle > ps->normal_angle_inner) {
+ mask *= (ps->normal_angle - angle) / ps->normal_angle_range;
+ } /* otherwise no mask normal is needed, were within the limit */
+ }
+
+ /* This only works when the opacity dosnt change while painting, stylus pressure messes with this
+ * so don't use it. */
+ // if (ps->is_airbrush == 0) mask *= BKE_brush_alpha_get(ps->brush);
+
+ return mask;
+}
+
+static int project_paint_pixel_sizeof(const short tool)
+{
+ if ((tool == PAINT_TOOL_CLONE) || (tool == PAINT_TOOL_SMEAR)) {
+ return sizeof(ProjPixelClone);
+ }
+ else {
+ return sizeof(ProjPixel);
+ }
+}
+
+
+/* run this function when we know a bucket's, face's pixel can be initialized,
+ * return the ProjPixel which is added to 'ps->bucketRect[bucket_index]' */
+static ProjPixel *project_paint_uvpixel_init(
+ const ProjPaintState *ps,
+ MemArena *arena,
+ const ImBuf *ibuf,
+ short x_px, short y_px,
+ const float mask,
+ const int face_index,
+ const int image_index,
+ const float pixelScreenCo[4],
+ const float world_spaceCo[3],
+ const int side,
+ const float w[3])
+{
+ ProjPixel *projPixel;
+
+ /* wrap pixel location */
+ x_px = x_px % ibuf->x;
+ if (x_px < 0) x_px += ibuf->x;
+ y_px = y_px % ibuf->y;
+ if (y_px < 0) y_px += ibuf->y;
+
+ BLI_assert(ps->pixel_sizeof == project_paint_pixel_sizeof(ps->tool));
+ projPixel = (ProjPixel *)BLI_memarena_alloc(arena, ps->pixel_sizeof);
+ //memset(projPixel, 0, size);
+
+ if (ibuf->rect_float) {
+ projPixel->pixel.f_pt = ibuf->rect_float + ((x_px + y_px * ibuf->x) * 4);
+ projPixel->origColor.f[0] = projPixel->newColor.f[0] = projPixel->pixel.f_pt[0];
+ projPixel->origColor.f[1] = projPixel->newColor.f[1] = projPixel->pixel.f_pt[1];
+ projPixel->origColor.f[2] = projPixel->newColor.f[2] = projPixel->pixel.f_pt[2];
+ projPixel->origColor.f[3] = projPixel->newColor.f[3] = projPixel->pixel.f_pt[3];
+ }
+ else {
+ projPixel->pixel.ch_pt = ((unsigned char *)ibuf->rect + ((x_px + y_px * ibuf->x) * 4));
+ projPixel->origColor.uint = projPixel->newColor.uint = *projPixel->pixel.uint_pt;
+ }
+
+ /* screenspace unclamped, we could keep its z and w values but don't need them at the moment */
+ if (ps->brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) {
+ copy_v3_v3(projPixel->worldCoSS, world_spaceCo);
+ }
+
+ copy_v2_v2(projPixel->projCoSS, pixelScreenCo);
+
+ projPixel->x_px = x_px;
+ projPixel->y_px = y_px;
+
+ projPixel->mask = (unsigned short)(mask * 65535);
+ projPixel->mask_max = 0;
+
+ /* which bounding box cell are we in?, needed for undo */
+ projPixel->bb_cell_index = ((int)(((float)x_px / (float)ibuf->x) * PROJ_BOUNDBOX_DIV)) +
+ ((int)(((float)y_px / (float)ibuf->y) * PROJ_BOUNDBOX_DIV)) * PROJ_BOUNDBOX_DIV;
+
+ /* done with view3d_project_float inline */
+ if (ps->tool == PAINT_TOOL_CLONE) {
+ if (ps->dm_mtface_clone) {
+ ImBuf *ibuf_other;
+ Image *other_tpage = project_paint_face_image(ps, ps->dm_mtface_clone, face_index);
+ const MTFace *tf_other = ps->dm_mtface_clone + face_index;
+
+ if (other_tpage && (ibuf_other = BKE_image_acquire_ibuf(other_tpage, NULL, NULL))) {
+ /* BKE_image_acquire_ibuf - TODO - this may be slow */
+
+ if (ibuf->rect_float) {
+ if (ibuf_other->rect_float) { /* from float to float */
+ project_face_pixel(tf_other, ibuf_other, w, side, NULL, ((ProjPixelClone *)projPixel)->clonepx.f);
+ }
+ else { /* from char to float */
+ unsigned char rgba_ub[4];
+ float rgba[4];
+ project_face_pixel(tf_other, ibuf_other, w, side, rgba_ub, NULL);
+ srgb_to_linearrgb_uchar4(rgba, rgba_ub);
+ straight_to_premul_v4_v4(((ProjPixelClone *)projPixel)->clonepx.f, rgba);
+ }
+ }
+ else {
+ if (ibuf_other->rect_float) { /* float to char */
+ float rgba[4];
+ project_face_pixel(tf_other, ibuf_other, w, side, NULL, rgba);
+ premul_to_straight_v4(rgba);
+ linearrgb_to_srgb_uchar3(((ProjPixelClone *)projPixel)->clonepx.ch, rgba);
+ }
+ else { /* char to char */
+ project_face_pixel(tf_other, ibuf_other, w, side, ((ProjPixelClone *)projPixel)->clonepx.ch, NULL);
+ }
+ }
+
+ BKE_image_release_ibuf(other_tpage, ibuf_other, NULL);
+ }
+ else {
+ if (ibuf->rect_float) {
+ ((ProjPixelClone *)projPixel)->clonepx.f[3] = 0;
+ }
+ else {
+ ((ProjPixelClone *)projPixel)->clonepx.ch[3] = 0;
+ }
+ }
+
+ }
+ else {
+ float co[2];
+ sub_v2_v2v2(co, projPixel->projCoSS, (float *)ps->cloneOffset);
+
+ /* no need to initialize the bucket, we're only checking buckets faces and for this
+ * the faces are already initialized in project_paint_delayed_face_init(...) */
+ if (ibuf->rect_float) {
+ if (!project_paint_PickColor(ps, co, ((ProjPixelClone *)projPixel)->clonepx.f, NULL, 1)) {
+ ((ProjPixelClone *)projPixel)->clonepx.f[3] = 0; /* zero alpha - ignore */
+ }
+ }
+ else {
+ if (!project_paint_PickColor(ps, co, NULL, ((ProjPixelClone *)projPixel)->clonepx.ch, 1)) {
+ ((ProjPixelClone *)projPixel)->clonepx.ch[3] = 0; /* zero alpha - ignore */
+ }
+ }
+ }
+ }
+
+#ifdef PROJ_DEBUG_PAINT
+ if (ibuf->rect_float) projPixel->pixel.f_pt[0] = 0;
+ else projPixel->pixel.ch_pt[0] = 0;
+#endif
+ projPixel->image_index = image_index;
+
+ return projPixel;
+}
+
+static int line_clip_rect2f(
+ rctf *rect,
+ const float l1[2], const float l2[2],
+ float l1_clip[2], float l2_clip[2])
+{
+ /* first account for horizontal, then vertical lines */
+ /* horiz */
+ if (fabsf(l1[1] - l2[1]) < PROJ_GEOM_TOLERANCE) {
+ /* is the line out of range on its Y axis? */
+ if (l1[1] < rect->ymin || l1[1] > rect->ymax) {
+ return 0;
+ }
+ /* line is out of range on its X axis */
+ if ((l1[0] < rect->xmin && l2[0] < rect->xmin) || (l1[0] > rect->xmax && l2[0] > rect->xmax)) {
+ return 0;
+ }
+
+
+ if (fabsf(l1[0] - l2[0]) < PROJ_GEOM_TOLERANCE) { /* this is a single point (or close to)*/
+ if (BLI_rctf_isect_pt_v(rect, l1)) {
+ copy_v2_v2(l1_clip, l1);
+ copy_v2_v2(l2_clip, l2);
+ return 1;
+ }
+ else {
+ return 0;
+ }
+ }
+
+ copy_v2_v2(l1_clip, l1);
+ copy_v2_v2(l2_clip, l2);
+ CLAMP(l1_clip[0], rect->xmin, rect->xmax);
+ CLAMP(l2_clip[0], rect->xmin, rect->xmax);
+ return 1;
+ }
+ else if (fabsf(l1[0] - l2[0]) < PROJ_GEOM_TOLERANCE) {
+ /* is the line out of range on its X axis? */
+ if (l1[0] < rect->xmin || l1[0] > rect->xmax) {
+ return 0;
+ }
+
+ /* line is out of range on its Y axis */
+ if ((l1[1] < rect->ymin && l2[1] < rect->ymin) || (l1[1] > rect->ymax && l2[1] > rect->ymax)) {
+ return 0;
+ }
+
+ if (fabsf(l1[1] - l2[1]) < PROJ_GEOM_TOLERANCE) { /* this is a single point (or close to)*/
+ if (BLI_rctf_isect_pt_v(rect, l1)) {
+ copy_v2_v2(l1_clip, l1);
+ copy_v2_v2(l2_clip, l2);
+ return 1;
+ }
+ else {
+ return 0;
+ }
+ }
+
+ copy_v2_v2(l1_clip, l1);
+ copy_v2_v2(l2_clip, l2);
+ CLAMP(l1_clip[1], rect->ymin, rect->ymax);
+ CLAMP(l2_clip[1], rect->ymin, rect->ymax);
+ return 1;
+ }
+ else {
+ float isect;
+ short ok1 = 0;
+ short ok2 = 0;
+
+ /* Done with vertical lines */
+
+ /* are either of the points inside the rectangle ? */
+ if (BLI_rctf_isect_pt_v(rect, l1)) {
+ copy_v2_v2(l1_clip, l1);
+ ok1 = 1;
+ }
+
+ if (BLI_rctf_isect_pt_v(rect, l2)) {
+ copy_v2_v2(l2_clip, l2);
+ ok2 = 1;
+ }
+
+ /* line inside rect */
+ if (ok1 && ok2) return 1;
+
+ /* top/bottom */
+ if (line_isect_y(l1, l2, rect->ymin, &isect) && (isect >= rect->xmin) && (isect <= rect->xmax)) {
+ if (l1[1] < l2[1]) { /* line 1 is outside */
+ l1_clip[0] = isect;
+ l1_clip[1] = rect->ymin;
+ ok1 = 1;
+ }
+ else {
+ l2_clip[0] = isect;
+ l2_clip[1] = rect->ymin;
+ ok2 = 2;
+ }
+ }
+
+ if (ok1 && ok2) return 1;
+
+ if (line_isect_y(l1, l2, rect->ymax, &isect) && (isect >= rect->xmin) && (isect <= rect->xmax)) {
+ if (l1[1] > l2[1]) { /* line 1 is outside */
+ l1_clip[0] = isect;
+ l1_clip[1] = rect->ymax;
+ ok1 = 1;
+ }
+ else {
+ l2_clip[0] = isect;
+ l2_clip[1] = rect->ymax;
+ ok2 = 2;
+ }
+ }
+
+ if (ok1 && ok2) return 1;
+
+ /* left/right */
+ if (line_isect_x(l1, l2, rect->xmin, &isect) && (isect >= rect->ymin) && (isect <= rect->ymax)) {
+ if (l1[0] < l2[0]) { /* line 1 is outside */
+ l1_clip[0] = rect->xmin;
+ l1_clip[1] = isect;
+ ok1 = 1;
+ }
+ else {
+ l2_clip[0] = rect->xmin;
+ l2_clip[1] = isect;
+ ok2 = 2;
+ }
+ }
+
+ if (ok1 && ok2) return 1;
+
+ if (line_isect_x(l1, l2, rect->xmax, &isect) && (isect >= rect->ymin) && (isect <= rect->ymax)) {
+ if (l1[0] > l2[0]) { /* line 1 is outside */
+ l1_clip[0] = rect->xmax;
+ l1_clip[1] = isect;
+ ok1 = 1;
+ }
+ else {
+ l2_clip[0] = rect->xmax;
+ l2_clip[1] = isect;
+ ok2 = 2;
+ }
+ }
+
+ if (ok1 && ok2) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+ }
+}
+
+
+
+/* scale the quad & tri about its center
+ * scaling by PROJ_FACE_SCALE_SEAM (0.99x) is used for getting fake UV pixel coords that are on the
+ * edge of the face but slightly inside it occlusion tests don't return hits on adjacent faces */
+#ifndef PROJ_DEBUG_NOSEAMBLEED
+static void scale_quad(float insetCos[4][3], float *origCos[4], const float inset)
+{
+ float cent[3];
+ cent[0] = (origCos[0][0] + origCos[1][0] + origCos[2][0] + origCos[3][0]) / 4.0f;
+ cent[1] = (origCos[0][1] + origCos[1][1] + origCos[2][1] + origCos[3][1]) / 4.0f;
+ cent[2] = (origCos[0][2] + origCos[1][2] + origCos[2][2] + origCos[3][2]) / 4.0f;
+
+ sub_v3_v3v3(insetCos[0], origCos[0], cent);
+ sub_v3_v3v3(insetCos[1], origCos[1], cent);
+ sub_v3_v3v3(insetCos[2], origCos[2], cent);
+ sub_v3_v3v3(insetCos[3], origCos[3], cent);
+
+ mul_v3_fl(insetCos[0], inset);
+ mul_v3_fl(insetCos[1], inset);
+ mul_v3_fl(insetCos[2], inset);
+ mul_v3_fl(insetCos[3], inset);
+
+ add_v3_v3(insetCos[0], cent);
+ add_v3_v3(insetCos[1], cent);
+ add_v3_v3(insetCos[2], cent);
+ add_v3_v3(insetCos[3], cent);
+}
+
+
+static void scale_tri(float insetCos[4][3], float *origCos[4], const float inset)
+{
+ float cent[3];
+ cent[0] = (origCos[0][0] + origCos[1][0] + origCos[2][0]) / 3.0f;
+ cent[1] = (origCos[0][1] + origCos[1][1] + origCos[2][1]) / 3.0f;
+ cent[2] = (origCos[0][2] + origCos[1][2] + origCos[2][2]) / 3.0f;
+
+ sub_v3_v3v3(insetCos[0], origCos[0], cent);
+ sub_v3_v3v3(insetCos[1], origCos[1], cent);
+ sub_v3_v3v3(insetCos[2], origCos[2], cent);
+
+ mul_v3_fl(insetCos[0], inset);
+ mul_v3_fl(insetCos[1], inset);
+ mul_v3_fl(insetCos[2], inset);
+
+ add_v3_v3(insetCos[0], cent);
+ add_v3_v3(insetCos[1], cent);
+ add_v3_v3(insetCos[2], cent);
+}
+#endif //PROJ_DEBUG_NOSEAMBLEED
+
+static float len_squared_v2v2_alt(const float *v1, const float v2_1, const float v2_2)
+{
+ float x, y;
+
+ x = v1[0] - v2_1;
+ y = v1[1] - v2_2;
+ return x * x + y * y;
+}
+
+/* note, use a squared value so we can use len_squared_v2v2
+ * be sure that you have done a bounds check first or this may fail */
+/* only give bucket_bounds as an arg because we need it elsewhere */
+static int project_bucket_isect_circle(const float cent[2], const float radius_squared, rctf *bucket_bounds)
+{
+
+ /* Would normally to a simple intersection test, however we know the bounds of these 2 already intersect
+ * so we only need to test if the center is inside the vertical or horizontal bounds on either axis,
+ * this is even less work then an intersection test
+ */
+#if 0
+ if (BLI_rctf_isect_pt_v(bucket_bounds, cent))
+ return 1;
+#endif
+
+ if ((bucket_bounds->xmin <= cent[0] && bucket_bounds->xmax >= cent[0]) ||
+ (bucket_bounds->ymin <= cent[1] && bucket_bounds->ymax >= cent[1]))
+ {
+ return 1;
+ }
+
+ /* out of bounds left */
+ if (cent[0] < bucket_bounds->xmin) {
+ /* lower left out of radius test */
+ if (cent[1] < bucket_bounds->ymin) {
+ return (len_squared_v2v2_alt(cent, bucket_bounds->xmin, bucket_bounds->ymin) < radius_squared) ? 1 : 0;
+ }
+ /* top left test */
+ else if (cent[1] > bucket_bounds->ymax) {
+ return (len_squared_v2v2_alt(cent, bucket_bounds->xmin, bucket_bounds->ymax) < radius_squared) ? 1 : 0;
+ }
+ }
+ else if (cent[0] > bucket_bounds->xmax) {
+ /* lower right out of radius test */
+ if (cent[1] < bucket_bounds->ymin) {
+ return (len_squared_v2v2_alt(cent, bucket_bounds->xmax, bucket_bounds->ymin) < radius_squared) ? 1 : 0;
+ }
+ /* top right test */
+ else if (cent[1] > bucket_bounds->ymax) {
+ return (len_squared_v2v2_alt(cent, bucket_bounds->xmax, bucket_bounds->ymax) < radius_squared) ? 1 : 0;
+ }
+ }
+
+ return 0;
+}
+
+
+
+/* Note for rect_to_uvspace_ortho() and rect_to_uvspace_persp()
+ * in ortho view this function gives good results when bucket_bounds are outside the triangle
+ * however in some cases, perspective view will mess up with faces that have minimal screenspace area
+ * (viewed from the side)
+ *
+ * for this reason its not reliable in this case so we'll use the Simple Barycentric'
+ * funcs that only account for points inside the triangle.
+ * however switching back to this for ortho is always an option */
+
+static void rect_to_uvspace_ortho(
+ rctf *bucket_bounds,
+ float *v1coSS, float *v2coSS, float *v3coSS,
+ float *uv1co, float *uv2co, float *uv3co,
+ float bucket_bounds_uv[4][2],
+ const int flip)
+{
+ float uv[2];
+ float w[3];
+
+ /* get the UV space bounding box */
+ uv[0] = bucket_bounds->xmax;
+ uv[1] = bucket_bounds->ymin;
+ barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w);
+ interp_v2_v2v2v2(bucket_bounds_uv[flip ? 3 : 0], uv1co, uv2co, uv3co, w);
+
+ //uv[0] = bucket_bounds->xmax; // set above
+ uv[1] = bucket_bounds->ymax;
+ barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w);
+ interp_v2_v2v2v2(bucket_bounds_uv[flip ? 2 : 1], uv1co, uv2co, uv3co, w);
+
+ uv[0] = bucket_bounds->xmin;
+ //uv[1] = bucket_bounds->ymax; // set above
+ barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w);
+ interp_v2_v2v2v2(bucket_bounds_uv[flip ? 1 : 2], uv1co, uv2co, uv3co, w);
+
+ //uv[0] = bucket_bounds->xmin; // set above
+ uv[1] = bucket_bounds->ymin;
+ barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w);
+ interp_v2_v2v2v2(bucket_bounds_uv[flip ? 0 : 3], uv1co, uv2co, uv3co, w);
+}
+
+/* same as above but use barycentric_weights_v2_persp */
+static void rect_to_uvspace_persp(
+ rctf *bucket_bounds,
+ float *v1coSS, float *v2coSS, float *v3coSS,
+ float *uv1co, float *uv2co, float *uv3co,
+ float bucket_bounds_uv[4][2],
+ const int flip
+ )
+{
+ float uv[2];
+ float w[3];
+
+ /* get the UV space bounding box */
+ uv[0] = bucket_bounds->xmax;
+ uv[1] = bucket_bounds->ymin;
+ barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w);
+ interp_v2_v2v2v2(bucket_bounds_uv[flip ? 3 : 0], uv1co, uv2co, uv3co, w);
+
+ //uv[0] = bucket_bounds->xmax; // set above
+ uv[1] = bucket_bounds->ymax;
+ barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w);
+ interp_v2_v2v2v2(bucket_bounds_uv[flip ? 2 : 1], uv1co, uv2co, uv3co, w);
+
+ uv[0] = bucket_bounds->xmin;
+ //uv[1] = bucket_bounds->ymax; // set above
+ barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w);
+ interp_v2_v2v2v2(bucket_bounds_uv[flip ? 1 : 2], uv1co, uv2co, uv3co, w);
+
+ //uv[0] = bucket_bounds->xmin; // set above
+ uv[1] = bucket_bounds->ymin;
+ barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w);
+ interp_v2_v2v2v2(bucket_bounds_uv[flip ? 0 : 3], uv1co, uv2co, uv3co, w);
+}
+
+/* This works as we need it to but we can save a few steps and not use it */
+
+#if 0
+static float angle_2d_clockwise(const float p1[2], const float p2[2], const float p3[2])
+{
+ float v1[2], v2[2];
+
+ v1[0] = p1[0] - p2[0]; v1[1] = p1[1] - p2[1];
+ v2[0] = p3[0] - p2[0]; v2[1] = p3[1] - p2[1];
+
+ return -atan2(v1[0] * v2[1] - v1[1] * v2[0], v1[0] * v2[0] + v1[1] * v2[1]);
+}
+#endif
+
+#define ISECT_1 (1)
+#define ISECT_2 (1 << 1)
+#define ISECT_3 (1 << 2)
+#define ISECT_4 (1 << 3)
+#define ISECT_ALL3 ((1 << 3) - 1)
+#define ISECT_ALL4 ((1 << 4) - 1)
+
+/* limit must be a fraction over 1.0f */
+static int IsectPT2Df_limit(float pt[2], float v1[2], float v2[2], float v3[2], float limit)
+{
+ return ((area_tri_v2(pt, v1, v2) + area_tri_v2(pt, v2, v3) + area_tri_v2(pt, v3, v1)) / (area_tri_v2(v1, v2, v3))) < limit;
+}
+
+/* Clip the face by a bucket and set the uv-space bucket_bounds_uv
+ * so we have the clipped UV's to do pixel intersection tests with
+ * */
+static int float_z_sort_flip(const void *p1, const void *p2)
+{
+ return (((float *)p1)[2] < ((float *)p2)[2] ? 1 : -1);
+}
+
+static int float_z_sort(const void *p1, const void *p2)
+{
+ return (((float *)p1)[2] < ((float *)p2)[2] ? -1 : 1);
+}
+
+static void project_bucket_clip_face(
+ const int is_ortho,
+ rctf *bucket_bounds,
+ float *v1coSS, float *v2coSS, float *v3coSS,
+ float *uv1co, float *uv2co, float *uv3co,
+ float bucket_bounds_uv[8][2],
+ int *tot)
+{
+ int inside_bucket_flag = 0;
+ int inside_face_flag = 0;
+ const int flip = ((line_point_side_v2(v1coSS, v2coSS, v3coSS) > 0.0f) != (line_point_side_v2(uv1co, uv2co, uv3co) > 0.0f));
+
+ float bucket_bounds_ss[4][2];
+
+ /* get the UV space bounding box */
+ inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v1coSS);
+ inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v2coSS) << 1;
+ inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v3coSS) << 2;
+
+ if (inside_bucket_flag == ISECT_ALL3) {
+ /* all screenspace points are inside the bucket bounding box, this means we don't need to clip and can simply return the UVs */
+ if (flip) { /* facing the back? */
+ copy_v2_v2(bucket_bounds_uv[0], uv3co);
+ copy_v2_v2(bucket_bounds_uv[1], uv2co);
+ copy_v2_v2(bucket_bounds_uv[2], uv1co);
+ }
+ else {
+ copy_v2_v2(bucket_bounds_uv[0], uv1co);
+ copy_v2_v2(bucket_bounds_uv[1], uv2co);
+ copy_v2_v2(bucket_bounds_uv[2], uv3co);
+ }
+
+ *tot = 3;
+ return;
+ }
+
+ /* get the UV space bounding box */
+ /* use IsectPT2Df_limit here so we catch points are are touching the tri edge (or a small fraction over) */
+ bucket_bounds_ss[0][0] = bucket_bounds->xmax;
+ bucket_bounds_ss[0][1] = bucket_bounds->ymin;
+ inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[0], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ? ISECT_1 : 0);
+
+ bucket_bounds_ss[1][0] = bucket_bounds->xmax;
+ bucket_bounds_ss[1][1] = bucket_bounds->ymax;
+ inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[1], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ? ISECT_2 : 0);
+
+ bucket_bounds_ss[2][0] = bucket_bounds->xmin;
+ bucket_bounds_ss[2][1] = bucket_bounds->ymax;
+ inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[2], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ? ISECT_3 : 0);
+
+ bucket_bounds_ss[3][0] = bucket_bounds->xmin;
+ bucket_bounds_ss[3][1] = bucket_bounds->ymin;
+ inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[3], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ? ISECT_4 : 0);
+
+ if (inside_face_flag == ISECT_ALL4) {
+ /* bucket is totally inside the screenspace face, we can safely use weights */
+
+ if (is_ortho) rect_to_uvspace_ortho(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, bucket_bounds_uv, flip);
+ else rect_to_uvspace_persp(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, bucket_bounds_uv, flip);
+
+ *tot = 4;
+ return;
+ }
+ else {
+ /* The Complicated Case!
+ *
+ * The 2 cases above are where the face is inside the bucket or the bucket is inside the face.
+ *
+ * we need to make a convex polyline from the intersection between the screenspace face
+ * and the bucket bounds.
+ *
+ * There are a number of ways this could be done, currently it just collects all intersecting verts,
+ * and line intersections, then sorts them clockwise, this is a lot easier then evaluating the geometry to
+ * do a correct clipping on both shapes. */
+
+
+ /* add a bunch of points, we know must make up the convex hull which is the clipped rect and triangle */
+
+
+
+ /* Maximum possible 6 intersections when using a rectangle and triangle */
+ float isectVCosSS[8][3]; /* The 3rd float is used to store angle for qsort(), NOT as a Z location */
+ float v1_clipSS[2], v2_clipSS[2];
+ float w[3];
+
+ /* calc center */
+ float cent[2] = {0.0f, 0.0f};
+ /*float up[2] = {0.0f, 1.0f};*/
+ int i;
+ short doubles;
+
+ (*tot) = 0;
+
+ if (inside_face_flag & ISECT_1) { copy_v2_v2(isectVCosSS[*tot], bucket_bounds_ss[0]); (*tot)++; }
+ if (inside_face_flag & ISECT_2) { copy_v2_v2(isectVCosSS[*tot], bucket_bounds_ss[1]); (*tot)++; }
+ if (inside_face_flag & ISECT_3) { copy_v2_v2(isectVCosSS[*tot], bucket_bounds_ss[2]); (*tot)++; }
+ if (inside_face_flag & ISECT_4) { copy_v2_v2(isectVCosSS[*tot], bucket_bounds_ss[3]); (*tot)++; }
+
+ if (inside_bucket_flag & ISECT_1) { copy_v2_v2(isectVCosSS[*tot], v1coSS); (*tot)++; }
+ if (inside_bucket_flag & ISECT_2) { copy_v2_v2(isectVCosSS[*tot], v2coSS); (*tot)++; }
+ if (inside_bucket_flag & ISECT_3) { copy_v2_v2(isectVCosSS[*tot], v3coSS); (*tot)++; }
+
+ if ((inside_bucket_flag & (ISECT_1 | ISECT_2)) != (ISECT_1 | ISECT_2)) {
+ if (line_clip_rect2f(bucket_bounds, v1coSS, v2coSS, v1_clipSS, v2_clipSS)) {
+ if ((inside_bucket_flag & ISECT_1) == 0) { copy_v2_v2(isectVCosSS[*tot], v1_clipSS); (*tot)++; }
+ if ((inside_bucket_flag & ISECT_2) == 0) { copy_v2_v2(isectVCosSS[*tot], v2_clipSS); (*tot)++; }
+ }
+ }
+
+ if ((inside_bucket_flag & (ISECT_2 | ISECT_3)) != (ISECT_2 | ISECT_3)) {
+ if (line_clip_rect2f(bucket_bounds, v2coSS, v3coSS, v1_clipSS, v2_clipSS)) {
+ if ((inside_bucket_flag & ISECT_2) == 0) { copy_v2_v2(isectVCosSS[*tot], v1_clipSS); (*tot)++; }
+ if ((inside_bucket_flag & ISECT_3) == 0) { copy_v2_v2(isectVCosSS[*tot], v2_clipSS); (*tot)++; }
+ }
+ }
+
+ if ((inside_bucket_flag & (ISECT_3 | ISECT_1)) != (ISECT_3 | ISECT_1)) {
+ if (line_clip_rect2f(bucket_bounds, v3coSS, v1coSS, v1_clipSS, v2_clipSS)) {
+ if ((inside_bucket_flag & ISECT_3) == 0) { copy_v2_v2(isectVCosSS[*tot], v1_clipSS); (*tot)++; }
+ if ((inside_bucket_flag & ISECT_1) == 0) { copy_v2_v2(isectVCosSS[*tot], v2_clipSS); (*tot)++; }
+ }
+ }
+
+
+ if ((*tot) < 3) { /* no intersections to speak of */
+ *tot = 0;
+ return;
+ }
+
+ /* now we have all points we need, collect their angles and sort them clockwise */
+
+ for (i = 0; i < (*tot); i++) {
+ cent[0] += isectVCosSS[i][0];
+ cent[1] += isectVCosSS[i][1];
+ }
+ cent[0] = cent[0] / (float)(*tot);
+ cent[1] = cent[1] / (float)(*tot);
+
+
+
+ /* Collect angles for every point around the center point */
+
+
+#if 0 /* uses a few more cycles then the above loop */
+ for (i = 0; i < (*tot); i++) {
+ isectVCosSS[i][2] = angle_2d_clockwise(up, cent, isectVCosSS[i]);
+ }
+#endif
+
+ v1_clipSS[0] = cent[0]; /* Abuse this var for the loop below */
+ v1_clipSS[1] = cent[1] + 1.0f;
+
+ for (i = 0; i < (*tot); i++) {
+ v2_clipSS[0] = isectVCosSS[i][0] - cent[0];
+ v2_clipSS[1] = isectVCosSS[i][1] - cent[1];
+ isectVCosSS[i][2] = atan2f(v1_clipSS[0] * v2_clipSS[1] - v1_clipSS[1] * v2_clipSS[0], v1_clipSS[0] * v2_clipSS[0] + v1_clipSS[1] * v2_clipSS[1]);
+ }
+
+ if (flip) qsort(isectVCosSS, *tot, sizeof(float) * 3, float_z_sort_flip);
+ else qsort(isectVCosSS, *tot, sizeof(float) * 3, float_z_sort);
+
+ /* remove doubles */
+ /* first/last check */
+ if (fabsf(isectVCosSS[0][0] - isectVCosSS[(*tot) - 1][0]) < PROJ_GEOM_TOLERANCE &&
+ fabsf(isectVCosSS[0][1] - isectVCosSS[(*tot) - 1][1]) < PROJ_GEOM_TOLERANCE)
+ {
+ (*tot)--;
+ }
+
+ /* its possible there is only a few left after remove doubles */
+ if ((*tot) < 3) {
+ // printf("removed too many doubles A\n");
+ *tot = 0;
+ return;
+ }
+
+ doubles = TRUE;
+ while (doubles == TRUE) {
+ doubles = FALSE;
+ for (i = 1; i < (*tot); i++) {
+ if (fabsf(isectVCosSS[i - 1][0] - isectVCosSS[i][0]) < PROJ_GEOM_TOLERANCE &&
+ fabsf(isectVCosSS[i - 1][1] - isectVCosSS[i][1]) < PROJ_GEOM_TOLERANCE)
+ {
+ int j;
+ for (j = i + 1; j < (*tot); j++) {
+ isectVCosSS[j - 1][0] = isectVCosSS[j][0];
+ isectVCosSS[j - 1][1] = isectVCosSS[j][1];
+ }
+ doubles = TRUE; /* keep looking for more doubles */
+ (*tot)--;
+ }
+ }
+ }
+
+ /* its possible there is only a few left after remove doubles */
+ if ((*tot) < 3) {
+ // printf("removed too many doubles B\n");
+ *tot = 0;
+ return;
+ }
+
+
+ if (is_ortho) {
+ for (i = 0; i < (*tot); i++) {
+ barycentric_weights_v2(v1coSS, v2coSS, v3coSS, isectVCosSS[i], w);
+ interp_v2_v2v2v2(bucket_bounds_uv[i], uv1co, uv2co, uv3co, w);
+ }
+ }
+ else {
+ for (i = 0; i < (*tot); i++) {
+ barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, isectVCosSS[i], w);
+ interp_v2_v2v2v2(bucket_bounds_uv[i], uv1co, uv2co, uv3co, w);
+ }
+ }
+ }
+
+#ifdef PROJ_DEBUG_PRINT_CLIP
+ /* include this at the bottom of the above function to debug the output */
+
+ {
+ /* If there are ever any problems, */
+ float test_uv[4][2];
+ int i;
+ if (is_ortho) rect_to_uvspace_ortho(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, test_uv, flip);
+ else rect_to_uvspace_persp(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, test_uv, flip);
+ printf("( [(%f,%f), (%f,%f), (%f,%f), (%f,%f)], ", test_uv[0][0], test_uv[0][1], test_uv[1][0], test_uv[1][1], test_uv[2][0], test_uv[2][1], test_uv[3][0], test_uv[3][1]);
+
+ printf(" [(%f,%f), (%f,%f), (%f,%f)], ", uv1co[0], uv1co[1], uv2co[0], uv2co[1], uv3co[0], uv3co[1]);
+
+ printf("[");
+ for (i = 0; i < (*tot); i++) {
+ printf("(%f, %f),", bucket_bounds_uv[i][0], bucket_bounds_uv[i][1]);
+ }
+ printf("]),\\\n");
+ }
+#endif
+}
+
+/*
+ * # This script creates faces in a blender scene from printed data above.
+ *
+ * project_ls = [
+ * ...(output from above block)...
+ * ]
+ *
+ * from Blender import Scene, Mesh, Window, sys, Mathutils
+ *
+ * import bpy
+ *
+ * V = Mathutils.Vector
+ *
+ * def main():
+ * sce = bpy.data.scenes.active
+ *
+ * for item in project_ls:
+ * bb = item[0]
+ * uv = item[1]
+ * poly = item[2]
+ *
+ * me = bpy.data.meshes.new()
+ * ob = sce.objects.new(me)
+ *
+ * me.verts.extend([V(bb[0]).xyz, V(bb[1]).xyz, V(bb[2]).xyz, V(bb[3]).xyz])
+ * me.faces.extend([(0,1,2,3),])
+ * me.verts.extend([V(uv[0]).xyz, V(uv[1]).xyz, V(uv[2]).xyz])
+ * me.faces.extend([(4,5,6),])
+ *
+ * vs = [V(p).xyz for p in poly]
+ * print len(vs)
+ * l = len(me.verts)
+ * me.verts.extend(vs)
+ *
+ * i = l
+ * while i < len(me.verts):
+ * ii = i + 1
+ * if ii == len(me.verts):
+ * ii = l
+ * me.edges.extend([i, ii])
+ * i += 1
+ *
+ * if __name__ == '__main__':
+ * main()
+ */
+
+
+#undef ISECT_1
+#undef ISECT_2
+#undef ISECT_3
+#undef ISECT_4
+#undef ISECT_ALL3
+#undef ISECT_ALL4
+
+
+/* checks if pt is inside a convex 2D polyline, the polyline must be ordered rotating clockwise
+ * otherwise it would have to test for mixed (line_point_side_v2 > 0.0f) cases */
+static int IsectPoly2Df(const float pt[2], float uv[][2], const int tot)
+{
+ int i;
+ if (line_point_side_v2(uv[tot - 1], uv[0], pt) < 0.0f)
+ return 0;
+
+ for (i = 1; i < tot; i++) {
+ if (line_point_side_v2(uv[i - 1], uv[i], pt) < 0.0f)
+ return 0;
+
+ }
+
+ return 1;
+}
+static int IsectPoly2Df_twoside(const float pt[2], float uv[][2], const int tot)
+{
+ int i;
+ int side = (line_point_side_v2(uv[tot - 1], uv[0], pt) > 0.0f);
+
+ for (i = 1; i < tot; i++) {
+ if ((line_point_side_v2(uv[i - 1], uv[i], pt) > 0.0f) != side)
+ return 0;
+
+ }
+
+ return 1;
+}
+
+/* One of the most important function for projection painting, since it selects the pixels to be added into each bucket.
+ * initialize pixels from this face where it intersects with the bucket_index, optionally initialize pixels for removing seams */
+static void project_paint_face_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, const int face_index, const int image_index, rctf *bucket_bounds, const ImBuf *ibuf, const short clamp_u, const short clamp_v)
+{
+ /* Projection vars, to get the 3D locations into screen space */
+ MemArena *arena = ps->arena_mt[thread_index];
+ LinkNode **bucketPixelNodes = ps->bucketRect + bucket_index;
+ LinkNode *bucketFaceNodes = ps->bucketFaces[bucket_index];
+
+ const MFace *mf = ps->dm_mface + face_index;
+ const MTFace *tf = ps->dm_mtface + face_index;
+
+ /* UV/pixel seeking data */
+ int x; /* Image X-Pixel */
+ int y; /* Image Y-Pixel */
+ float mask;
+ float uv[2]; /* Image floating point UV - same as x, y but from 0.0-1.0 */
+
+ int side;
+ float *v1coSS, *v2coSS, *v3coSS; /* vert co screen-space, these will be assigned to mf->v1,2,3 or mf->v1,3,4 */
+
+ float *vCo[4]; /* vertex screenspace coords */
+
+ float w[3], wco[3];
+
+ float *uv1co, *uv2co, *uv3co; /* for convenience only, these will be assigned to tf->uv[0],1,2 or tf->uv[0],2,3 */
+ float pixelScreenCo[4];
+ bool do_3d_mapping = ps->brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D;
+
+ rcti bounds_px; /* ispace bounds */
+ /* vars for getting uvspace bounds */
+
+ float tf_uv_pxoffset[4][2]; /* bucket bounds in UV space so we can init pixels only for this face, */
+ float xhalfpx, yhalfpx;
+ const float ibuf_xf = (float)ibuf->x, ibuf_yf = (float)ibuf->y;
+
+ int has_x_isect = 0, has_isect = 0; /* for early loop exit */
+
+ int i1, i2, i3;
+
+ float uv_clip[8][2];
+ int uv_clip_tot;
+ const short is_ortho = ps->is_ortho;
+ const short do_backfacecull = ps->do_backfacecull;
+ const short do_clip = ps->rv3d ? ps->rv3d->rflag & RV3D_CLIPPING : 0;
+
+ vCo[0] = ps->dm_mvert[mf->v1].co;
+ vCo[1] = ps->dm_mvert[mf->v2].co;
+ vCo[2] = ps->dm_mvert[mf->v3].co;
+
+
+ /* Use tf_uv_pxoffset instead of tf->uv so we can offset the UV half a pixel
+ * this is done so we can avoid offsetting all the pixels by 0.5 which causes
+ * problems when wrapping negative coords */
+ xhalfpx = (0.5f + (PROJ_GEOM_TOLERANCE / 3.0f)) / ibuf_xf;
+ yhalfpx = (0.5f + (PROJ_GEOM_TOLERANCE / 4.0f)) / ibuf_yf;
+
+ /* Note about (PROJ_GEOM_TOLERANCE/x) above...
+ * Needed to add this offset since UV coords are often quads aligned to pixels.
+ * In this case pixels can be exactly between 2 triangles causing nasty
+ * artifacts.
+ *
+ * This workaround can be removed and painting will still work on most cases
+ * but since the first thing most people try is painting onto a quad- better make it work.
+ */
+
+
+
+ tf_uv_pxoffset[0][0] = tf->uv[0][0] - xhalfpx;
+ tf_uv_pxoffset[0][1] = tf->uv[0][1] - yhalfpx;
+
+ tf_uv_pxoffset[1][0] = tf->uv[1][0] - xhalfpx;
+ tf_uv_pxoffset[1][1] = tf->uv[1][1] - yhalfpx;
+
+ tf_uv_pxoffset[2][0] = tf->uv[2][0] - xhalfpx;
+ tf_uv_pxoffset[2][1] = tf->uv[2][1] - yhalfpx;
+
+ if (mf->v4) {
+ vCo[3] = ps->dm_mvert[mf->v4].co;
+
+ tf_uv_pxoffset[3][0] = tf->uv[3][0] - xhalfpx;
+ tf_uv_pxoffset[3][1] = tf->uv[3][1] - yhalfpx;
+ side = 1;
+ }
+ else {
+ side = 0;
+ }
+
+ do {
+ if (side == 1) {
+ i1 = 0; i2 = 2; i3 = 3;
+ }
+ else {
+ i1 = 0; i2 = 1; i3 = 2;
+ }
+
+ uv1co = tf_uv_pxoffset[i1]; // was tf->uv[i1];
+ uv2co = tf_uv_pxoffset[i2]; // was tf->uv[i2];
+ uv3co = tf_uv_pxoffset[i3]; // was tf->uv[i3];
+
+ v1coSS = ps->screenCoords[(*(&mf->v1 + i1))];
+ v2coSS = ps->screenCoords[(*(&mf->v1 + i2))];
+ v3coSS = ps->screenCoords[(*(&mf->v1 + i3))];
+
+ /* This funtion gives is a concave polyline in UV space from the clipped quad and tri*/
+ project_bucket_clip_face(
+ is_ortho, bucket_bounds,
+ v1coSS, v2coSS, v3coSS,
+ uv1co, uv2co, uv3co,
+ uv_clip, &uv_clip_tot
+ );
+
+ /* sometimes this happens, better just allow for 8 intersectiosn even though there should be max 6 */
+#if 0
+ if (uv_clip_tot > 6) {
+ printf("this should never happen! %d\n", uv_clip_tot);
+ }
+#endif
+
+ if (pixel_bounds_array(uv_clip, &bounds_px, ibuf->x, ibuf->y, uv_clip_tot)) {
+
+ if (clamp_u) {
+ CLAMP(bounds_px.xmin, 0, ibuf->x);
+ CLAMP(bounds_px.xmax, 0, ibuf->x);
+ }
+
+ if (clamp_v) {
+ CLAMP(bounds_px.ymin, 0, ibuf->y);
+ CLAMP(bounds_px.ymax, 0, ibuf->y);
+ }
+
+ /* clip face and */
+
+ has_isect = 0;
+ for (y = bounds_px.ymin; y < bounds_px.ymax; y++) {
+ //uv[1] = (((float)y) + 0.5f) / (float)ibuf->y;
+ uv[1] = (float)y / ibuf_yf; /* use pixel offset UV coords instead */
+
+ has_x_isect = 0;
+ for (x = bounds_px.xmin; x < bounds_px.xmax; x++) {
+ //uv[0] = (((float)x) + 0.5f) / ibuf->x;
+ uv[0] = (float)x / ibuf_xf; /* use pixel offset UV coords instead */
+
+ /* Note about IsectPoly2Df_twoside, checking the face or uv flipping doesnt work,
+ * could check the poly direction but better to do this */
+ if ((do_backfacecull == TRUE && IsectPoly2Df(uv, uv_clip, uv_clip_tot)) ||
+ (do_backfacecull == FALSE && IsectPoly2Df_twoside(uv, uv_clip, uv_clip_tot)))
+ {
+
+ has_x_isect = has_isect = 1;
+
+ if (is_ortho) screen_px_from_ortho(uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w);
+ else screen_px_from_persp(uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w);
+
+ /* a pity we need to get the worldspace pixel location here */
+ if (do_clip || do_3d_mapping) {
+ interp_v3_v3v3v3(wco, ps->dm_mvert[(*(&mf->v1 + i1))].co, ps->dm_mvert[(*(&mf->v1 + i2))].co, ps->dm_mvert[(*(&mf->v1 + i3))].co, w);
+ if (do_clip && ED_view3d_clipping_test(ps->rv3d, wco, TRUE)) {
+ continue; /* Watch out that no code below this needs to run */
+ }
+ }
+
+ /* Is this UV visible from the view? - raytrace */
+ /* project_paint_PickFace is less complex, use for testing */
+ //if (project_paint_PickFace(ps, pixelScreenCo, w, &side) == face_index) {
+ if ((ps->do_occlude == FALSE) ||
+ !project_bucket_point_occluded(ps, bucketFaceNodes, face_index, pixelScreenCo))
+ {
+ mask = project_paint_uvpixel_mask(ps, face_index, side, w);
+
+ if (mask > 0.0f) {
+ BLI_linklist_prepend_arena(
+ bucketPixelNodes,
+ project_paint_uvpixel_init(ps, arena, ibuf, x, y, mask, face_index,
+ image_index, pixelScreenCo, wco, side, w),
+ arena
+ );
+ }
+ }
+
+ }
+//#if 0
+ else if (has_x_isect) {
+ /* assuming the face is not a bow-tie - we know we cant intersect again on the X */
+ break;
+ }
+//#endif
+ }
+
+
+#if 0 /* TODO - investigate why this dosnt work sometimes! it should! */
+ /* no intersection for this entire row, after some intersection above means we can quit now */
+ if (has_x_isect == 0 && has_isect) {
+ break;
+ }
+#endif
+ }
+ }
+ } while (side--);
+
+
+
+#ifndef PROJ_DEBUG_NOSEAMBLEED
+ if (ps->seam_bleed_px > 0.0f) {
+ int face_seam_flag;
+
+ if (ps->thread_tot > 1)
+ BLI_lock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */
+
+ face_seam_flag = ps->faceSeamFlags[face_index];
+
+ /* are any of our edges un-initialized? */
+ if ((face_seam_flag & (PROJ_FACE_SEAM1 | PROJ_FACE_NOSEAM1)) == 0 ||
+ (face_seam_flag & (PROJ_FACE_SEAM2 | PROJ_FACE_NOSEAM2)) == 0 ||
+ (face_seam_flag & (PROJ_FACE_SEAM3 | PROJ_FACE_NOSEAM3)) == 0 ||
+ (face_seam_flag & (PROJ_FACE_SEAM4 | PROJ_FACE_NOSEAM4)) == 0)
+ {
+ project_face_seams_init(ps, face_index, mf->v4);
+ face_seam_flag = ps->faceSeamFlags[face_index];
+ //printf("seams - %d %d %d %d\n", flag&PROJ_FACE_SEAM1, flag&PROJ_FACE_SEAM2, flag&PROJ_FACE_SEAM3, flag&PROJ_FACE_SEAM4);
+ }
+
+ if ((face_seam_flag & (PROJ_FACE_SEAM1 | PROJ_FACE_SEAM2 | PROJ_FACE_SEAM3 | PROJ_FACE_SEAM4)) == 0) {
+
+ if (ps->thread_tot > 1)
+ BLI_unlock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */
+
+ }
+ else {
+ /* we have a seam - deal with it! */
+
+ /* Now create new UV's for the seam face */
+ float (*outset_uv)[2] = ps->faceSeamUVs[face_index];
+ float insetCos[4][3]; /* inset face coords. NOTE!!! ScreenSace for ortho, Worldspace in prespective view */
+
+ float *vCoSS[4]; /* vertex screenspace coords */
+
+ float bucket_clip_edges[2][2]; /* store the screenspace coords of the face, clipped by the bucket's screen aligned rectangle */
+ float edge_verts_inset_clip[2][3];
+ int fidx1, fidx2; /* face edge pairs - loop throuh these ((0,1), (1,2), (2,3), (3,0)) or ((0,1), (1,2), (2,0)) for a tri */
+
+ float seam_subsection[4][2];
+ float fac1, fac2, ftot;
+
+
+ if (outset_uv[0][0] == FLT_MAX) /* first time initialize */
+ uv_image_outset(tf_uv_pxoffset, outset_uv, ps->seam_bleed_px, ibuf->x, ibuf->y, mf->v4);
+
+ /* ps->faceSeamUVs cant be modified when threading, now this is done we can unlock */
+ if (ps->thread_tot > 1)
+ BLI_unlock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */
+
+ vCoSS[0] = ps->screenCoords[mf->v1];
+ vCoSS[1] = ps->screenCoords[mf->v2];
+ vCoSS[2] = ps->screenCoords[mf->v3];
+ if (mf->v4)
+ vCoSS[3] = ps->screenCoords[mf->v4];
+
+ /* PROJ_FACE_SCALE_SEAM must be slightly less then 1.0f */
+ if (is_ortho) {
+ if (mf->v4) scale_quad(insetCos, vCoSS, PROJ_FACE_SCALE_SEAM);
+ else scale_tri(insetCos, vCoSS, PROJ_FACE_SCALE_SEAM);
+ }
+ else {
+ if (mf->v4) scale_quad(insetCos, vCo, PROJ_FACE_SCALE_SEAM);
+ else scale_tri(insetCos, vCo, PROJ_FACE_SCALE_SEAM);
+ }
+
+ side = 0; /* for triangles this wont need to change */
+
+ for (fidx1 = 0; fidx1 < (mf->v4 ? 4 : 3); fidx1++) {
+ if (mf->v4) fidx2 = (fidx1 == 3) ? 0 : fidx1 + 1; /* next fidx in the face (0,1,2,3) -> (1,2,3,0) */
+ else fidx2 = (fidx1 == 2) ? 0 : fidx1 + 1; /* next fidx in the face (0,1,2) -> (1,2,0) */
+
+ if ((face_seam_flag & (1 << fidx1)) && /* 1<<fidx1 -> PROJ_FACE_SEAM# */
+ line_clip_rect2f(bucket_bounds, vCoSS[fidx1], vCoSS[fidx2], bucket_clip_edges[0], bucket_clip_edges[1]))
+ {
+
+ ftot = len_v2v2(vCoSS[fidx1], vCoSS[fidx2]); /* screenspace edge length */
+
+ if (ftot > 0.0f) { /* avoid div by zero */
+ if (mf->v4) {
+ if (fidx1 == 2 || fidx2 == 2) side = 1;
+ else side = 0;
+ }
+
+ fac1 = len_v2v2(vCoSS[fidx1], bucket_clip_edges[0]) / ftot;
+ fac2 = len_v2v2(vCoSS[fidx1], bucket_clip_edges[1]) / ftot;
+
+ interp_v2_v2v2(seam_subsection[0], tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2], fac1);
+ interp_v2_v2v2(seam_subsection[1], tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2], fac2);
+
+ interp_v2_v2v2(seam_subsection[2], outset_uv[fidx1], outset_uv[fidx2], fac2);
+ interp_v2_v2v2(seam_subsection[3], outset_uv[fidx1], outset_uv[fidx2], fac1);
+
+ /* if the bucket_clip_edges values Z values was kept we could avoid this
+ * Inset needs to be added so occlusion tests wont hit adjacent faces */
+ interp_v3_v3v3(edge_verts_inset_clip[0], insetCos[fidx1], insetCos[fidx2], fac1);
+ interp_v3_v3v3(edge_verts_inset_clip[1], insetCos[fidx1], insetCos[fidx2], fac2);
+
+
+ if (pixel_bounds_uv(seam_subsection[0], seam_subsection[1], seam_subsection[2], seam_subsection[3], &bounds_px, ibuf->x, ibuf->y, 1)) {
+ /* bounds between the seam rect and the uvspace bucket pixels */
+
+ has_isect = 0;
+ for (y = bounds_px.ymin; y < bounds_px.ymax; y++) {
+ // uv[1] = (((float)y) + 0.5f) / (float)ibuf->y;
+ uv[1] = (float)y / ibuf_yf; /* use offset uvs instead */
+
+ has_x_isect = 0;
+ for (x = bounds_px.xmin; x < bounds_px.xmax; x++) {
+ //uv[0] = (((float)x) + 0.5f) / (float)ibuf->x;
+ uv[0] = (float)x / ibuf_xf; /* use offset uvs instead */
+
+ /* test we're inside uvspace bucket and triangle bounds */
+ if (isect_point_quad_v2(uv, seam_subsection[0], seam_subsection[1], seam_subsection[2], seam_subsection[3])) {
+ float fac;
+
+ /* We need to find the closest point along the face edge,
+ * getting the screen_px_from_*** wont work because our actual location
+ * is not relevant, since we are outside the face, Use VecLerpf to find
+ * our location on the side of the face's UV */
+#if 0
+ if (is_ortho) screen_px_from_ortho(ps, uv, v1co, v2co, v3co, uv1co, uv2co, uv3co, pixelScreenCo);
+ else screen_px_from_persp(ps, uv, v1co, v2co, v3co, uv1co, uv2co, uv3co, pixelScreenCo);
+#endif
+
+ /* Since this is a seam we need to work out where on the line this pixel is */
+ //fac = line_point_factor_v2(uv, uv_seam_quad[0], uv_seam_quad[1]);
+
+ fac = line_point_factor_v2(uv, seam_subsection[0], seam_subsection[1]);
+ if (fac < 0.0f) { copy_v3_v3(pixelScreenCo, edge_verts_inset_clip[0]); }
+ else if (fac > 1.0f) { copy_v3_v3(pixelScreenCo, edge_verts_inset_clip[1]); }
+ else { interp_v3_v3v3(pixelScreenCo, edge_verts_inset_clip[0], edge_verts_inset_clip[1], fac); }
+
+ if (!is_ortho) {
+ pixelScreenCo[3] = 1.0f;
+ mul_m4_v4((float(*)[4])ps->projectMat, pixelScreenCo); /* cast because of const */
+ pixelScreenCo[0] = (float)(ps->winx / 2.0f) + (ps->winx / 2.0f) * pixelScreenCo[0] / pixelScreenCo[3];
+ pixelScreenCo[1] = (float)(ps->winy / 2.0f) + (ps->winy / 2.0f) * pixelScreenCo[1] / pixelScreenCo[3];
+ pixelScreenCo[2] = pixelScreenCo[2] / pixelScreenCo[3]; /* Use the depth for bucket point occlusion */
+ }
+
+ if ((ps->do_occlude == FALSE) ||
+ !project_bucket_point_occluded(ps, bucketFaceNodes, face_index, pixelScreenCo))
+ {
+ /* Only bother calculating the weights if we intersect */
+ if (ps->do_mask_normal || ps->dm_mtface_clone) {
+#if 1
+ /* get the UV on the line since we want to copy the pixels from there for bleeding */
+ float uv_close[2];
+ float uv_fac = closest_to_line_v2(uv_close, uv, tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2]);
+ if (uv_fac < 0.0f) copy_v2_v2(uv_close, tf_uv_pxoffset[fidx1]);
+ else if (uv_fac > 1.0f) copy_v2_v2(uv_close, tf_uv_pxoffset[fidx2]);
+
+ if (side) {
+ barycentric_weights_v2(tf_uv_pxoffset[0], tf_uv_pxoffset[2], tf_uv_pxoffset[3], uv_close, w);
+ }
+ else {
+ barycentric_weights_v2(tf_uv_pxoffset[0], tf_uv_pxoffset[1], tf_uv_pxoffset[2], uv_close, w);
+ }
+#else /* this is buggy with quads, don't use for now */
+
+ /* Cheat, we know where we are along the edge so work out the weights from that */
+ uv_fac = fac1 + (uv_fac * (fac2 - fac1));
+
+ w[0] = w[1] = w[2] = 0.0;
+ if (side) {
+ w[fidx1 ? fidx1 - 1 : 0] = 1.0f - uv_fac;
+ w[fidx2 ? fidx2 - 1 : 0] = uv_fac;
+ }
+ else {
+ w[fidx1] = 1.0f - uv_fac;
+ w[fidx2] = uv_fac;
+ }
+#endif
+ }
+
+ /* a pity we need to get the worldspace pixel location here */
+ if (do_clip || do_3d_mapping) {
+ if (side) interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v3].co, ps->dm_mvert[mf->v4].co, w);
+ else interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v2].co, ps->dm_mvert[mf->v3].co, w);
+
+ if (do_clip && ED_view3d_clipping_test(ps->rv3d, wco, TRUE)) {
+ continue; /* Watch out that no code below this needs to run */
+ }
+ }
+
+ mask = project_paint_uvpixel_mask(ps, face_index, side, w);
+
+ if (mask > 0.0f) {
+ BLI_linklist_prepend_arena(
+ bucketPixelNodes,
+ project_paint_uvpixel_init(ps, arena, ibuf, x, y, mask, face_index, image_index, pixelScreenCo, wco, side, w),
+ arena
+ );
+ }
+
+ }
+ }
+ else if (has_x_isect) {
+ /* assuming the face is not a bow-tie - we know we cant intersect again on the X */
+ break;
+ }
+ }
+
+#if 0 /* TODO - investigate why this dosnt work sometimes! it should! */
+ /* no intersection for this entire row, after some intersection above means we can quit now */
+ if (has_x_isect == 0 && has_isect) {
+ break;
+ }
+#endif
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+#endif // PROJ_DEBUG_NOSEAMBLEED
+}
+
+
+/* takes floating point screenspace min/max and returns int min/max to be used as indices for ps->bucketRect, ps->bucketFlags */
+static void project_paint_bucket_bounds(const ProjPaintState *ps, const float min[2], const float max[2], int bucketMin[2], int bucketMax[2])
+{
+ /* divide by bucketWidth & bucketHeight so the bounds are offset in bucket grid units */
+ /* XXX: the offset of 0.5 is always truncated to zero and the offset of 1.5f is always truncated to 1, is this really correct?? - jwilkins */
+ bucketMin[0] = (int)((int)(((float)(min[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x) + 0.5f); /* these offsets of 0.5 and 1.5 seem odd but they are correct */
+ bucketMin[1] = (int)((int)(((float)(min[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y) + 0.5f);
+
+ bucketMax[0] = (int)((int)(((float)(max[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x) + 1.5f);
+ bucketMax[1] = (int)((int)(((float)(max[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y) + 1.5f);
+
+ /* in case the rect is outside the mesh 2d bounds */
+ CLAMP(bucketMin[0], 0, ps->buckets_x);
+ CLAMP(bucketMin[1], 0, ps->buckets_y);
+
+ CLAMP(bucketMax[0], 0, ps->buckets_x);
+ CLAMP(bucketMax[1], 0, ps->buckets_y);
+}
+
+/* set bucket_bounds to a screen space-aligned floating point bound-box */
+static void project_bucket_bounds(const ProjPaintState *ps, const int bucket_x, const int bucket_y, rctf *bucket_bounds)
+{
+ bucket_bounds->xmin = ps->screenMin[0] + ((bucket_x) * (ps->screen_width / ps->buckets_x)); /* left */
+ bucket_bounds->xmax = ps->screenMin[0] + ((bucket_x + 1) * (ps->screen_width / ps->buckets_x)); /* right */
+
+ bucket_bounds->ymin = ps->screenMin[1] + ((bucket_y) * (ps->screen_height / ps->buckets_y)); /* bottom */
+ bucket_bounds->ymax = ps->screenMin[1] + ((bucket_y + 1) * (ps->screen_height / ps->buckets_y)); /* top */
+}
+
+/* Fill this bucket with pixels from the faces that intersect it.
+ *
+ * have bucket_bounds as an argument so we don't need to give bucket_x/y the rect function needs */
+static void project_bucket_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, rctf *bucket_bounds)
+{
+ LinkNode *node;
+ int face_index, image_index = 0;
+ ImBuf *ibuf = NULL;
+ Image *tpage_last = NULL, *tpage;
+ Image *ima = NULL;
+
+ if (ps->image_tot == 1) {
+ /* Simple loop, no context switching */
+ ibuf = ps->projImages[0].ibuf;
+ ima = ps->projImages[0].ima;
+
+ for (node = ps->bucketFaces[bucket_index]; node; node = node->next) {
+ project_paint_face_init(ps, thread_index, bucket_index, GET_INT_FROM_POINTER(node->link), 0, bucket_bounds, ibuf, ima->tpageflag & IMA_CLAMP_U, ima->tpageflag & IMA_CLAMP_V);
+ }
+ }
+ else {
+
+ /* More complicated loop, switch between images */
+ for (node = ps->bucketFaces[bucket_index]; node; node = node->next) {
+ face_index = GET_INT_FROM_POINTER(node->link);
+
+ /* Image context switching */
+ tpage = project_paint_face_image(ps, ps->dm_mtface, face_index);
+ if (tpage_last != tpage) {
+ tpage_last = tpage;
+
+ for (image_index = 0; image_index < ps->image_tot; image_index++) {
+ if (ps->projImages[image_index].ima == tpage_last) {
+ ibuf = ps->projImages[image_index].ibuf;
+ ima = ps->projImages[image_index].ima;
+ break;
+ }
+ }
+ }
+ /* context switching done */
+
+ project_paint_face_init(ps, thread_index, bucket_index, face_index, image_index, bucket_bounds, ibuf, ima->tpageflag & IMA_CLAMP_U, ima->tpageflag & IMA_CLAMP_V);
+ }
+ }
+
+ ps->bucketFlags[bucket_index] |= PROJ_BUCKET_INIT;
+}
+
+
+/* We want to know if a bucket and a face overlap in screen-space
+ *
+ * Note, if this ever returns false positives its not that bad, since a face in the bounding area will have its pixels
+ * calculated when it might not be needed later, (at the moment at least)
+ * obviously it shouldn't have bugs though */
+
+static int project_bucket_face_isect(ProjPaintState *ps, int bucket_x, int bucket_y, const MFace *mf)
+{
+ /* TODO - replace this with a tricker method that uses sideofline for all screenCoords's edges against the closest bucket corner */
+ rctf bucket_bounds;
+ float p1[2], p2[2], p3[2], p4[2];
+ float *v, *v1, *v2, *v3, *v4 = NULL;
+ int fidx;
+
+ project_bucket_bounds(ps, bucket_x, bucket_y, &bucket_bounds);
+
+ /* Is one of the faces verts in the bucket bounds? */
+
+ fidx = mf->v4 ? 3 : 2;
+ do {
+ v = ps->screenCoords[(*(&mf->v1 + fidx))];
+ if (BLI_rctf_isect_pt_v(&bucket_bounds, v)) {
+ return 1;
+ }
+ } while (fidx--);
+
+ v1 = ps->screenCoords[mf->v1];
+ v2 = ps->screenCoords[mf->v2];
+ v3 = ps->screenCoords[mf->v3];
+ if (mf->v4) {
+ v4 = ps->screenCoords[mf->v4];
+ }
+
+ p1[0] = bucket_bounds.xmin; p1[1] = bucket_bounds.ymin;
+ p2[0] = bucket_bounds.xmin; p2[1] = bucket_bounds.ymax;
+ p3[0] = bucket_bounds.xmax; p3[1] = bucket_bounds.ymax;
+ p4[0] = bucket_bounds.xmax; p4[1] = bucket_bounds.ymin;
+
+ if (mf->v4) {
+ if (isect_point_quad_v2(p1, v1, v2, v3, v4) ||
+ isect_point_quad_v2(p2, v1, v2, v3, v4) ||
+ isect_point_quad_v2(p3, v1, v2, v3, v4) ||
+ isect_point_quad_v2(p4, v1, v2, v3, v4) ||
+
+ /* we can avoid testing v3,v1 because another intersection MUST exist if this intersects */
+ (isect_line_line_v2(p1, p2, v1, v2) || isect_line_line_v2(p1, p2, v2, v3) || isect_line_line_v2(p1, p2, v3, v4)) ||
+ (isect_line_line_v2(p2, p3, v1, v2) || isect_line_line_v2(p2, p3, v2, v3) || isect_line_line_v2(p2, p3, v3, v4)) ||
+ (isect_line_line_v2(p3, p4, v1, v2) || isect_line_line_v2(p3, p4, v2, v3) || isect_line_line_v2(p3, p4, v3, v4)) ||
+ (isect_line_line_v2(p4, p1, v1, v2) || isect_line_line_v2(p4, p1, v2, v3) || isect_line_line_v2(p4, p1, v3, v4)))
+ {
+ return 1;
+ }
+ }
+ else {
+ if (isect_point_tri_v2(p1, v1, v2, v3) ||
+ isect_point_tri_v2(p2, v1, v2, v3) ||
+ isect_point_tri_v2(p3, v1, v2, v3) ||
+ isect_point_tri_v2(p4, v1, v2, v3) ||
+ /* we can avoid testing v3,v1 because another intersection MUST exist if this intersects */
+ (isect_line_line_v2(p1, p2, v1, v2) || isect_line_line_v2(p1, p2, v2, v3)) ||
+ (isect_line_line_v2(p2, p3, v1, v2) || isect_line_line_v2(p2, p3, v2, v3)) ||
+ (isect_line_line_v2(p3, p4, v1, v2) || isect_line_line_v2(p3, p4, v2, v3)) ||
+ (isect_line_line_v2(p4, p1, v1, v2) || isect_line_line_v2(p4, p1, v2, v3)))
+ {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* Add faces to the bucket but don't initialize its pixels
+ * TODO - when painting occluded, sort the faces on their min-Z and only add faces that faces that are not occluded */
+static void project_paint_delayed_face_init(ProjPaintState *ps, const MFace *mf, const int face_index)
+{
+ float min[2], max[2], *vCoSS;
+ int bucketMin[2], bucketMax[2]; /* for ps->bucketRect indexing */
+ int fidx, bucket_x, bucket_y;
+ int has_x_isect = -1, has_isect = 0; /* for early loop exit */
+ MemArena *arena = ps->arena_mt[0]; /* just use the first thread arena since threading has not started yet */
+
+ INIT_MINMAX2(min, max);
+
+ fidx = mf->v4 ? 3 : 2;
+ do {
+ vCoSS = ps->screenCoords[*(&mf->v1 + fidx)];
+ minmax_v2v2_v2(min, max, vCoSS);
+ } while (fidx--);
+
+ project_paint_bucket_bounds(ps, min, max, bucketMin, bucketMax);
+
+ for (bucket_y = bucketMin[1]; bucket_y < bucketMax[1]; bucket_y++) {
+ has_x_isect = 0;
+ for (bucket_x = bucketMin[0]; bucket_x < bucketMax[0]; bucket_x++) {
+ if (project_bucket_face_isect(ps, bucket_x, bucket_y, mf)) {
+ int bucket_index = bucket_x + (bucket_y * ps->buckets_x);
+ BLI_linklist_prepend_arena(
+ &ps->bucketFaces[bucket_index],
+ SET_INT_IN_POINTER(face_index), /* cast to a pointer to shut up the compiler */
+ arena
+ );
+
+ has_x_isect = has_isect = 1;
+ }
+ else if (has_x_isect) {
+ /* assuming the face is not a bow-tie - we know we cant intersect again on the X */
+ break;
+ }
+ }
+
+ /* no intersection for this entire row, after some intersection above means we can quit now */
+ if (has_x_isect == 0 && has_isect) {
+ break;
+ }
+ }
+
+#ifndef PROJ_DEBUG_NOSEAMBLEED
+ if (ps->seam_bleed_px > 0.0f) {
+ if (!mf->v4) {
+ ps->faceSeamFlags[face_index] |= PROJ_FACE_NOSEAM4; /* so this wont show up as an untagged edge */
+ }
+ **ps->faceSeamUVs[face_index] = FLT_MAX; /* set as uninitialized */
+ }
+#endif
+}
+
+/* run once per stroke before projection painting */
+static void project_paint_begin(ProjPaintState *ps)
+{
+ /* Viewport vars */
+ float mat[3][3];
+
+ float no[3];
+
+ float *projScreenCo; /* Note, we could have 4D vectors are only needed for */
+ float projMargin;
+
+ /* Image Vars - keep track of images we have used */
+ LinkNode *image_LinkList = NULL;
+ LinkNode *node;
+
+ ProjPaintImage *projIma;
+ Image *tpage_last = NULL, *tpage;
+
+ /* Face vars */
+ MFace *mf;
+ MTFace *tf;
+
+ int a, i; /* generic looping vars */
+ int image_index = -1, face_index;
+ MVert *mv;
+
+ MemArena *arena; /* at the moment this is just ps->arena_mt[0], but use this to show were not multithreading */
+
+ const int diameter = 2 * BKE_brush_size_get(ps->scene, ps->brush);
+
+ /* ---- end defines ---- */
+
+ if (ps->source == PROJ_SRC_VIEW)
+ ED_view3d_clipping_local(ps->rv3d, ps->ob->obmat); /* faster clipping lookups */
+
+ /* paint onto the derived mesh */
+
+ /* Workaround for subsurf selection, try the display mesh first */
+ if (ps->source == PROJ_SRC_IMAGE_CAM) {
+ /* using render mesh, assume only camera was rendered from */
+ ps->dm = mesh_create_derived_render(ps->scene, ps->ob, ps->scene->customdata_mask | CD_MASK_MTFACE);
+ ps->dm_release = TRUE;
+ }
+ else if (ps->ob->derivedFinal && CustomData_has_layer(&ps->ob->derivedFinal->faceData, CD_MTFACE)) {
+ ps->dm = ps->ob->derivedFinal;
+ ps->dm_release = FALSE;
+ }
+ else {
+ ps->dm = mesh_get_derived_final(ps->scene, ps->ob, ps->scene->customdata_mask | CD_MASK_MTFACE);
+ ps->dm_release = TRUE;
+ }
+
+ if (!CustomData_has_layer(&ps->dm->faceData, CD_MTFACE) ) {
+
+ if (ps->dm_release)
+ ps->dm->release(ps->dm);
+
+ ps->dm = NULL;
+ return;
+ }
+
+ ps->dm_mvert = ps->dm->getVertArray(ps->dm);
+ ps->dm_mface = ps->dm->getTessFaceArray(ps->dm);
+ ps->dm_mtface = ps->dm->getTessFaceDataArray(ps->dm, CD_MTFACE);
+
+ ps->dm_totvert = ps->dm->getNumVerts(ps->dm);
+ ps->dm_totface = ps->dm->getNumTessFaces(ps->dm);
+
+ /* use clone mtface? */
+
+
+ /* Note, use the original mesh for getting the clone and mask layer index
+ * this avoids re-generating the derived mesh just to get the new index */
+ if (ps->do_layer_clone) {
+ //int layer_num = CustomData_get_clone_layer(&ps->dm->faceData, CD_MTFACE);
+ int layer_num = CustomData_get_clone_layer(&((Mesh *)ps->ob->data)->fdata, CD_MTFACE);
+ if (layer_num != -1)
+ ps->dm_mtface_clone = CustomData_get_layer_n(&ps->dm->faceData, CD_MTFACE, layer_num);
+
+ if (ps->dm_mtface_clone == NULL || ps->dm_mtface_clone == ps->dm_mtface) {
+ ps->do_layer_clone = FALSE;
+ ps->dm_mtface_clone = NULL;
+ printf("ACK!\n");
+ }
+ }
+
+ if (ps->do_layer_stencil) {
+ //int layer_num = CustomData_get_stencil_layer(&ps->dm->faceData, CD_MTFACE);
+ int layer_num = CustomData_get_stencil_layer(&((Mesh *)ps->ob->data)->fdata, CD_MTFACE);
+ if (layer_num != -1)
+ ps->dm_mtface_stencil = CustomData_get_layer_n(&ps->dm->faceData, CD_MTFACE, layer_num);
+
+ if (ps->dm_mtface_stencil == NULL || ps->dm_mtface_stencil == ps->dm_mtface) {
+ ps->do_layer_stencil = FALSE;
+ ps->dm_mtface_stencil = NULL;
+ }
+ }
+
+ /* when using subsurf or multires, mface arrays are thrown away, we need to keep a copy */
+ if (ps->dm->type != DM_TYPE_CDDM) {
+ ps->dm_mvert = MEM_dupallocN(ps->dm_mvert);
+ ps->dm_mface = MEM_dupallocN(ps->dm_mface);
+ /* looks like these are ok for now.*/
+#if 0
+ ps->dm_mtface = MEM_dupallocN(ps->dm_mtface);
+ ps->dm_mtface_clone = MEM_dupallocN(ps->dm_mtface_clone);
+ ps->dm_mtface_stencil = MEM_dupallocN(ps->dm_mtface_stencil);
+#endif
+ }
+
+ ps->viewDir[0] = 0.0f;
+ ps->viewDir[1] = 0.0f;
+ ps->viewDir[2] = 1.0f;
+
+ {
+ float viewmat[4][4];
+ float viewinv[4][4];
+
+ invert_m4_m4(ps->ob->imat, ps->ob->obmat);
+
+ if (ps->source == PROJ_SRC_VIEW) {
+ /* normal drawing */
+ ps->winx = ps->ar->winx;
+ ps->winy = ps->ar->winy;
+
+ copy_m4_m4(viewmat, ps->rv3d->viewmat);
+ copy_m4_m4(viewinv, ps->rv3d->viewinv);
+
+ ED_view3d_ob_project_mat_get(ps->rv3d, ps->ob, ps->projectMat);
+
+ ps->is_ortho = ED_view3d_clip_range_get(ps->v3d, ps->rv3d, &ps->clipsta, &ps->clipend, true);
+ }
+ else {
+ /* re-projection */
+ float winmat[4][4];
+ float vmat[4][4];
+
+ ps->winx = ps->reproject_ibuf->x;
+ ps->winy = ps->reproject_ibuf->y;
+
+ if (ps->source == PROJ_SRC_IMAGE_VIEW) {
+ /* image stores camera data, tricky */
+ IDProperty *idgroup = IDP_GetProperties(&ps->reproject_image->id, 0);
+ IDProperty *view_data = IDP_GetPropertyFromGroup(idgroup, PROJ_VIEW_DATA_ID);
+
+ float *array = (float *)IDP_Array(view_data);
+
+ /* use image array, written when creating image */
+ memcpy(winmat, array, sizeof(winmat)); array += sizeof(winmat) / sizeof(float);
+ memcpy(viewmat, array, sizeof(viewmat)); array += sizeof(viewmat) / sizeof(float);
+ ps->clipsta = array[0];
+ ps->clipend = array[1];
+ ps->is_ortho = array[2] ? 1 : 0;
+
+ invert_m4_m4(viewinv, viewmat);
+ }
+ else if (ps->source == PROJ_SRC_IMAGE_CAM) {
+ Object *cam_ob = ps->scene->camera;
+ CameraParams params;
+
+ /* viewmat & viewinv */
+ copy_m4_m4(viewinv, cam_ob->obmat);
+ normalize_m4(viewinv);
+ invert_m4_m4(viewmat, viewinv);
+
+ /* window matrix, clipping and ortho */
+ BKE_camera_params_init(&params);
+ BKE_camera_params_from_object(&params, cam_ob);
+ BKE_camera_params_compute_viewplane(&params, ps->winx, ps->winy, 1.0f, 1.0f);
+ BKE_camera_params_compute_matrix(&params);
+
+ copy_m4_m4(winmat, params.winmat);
+ ps->clipsta = params.clipsta;
+ ps->clipend = params.clipend;
+ ps->is_ortho = params.is_ortho;
+ }
+
+ /* same as #ED_view3d_ob_project_mat_get */
+ mult_m4_m4m4(vmat, viewmat, ps->ob->obmat);
+ mult_m4_m4m4(ps->projectMat, winmat, vmat);
+ }
+
+
+ /* viewDir - object relative */
+ invert_m4_m4(ps->ob->imat, ps->ob->obmat);
+ copy_m3_m4(mat, viewinv);
+ mul_m3_v3(mat, ps->viewDir);
+ copy_m3_m4(mat, ps->ob->imat);
+ mul_m3_v3(mat, ps->viewDir);
+ normalize_v3(ps->viewDir);
+
+ /* viewPos - object relative */
+ copy_v3_v3(ps->viewPos, viewinv[3]);
+ copy_m3_m4(mat, ps->ob->imat);
+ mul_m3_v3(mat, ps->viewPos);
+ add_v3_v3(ps->viewPos, ps->ob->imat[3]);
+ }
+
+ /* calculate vert screen coords
+ * run this early so we can calculate the x/y resolution of our bucket rect */
+ INIT_MINMAX2(ps->screenMin, ps->screenMax);
+
+ ps->screenCoords = MEM_mallocN(sizeof(float) * ps->dm_totvert * 4, "ProjectPaint ScreenVerts");
+ projScreenCo = *ps->screenCoords;
+
+ if (ps->is_ortho) {
+ for (a = 0, mv = ps->dm_mvert; a < ps->dm_totvert; a++, mv++, projScreenCo += 4) {
+ mul_v3_m4v3(projScreenCo, ps->projectMat, mv->co);
+
+ /* screen space, not clamped */
+ projScreenCo[0] = (float)(ps->winx / 2.0f) + (ps->winx / 2.0f) * projScreenCo[0];
+ projScreenCo[1] = (float)(ps->winy / 2.0f) + (ps->winy / 2.0f) * projScreenCo[1];
+ minmax_v2v2_v2(ps->screenMin, ps->screenMax, projScreenCo);
+ }
+ }
+ else {
+ for (a = 0, mv = ps->dm_mvert; a < ps->dm_totvert; a++, mv++, projScreenCo += 4) {
+ copy_v3_v3(projScreenCo, mv->co);
+ projScreenCo[3] = 1.0f;
+
+ mul_m4_v4(ps->projectMat, projScreenCo);
+
+ if (projScreenCo[3] > ps->clipsta) {
+ /* screen space, not clamped */
+ projScreenCo[0] = (float)(ps->winx / 2.0f) + (ps->winx / 2.0f) * projScreenCo[0] / projScreenCo[3];
+ projScreenCo[1] = (float)(ps->winy / 2.0f) + (ps->winy / 2.0f) * projScreenCo[1] / projScreenCo[3];
+ projScreenCo[2] = projScreenCo[2] / projScreenCo[3]; /* Use the depth for bucket point occlusion */
+ minmax_v2v2_v2(ps->screenMin, ps->screenMax, projScreenCo);
+ }
+ else {
+ /* TODO - deal with cases where 1 side of a face goes behind the view ?
+ *
+ * After some research this is actually very tricky, only option is to
+ * clip the derived mesh before painting, which is a Pain */
+ projScreenCo[0] = FLT_MAX;
+ }
+ }
+ }
+
+ /* If this border is not added we get artifacts for faces that
+ * have a parallel edge and at the bounds of the the 2D projected verts eg
+ * - a single screen aligned quad */
+ projMargin = (ps->screenMax[0] - ps->screenMin[0]) * 0.000001f;
+ ps->screenMax[0] += projMargin;
+ ps->screenMin[0] -= projMargin;
+ projMargin = (ps->screenMax[1] - ps->screenMin[1]) * 0.000001f;
+ ps->screenMax[1] += projMargin;
+ ps->screenMin[1] -= projMargin;
+
+ if (ps->source == PROJ_SRC_VIEW) {
+#ifdef PROJ_DEBUG_WINCLIP
+ CLAMP(ps->screenMin[0], (float)(-diameter), (float)(ps->winx + diameter));
+ CLAMP(ps->screenMax[0], (float)(-diameter), (float)(ps->winx + diameter));
+
+ CLAMP(ps->screenMin[1], (float)(-diameter), (float)(ps->winy + diameter));
+ CLAMP(ps->screenMax[1], (float)(-diameter), (float)(ps->winy + diameter));
+#endif
+ }
+ else { /* re-projection, use bounds */
+ ps->screenMin[0] = 0;
+ ps->screenMax[0] = (float)(ps->winx);
+
+ ps->screenMin[1] = 0;
+ ps->screenMax[1] = (float)(ps->winy);
+ }
+
+ /* only for convenience */
+ ps->screen_width = ps->screenMax[0] - ps->screenMin[0];
+ ps->screen_height = ps->screenMax[1] - ps->screenMin[1];
+
+ ps->buckets_x = (int)(ps->screen_width / (((float)diameter) / PROJ_BUCKET_BRUSH_DIV));
+ ps->buckets_y = (int)(ps->screen_height / (((float)diameter) / PROJ_BUCKET_BRUSH_DIV));
+
+ /* printf("\tscreenspace bucket division x:%d y:%d\n", ps->buckets_x, ps->buckets_y); */
+
+ /* really high values could cause problems since it has to allocate a few
+ * (ps->buckets_x*ps->buckets_y) sized arrays */
+ CLAMP(ps->buckets_x, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX);
+ CLAMP(ps->buckets_y, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX);
+
+ ps->bucketRect = (LinkNode **)MEM_callocN(sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y, "paint-bucketRect");
+ ps->bucketFaces = (LinkNode **)MEM_callocN(sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y, "paint-bucketFaces");
+
+ ps->bucketFlags = (unsigned char *)MEM_callocN(sizeof(char) * ps->buckets_x * ps->buckets_y, "paint-bucketFaces");
+#ifndef PROJ_DEBUG_NOSEAMBLEED
+ if (ps->seam_bleed_px > 0.0f) {
+ ps->vertFaces = (LinkNode **)MEM_callocN(sizeof(LinkNode *) * ps->dm_totvert, "paint-vertFaces");
+ ps->faceSeamFlags = (char *)MEM_callocN(sizeof(char) * ps->dm_totface, "paint-faceSeamFlags");
+ ps->faceSeamUVs = MEM_mallocN(sizeof(float) * ps->dm_totface * 8, "paint-faceSeamUVs");
+ }
+#endif
+
+ /* Thread stuff
+ *
+ * very small brushes run a lot slower multithreaded since the advantage with
+ * threads is being able to fill in multiple buckets at once.
+ * Only use threads for bigger brushes. */
+
+ if (ps->scene->r.mode & R_FIXED_THREADS) {
+ ps->thread_tot = ps->scene->r.threads;
+ }
+ else {
+ ps->thread_tot = BLI_system_thread_count();
+ }
+ for (a = 0; a < ps->thread_tot; a++) {
+ ps->arena_mt[a] = BLI_memarena_new(1 << 16, "project paint arena");
+ }
+
+ arena = ps->arena_mt[0];
+
+ if (ps->do_backfacecull && ps->do_mask_normal) {
+ float viewDirPersp[3];
+
+ ps->vertFlags = MEM_callocN(sizeof(char) * ps->dm_totvert, "paint-vertFlags");
+
+ for (a = 0, mv = ps->dm_mvert; a < ps->dm_totvert; a++, mv++) {
+ normal_short_to_float_v3(no, mv->no);
+
+ if (ps->is_ortho) {
+ if (angle_normalized_v3v3(ps->viewDir, no) >= ps->normal_angle) { /* 1 vert of this face is towards us */
+ ps->vertFlags[a] |= PROJ_VERT_CULL;
+ }
+ }
+ else {
+ sub_v3_v3v3(viewDirPersp, ps->viewPos, mv->co);
+ normalize_v3(viewDirPersp);
+ if (angle_normalized_v3v3(viewDirPersp, no) >= ps->normal_angle) { /* 1 vert of this face is towards us */
+ ps->vertFlags[a] |= PROJ_VERT_CULL;
+ }
+ }
+ }
+ }
+
+
+ for (face_index = 0, tf = ps->dm_mtface, mf = ps->dm_mface; face_index < ps->dm_totface; mf++, tf++, face_index++) {
+
+#ifndef PROJ_DEBUG_NOSEAMBLEED
+ /* add face user if we have bleed enabled, set the UV seam flags later */
+ /* annoying but we need to add all faces even ones we never use elsewhere */
+ if (ps->seam_bleed_px > 0.0f) {
+ BLI_linklist_prepend_arena(&ps->vertFaces[mf->v1], SET_INT_IN_POINTER(face_index), arena);
+ BLI_linklist_prepend_arena(&ps->vertFaces[mf->v2], SET_INT_IN_POINTER(face_index), arena);
+ BLI_linklist_prepend_arena(&ps->vertFaces[mf->v3], SET_INT_IN_POINTER(face_index), arena);
+ if (mf->v4) {
+ BLI_linklist_prepend_arena(&ps->vertFaces[mf->v4], SET_INT_IN_POINTER(face_index), arena);
+ }
+ }
+#endif
+
+ tpage = project_paint_face_image(ps, ps->dm_mtface, face_index);
+
+ if (tpage && ((((Mesh *)ps->ob->data)->editflag & ME_EDIT_PAINT_FACE_SEL) == 0 || mf->flag & ME_FACE_SEL)) {
+
+ float *v1coSS, *v2coSS, *v3coSS, *v4coSS = NULL;
+
+ v1coSS = ps->screenCoords[mf->v1];
+ v2coSS = ps->screenCoords[mf->v2];
+ v3coSS = ps->screenCoords[mf->v3];
+ if (mf->v4) {
+ v4coSS = ps->screenCoords[mf->v4];
+ }
+
+
+ if (!ps->is_ortho) {
+ if (v1coSS[0] == FLT_MAX ||
+ v2coSS[0] == FLT_MAX ||
+ v3coSS[0] == FLT_MAX ||
+ (mf->v4 && v4coSS[0] == FLT_MAX))
+ {
+ continue;
+ }
+ }
+
+#ifdef PROJ_DEBUG_WINCLIP
+ /* ignore faces outside the view */
+ if (
+ (v1coSS[0] < ps->screenMin[0] &&
+ v2coSS[0] < ps->screenMin[0] &&
+ v3coSS[0] < ps->screenMin[0] &&
+ (mf->v4 && v4coSS[0] < ps->screenMin[0])) ||
+
+ (v1coSS[0] > ps->screenMax[0] &&
+ v2coSS[0] > ps->screenMax[0] &&
+ v3coSS[0] > ps->screenMax[0] &&
+ (mf->v4 && v4coSS[0] > ps->screenMax[0])) ||
+
+ (v1coSS[1] < ps->screenMin[1] &&
+ v2coSS[1] < ps->screenMin[1] &&
+ v3coSS[1] < ps->screenMin[1] &&
+ (mf->v4 && v4coSS[1] < ps->screenMin[1])) ||
+
+ (v1coSS[1] > ps->screenMax[1] &&
+ v2coSS[1] > ps->screenMax[1] &&
+ v3coSS[1] > ps->screenMax[1] &&
+ (mf->v4 && v4coSS[1] > ps->screenMax[1]))
+ )
+ {
+ continue;
+ }
+
+#endif //PROJ_DEBUG_WINCLIP
+
+
+ if (ps->do_backfacecull) {
+ if (ps->do_mask_normal) {
+ /* Since we are interpolating the normals of faces, we want to make
+ * sure all the verts are pointing away from the view,
+ * not just the face */
+ if ((ps->vertFlags[mf->v1] & PROJ_VERT_CULL) &&
+ (ps->vertFlags[mf->v2] & PROJ_VERT_CULL) &&
+ (ps->vertFlags[mf->v3] & PROJ_VERT_CULL) &&
+ (mf->v4 == 0 || ps->vertFlags[mf->v4] & PROJ_VERT_CULL)
+ )
+ {
+ continue;
+ }
+ }
+ else {
+ if (line_point_side_v2(v1coSS, v2coSS, v3coSS) < 0.0f) {
+ continue;
+ }
+
+ }
+ }
+
+ if (tpage_last != tpage) {
+
+ image_index = BLI_linklist_index(image_LinkList, tpage);
+
+ if (image_index == -1 && BKE_image_has_ibuf(tpage, NULL)) { /* MemArena dosnt have an append func */
+ BLI_linklist_append(&image_LinkList, tpage);
+ image_index = ps->image_tot;
+ ps->image_tot++;
+ }
+
+ tpage_last = tpage;
+ }
+
+ if (image_index != -1) {
+ /* Initialize the faces screen pixels */
+ /* Add this to a list to initialize later */
+ project_paint_delayed_face_init(ps, mf, face_index);
+ }
+ }
+ }
+
+ /* build an array of images we use*/
+ projIma = ps->projImages = (ProjPaintImage *)BLI_memarena_alloc(arena, sizeof(ProjPaintImage) * ps->image_tot);
+
+ for (node = image_LinkList, i = 0; node; node = node->next, i++, projIma++) {
+ projIma->ima = node->link;
+ projIma->touch = 0;
+ projIma->ibuf = BKE_image_acquire_ibuf(projIma->ima, NULL, NULL);
+ projIma->partRedrawRect = BLI_memarena_alloc(arena, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
+ memset(projIma->partRedrawRect, 0, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
+ }
+
+ /* we have built the array, discard the linked list */
+ BLI_linklist_free(image_LinkList, NULL);
+}
+
+static void paint_proj_begin_clone(ProjPaintState *ps, const int mouse[2])
+{
+ /* setup clone offset */
+ if (ps->tool == PAINT_TOOL_CLONE) {
+ float projCo[4];
+ copy_v3_v3(projCo, give_cursor(ps->scene, ps->v3d));
+ mul_m4_v3(ps->ob->imat, projCo);
+
+ projCo[3] = 1.0f;
+ mul_m4_v4(ps->projectMat, projCo);
+ ps->cloneOffset[0] = mouse[0] - ((float)(ps->winx / 2.0f) + (ps->winx / 2.0f) * projCo[0] / projCo[3]);
+ ps->cloneOffset[1] = mouse[1] - ((float)(ps->winy / 2.0f) + (ps->winy / 2.0f) * projCo[1] / projCo[3]);
+ }
+}
+
+static void project_paint_end(ProjPaintState *ps)
+{
+ int a;
+ ProjPaintImage *projIma;
+
+ /* build undo data from original pixel colors */
+ if (U.uiflag & USER_GLOBALUNDO) {
+ ProjPixel *projPixel;
+ ImBuf *tmpibuf = NULL, *tmpibuf_float = NULL;
+ LinkNode *pixel_node;
+ void *tilerect;
+ MemArena *arena = ps->arena_mt[0]; /* threaded arena re-used for non threaded case */
+
+ int bucket_tot = (ps->buckets_x * ps->buckets_y); /* we could get an X/Y but easier to loop through all possible buckets */
+ int bucket_index;
+ int tile_index;
+ int x_round, y_round;
+ int x_tile, y_tile;
+ int is_float = -1;
+
+ /* context */
+ ProjPaintImage *last_projIma;
+ int last_image_index = -1;
+ int last_tile_width = 0;
+
+ for (a = 0, last_projIma = ps->projImages; a < ps->image_tot; a++, last_projIma++) {
+ int size = sizeof(void **) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->x) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->y);
+ last_projIma->undoRect = (void **) BLI_memarena_alloc(arena, size);
+ memset(last_projIma->undoRect, 0, size);
+ last_projIma->ibuf->userflags |= IB_BITMAPDIRTY;
+ }
+
+ for (bucket_index = 0; bucket_index < bucket_tot; bucket_index++) {
+ /* loop through all pixels */
+ for (pixel_node = ps->bucketRect[bucket_index]; pixel_node; pixel_node = pixel_node->next) {
+
+ /* ok we have a pixel, was it modified? */
+ projPixel = (ProjPixel *)pixel_node->link;
+
+ if (last_image_index != projPixel->image_index) {
+ /* set the context */
+ last_image_index = projPixel->image_index;
+ last_projIma = ps->projImages + last_image_index;
+ last_tile_width = IMAPAINT_TILE_NUMBER(last_projIma->ibuf->x);
+ is_float = last_projIma->ibuf->rect_float ? 1 : 0;
+ }
+
+
+ if ((is_float == 0 && projPixel->origColor.uint != *projPixel->pixel.uint_pt) ||
+ (is_float == 1 &&
+ (projPixel->origColor.f[0] != projPixel->pixel.f_pt[0] ||
+ projPixel->origColor.f[1] != projPixel->pixel.f_pt[1] ||
+ projPixel->origColor.f[2] != projPixel->pixel.f_pt[2] ||
+ projPixel->origColor.f[3] != projPixel->pixel.f_pt[3]))
+ )
+ {
+
+ x_tile = projPixel->x_px >> IMAPAINT_TILE_BITS;
+ y_tile = projPixel->y_px >> IMAPAINT_TILE_BITS;
+
+ x_round = x_tile * IMAPAINT_TILE_SIZE;
+ y_round = y_tile * IMAPAINT_TILE_SIZE;
+
+ tile_index = x_tile + y_tile * last_tile_width;
+
+ if (last_projIma->undoRect[tile_index] == NULL) {
+ /* add the undo tile from the modified image, then write the original colors back into it */
+ tilerect = last_projIma->undoRect[tile_index] = image_undo_push_tile(last_projIma->ima, last_projIma->ibuf, is_float ? (&tmpibuf_float) : (&tmpibuf), x_tile, y_tile);
+ }
+ else {
+ tilerect = last_projIma->undoRect[tile_index];
+ }
+
+ /* This is a BIT ODD, but overwrite the undo tiles image info with this pixels original color
+ * because allocating the tiles along the way slows down painting */
+
+ if (is_float) {
+ float *rgba_fp = (float *)tilerect + (((projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE)) * 4;
+ copy_v4_v4(rgba_fp, projPixel->origColor.f);
+ }
+ else {
+ ((unsigned int *)tilerect)[(projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE] = projPixel->origColor.uint;
+ }
+ }
+ }
+ }
+
+ if (tmpibuf) IMB_freeImBuf(tmpibuf);
+ if (tmpibuf_float) IMB_freeImBuf(tmpibuf_float);
+ }
+ /* done calculating undo data */
+
+ /* dereference used image buffers */
+ for (a = 0, projIma = ps->projImages; a < ps->image_tot; a++, projIma++) {
+ BKE_image_release_ibuf(projIma->ima, projIma->ibuf, NULL);
+ }
+
+ BKE_image_release_ibuf(ps->reproject_image, ps->reproject_ibuf, NULL);
+
+ MEM_freeN(ps->screenCoords);
+ MEM_freeN(ps->bucketRect);
+ MEM_freeN(ps->bucketFaces);
+ MEM_freeN(ps->bucketFlags);
+
+#ifndef PROJ_DEBUG_NOSEAMBLEED
+ if (ps->seam_bleed_px > 0.0f) {
+ MEM_freeN(ps->vertFaces);
+ MEM_freeN(ps->faceSeamFlags);
+ MEM_freeN(ps->faceSeamUVs);
+ }
+#endif
+
+ if (ps->vertFlags) MEM_freeN(ps->vertFlags);
+
+ for (a = 0; a < ps->thread_tot; a++) {
+ BLI_memarena_free(ps->arena_mt[a]);
+ }
+
+ /* copy for subsurf/multires, so throw away */
+ if (ps->dm->type != DM_TYPE_CDDM) {
+ if (ps->dm_mvert) MEM_freeN(ps->dm_mvert);
+ if (ps->dm_mface) MEM_freeN(ps->dm_mface);
+ /* looks like these don't need copying */
+#if 0
+ if (ps->dm_mtface) MEM_freeN(ps->dm_mtface);
+ if (ps->dm_mtface_clone) MEM_freeN(ps->dm_mtface_clone);
+ if (ps->dm_mtface_stencil) MEM_freeN(ps->dm_mtface_stencil);
+#endif
+ }
+
+ if (ps->dm_release)
+ ps->dm->release(ps->dm);
+}
+
+/* 1 = an undo, -1 is a redo. */
+static void partial_redraw_array_init(ImagePaintPartialRedraw *pr)
+{
+ int tot = PROJ_BOUNDBOX_SQUARED;
+ while (tot--) {
+ pr->x1 = 10000000;
+ pr->y1 = 10000000;
+
+ pr->x2 = -1;
+ pr->y2 = -1;
+
+ pr->enabled = 1;
+
+ pr++;
+ }
+}
+
+
+static int partial_redraw_array_merge(ImagePaintPartialRedraw *pr, ImagePaintPartialRedraw *pr_other, int tot)
+{
+ int touch = 0;
+ while (tot--) {
+ pr->x1 = min_ii(pr->x1, pr_other->x1);
+ pr->y1 = min_ii(pr->y1, pr_other->y1);
+
+ pr->x2 = max_ii(pr->x2, pr_other->x2);
+ pr->y2 = max_ii(pr->y2, pr_other->y2);
+
+ if (pr->x2 != -1)
+ touch = 1;
+
+ pr++; pr_other++;
+ }
+
+ return touch;
+}
+
+/* Loop over all images on this mesh and update any we have touched */
+static int project_image_refresh_tagged(ProjPaintState *ps)
+{
+ ImagePaintPartialRedraw *pr;
+ ProjPaintImage *projIma;
+ int a, i;
+ int redraw = 0;
+
+
+ for (a = 0, projIma = ps->projImages; a < ps->image_tot; a++, projIma++) {
+ if (projIma->touch) {
+ /* look over each bound cell */
+ for (i = 0; i < PROJ_BOUNDBOX_SQUARED; i++) {
+ pr = &(projIma->partRedrawRect[i]);
+ if (pr->x2 != -1) { /* TODO - use 'enabled' ? */
+ set_imapaintpartial(pr);
+ imapaint_image_update(NULL, projIma->ima, projIma->ibuf, true);
+ redraw = 1;
+ }
+ }
+
+ projIma->touch = 0; /* clear for reuse */
+ }
+ }
+
+ return redraw;
+}
+
+/* run this per painting onto each mouse location */
+static int project_bucket_iter_init(ProjPaintState *ps, const float mval_f[2])
+{
+ if (ps->source == PROJ_SRC_VIEW) {
+ float min_brush[2], max_brush[2];
+ const float radius = (float)BKE_brush_size_get(ps->scene, ps->brush);
+
+ /* so we don't have a bucket bounds that is way too small to paint into */
+ // if (radius < 1.0f) radius = 1.0f; // this doesn't work yet :/
+
+ min_brush[0] = mval_f[0] - radius;
+ min_brush[1] = mval_f[1] - radius;
+
+ max_brush[0] = mval_f[0] + radius;
+ max_brush[1] = mval_f[1] + radius;
+
+ /* offset to make this a valid bucket index */
+ project_paint_bucket_bounds(ps, min_brush, max_brush, ps->bucketMin, ps->bucketMax);
+
+ /* mouse outside the model areas? */
+ if (ps->bucketMin[0] == ps->bucketMax[0] || ps->bucketMin[1] == ps->bucketMax[1]) {
+ return 0;
+ }
+
+ ps->context_bucket_x = ps->bucketMin[0];
+ ps->context_bucket_y = ps->bucketMin[1];
+ }
+ else { /* reproject: PROJ_SRC_* */
+ ps->bucketMin[0] = 0;
+ ps->bucketMin[1] = 0;
+
+ ps->bucketMax[0] = ps->buckets_x;
+ ps->bucketMax[1] = ps->buckets_y;
+
+ ps->context_bucket_x = 0;
+ ps->context_bucket_y = 0;
+ }
+ return 1;
+}
+
+
+static int project_bucket_iter_next(ProjPaintState *ps, int *bucket_index, rctf *bucket_bounds, const float mval[2])
+{
+ const int diameter = 2 * BKE_brush_size_get(ps->scene, ps->brush);
+
+ if (ps->thread_tot > 1)
+ BLI_lock_thread(LOCK_CUSTOM1);
+
+ //printf("%d %d\n", ps->context_bucket_x, ps->context_bucket_y);
+
+ for (; ps->context_bucket_y < ps->bucketMax[1]; ps->context_bucket_y++) {
+ for (; ps->context_bucket_x < ps->bucketMax[0]; ps->context_bucket_x++) {
+
+ /* use bucket_bounds for project_bucket_isect_circle and project_bucket_init*/
+ project_bucket_bounds(ps, ps->context_bucket_x, ps->context_bucket_y, bucket_bounds);
+
+ if ((ps->source != PROJ_SRC_VIEW) ||
+ project_bucket_isect_circle(mval, (float)(diameter * diameter), bucket_bounds))
+ {
+ *bucket_index = ps->context_bucket_x + (ps->context_bucket_y * ps->buckets_x);
+ ps->context_bucket_x++;
+
+ if (ps->thread_tot > 1)
+ BLI_unlock_thread(LOCK_CUSTOM1);
+
+ return 1;
+ }
+ }
+ ps->context_bucket_x = ps->bucketMin[0];
+ }
+
+ if (ps->thread_tot > 1)
+ BLI_unlock_thread(LOCK_CUSTOM1);
+ return 0;
+}
+
+/* Each thread gets one of these, also used as an argument to pass to project_paint_op */
+typedef struct ProjectHandle {
+ /* args */
+ ProjPaintState *ps;
+ float prevmval[2];
+ float mval[2];
+
+ /* annoying but we need to have image bounds per thread, then merge into ps->projectPartialRedraws */
+ ProjPaintImage *projImages; /* array of partial redraws */
+
+ /* thread settings */
+ int thread_index;
+
+ struct ImagePool *pool;
+} ProjectHandle;
+
+static void blend_color_mix(unsigned char cp[4], const unsigned char cp1[4], const unsigned char cp2[4], const int fac)
+{
+ /* this and other blending modes previously used >>8 instead of /255. both
+ * are not equivalent (>>8 is /256), and the former results in rounding
+ * errors that can turn colors black fast after repeated blending */
+ const int mfac = 255 - fac;
+
+ cp[0] = (mfac * cp1[0] + fac * cp2[0]) / 255;
+ cp[1] = (mfac * cp1[1] + fac * cp2[1]) / 255;
+ cp[2] = (mfac * cp1[2] + fac * cp2[2]) / 255;
+ cp[3] = (mfac * cp1[3] + fac * cp2[3]) / 255;
+}
+
+static void blend_color_mix_float(float cp[4], const float cp1[4], const float cp2[4], const float fac)
+{
+ const float mfac = 1.0f - fac;
+ cp[0] = mfac * cp1[0] + fac * cp2[0];
+ cp[1] = mfac * cp1[1] + fac * cp2[1];
+ cp[2] = mfac * cp1[2] + fac * cp2[2];
+ cp[3] = mfac * cp1[3] + fac * cp2[3];
+}
+
+static void blend_color_mix_accum(unsigned char cp[4], const unsigned char cp1[4], const unsigned char cp2[4], const int fac)
+{
+ /* this and other blending modes previously used >>8 instead of /255. both
+ * are not equivalent (>>8 is /256), and the former results in rounding
+ * errors that can turn colors black fast after repeated blending */
+ const int mfac = 255 - fac;
+ const int alpha = cp1[3] + ((fac * cp2[3]) / 255);
+
+ cp[0] = (mfac * cp1[0] + fac * cp2[0]) / 255;
+ cp[1] = (mfac * cp1[1] + fac * cp2[1]) / 255;
+ cp[2] = (mfac * cp1[2] + fac * cp2[2]) / 255;
+ cp[3] = alpha > 255 ? 255 : alpha;
+}
+static void blend_color_mix_accum_float(float cp[4], const float cp1[4], const unsigned char cp2[4], const float fac)
+{
+ const float mfac = 1.0f - fac;
+ const float alpha = cp1[3] + (fac * (cp2[3] / 255.0f));
+
+ cp[0] = (mfac * cp1[0] + (fac * (cp2[0] / 255.0f)));
+ cp[1] = (mfac * cp1[1] + (fac * (cp2[1] / 255.0f)));
+ cp[2] = (mfac * cp1[2] + (fac * (cp2[2] / 255.0f)));
+ cp[3] = alpha > 1.0f ? 1.0f : alpha;
+}
+
+
+static void do_projectpaint_clone(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask)
+{
+ if (ps->do_masking && mask < 1.0f) {
+ projPixel->newColor.uint = IMB_blend_color(projPixel->newColor.uint, ((ProjPixelClone *)projPixel)->clonepx.uint, (int)(alpha * 255), ps->blend);
+ blend_color_mix(projPixel->pixel.ch_pt, projPixel->origColor.ch, projPixel->newColor.ch, (int)(mask * 255));
+ }
+ else {
+ *projPixel->pixel.uint_pt = IMB_blend_color(*projPixel->pixel.uint_pt, ((ProjPixelClone *)projPixel)->clonepx.uint, (int)(alpha * mask * 255), ps->blend);
+ }
+}
+
+static void do_projectpaint_clone_f(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask)
+{
+ if (ps->do_masking && mask < 1.0f) {
+ IMB_blend_color_float(projPixel->newColor.f, projPixel->newColor.f, ((ProjPixelClone *)projPixel)->clonepx.f, alpha, ps->blend);
+ blend_color_mix_float(projPixel->pixel.f_pt, projPixel->origColor.f, projPixel->newColor.f, mask);
+ }
+ else {
+ IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, ((ProjPixelClone *)projPixel)->clonepx.f, alpha * mask, ps->blend);
+ }
+}
+
+/* do_projectpaint_smear*
+ *
+ * note, mask is used to modify the alpha here, this is not correct since it allows
+ * accumulation of color greater then 'projPixel->mask' however in the case of smear its not
+ * really that important to be correct as it is with clone and painting
+ */
+static void do_projectpaint_smear(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask,
+ MemArena *smearArena, LinkNode **smearPixels, const float co[2])
+{
+ unsigned char rgba_ub[4];
+
+ if (project_paint_PickColor(ps, co, NULL, rgba_ub, 1) == 0)
+ return;
+ /* ((ProjPixelClone *)projPixel)->clonepx.uint = IMB_blend_color(*projPixel->pixel.uint_pt, *((unsigned int *)rgba_ub), (int)(alpha*mask*255), ps->blend); */
+ blend_color_mix(((ProjPixelClone *)projPixel)->clonepx.ch, projPixel->pixel.ch_pt, rgba_ub, (int)(alpha * mask * 255));
+ BLI_linklist_prepend_arena(smearPixels, (void *)projPixel, smearArena);
+}
+
+static void do_projectpaint_smear_f(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask,
+ MemArena *smearArena, LinkNode **smearPixels_f, const float co[2])
+{
+ float rgba[4];
+
+ if (project_paint_PickColor(ps, co, rgba, NULL, 1) == 0)
+ return;
+
+ /* (ProjPixelClone *)projPixel)->clonepx.uint = IMB_blend_color(*((unsigned int *)rgba_smear), *((unsigned int *)rgba_ub), (int)(alpha*mask*255), ps->blend); */
+ blend_color_mix_float(((ProjPixelClone *)projPixel)->clonepx.f, projPixel->pixel.f_pt, rgba, alpha * mask);
+ BLI_linklist_prepend_arena(smearPixels_f, (void *)projPixel, smearArena);
+}
+
+/* do_projectpaint_soften for float & byte
+ */
+static float inv_pow2(float f)
+{
+ f = 1.0f - f;
+ f = f * f;
+ return 1.0f - f;
+}
+
+static void do_projectpaint_soften_f(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask,
+ MemArena *softenArena, LinkNode **softenPixels)
+{
+ unsigned int accum_tot = 0;
+ unsigned int i;
+
+ float *rgba = projPixel->newColor.f;
+
+ /* sigh, alpha values tend to need to be a _lot_ stronger with blur */
+ mask = inv_pow2(mask);
+ alpha = inv_pow2(alpha);
+
+ /* rather then painting, accumulate surrounding colors */
+ zero_v4(rgba);
+
+ for (i = 0; i < PROJ_PIXEL_SOFTEN_TOT; i++) {
+ float co_ofs[2];
+ float rgba_tmp[4];
+ sub_v2_v2v2(co_ofs, projPixel->projCoSS, proj_pixel_soften_v2[i]);
+ if (project_paint_PickColor(ps, co_ofs, rgba_tmp, NULL, TRUE)) {
+ add_v4_v4(rgba, rgba_tmp);
+ accum_tot++;
+ }
+ }
+
+ if (LIKELY(accum_tot != 0)) {
+ mul_v4_fl(rgba, 1.0f / (float)accum_tot);
+ blend_color_mix_float(rgba, projPixel->pixel.f_pt, rgba, alpha);
+ if (mask < 1.0f) blend_color_mix_float(rgba, projPixel->origColor.f, rgba, mask);
+ BLI_linklist_prepend_arena(softenPixels, (void *)projPixel, softenArena);
+ }
+}
+
+static void do_projectpaint_soften(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask,
+ MemArena *softenArena, LinkNode **softenPixels)
+{
+ unsigned int accum_tot = 0;
+ unsigned int i;
+
+ float rgba[4]; /* convert to byte after */
+
+ /* sigh, alpha values tend to need to be a _lot_ stronger with blur */
+ mask = inv_pow2(mask);
+ alpha = inv_pow2(alpha);
+
+ /* rather then painting, accumulate surrounding colors */
+ zero_v4(rgba);
+
+ for (i = 0; i < PROJ_PIXEL_SOFTEN_TOT; i++) {
+ float co_ofs[2];
+ float rgba_tmp[4];
+ sub_v2_v2v2(co_ofs, projPixel->projCoSS, proj_pixel_soften_v2[i]);
+ if (project_paint_PickColor(ps, co_ofs, rgba_tmp, NULL, TRUE)) {
+ add_v4_v4(rgba, rgba_tmp);
+ accum_tot++;
+ }
+ }
+
+ if (LIKELY(accum_tot != 0)) {
+ unsigned char *rgba_ub = projPixel->newColor.ch;
+
+ mul_v4_fl(rgba, 1.0f / (float)accum_tot);
+ IMAPAINT_FLOAT_RGBA_TO_CHAR(rgba_ub, rgba);
+
+ blend_color_mix(rgba_ub, projPixel->pixel.ch_pt, rgba_ub, (int)(alpha * 255));
+ if (mask != 1.0f) blend_color_mix(rgba_ub, projPixel->origColor.ch, rgba_ub, (int)(mask * 255));
+ BLI_linklist_prepend_arena(softenPixels, (void *)projPixel, softenArena);
+ }
+}
+
+BLI_INLINE void rgba_float_to_uchar__mul_v3(unsigned char rgba_ub[4], const float rgba[4], const float rgb[3])
+{
+ rgba_ub[0] = f_to_char(rgba[0] * rgb[0]);
+ rgba_ub[1] = f_to_char(rgba[1] * rgb[1]);
+ rgba_ub[2] = f_to_char(rgba[2] * rgb[2]);
+ rgba_ub[3] = f_to_char(rgba[3]);
+}
+
+static void do_projectpaint_draw(ProjPaintState *ps, ProjPixel *projPixel, const float rgba[4], float alpha, float mask)
+{
+ unsigned char rgba_ub[4];
+
+ if (ps->is_texbrush) {
+ rgba_float_to_uchar__mul_v3(rgba_ub, rgba, ps->brush->rgb);
+ }
+ else {
+ IMAPAINT_FLOAT_RGB_TO_CHAR(rgba_ub, ps->brush->rgb);
+ rgba_ub[3] = 255;
+ }
+
+ if (ps->do_masking && mask < 1.0f) {
+ projPixel->newColor.uint = IMB_blend_color(projPixel->newColor.uint, *((unsigned int *)rgba_ub), (int)(alpha * 255), ps->blend);
+ blend_color_mix(projPixel->pixel.ch_pt, projPixel->origColor.ch, projPixel->newColor.ch, (int)(mask * 255));
+ }
+ else {
+ *projPixel->pixel.uint_pt = IMB_blend_color(*projPixel->pixel.uint_pt, *((unsigned int *)rgba_ub), (int)(alpha * mask * 255), ps->blend);
+ }
+}
+
+static void do_projectpaint_draw_f(ProjPaintState *ps, ProjPixel *projPixel, float rgba[4], float alpha, float mask)
+{
+ if (ps->is_texbrush) {
+ /* rgba already holds a texture result here from higher level function */
+ float rgba_br[3];
+ srgb_to_linearrgb_v3_v3(rgba_br, ps->brush->rgb);
+ mul_v3_v3(rgba, rgba_br);
+ }
+ else {
+ srgb_to_linearrgb_v3_v3(rgba, ps->brush->rgb);
+ rgba[3] = 1.0;
+ }
+
+ if (ps->do_masking && mask < 1.0f) {
+ IMB_blend_color_float(projPixel->newColor.f, projPixel->newColor.f, rgba, alpha, ps->blend);
+ blend_color_mix_float(projPixel->pixel.f_pt, projPixel->origColor.f, projPixel->newColor.f, mask);
+ }
+ else {
+ IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, rgba, alpha * mask, ps->blend);
+ }
+}
+
+
+
+/* run this for single and multithreaded painting */
+static void *do_projectpaint_thread(void *ph_v)
+{
+ /* First unpack args from the struct */
+ ProjPaintState *ps = ((ProjectHandle *)ph_v)->ps;
+ ProjPaintImage *projImages = ((ProjectHandle *)ph_v)->projImages;
+ const float *lastpos = ((ProjectHandle *)ph_v)->prevmval;
+ const float *pos = ((ProjectHandle *)ph_v)->mval;
+ const int thread_index = ((ProjectHandle *)ph_v)->thread_index;
+ struct ImagePool *pool = ((ProjectHandle *)ph_v)->pool;
+ /* Done with args from ProjectHandle */
+
+ LinkNode *node;
+ ProjPixel *projPixel;
+ Brush *brush = ps->brush;
+
+ int last_index = -1;
+ ProjPaintImage *last_projIma = NULL;
+ ImagePaintPartialRedraw *last_partial_redraw_cell;
+
+ float rgba[4], alpha, dist_nosqrt, dist;
+
+ float falloff;
+ int bucket_index;
+ int is_floatbuf = 0;
+ const short tool = ps->tool;
+ rctf bucket_bounds;
+
+ /* for smear only */
+ float pos_ofs[2] = {0};
+ float co[2];
+ float mask = 1.0f; /* airbrush wont use mask */
+ unsigned short mask_short;
+ const float radius = (float)BKE_brush_size_get(ps->scene, brush);
+ const float radius_squared = radius * radius; /* avoid a square root with every dist comparison */
+
+ short lock_alpha = ELEM(brush->blend, IMB_BLEND_ERASE_ALPHA, IMB_BLEND_ADD_ALPHA) ? 0 : brush->flag & BRUSH_LOCK_ALPHA;
+
+ LinkNode *smearPixels = NULL;
+ LinkNode *smearPixels_f = NULL;
+ MemArena *smearArena = NULL; /* mem arena for this brush projection only */
+
+ LinkNode *softenPixels = NULL;
+ LinkNode *softenPixels_f = NULL;
+ MemArena *softenArena = NULL; /* mem arena for this brush projection only */
+
+ if (tool == PAINT_TOOL_SMEAR) {
+ pos_ofs[0] = pos[0] - lastpos[0];
+ pos_ofs[1] = pos[1] - lastpos[1];
+
+ smearArena = BLI_memarena_new(1 << 16, "paint smear arena");
+ }
+ else if (tool == PAINT_TOOL_SOFTEN) {
+ softenArena = BLI_memarena_new(1 << 16, "paint soften arena");
+ }
+
+ /* printf("brush bounds %d %d %d %d\n", bucketMin[0], bucketMin[1], bucketMax[0], bucketMax[1]); */
+
+ while (project_bucket_iter_next(ps, &bucket_index, &bucket_bounds, pos)) {
+
+ /* Check this bucket and its faces are initialized */
+ if (ps->bucketFlags[bucket_index] == PROJ_BUCKET_NULL) {
+ /* No pixels initialized */
+ project_bucket_init(ps, thread_index, bucket_index, &bucket_bounds);
+ }
+
+ if (ps->source != PROJ_SRC_VIEW) {
+
+ /* Re-Projection, simple, no brushes! */
+
+ for (node = ps->bucketRect[bucket_index]; node; node = node->next) {
+ projPixel = (ProjPixel *)node->link;
+
+ /* copy of code below */
+ if (last_index != projPixel->image_index) {
+ last_index = projPixel->image_index;
+ last_projIma = projImages + last_index;
+
+ last_projIma->touch = 1;
+ is_floatbuf = last_projIma->ibuf->rect_float ? 1 : 0;
+ }
+ /* end copy */
+
+ if (is_floatbuf) {
+ /* re-project buffer is assumed byte - TODO, allow float */
+ bicubic_interpolation_color(ps->reproject_ibuf, projPixel->newColor.ch, NULL,
+ projPixel->projCoSS[0], projPixel->projCoSS[1]);
+ if (projPixel->newColor.ch[3]) {
+ mask = ((float)projPixel->mask) / 65535.0f;
+ blend_color_mix_accum_float(projPixel->pixel.f_pt, projPixel->origColor.f,
+ projPixel->newColor.ch, (mask * (projPixel->newColor.ch[3] / 255.0f)));
+ }
+ }
+ else {
+ /* re-project buffer is assumed byte - TODO, allow float */
+ bicubic_interpolation_color(ps->reproject_ibuf, projPixel->newColor.ch, NULL,
+ projPixel->projCoSS[0], projPixel->projCoSS[1]);
+ if (projPixel->newColor.ch[3]) {
+ mask = ((float)projPixel->mask) / 65535.0f;
+ blend_color_mix_accum(projPixel->pixel.ch_pt, projPixel->origColor.ch,
+ projPixel->newColor.ch, (int)(mask * projPixel->newColor.ch[3]));
+ }
+ }
+ }
+ }
+ else {
+ /* Normal brush painting */
+
+ for (node = ps->bucketRect[bucket_index]; node; node = node->next) {
+
+ projPixel = (ProjPixel *)node->link;
+
+ dist_nosqrt = len_squared_v2v2(projPixel->projCoSS, pos);
+
+ /*if (dist < radius) {*/ /* correct but uses a sqrtf */
+ if (dist_nosqrt <= radius_squared) {
+ float samplecos[3];
+ dist = sqrtf(dist_nosqrt);
+
+ falloff = BKE_brush_curve_strength_clamp(ps->brush, dist, radius);
+
+ if (ps->is_texbrush) {
+ MTex *mtex = &brush->mtex;
+ /* taking 3d copy to account for 3D mapping too. It gets concatenated during sampling */
+ if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
+ copy_v3_v3(samplecos, projPixel->worldCoSS);
+ }
+ else {
+ copy_v2_v2(samplecos, projPixel->projCoSS);
+ samplecos[2] = 0.0f;
+ }
+ }
+
+ if (falloff > 0.0f) {
+ if (ps->is_texbrush) {
+ /* note, for clone and smear, we only use the alpha, could be a special function */
+ BKE_brush_sample_tex_3D(ps->scene, brush, samplecos, rgba, thread_index, pool);
+ alpha = rgba[3];
+ }
+ else {
+ alpha = 1.0f;
+ }
+
+ if (!ps->do_masking) {
+ /* for an aurbrush there is no real mask, so just multiply the alpha by it */
+ alpha *= falloff * BKE_brush_alpha_get(ps->scene, brush);
+ mask = ((float)projPixel->mask) / 65535.0f;
+ }
+ else {
+ /* This brush dosnt accumulate so add some curve to the brushes falloff */
+ falloff = 1.0f - falloff;
+ falloff = 1.0f - (falloff * falloff);
+
+ mask_short = (unsigned short)(projPixel->mask * (BKE_brush_alpha_get(ps->scene, brush) * falloff));
+ if (mask_short > projPixel->mask_max) {
+ mask = ((float)mask_short) / 65535.0f;
+ projPixel->mask_max = mask_short;
+ }
+ else {
+ /*mask = ((float)projPixel->mask_max)/65535.0f;*/
+
+ /* Go onto the next pixel */
+ continue;
+ }
+ }
+
+ if (alpha > 0.0f) {
+
+ /* copy of code above */
+ if (last_index != projPixel->image_index) {
+ last_index = projPixel->image_index;
+ last_projIma = projImages + last_index;
+
+ last_projIma->touch = 1;
+ is_floatbuf = last_projIma->ibuf->rect_float ? 1 : 0;
+ }
+ /* end copy */
+
+ last_partial_redraw_cell = last_projIma->partRedrawRect + projPixel->bb_cell_index;
+ last_partial_redraw_cell->x1 = min_ii(last_partial_redraw_cell->x1, (int)projPixel->x_px);
+ last_partial_redraw_cell->y1 = min_ii(last_partial_redraw_cell->y1, (int)projPixel->y_px);
+
+ last_partial_redraw_cell->x2 = max_ii(last_partial_redraw_cell->x2, (int)projPixel->x_px + 1);
+ last_partial_redraw_cell->y2 = max_ii(last_partial_redraw_cell->y2, (int)projPixel->y_px + 1);
+
+
+ switch (tool) {
+ case PAINT_TOOL_CLONE:
+ if (is_floatbuf) {
+ if (((ProjPixelClone *)projPixel)->clonepx.f[3]) {
+ do_projectpaint_clone_f(ps, projPixel, alpha, mask); /* rgba isn't used for cloning, only alpha */
+ }
+ }
+ else {
+ if (((ProjPixelClone *)projPixel)->clonepx.ch[3]) {
+ do_projectpaint_clone(ps, projPixel, alpha, mask); /* rgba isn't used for cloning, only alpha */
+ }
+ }
+ break;
+ case PAINT_TOOL_SMEAR:
+ sub_v2_v2v2(co, projPixel->projCoSS, pos_ofs);
+
+ if (is_floatbuf) do_projectpaint_smear_f(ps, projPixel, alpha, mask, smearArena, &smearPixels_f, co);
+ else do_projectpaint_smear(ps, projPixel, alpha, mask, smearArena, &smearPixels, co);
+ break;
+ case PAINT_TOOL_SOFTEN:
+ if (is_floatbuf) do_projectpaint_soften_f(ps, projPixel, alpha, mask, softenArena, &softenPixels_f);
+ else do_projectpaint_soften(ps, projPixel, alpha, mask, softenArena, &softenPixels);
+ break;
+ default:
+ if (is_floatbuf) do_projectpaint_draw_f(ps, projPixel, rgba, alpha, mask);
+ else do_projectpaint_draw(ps, projPixel, rgba, alpha, mask);
+ break;
+ }
+ }
+
+ if (lock_alpha) {
+ if (is_floatbuf) projPixel->pixel.f_pt[3] = projPixel->origColor.f[3];
+ else projPixel->pixel.ch_pt[3] = projPixel->origColor.ch[3];
+ }
+
+ /* done painting */
+ }
+ }
+ }
+ }
+ }
+
+
+ if (tool == PAINT_TOOL_SMEAR) {
+
+ for (node = smearPixels; node; node = node->next) { /* this wont run for a float image */
+ projPixel = node->link;
+ *projPixel->pixel.uint_pt = ((ProjPixelClone *)projPixel)->clonepx.uint;
+ }
+
+ for (node = smearPixels_f; node; node = node->next) {
+ projPixel = node->link;
+ copy_v4_v4(projPixel->pixel.f_pt, ((ProjPixelClone *)projPixel)->clonepx.f);
+ }
+
+ BLI_memarena_free(smearArena);
+ }
+ else if (tool == PAINT_TOOL_SOFTEN) {
+
+ for (node = softenPixels; node; node = node->next) { /* this wont run for a float image */
+ projPixel = node->link;
+ *projPixel->pixel.uint_pt = projPixel->newColor.uint;
+ }
+
+ for (node = softenPixels_f; node; node = node->next) {
+ projPixel = node->link;
+ copy_v4_v4(projPixel->pixel.f_pt, projPixel->newColor.f);
+ }
+
+ BLI_memarena_free(softenArena);
+ }
+
+ return NULL;
+}
+
+static int project_paint_op(void *state, const float lastpos[2], const float pos[2])
+{
+ /* First unpack args from the struct */
+ ProjPaintState *ps = (ProjPaintState *)state;
+ int touch_any = 0;
+
+ ProjectHandle handles[BLENDER_MAX_THREADS];
+ ListBase threads;
+ int a, i;
+
+ struct ImagePool *pool;
+
+ if (!project_bucket_iter_init(ps, pos)) {
+ return 0;
+ }
+
+ if (ps->thread_tot > 1)
+ BLI_init_threads(&threads, do_projectpaint_thread, ps->thread_tot);
+
+ pool = BKE_image_pool_new();
+
+ /* get the threads running */
+ for (a = 0; a < ps->thread_tot; a++) {
+
+ /* set defaults in handles */
+ //memset(&handles[a], 0, sizeof(BakeShade));
+
+ handles[a].ps = ps;
+ copy_v2_v2(handles[a].mval, pos);
+ copy_v2_v2(handles[a].prevmval, lastpos);
+
+ /* thread specific */
+ handles[a].thread_index = a;
+
+ handles[a].projImages = (ProjPaintImage *)BLI_memarena_alloc(ps->arena_mt[a], ps->image_tot * sizeof(ProjPaintImage));
+
+ memcpy(handles[a].projImages, ps->projImages, ps->image_tot * sizeof(ProjPaintImage));
+
+ /* image bounds */
+ for (i = 0; i < ps->image_tot; i++) {
+ handles[a].projImages[i].partRedrawRect = (ImagePaintPartialRedraw *)BLI_memarena_alloc(ps->arena_mt[a], sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
+ memcpy(handles[a].projImages[i].partRedrawRect, ps->projImages[i].partRedrawRect, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
+ }
+
+ handles[a].pool = pool;
+
+ if (ps->thread_tot > 1)
+ BLI_insert_thread(&threads, &handles[a]);
+ }
+
+ if (ps->thread_tot > 1) /* wait for everything to be done */
+ BLI_end_threads(&threads);
+ else
+ do_projectpaint_thread(&handles[0]);
+
+
+ BKE_image_pool_free(pool);
+
+ /* move threaded bounds back into ps->projectPartialRedraws */
+ for (i = 0; i < ps->image_tot; i++) {
+ int touch = 0;
+ for (a = 0; a < ps->thread_tot; a++) {
+ touch |= partial_redraw_array_merge(ps->projImages[i].partRedrawRect, handles[a].projImages[i].partRedrawRect, PROJ_BOUNDBOX_SQUARED);
+ }
+
+ if (touch) {
+ ps->projImages[i].touch = 1;
+ touch_any = 1;
+ }
+ }
+
+ return touch_any;
+}
+
+
+int paint_proj_stroke(bContext *C, void *pps, const int prevmval_i[2], const int mval_i[2])
+{
+ ProjPaintState *ps = pps;
+ int a, redraw;
+ float pos[2], prev_pos[2];
+
+ pos[0] = (float)(mval_i[0]);
+ pos[1] = (float)(mval_i[1]);
+
+ prev_pos[0] = (float)(prevmval_i[0]);
+ prev_pos[1] = (float)(prevmval_i[1]);
+
+ /* clone gets special treatment here to avoid going through image initialization */
+ if (ps->tool == PAINT_TOOL_CLONE && ps->mode == BRUSH_STROKE_INVERT) {
+ Scene *scene = ps->scene;
+ View3D *v3d = ps->v3d;
+ float *cursor = give_cursor(scene, v3d);
+
+ view3d_operator_needs_opengl(C);
+
+ if (!ED_view3d_autodist(scene, ps->ar, v3d, mval_i, cursor))
+ return 0;
+
+ ED_region_tag_redraw(ps->ar);
+
+ return 0;
+ }
+
+ for (a = 0; a < ps->image_tot; a++)
+ partial_redraw_array_init(ps->projImages[a].partRedrawRect);
+
+ redraw = project_paint_op(ps, prev_pos, pos) ? 1 : 0;
+
+ if (project_image_refresh_tagged(ps))
+ return redraw;
+
+ return 0;
+}
+
+
+/* initialize project paint settings from context */
+static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int mode)
+{
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *settings = scene->toolsettings;
+
+ /* brush */
+ ps->mode = mode;
+ ps->brush = paint_brush(&settings->imapaint.paint);
+ if (ps->brush) {
+ Brush *brush = ps->brush;
+ ps->tool = brush->imagepaint_tool;
+ ps->blend = brush->blend;
+
+ /* disable for 3d mapping also because painting on mirrored mesh can create "stripes" */
+ ps->do_masking = (brush->flag & BRUSH_AIRBRUSH || brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW ||
+ brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) ? false : true;
+ ps->is_texbrush = (brush->mtex.tex && brush->imagepaint_tool == PAINT_TOOL_DRAW) ? 1 : 0;
+ }
+ else {
+ /* brush may be NULL*/
+ ps->do_masking = false;
+ ps->is_texbrush = false;
+ }
+
+ /* sizeof(ProjPixel), since we alloc this a _lot_ */
+ ps->pixel_sizeof = project_paint_pixel_sizeof(ps->tool);
+ BLI_assert(ps->pixel_sizeof >= sizeof(ProjPixel));
+
+ /* these can be NULL */
+ ps->v3d = CTX_wm_view3d(C);
+ ps->rv3d = CTX_wm_region_view3d(C);
+ ps->ar = CTX_wm_region(C);
+
+ ps->scene = scene;
+ ps->ob = ob; /* allow override of active object */
+
+ /* setup projection painting data */
+ ps->do_backfacecull = (settings->imapaint.flag & IMAGEPAINT_PROJECT_BACKFACE) ? 0 : 1;
+ ps->do_occlude = (settings->imapaint.flag & IMAGEPAINT_PROJECT_XRAY) ? 0 : 1;
+ ps->do_mask_normal = (settings->imapaint.flag & IMAGEPAINT_PROJECT_FLAT) ? 0 : 1;
+ ps->do_new_shading_nodes = BKE_scene_use_new_shading_nodes(scene); /* only cache the value */
+
+ if (ps->tool == PAINT_TOOL_CLONE)
+ ps->do_layer_clone = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE);
+
+ ps->do_layer_stencil = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL) ? 1 : 0;
+ ps->do_layer_stencil_inv = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) ? 1 : 0;
+
+
+#ifndef PROJ_DEBUG_NOSEAMBLEED
+ ps->seam_bleed_px = settings->imapaint.seam_bleed; /* pixel num to bleed */
+#endif
+
+ if (ps->do_mask_normal) {
+ ps->normal_angle_inner = settings->imapaint.normal_angle;
+ ps->normal_angle = (ps->normal_angle_inner + 90.0f) * 0.5f;
+ }
+ else {
+ ps->normal_angle_inner = ps->normal_angle = settings->imapaint.normal_angle;
+ }
+
+ ps->normal_angle_inner *= (float)(M_PI_2 / 90);
+ ps->normal_angle *= (float)(M_PI_2 / 90);
+ ps->normal_angle_range = ps->normal_angle - ps->normal_angle_inner;
+
+ if (ps->normal_angle_range <= 0.0f)
+ ps->do_mask_normal = FALSE; /* no need to do blending */
+
+ return;
+}
+
+void *paint_proj_new_stroke(bContext *C, Object *ob, const int mouse[2], int mode)
+{
+ ProjPaintState *ps = MEM_callocN(sizeof(ProjPaintState), "ProjectionPaintState");
+ project_state_init(C, ob, ps, mode);
+
+ if (ps->tool == PAINT_TOOL_CLONE && mode == BRUSH_STROKE_INVERT) {
+ view3d_operator_needs_opengl(C);
+ return ps;
+ }
+
+ /* needed so multiple threads don't try to initialize the brush at once (can leak memory) */
+ curvemapping_initialize(ps->brush->curve);
+
+ paint_brush_init_tex(ps->brush);
+
+ ps->source = PROJ_SRC_VIEW;
+
+ if (ps->ob == NULL || !(ps->ob->lay & ps->v3d->lay)) {
+ MEM_freeN(ps);
+ return NULL;
+ }
+
+ ps->orig_brush_size = BKE_brush_size_get(ps->scene, ps->brush);
+
+ /* Don't allow brush size below 2 */
+ if (BKE_brush_size_get(ps->scene, ps->brush) < 2)
+ BKE_brush_size_set(ps->scene, ps->brush, 2);
+
+ /* allocate and initialize spatial data structures */
+ project_paint_begin(ps);
+
+ if (ps->dm == NULL) {
+ MEM_freeN(ps);
+ return NULL;
+ }
+
+ paint_proj_begin_clone(ps, mouse);
+
+ return ps;
+}
+
+void paint_proj_stroke_done(void *pps)
+{
+ ProjPaintState *ps = pps;
+ if (ps->tool == PAINT_TOOL_CLONE && ps->mode == BRUSH_STROKE_INVERT) {
+ MEM_freeN(ps);
+ return;
+ }
+ BKE_brush_size_set(ps->scene, ps->brush, ps->orig_brush_size);
+
+ paint_brush_exit_tex(ps->brush);
+
+ project_paint_end(ps);
+ MEM_freeN(ps);
+}
+/* use project paint to re-apply an image */
+static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
+{
+ Image *image = BLI_findlink(&CTX_data_main(C)->image, RNA_enum_get(op->ptr, "image"));
+ Scene *scene = CTX_data_scene(C);
+ ProjPaintState ps = {NULL};
+ int orig_brush_size;
+ IDProperty *idgroup;
+ IDProperty *view_data = NULL;
+
+ project_state_init(C, OBACT, &ps, BRUSH_STROKE_NORMAL);
+
+ if (ps.ob == NULL || ps.ob->type != OB_MESH) {
+ BKE_report(op->reports, RPT_ERROR, "No active mesh object");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (image == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Image could not be found");
+ return OPERATOR_CANCELLED;
+ }
+
+ ps.reproject_image = image;
+ ps.reproject_ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
+
+ if (ps.reproject_ibuf == NULL || ps.reproject_ibuf->rect == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Image data could not be found");
+ return OPERATOR_CANCELLED;
+ }
+
+ idgroup = IDP_GetProperties(&image->id, 0);
+
+ if (idgroup) {
+ view_data = IDP_GetPropertyTypeFromGroup(idgroup, PROJ_VIEW_DATA_ID, IDP_ARRAY);
+
+ /* type check to make sure its ok */
+ if (view_data->len != PROJ_VIEW_DATA_SIZE || view_data->subtype != IDP_FLOAT) {
+ BKE_report(op->reports, RPT_ERROR, "Image project data invalid");
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ if (view_data) {
+ /* image has stored view projection info */
+ ps.source = PROJ_SRC_IMAGE_VIEW;
+ }
+ else {
+ ps.source = PROJ_SRC_IMAGE_CAM;
+
+ if (scene->camera == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No active camera set");
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ /* override */
+ ps.is_texbrush = 0;
+ ps.do_masking = false;
+ orig_brush_size = BKE_brush_size_get(scene, ps.brush);
+ BKE_brush_size_set(scene, ps.brush, 32); /* cover the whole image */
+
+ ps.tool = PAINT_TOOL_DRAW; /* so pixels are initialized with minimal info */
+
+ scene->toolsettings->imapaint.flag |= IMAGEPAINT_DRAWING;
+
+ undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name,
+ image_undo_restore, image_undo_free);
+
+ /* allocate and initialize spatial data structures */
+ project_paint_begin(&ps);
+
+ if (ps.dm == NULL) {
+ BKE_brush_size_set(scene, ps.brush, orig_brush_size);
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ float pos[2] = {0.0, 0.0};
+ float lastpos[2] = {0.0, 0.0};
+ int a;
+
+ for (a = 0; a < ps.image_tot; a++)
+ partial_redraw_array_init(ps.projImages[a].partRedrawRect);
+
+ project_paint_op(&ps, lastpos, pos);
+
+ project_image_refresh_tagged(&ps);
+
+ for (a = 0; a < ps.image_tot; a++) {
+ GPU_free_image(ps.projImages[a].ima);
+ WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ps.projImages[a].ima);
+ }
+ }
+
+ project_paint_end(&ps);
+
+ scene->toolsettings->imapaint.flag &= ~IMAGEPAINT_DRAWING;
+ BKE_brush_size_set(scene, ps.brush, orig_brush_size);
+
+ return OPERATOR_FINISHED;
+}
+
+void PAINT_OT_project_image(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Project Image";
+ ot->idname = "PAINT_OT_project_image";
+ ot->description = "Project an edited render from the active camera back onto the object";
+
+ /* api callbacks */
+ ot->invoke = WM_enum_search_invoke;
+ ot->exec = texture_paint_camera_project_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ prop = RNA_def_enum(ot->srna, "image", DummyRNA_NULL_items, 0, "Image", "");
+ RNA_def_enum_funcs(prop, RNA_image_itemf);
+ ot->prop = prop;
+}
+
+static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
+{
+ Image *image;
+ ImBuf *ibuf;
+ char filename[FILE_MAX];
+
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *settings = scene->toolsettings;
+ int w = settings->imapaint.screen_grab_size[0];
+ int h = settings->imapaint.screen_grab_size[1];
+ int maxsize;
+ char err_out[256] = "unknown";
+
+ RNA_string_get(op->ptr, "filepath", filename);
+
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize);
+
+ if (w > maxsize) w = maxsize;
+ if (h > maxsize) h = maxsize;
+
+ ibuf = ED_view3d_draw_offscreen_imbuf(CTX_data_scene(C), CTX_wm_view3d(C), CTX_wm_region(C), w, h, IB_rect, FALSE, R_ALPHAPREMUL, err_out);
+ if (!ibuf) {
+ /* Mostly happens when OpenGL offscreen buffer was failed to create, */
+ /* but could be other reasons. Should be handled in the future. nazgul */
+ BKE_reportf(op->reports, RPT_ERROR, "Failed to create OpenGL off-screen buffer: %s", err_out);
+ return OPERATOR_CANCELLED;
+ }
+
+ image = BKE_image_add_from_imbuf(ibuf);
+
+ if (image) {
+ /* now for the trickyness. store the view projection here!
+ * re-projection will reuse this */
+ View3D *v3d = CTX_wm_view3d(C);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+
+ IDPropertyTemplate val;
+ IDProperty *idgroup = IDP_GetProperties(&image->id, 1);
+ IDProperty *view_data;
+ bool is_ortho;
+ float *array;
+
+ val.array.len = PROJ_VIEW_DATA_SIZE;
+ val.array.type = IDP_FLOAT;
+ view_data = IDP_New(IDP_ARRAY, &val, PROJ_VIEW_DATA_ID);
+
+ array = (float *)IDP_Array(view_data);
+ memcpy(array, rv3d->winmat, sizeof(rv3d->winmat)); array += sizeof(rv3d->winmat) / sizeof(float);
+ memcpy(array, rv3d->viewmat, sizeof(rv3d->viewmat)); array += sizeof(rv3d->viewmat) / sizeof(float);
+ is_ortho = ED_view3d_clip_range_get(v3d, rv3d, &array[0], &array[1], true);
+ array[2] = is_ortho ? 1.0f : 0.0f; /* using float for a bool is dodgy but since its an extra member in the array... easier then adding a single bool prop */
+
+ IDP_AddToGroup(idgroup, view_data);
+
+ rename_id(&image->id, "image_view");
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void PAINT_OT_image_from_view(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Image from View";
+ ot->idname = "PAINT_OT_image_from_view";
+ ot->description = "Make an image from the current 3D view for re-projection";
+
+ /* api callbacks */
+ ot->exec = texture_paint_image_from_view_exec;
+ ot->poll = ED_operator_region_view3d_active;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER;
+
+ RNA_def_string_file_name(ot->srna, "filepath", "", FILE_MAX, "File Path", "Name of the file");
+}
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index e7c3ddd071b..a15795dc2da 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -50,6 +50,8 @@ struct ViewContext;
struct wmEvent;
struct wmOperator;
struct wmOperatorType;
+struct ImagePaintState;
+enum PaintMode;
/* paint_stroke.c */
typedef int (*StrokeGetLocation)(struct bContext *C, float location[3], const float mouse[2]);
@@ -62,11 +64,14 @@ struct PaintStroke *paint_stroke_new(struct bContext *C,
StrokeUpdateStep update_step, StrokeDone done, int event_type);
void paint_stroke_data_free(struct wmOperator *op);
-bool paint_space_stroke_enabled(struct Brush *br);
-bool paint_supports_dynamic_size(struct Brush *br);
+bool paint_space_stroke_enabled(struct Brush *br, enum PaintMode mode);
+bool paint_supports_dynamic_size(struct Brush *br, enum PaintMode mode);
+bool paint_supports_dynamic_tex_coords(struct Brush *br, enum PaintMode mode);
+bool paint_supports_smooth_stroke(struct Brush *br, enum PaintMode mode);
+bool paint_supports_jitter(enum PaintMode mode);
struct wmKeyMap *paint_stroke_modal_keymap(struct wmKeyConfig *keyconf);
-int paint_stroke_modal(struct bContext *C, struct wmOperator *op, struct wmEvent *event);
+int paint_stroke_modal(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
int paint_stroke_exec(struct bContext *C, struct wmOperator *op);
int paint_stroke_cancel(struct bContext *C, struct wmOperator *op);
struct ViewContext *paint_stroke_view_context(struct PaintStroke *stroke);
@@ -103,16 +108,46 @@ void PAINT_OT_vertex_paint(struct wmOperatorType *ot);
unsigned int vpaint_get_current_col(struct VPaint *vp);
/* paint_image.c */
+typedef struct ImagePaintPartialRedraw {
+ int x1, y1, x2, y2; /* XXX, could use 'rcti' */
+ int enabled;
+} ImagePaintPartialRedraw;
+
+#define IMAPAINT_TILE_BITS 6
+#define IMAPAINT_TILE_SIZE (1 << IMAPAINT_TILE_BITS)
+#define IMAPAINT_TILE_NUMBER(size) (((size) + IMAPAINT_TILE_SIZE - 1) >> IMAPAINT_TILE_BITS)
+
+#define IMAPAINT_CHAR_TO_FLOAT(c) ((c) / 255.0f)
+
int image_texture_paint_poll(struct bContext *C);
+void *image_undo_push_tile(struct Image *ima, struct ImBuf *ibuf, struct ImBuf **tmpibuf, int x_tile, int y_tile);
+void image_undo_restore(struct bContext *C, struct ListBase *lb);
+void image_undo_free(struct ListBase *lb);
+void imapaint_image_update(struct SpaceImage *sima, struct Image *image, struct ImBuf *ibuf, short texpaint);
+struct ImagePaintPartialRedraw *get_imapaintpartial(void);
+void set_imapaintpartial(struct ImagePaintPartialRedraw * ippr);
+void imapaint_clear_partial_redraw(void);
+void imapaint_dirty_region(struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h);
+int get_imapaint_zoom(struct bContext *C, float *zoomx, float *zoomy);
+void *paint_2d_new_stroke(struct bContext *, struct wmOperator *);
+void paint_2d_redraw(const bContext *C, void *ps, int final);
+void paint_2d_stroke_done(void *ps);
+int paint_2d_stroke(void *ps, const int prev_mval[2], const int mval[2], int eraser);
+void *paint_proj_new_stroke(struct bContext *C, struct Object *ob, const int mouse[2], int mode);
+int paint_proj_stroke(struct bContext *C, void *ps, const int prevmval_i[2], const int mval_i[2]);
+void paint_proj_stroke_done(void *ps);
+void paint_brush_init_tex(struct Brush *brush);
+void paint_brush_exit_tex(struct Brush *brush);
-void PAINT_OT_image_paint(struct wmOperatorType *ot);
void PAINT_OT_grab_clone(struct wmOperatorType *ot);
void PAINT_OT_sample_color(struct wmOperatorType *ot);
-void PAINT_OT_clone_cursor_set(struct wmOperatorType *ot);
void PAINT_OT_texture_paint_toggle(struct wmOperatorType *ot);
void PAINT_OT_project_image(struct wmOperatorType *ot);
void PAINT_OT_image_from_view(struct wmOperatorType *ot);
+/* new texture painting */
+void PAINT_OT_image_paint(struct wmOperatorType *ot);
+
/* uv sculpting */
int uv_sculpt_poll(struct bContext *C);
@@ -144,6 +179,7 @@ float paint_calc_object_space_radius(struct ViewContext *vc, const float center[
float paint_get_tex_pixel(struct Brush *br, float u, float v, struct ImagePool *pool);
int imapaint_pick_face(struct ViewContext *vc, const int mval[2], unsigned int *index, unsigned int totface);
void imapaint_pick_uv(struct Scene *scene, struct Object *ob, unsigned int faceindex, const int xy[2], float uv[2]);
+void brush_drawcursor_texpaint_uvsculpt(struct bContext *C, int x, int y, void *customdata);
void paint_sample_color(const struct bContext *C, struct ARegion *ar, int x, int y);
void BRUSH_OT_curve_preset(struct wmOperatorType *ot);
@@ -155,6 +191,7 @@ void PAINT_OT_face_select_hide(struct wmOperatorType *ot);
void PAINT_OT_face_select_reveal(struct wmOperatorType *ot);
void PAINT_OT_vert_select_all(struct wmOperatorType *ot);
+void PAINT_OT_vert_select_ungrouped(struct wmOperatorType *ot);
int vert_paint_poll(struct bContext *C);
int mask_paint_poll(struct bContext *C);
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index dffb8c39bf2..e0b3905b30f 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -38,6 +38,7 @@
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
+#include "BLI_utildefines.h"
#include "BKE_pbvh.h"
#include "BKE_ccg.h"
#include "BKE_context.h"
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index 7385c2f0cf1..120d0a3b10a 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -467,7 +467,6 @@ void ED_operatortypes_paint(void)
WM_operatortype_append(PAINT_OT_image_paint);
WM_operatortype_append(PAINT_OT_sample_color);
WM_operatortype_append(PAINT_OT_grab_clone);
- WM_operatortype_append(PAINT_OT_clone_cursor_set);
WM_operatortype_append(PAINT_OT_project_image);
WM_operatortype_append(PAINT_OT_image_from_view);
@@ -485,6 +484,7 @@ void ED_operatortypes_paint(void)
/* vertex selection */
WM_operatortype_append(PAINT_OT_vert_select_all);
+ WM_operatortype_append(PAINT_OT_vert_select_ungrouped);
/* vertex */
WM_operatortype_append(PAINT_OT_vertex_paint_toggle);
@@ -533,7 +533,7 @@ static void ed_keymap_paint_brush_size(wmKeyMap *keymap, const char *UNUSED(path
typedef enum {
RC_COLOR = 1,
RC_ROTATION = 2,
- RC_ZOOM = 4,
+ RC_ZOOM = 4
} RCFlags;
static void set_brush_rc_path(PointerRNA *ptr, const char *brush_path,
@@ -707,11 +707,17 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
ed_keymap_paint_brush_switch(keymap, "vertex_paint");
ed_keymap_paint_brush_size(keymap, "tool_settings.vertex_paint.brush.size");
- ed_keymap_paint_brush_radial_control(keymap, "vertex_paint", RC_COLOR);
+ ed_keymap_paint_brush_radial_control(keymap, "vertex_paint", RC_COLOR | RC_ROTATION);
kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", MKEY, KM_PRESS, 0, 0); /* mask toggle */
RNA_string_set(kmi->ptr, "data_path", "vertex_paint_object.data.use_paint_mask");
+ kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", SKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_string_set(kmi->ptr, "data_path", "tool_settings.vertex_paint.brush.use_smooth_stroke");
+
+ kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", RKEY, KM_PRESS, 0, 0);
+ RNA_string_set(kmi->ptr, "data_path", "tool_settings.vertex_paint.brush.texture_angle_source_random");
+
/* Weight Paint mode */
keymap = WM_keymap_find(keyconf, "Weight Paint", 0, 0);
keymap->poll = weight_paint_mode_poll;
@@ -741,7 +747,9 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
WM_keymap_verify_item(keymap, "PAINT_OT_weight_from_bones", WKEY, KM_PRESS, 0, 0);
-
+ kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", SKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_string_set(kmi->ptr, "data_path", "tool_settings.weight_paint.brush.use_smooth_stroke");
+
/*Weight paint's Vertex Selection Mode */
keymap = WM_keymap_find(keyconf, "Weight Paint Vertex Selection", 0, 0);
keymap->poll = vert_paint_poll;
@@ -759,18 +767,24 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
keymap = WM_keymap_find(keyconf, "Image Paint", 0, 0);
keymap->poll = image_texture_paint_poll;
- WM_keymap_add_item(keymap, "PAINT_OT_image_paint", LEFTMOUSE, KM_PRESS, 0, 0);
+ RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_image_paint", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "mode", BRUSH_STROKE_NORMAL);
+ RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_image_paint", LEFTMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "mode", BRUSH_STROKE_INVERT);
WM_keymap_add_item(keymap, "PAINT_OT_grab_clone", RIGHTMOUSE, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "PAINT_OT_sample_color", RIGHTMOUSE, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "PAINT_OT_clone_cursor_set", LEFTMOUSE, KM_PRESS, KM_CTRL, 0);
ed_keymap_paint_brush_switch(keymap, "image_paint");
ed_keymap_paint_brush_size(keymap, "tool_settings.image_paint.brush.size");
- ed_keymap_paint_brush_radial_control(keymap, "image_paint", RC_COLOR | RC_ZOOM);
+ ed_keymap_paint_brush_radial_control(keymap, "image_paint", RC_COLOR | RC_ZOOM | RC_ROTATION);
kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", MKEY, KM_PRESS, 0, 0); /* mask toggle */
RNA_string_set(kmi->ptr, "data_path", "image_paint_object.data.use_paint_mask");
+ kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", SKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_string_set(kmi->ptr, "data_path", "tool_settings.image_paint.brush.use_smooth_stroke");
+
+ kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", RKEY, KM_PRESS, 0, 0);
+ RNA_string_set(kmi->ptr, "data_path", "tool_settings.image_paint.brush.texture_angle_source_random");
+
/* face-mask mode */
keymap = WM_keymap_find(keyconf, "Face Mask", 0, 0);
keymap->poll = facemask_paint_poll;
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index 5d9313485d2..8c5552f48bc 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -35,6 +35,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLI_rand.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -91,6 +92,12 @@ typedef struct PaintStroke {
/* event that started stroke, for modal() return */
int event_type;
+ bool brush_init;
+ float initial_mouse[2];
+ float cached_pressure;
+
+ float zoom_2d;
+
StrokeGetLocation get_location;
StrokeTestStart test_start;
StrokeUpdateStep update_step;
@@ -104,23 +111,21 @@ static void paint_draw_smooth_stroke(bContext *C, int x, int y, void *customdata
Brush *brush = paint_brush(paint);
PaintStroke *stroke = customdata;
- glColor4ubv(paint->paint_cursor_col);
- glEnable(GL_LINE_SMOOTH);
- glEnable(GL_BLEND);
-
if (stroke && brush && (brush->flag & BRUSH_SMOOTH_STROKE)) {
- ARegion *ar = CTX_wm_region(C);
- sdrawline(x, y, (int)stroke->last_mouse_position[0] - ar->winrct.xmin,
- (int)stroke->last_mouse_position[1] - ar->winrct.ymin);
+ glColor4ubv(paint->paint_cursor_col);
+ glEnable(GL_LINE_SMOOTH);
+ glEnable(GL_BLEND);
+
+ sdrawline(x, y, (int)stroke->last_mouse_position[0],
+ (int)stroke->last_mouse_position[1]);
+ glDisable(GL_BLEND);
+ glDisable(GL_LINE_SMOOTH);
}
-
- glDisable(GL_BLEND);
- glDisable(GL_LINE_SMOOTH);
}
/* if this is a tablet event, return tablet pressure and set *pen_flip
* to 1 if the eraser tool is being used, 0 otherwise */
-static float event_tablet_data(wmEvent *event, int *pen_flip)
+static float event_tablet_data(const wmEvent *event, int *pen_flip)
{
int erasor = 0;
float pressure = 1;
@@ -138,11 +143,105 @@ static float event_tablet_data(wmEvent *event, int *pen_flip)
return pressure;
}
+
+/* Initialize the stroke cache variants from operator properties */
+static void paint_brush_update(bContext *C, Brush *brush, PaintMode mode,
+ struct PaintStroke *stroke,
+ const float mouse[2], float pressure)
+{
+ Scene *scene = CTX_data_scene(C);
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+
+ /* XXX: Use pressure value from first brush step for brushes which don't
+ * support strokes (grab, thumb). They depends on initial state and
+ * brush coord/pressure/etc.
+ * It's more an events design issue, which doesn't split coordinate/pressure/angle
+ * changing events. We should avoid this after events system re-design */
+ if (paint_supports_dynamic_size(brush, mode) || !stroke->brush_init) {
+ copy_v2_v2(stroke->initial_mouse, mouse);
+ copy_v2_v2(ups->tex_mouse, mouse);
+ stroke->cached_pressure = pressure;
+ }
+
+ /* Truly temporary data that isn't stored in properties */
+
+ ups->draw_pressure = TRUE;
+ ups->pressure_value = stroke->cached_pressure;
+
+ ups->pixel_radius = BKE_brush_size_get(scene, brush);
+
+ if (BKE_brush_use_size_pressure(scene, brush) && paint_supports_dynamic_size(brush, mode)) {
+ ups->pixel_radius *= stroke->cached_pressure;
+ }
+
+ if (!(brush->flag & BRUSH_ANCHORED ||
+ ELEM4(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK,
+ SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE)))
+ {
+ copy_v2_v2(ups->tex_mouse, mouse);
+
+ if ((brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) &&
+ (brush->flag & BRUSH_RANDOM_ROTATION) &&
+ !(brush->flag & BRUSH_RAKE))
+ {
+ ups->brush_rotation = 2.0f * (float)M_PI * BLI_frand();
+ }
+ }
+
+ if (brush->flag & BRUSH_ANCHORED) {
+ bool hit = false;
+ float halfway[2];
+
+ const float dx = mouse[0] - stroke->initial_mouse[0];
+ const float dy = mouse[1] - stroke->initial_mouse[1];
+
+ ups->anchored_size = ups->pixel_radius = sqrt(dx * dx + dy * dy);
+
+ ups->brush_rotation = atan2(dx, dy) + M_PI;
+
+ if (brush->flag & BRUSH_EDGE_TO_EDGE) {
+ float out[3];
+
+ halfway[0] = dx * 0.5f + stroke->initial_mouse[0];
+ halfway[1] = dy * 0.5f + stroke->initial_mouse[1];
+
+ if (stroke->get_location) {
+ if (stroke->get_location(C, out, halfway)) {
+ hit = true;
+ }
+ }
+ else {
+ hit = true;
+ }
+ }
+ if (hit) {
+ copy_v2_v2(ups->anchored_initial_mouse, halfway);
+ copy_v2_v2(ups->tex_mouse, halfway);
+ ups->anchored_size /= 2.0f;
+ ups->pixel_radius /= 2.0f;
+ }
+ else
+ copy_v2_v2(ups->anchored_initial_mouse, stroke->initial_mouse);
+
+ ups->draw_anchored = 1;
+ }
+ else if (brush->flag & BRUSH_RAKE) {
+ if (!stroke->brush_init)
+ copy_v2_v2(ups->last_rake, mouse);
+ else
+ paint_calculate_rake_rotation(ups, mouse);
+ }
+
+ stroke->brush_init = TRUE;
+}
+
+
/* Put the location of the next stroke dot into the stroke RNA and apply it to the mesh */
-static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *event, const float mouse_in[2])
+static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, const wmEvent *event, const float mouse_in[2])
{
Scene *scene = CTX_data_scene(C);
Paint *paint = paint_get_active_from_context(C);
+ PaintMode mode = paintmode_get_active_from_context(C);
Brush *brush = paint_brush(paint);
PaintStroke *stroke = op->customdata;
float mouse_out[2];
@@ -154,19 +253,45 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *ev
/* see if tablet affects event */
pressure = event_tablet_data(event, &pen_flip);
+/* the following code is adapted from texture paint. It may not be needed but leaving here
+ * just in case for reference (code in texpaint removed as part of refactoring).
+ * It's strange that only texpaint had these guards. */
+#if 0
+ /* special exception here for too high pressure values on first touch in
+ * windows for some tablets, then we just skip first touch .. */
+ if (tablet && (pressure >= 0.99f) && ((pop->s.brush->flag & BRUSH_SPACING_PRESSURE) || BKE_brush_use_alpha_pressure(scene, pop->s.brush) || BKE_brush_use_size_pressure(scene, pop->s.brush)))
+ return;
+
+ /* This can be removed once fixed properly in
+ * BKE_brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, double time, float pressure, void *user)
+ * at zero pressure we should do nothing 1/2^12 is 0.0002 which is the sensitivity of the most sensitive pen tablet available */
+ if (tablet && (pressure < 0.0002f) && ((pop->s.brush->flag & BRUSH_SPACING_PRESSURE) || BKE_brush_use_alpha_pressure(scene, pop->s.brush) || BKE_brush_use_size_pressure(scene, pop->s.brush)))
+ return;
+#endif
+
+ /* copy last position -before- jittering, or space fill code
+ * will create too many dabs */
+ copy_v2_v2(stroke->last_mouse_position, mouse_in);
+
+ paint_brush_update(C, brush, mode, stroke, mouse_in, pressure);
+
/* TODO: as sculpt and other paint modes are unified, this
* separation will go away */
- if (stroke->vc.obact->sculpt) {
+ if (paint_supports_jitter(mode)) {
float delta[2];
+ float factor = stroke->zoom_2d;
+
+ if (brush->flag & BRUSH_JITTER_PRESSURE)
+ factor *= pressure;
BKE_brush_jitter_pos(scene, brush, mouse_in, mouse_out);
/* XXX: meh, this is round about because
* BKE_brush_jitter_pos isn't written in the best way to
* be reused here */
- if (brush->flag & BRUSH_JITTER_PRESSURE) {
+ if (factor != 1.0f) {
sub_v2_v2v2(delta, mouse_out, mouse_in);
- mul_v2_fl(delta, pressure);
+ mul_v2_fl(delta, factor);
add_v2_v2v2(mouse_out, mouse_in, delta);
}
}
@@ -188,34 +313,25 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *ev
RNA_boolean_set(&itemptr, "pen_flip", pen_flip);
RNA_float_set(&itemptr, "pressure", pressure);
- copy_v2_v2(stroke->last_mouse_position, mouse_out);
-
stroke->update_step(C, stroke, &itemptr);
}
/* Returns zero if no sculpt changes should be made, non-zero otherwise */
static int paint_smooth_stroke(PaintStroke *stroke, float output[2],
- const PaintSample *sample)
+ const PaintSample *sample, PaintMode mode)
{
output[0] = sample->mouse[0];
output[1] = sample->mouse[1];
- if ((stroke->brush->flag & BRUSH_SMOOTH_STROKE) &&
- !ELEM4(stroke->brush->sculpt_tool,
- SCULPT_TOOL_GRAB,
- SCULPT_TOOL_THUMB,
- SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_SNAKE_HOOK) &&
- !(stroke->brush->flag & BRUSH_ANCHORED) &&
- !(stroke->brush->flag & BRUSH_RESTORE_MESH))
- {
+ if (paint_supports_smooth_stroke(stroke->brush, mode)) {
+ float radius = stroke->brush->smooth_stroke_radius * stroke->zoom_2d;
float u = stroke->brush->smooth_stroke_factor, v = 1.0f - u;
float dx = stroke->last_mouse_position[0] - sample->mouse[0];
float dy = stroke->last_mouse_position[1] - sample->mouse[1];
/* If the mouse is moving within the radius of the last move,
* don't update the mouse position. This allows sharp turns. */
- if (dx * dx + dy * dy < stroke->brush->smooth_stroke_radius * stroke->brush->smooth_stroke_radius)
+ if (dx * dx + dy * dy < radius * radius)
return 0;
output[0] = sample->mouse[0] * v + stroke->last_mouse_position[0] * u;
@@ -227,12 +343,14 @@ static int paint_smooth_stroke(PaintStroke *stroke, float output[2],
/* For brushes with stroke spacing enabled, moves mouse in steps
* towards the final mouse location. */
-static int paint_space_stroke(bContext *C, wmOperator *op, wmEvent *event, const float final_mouse[2])
+static int paint_space_stroke(bContext *C, wmOperator *op, const wmEvent *event, const float final_mouse[2])
{
PaintStroke *stroke = op->customdata;
+ PaintMode mode = paintmode_get_active_from_context(C);
+
int cnt = 0;
- if (paint_space_stroke_enabled(stroke->brush)) {
+ if (paint_space_stroke_enabled(stroke->brush, mode)) {
float mouse[2];
float vec[2];
float length, scale;
@@ -246,17 +364,28 @@ static int paint_space_stroke(bContext *C, wmOperator *op, wmEvent *event, const
const Scene *scene = CTX_data_scene(C);
int steps;
int i;
- float pressure = 1.0f;
+ float size_pressure = 1.0f;
+ float pressure = event_tablet_data(event, NULL);
/* XXX mysterious :) what has 'use size' do with this here... if you don't check for it, pressure fails */
if (BKE_brush_use_size_pressure(scene, stroke->brush))
- pressure = event_tablet_data(event, NULL);
+ size_pressure = pressure;
- if (pressure > FLT_EPSILON) {
+ if (size_pressure > FLT_EPSILON) {
/* brushes can have a minimum size of 1.0 but with pressure it can be smaller then a pixel
* causing very high step sizes, hanging blender [#32381] */
- const float size_clamp = max_ff(1.0f, BKE_brush_size_get(scene, stroke->brush) * pressure);
- scale = (size_clamp * stroke->brush->spacing / 50.0f) / length;
+ const float size_clamp = max_ff(1.0f, BKE_brush_size_get(scene, stroke->brush) * size_pressure);
+ float spacing = stroke->brush->spacing;
+
+ /* stroke system is used for 2d paint too, so we need to account for
+ * the fact that brush can be scaled there. */
+
+ if (stroke->brush->flag & BRUSH_SPACING_PRESSURE)
+ spacing = max_ff(1.0f, spacing * (1.5f - pressure));
+
+ spacing *= stroke->zoom_2d;
+
+ scale = (size_clamp * spacing / 50.0f) / length;
if (scale > FLT_EPSILON) {
mul_v2_fl(vec, scale);
@@ -286,7 +415,8 @@ PaintStroke *paint_stroke_new(bContext *C,
stroke->brush = paint_brush(paint_get_active_from_context(C));
view3d_set_viewcontext(C, &stroke->vc);
- view3d_get_transformation(stroke->vc.ar, stroke->vc.rv3d, stroke->vc.obact, &stroke->mats);
+ if (stroke->vc.v3d)
+ view3d_get_transformation(stroke->vc.ar, stroke->vc.rv3d, stroke->vc.obact, &stroke->mats);
stroke->get_location = get_location;
stroke->test_start = test_start;
@@ -324,16 +454,77 @@ static void stroke_done(struct bContext *C, struct wmOperator *op)
}
/* Returns zero if the stroke dots should not be spaced, non-zero otherwise */
-bool paint_space_stroke_enabled(Brush *br)
+bool paint_space_stroke_enabled(Brush *br, PaintMode mode)
+{
+ return (br->flag & BRUSH_SPACE) && paint_supports_dynamic_size(br, mode);
+}
+
+/* return true if the brush size can change during paint (normally used for pressure) */
+bool paint_supports_dynamic_size(Brush *br, PaintMode mode)
{
- return (br->flag & BRUSH_SPACE) && paint_supports_dynamic_size(br);
+ if (br->flag & BRUSH_ANCHORED)
+ return false;
+
+ switch (mode) {
+ case PAINT_SCULPT:
+ if (ELEM4(br->sculpt_tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_SNAKE_HOOK))
+ {
+ return false;
+ }
+ default:
+ ;
+ }
+ return true;
+}
+
+bool paint_supports_smooth_stroke(Brush *br, PaintMode mode)
+{
+ if (!(br->flag & BRUSH_SMOOTH_STROKE) ||
+ (br->flag & BRUSH_ANCHORED) ||
+ (br->flag & BRUSH_RESTORE_MESH))
+ {
+ return false;
+ }
+
+ switch (mode) {
+ case PAINT_SCULPT:
+ if (ELEM4(br->sculpt_tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_SNAKE_HOOK))
+ {
+ return false;
+ }
+ default:
+ ;
+ }
+ return true;
}
/* return true if the brush size can change during paint (normally used for pressure) */
-bool paint_supports_dynamic_size(Brush *br)
+bool paint_supports_dynamic_tex_coords(Brush *br, PaintMode mode)
{
- return !(br->flag & BRUSH_ANCHORED) &&
- !ELEM4(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_SNAKE_HOOK);
+ if (br->flag & BRUSH_ANCHORED)
+ return false;
+
+ switch (mode) {
+ case PAINT_SCULPT:
+ if (ELEM4(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_SNAKE_HOOK))
+ return false;
+ default:
+ ;
+ }
+ return true;
+}
+
+bool paint_supports_jitter(PaintMode mode)
+{
+ return ELEM3(mode, PAINT_SCULPT, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D);
}
#define PAINT_STROKE_MODAL_CANCEL 1
@@ -400,17 +591,22 @@ static void paint_stroke_sample_average(const PaintStroke *stroke,
/*printf("avg=(%f, %f), num=%d\n", average->mouse[0], average->mouse[1], stroke->num_samples);*/
}
-int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
+int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
Paint *p = paint_get_active_from_context(C);
+ PaintMode mode = paintmode_get_active_from_context(C);
PaintStroke *stroke = op->customdata;
PaintSample sample_average;
float mouse[2];
int first = 0;
+ float zoomx, zoomy;
- paint_stroke_add_sample(p, stroke, event->x, event->y);
+ paint_stroke_add_sample(p, stroke, event->mval[0], event->mval[1]);
paint_stroke_sample_average(stroke, &sample_average);
+ get_imapaint_zoom(C, &zoomx, &zoomy);
+ stroke->zoom_2d = max_ff(zoomx, zoomy);
+
/* let NDOF motion pass through to the 3D view so we can paint and rotate simultaneously!
* this isn't perfect... even when an extra MOUSEMOVE is spoofed, the stroke discards it
* since the 2D deltas are zero -- code in this file needs to be updated to use the
@@ -452,8 +648,8 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
(event->type == TIMER && (event->customdata == stroke->timer)) )
{
if (stroke->stroke_started) {
- if (paint_smooth_stroke(stroke, mouse, &sample_average)) {
- if (paint_space_stroke_enabled(stroke->brush)) {
+ if (paint_smooth_stroke(stroke, mouse, &sample_average, mode)) {
+ if (paint_space_stroke_enabled(stroke->brush, mode)) {
if (!paint_space_stroke(C, op, event, mouse)) {
//ED_region_tag_redraw(ar);
}
@@ -472,7 +668,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
* instead of waiting till we have moved the space distance */
if (first &&
stroke->stroke_started &&
- paint_space_stroke_enabled(stroke->brush) &&
+ paint_space_stroke_enabled(stroke->brush, mode) &&
!(stroke->brush->flag & BRUSH_ANCHORED) &&
!(stroke->brush->flag & BRUSH_SMOOTH_STROKE))
{
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index dc3f310b405..5e88c7b5730 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -47,6 +47,7 @@
#include "BKE_context.h"
#include "BKE_DerivedMesh.h"
#include "BKE_paint.h"
+#include "BKE_report.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -160,12 +161,12 @@ float paint_calc_object_space_radius(ViewContext *vc, const float center[3],
Object *ob = vc->obact;
float delta[3], scale, loc[3];
const float mval_f[2] = {pixel_radius, 0.0f};
+ float zfac;
mul_v3_m4v3(loc, ob->obmat, center);
- initgrabz(vc->rv3d, loc[0], loc[1], loc[2]);
-
- ED_view3d_win_to_delta(vc->ar, mval_f, delta);
+ zfac = ED_view3d_calc_zfac(vc->rv3d, loc, NULL);
+ ED_view3d_win_to_delta(vc->ar, mval_f, delta, zfac);
scale = fabsf(mat4_to_scale(ob->obmat));
scale = (scale == 0.0f) ? 1.0f : scale;
@@ -414,7 +415,7 @@ void PAINT_OT_face_select_linked(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-static int paint_select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int paint_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
int mode = RNA_boolean_get(op->ptr, "extend") ? 1 : 0;
paintface_select_linked(C, CTX_data_active_object(C), event->mval, mode);
@@ -484,6 +485,39 @@ void PAINT_OT_vert_select_all(wmOperatorType *ot)
WM_operator_properties_select_all(ot);
}
+
+static int vert_select_ungrouped_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ Mesh *me = ob->data;
+
+ if ((ob->defbase.first == NULL) || (me->dvert == NULL)) {
+ BKE_report(op->reports, RPT_ERROR, "No weights/vertex groups on object");
+ return OPERATOR_CANCELLED;
+ }
+
+ paintvert_select_ungrouped(ob, RNA_boolean_get(op->ptr, "extend"), TRUE);
+ ED_region_tag_redraw(CTX_wm_region(C));
+ return OPERATOR_FINISHED;
+}
+
+void PAINT_OT_vert_select_ungrouped(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Ungrouped";
+ ot->idname = "PAINT_OT_vert_select_ungrouped";
+ ot->description = "Select vertices without a group";
+
+ /* api callbacks */
+ ot->exec = vert_select_ungrouped_exec;
+ ot->poll = vert_paint_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
+}
+
static int face_select_hide_exec(bContext *C, wmOperator *op)
{
const int unselected = RNA_boolean_get(op->ptr, "unselected");
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 0277e1e11dc..2bdcda1430d 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -43,6 +43,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_math_color.h"
#include "BLI_memarena.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -854,36 +855,46 @@ static int sample_backbuf_area(ViewContext *vc, int *indexar, int totface, int x
}
/* whats _dl mean? */
-static float calc_vp_strength_dl(VPaint *vp, ViewContext *vc, const float co[3],
- const float mval[2], const float brush_size_pressure)
+static float calc_vp_strength_col_dl(VPaint *vp, ViewContext *vc, const float co[3],
+ const float mval[2], const float brush_size_pressure, float rgba[4])
{
- float vertco[2];
+ float co_ss[2]; /* screenspace */
if (ED_view3d_project_float_object(vc->ar,
- co, vertco,
+ co, co_ss,
V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
{
float delta[2];
float dist_squared;
- sub_v2_v2v2(delta, mval, vertco);
+ sub_v2_v2v2(delta, mval, co_ss);
dist_squared = dot_v2v2(delta, delta); /* len squared */
if (dist_squared <= brush_size_pressure * brush_size_pressure) {
Brush *brush = paint_brush(&vp->paint);
const float dist = sqrtf(dist_squared);
+ if (brush->mtex.tex && rgba) {
+ if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) {
+ BKE_brush_sample_tex_3D(vc->scene, brush, co, rgba, 0, NULL);
+ }
+ else {
+ const float co_ss_3d[3] = {co_ss[0], co_ss[1], 0.0f}; /* we need a 3rd empty value */
+ BKE_brush_sample_tex_3D(vc->scene, brush, co_ss_3d, rgba, 0, NULL);
+ }
+ }
return BKE_brush_curve_strength_clamp(brush, dist, brush_size_pressure);
}
}
-
+ if (rgba)
+ zero_v4(rgba);
return 0.0f;
}
-static float calc_vp_alpha_dl(VPaint *vp, ViewContext *vc,
+static float calc_vp_alpha_col_dl(VPaint *vp, ViewContext *vc,
float vpimat[3][3], const DMCoNo *v_co_no,
const float mval[2],
- const float brush_size_pressure, const float brush_alpha_pressure)
+ const float brush_size_pressure, const float brush_alpha_pressure, float rgba[4])
{
- float strength = calc_vp_strength_dl(vp, vc, v_co_no->co, mval, brush_size_pressure);
+ float strength = calc_vp_strength_col_dl(vp, vc, v_co_no->co, mval, brush_size_pressure, rgba);
if (strength > 0.0f) {
float alpha = brush_alpha_pressure * strength;
@@ -1015,7 +1026,7 @@ static float wpaint_blend(VPaint *wp, float weight, float weight_prev,
/* sets wp->weight to the closest weight value to vertex */
/* note: we cant sample frontbuf, weight colors are interpolated too unpredictable */
-static int weight_sample_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewContext vc;
Mesh *me;
@@ -1467,7 +1478,7 @@ static void enforce_locks(MDeformVert *odv, MDeformVert *ndv,
MDeformWeight *ndw;
MDeformWeight *odw;
- float changed_sum = 0.0f;
+ // float changed_sum = 0.0f; // UNUSED
char *change_status;
@@ -1496,7 +1507,7 @@ static void enforce_locks(MDeformVert *odv, MDeformVert *ndv,
}
else if (ndw->weight != odw->weight) { /* changed groups are handled here */
totchange += ndw->weight - odw->weight;
- changed_sum += ndw->weight;
+ // changed_sum += ndw->weight; // UNUSED
change_status[i] = 2; /* was altered already */
total_changed++;
} /* unchanged, unlocked bone groups are handled here */
@@ -2239,11 +2250,6 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
mult_m4_m4m4(mat, vc->rv3d->persmat, ob->obmat);
RNA_float_get_array(itemptr, "mouse", mval);
- mval[0] -= vc->ar->winrct.xmin;
- mval[1] -= vc->ar->winrct.ymin;
-
-
-
/* *** setup WeightPaintInfo - pass onto do_weight_paint_vertex *** */
wpi.defbase_tot = wpd->defbase_tot;
@@ -2312,7 +2318,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
#define WP_BLUR_ACCUM(v_idx_var) \
{ \
const unsigned int vidx = v_idx_var; \
- const float fac = calc_vp_strength_dl(wp, vc, wpd->vertexcosnos[vidx].co, mval, brush_size_pressure); \
+ const float fac = calc_vp_strength_col_dl(wp, vc, wpd->vertexcosnos[vidx].co, mval, brush_size_pressure, NULL); \
if (fac > 0.0f) { \
MDeformWeight *dw = dw_func(&me->dvert[vidx], wpi.vgroup_active); \
paintweight += dw ? (dw->weight * fac) : 0.0f; \
@@ -2382,8 +2388,8 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
{ \
unsigned int vidx = v_idx_var; \
if (me->dvert[vidx].flag) { \
- alpha = calc_vp_alpha_dl(wp, vc, wpd->wpimat, &wpd->vertexcosnos[vidx], \
- mval, brush_size_pressure, brush_alpha_pressure); \
+ alpha = calc_vp_alpha_col_dl(wp, vc, wpd->wpimat, &wpd->vertexcosnos[vidx], \
+ mval, brush_size_pressure, brush_alpha_pressure, NULL); \
if (alpha) { \
do_weight_paint_vertex(wp, ob, &wpi, vidx, alpha, paintweight); \
} \
@@ -2480,7 +2486,7 @@ static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
}
-static int wpaint_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
int retval;
@@ -2667,6 +2673,8 @@ typedef struct VPaintData {
/* mpoly -> mface mapping */
MemArena *polyfacemap_arena;
ListBase *polyfacemap;
+
+ bool is_texbrush;
} VPaintData;
static void vpaint_build_poly_facemap(struct VPaintData *vd, Mesh *me)
@@ -2703,6 +2711,7 @@ static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const fl
ToolSettings *ts = CTX_data_tool_settings(C);
struct PaintStroke *stroke = op->customdata;
VPaint *vp = ts->vpaint;
+ Brush *brush = paint_brush(&vp->paint);
struct VPaintData *vpd;
Object *ob = CTX_data_active_object(C);
Mesh *me;
@@ -2732,6 +2741,8 @@ static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const fl
vpd->indexar = get_indexarray(me);
vpd->paintcol = vpaint_get_current_col(vp);
+ vpd->is_texbrush = !(brush->vertexpaint_tool == PAINT_BLEND_BLUR) &&
+ brush->mtex.tex;
/* are we painting onto a modified mesh?,
* if not we can skip face map trickyness */
@@ -2808,12 +2819,24 @@ static void vpaint_paint_poly(VPaint *vp, VPaintData *vpd, Mesh *me,
ml = me->mloop + mpoly->loopstart;
for (i = 0; i < mpoly->totloop; i++, ml++) {
- alpha = calc_vp_alpha_dl(vp, vc, vpd->vpimat,
+ float rgba[4];
+ unsigned int paintcol;
+ alpha = calc_vp_alpha_col_dl(vp, vc, vpd->vpimat,
&vpd->vertexcosnos[ml->v], mval,
- brush_size_pressure, brush_alpha_pressure);
+ brush_size_pressure, brush_alpha_pressure, rgba);
+
+ if (vpd->is_texbrush) {
+ float rgba_br[3];
+ rgb_uchar_to_float(rgba_br, (const unsigned char *)&vpd->paintcol);
+ mul_v3_v3(rgba_br, rgba);
+ rgb_float_to_uchar((unsigned char *)&paintcol, rgba_br);
+ }
+ else
+ paintcol = vpd->paintcol;
+
if (alpha > 0.0f) {
const int alpha_i = (int)(alpha * 255.0f);
- lcol[i] = vpaint_blend(vp, lcol[i], lcolorig[i], vpd->paintcol, alpha_i, brush_alpha_pressure_i);
+ lcol[i] = vpaint_blend(vp, lcol[i], lcolorig[i], paintcol, alpha_i, brush_alpha_pressure_i);
}
}
@@ -2872,10 +2895,6 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
/* load projection matrix */
mult_m4_m4m4(mat, vc->rv3d->persmat, ob->obmat);
- mval[0] -= vc->ar->winrct.xmin;
- mval[1] -= vc->ar->winrct.ymin;
-
-
/* which faces are involved */
if (vp->flag & VP_AREA) {
totindex = sample_backbuf_area(vc, indexar, me->totpoly, mval[0], mval[1], brush_size_pressure);
@@ -2959,7 +2978,7 @@ static void vpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
MEM_freeN(vpd);
}
-static int vpaint_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
int retval;
@@ -3165,7 +3184,7 @@ static void gradientVert__mapFunc(void *userData, int index, const float co[3],
}
}
-static int paint_weight_gradient_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int paint_weight_gradient_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
int ret = WM_gesture_straightline_modal(C, op, event);
@@ -3273,7 +3292,7 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int paint_weight_gradient_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int paint_weight_gradient_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
int ret;
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 90e7645032b..376622e95a6 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -43,6 +43,8 @@
#include "BLI_threads.h"
#include "BLI_rand.h"
+#include "BLF_translation.h"
+
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_node_types.h"
@@ -243,7 +245,6 @@ typedef struct StrokeCache {
float pressure;
float mouse[2];
float bstrength;
- float tex_mouse[2];
/* The rest is temporary storage that isn't saved as a property */
@@ -257,8 +258,8 @@ typedef struct StrokeCache {
Brush *brush;
float (*face_norms)[3]; /* Copy of the mesh faces' normals */
- float special_rotation; /* Texture rotation (radians) for anchored and rake modes */
- int pixel_radius, previous_pixel_radius;
+
+ float special_rotation;
float grab_delta[3], grab_delta_symmetry[3];
float old_grab_location[3], orig_grab_location[3];
@@ -282,8 +283,8 @@ typedef struct StrokeCache {
int radial_symmetry_pass;
float symm_rot_mat[4][4];
float symm_rot_mat_inv[4][4];
- float last_rake[2]; /* Last location of updating rake rotation */
int original;
+ float anchored_location[3];
float vertex_rotation;
@@ -316,8 +317,8 @@ typedef struct {
/* Initialize a SculptOrigVertData for accessing original vertex data;
* handles BMesh, mesh, and multires */
static void sculpt_orig_vert_data_unode_init(SculptOrigVertData *data,
- Object *ob,
- SculptUndoNode *unode)
+ Object *ob,
+ SculptUndoNode *unode)
{
SculptSession *ss = ob->sculpt;
BMesh *bm = ss->bm;
@@ -338,19 +339,18 @@ static void sculpt_orig_vert_data_unode_init(SculptOrigVertData *data,
/* Initialize a SculptOrigVertData for accessing original vertex data;
* handles BMesh, mesh, and multires */
static void sculpt_orig_vert_data_init(SculptOrigVertData *data,
- Object *ob,
- PBVHNode *node)
+ Object *ob,
+ PBVHNode *node)
{
SculptUndoNode *unode;
unode = sculpt_undo_push_node(ob, node, SCULPT_UNDO_COORDS);
sculpt_orig_vert_data_unode_init(data, ob, unode);
-
}
/* Update a SculptOrigVertData for a particular vertex from the PBVH
* iterator */
static void sculpt_orig_vert_data_update(SculptOrigVertData *orig_data,
- PBVHVertexIter *iter)
+ PBVHVertexIter *iter)
{
if (orig_data->unode->type == SCULPT_UNDO_COORDS) {
if (orig_data->coords) {
@@ -387,30 +387,30 @@ static void sculpt_orig_vert_data_update(SculptOrigVertData *orig_data,
Others, like smooth, are better without. Same goes for alt-
key smoothing. */
static int sculpt_stroke_dynamic_topology(const SculptSession *ss,
- const Brush *brush)
+ const Brush *brush)
{
return ((BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) &&
- (!ss->cache || (!ss->cache->alt_smooth)) &&
-
- /* Requires mesh restore, which doesn't work with
- * dynamic-topology */
- !(brush->flag & BRUSH_ANCHORED) &&
- !(brush->flag & BRUSH_RESTORE_MESH) &&
+ (!ss->cache || (!ss->cache->alt_smooth)) &&
- (!ELEM6(brush->sculpt_tool,
- /* These brushes, as currently coded, cannot
- * support dynamic topology */
- SCULPT_TOOL_GRAB,
- SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_THUMB,
- SCULPT_TOOL_LAYER,
+ /* Requires mesh restore, which doesn't work with
+ * dynamic-topology */
+ !(brush->flag & BRUSH_ANCHORED) &&
+ !(brush->flag & BRUSH_RESTORE_MESH) &&
+
+ (!ELEM6(brush->sculpt_tool,
+ /* These brushes, as currently coded, cannot
+ * support dynamic topology */
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_LAYER,
- /* These brushes could handle dynamic topology,
- * but user feedback indicates it's better not
- * to */
- SCULPT_TOOL_SMOOTH,
- SCULPT_TOOL_MASK)));
+ /* These brushes could handle dynamic topology,
+ * but user feedback indicates it's better not
+ * to */
+ SCULPT_TOOL_SMOOTH,
+ SCULPT_TOOL_MASK)));
}
/*** paint mesh ***/
@@ -439,7 +439,7 @@ static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
for (n = 0; n < totnode; n++) {
SculptUndoNode *unode;
SculptUndoType type = (brush->sculpt_tool == SCULPT_TOOL_MASK ?
- SCULPT_UNDO_MASK : SCULPT_UNDO_COORDS);
+ SCULPT_UNDO_MASK : SCULPT_UNDO_COORDS);
if (ss->bm) {
unode = sculpt_undo_push_node(ob, nodes[n], type);
@@ -545,13 +545,32 @@ typedef struct SculptBrushTest {
float radius_squared;
float location[3];
float dist;
+
+ /* View3d clipping - only set rv3d for clipping */
+ RegionView3D *clip_rv3d;
} SculptBrushTest;
static void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test)
{
+ RegionView3D *rv3d = ss->cache->vc->rv3d;
+
test->radius_squared = ss->cache->radius_squared;
copy_v3_v3(test->location, ss->cache->location);
test->dist = 0.0f; /* just for initialize */
+
+
+ if (rv3d->rflag & RV3D_CLIPPING) {
+ test->clip_rv3d = rv3d;
+ }
+ else {
+ test->clip_rv3d = NULL;
+ }
+}
+
+BLI_INLINE bool sculpt_brush_test_clipping(SculptBrushTest *test, const float co[3])
+{
+ RegionView3D *rv3d = test->clip_rv3d;
+ return (rv3d && (ED_view3d_clipping_test(rv3d, co, true)));
}
static int sculpt_brush_test(SculptBrushTest *test, const float co[3])
@@ -559,6 +578,9 @@ static int sculpt_brush_test(SculptBrushTest *test, const float co[3])
float distsq = len_squared_v3v3(co, test->location);
if (distsq <= test->radius_squared) {
+ if (sculpt_brush_test_clipping(test, co)) {
+ return 0;
+ }
test->dist = sqrt(distsq);
return 1;
}
@@ -572,6 +594,9 @@ static int sculpt_brush_test_sq(SculptBrushTest *test, const float co[3])
float distsq = len_squared_v3v3(co, test->location);
if (distsq <= test->radius_squared) {
+ if (sculpt_brush_test_clipping(test, co)) {
+ return 0;
+ }
test->dist = distsq;
return 1;
}
@@ -582,6 +607,9 @@ static int sculpt_brush_test_sq(SculptBrushTest *test, const float co[3])
static int sculpt_brush_test_fast(SculptBrushTest *test, float co[3])
{
+ if (sculpt_brush_test_clipping(test, co)) {
+ return 0;
+ }
return len_squared_v3v3(co, test->location) <= test->radius_squared;
}
@@ -590,6 +618,10 @@ static int sculpt_brush_test_cube(SculptBrushTest *test, float co[3], float loca
float side = M_SQRT1_2;
float local_co[3];
+ if (sculpt_brush_test_clipping(test, co)) {
+ return 0;
+ }
+
mul_v3_m4v3(local_co, local, co);
local_co[0] = fabs(local_co[0]);
@@ -890,25 +922,22 @@ static float tex_strength(SculptSession *ss, Brush *br,
const float fno[3],
const float mask)
{
+ const Scene *scene = ss->cache->vc->scene;
MTex *mtex = &br->mtex;
float avg = 1;
+ float rgba[4];
if (!mtex->tex) {
avg = 1;
}
else if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
- float jnk;
-
/* Get strength by feeding the vertex
* location directly into a texture */
- externtex(mtex, point, &avg,
- &jnk, &jnk, &jnk, &jnk, 0, ss->tex_pool);
+ avg = BKE_brush_sample_tex_3D(scene, br, point, rgba, 0, ss->tex_pool);
}
else if (ss->texcache) {
- float rotation = -mtex->rot;
float symm_point[3], point_2d[2];
float x = 0.0f, y = 0.0f; /* Quite warnings */
- float radius = 1.0f; /* Quite warnings */
/* if the active area is being applied for symmetry, flip it
* across the symmetry axis and rotate it back to the original
@@ -922,77 +951,33 @@ static float tex_strength(SculptSession *ss, Brush *br,
ED_view3d_project_float_v2_m4(ss->cache->vc->ar, symm_point, point_2d, ss->cache->projection_mat);
- if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
- /* keep coordinates relative to mouse */
-
- rotation += ss->cache->special_rotation;
-
- point_2d[0] -= ss->cache->tex_mouse[0];
- point_2d[1] -= ss->cache->tex_mouse[1];
-
- /* use pressure adjusted size for fixed mode */
- radius = ss->cache->pixel_radius;
-
- x = point_2d[0] + ss->cache->vc->ar->winrct.xmin;
- y = point_2d[1] + ss->cache->vc->ar->winrct.ymin;
- }
- else if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
- /* leave the coordinates relative to the screen */
-
- /* use unadjusted size for tiled mode */
- radius = BKE_brush_size_get(ss->cache->vc->scene, br);
-
- x = point_2d[0];
- y = point_2d[1];
- }
- else if (mtex->brush_map_mode == MTEX_MAP_MODE_AREA) {
+ /* still no symmetry supported for other paint modes.
+ * Sculpt does it DIY */
+ if (mtex->brush_map_mode == MTEX_MAP_MODE_AREA) {
/* Similar to fixed mode, but projects from brush angle
* rather than view direction */
- /* Rotation is handled by the brush_local_mat */
- rotation = 0;
-
mul_m4_v3(ss->cache->brush_local_mat, symm_point);
x = symm_point[0];
y = symm_point[1];
- }
- if (mtex->brush_map_mode != MTEX_MAP_MODE_AREA) {
- x /= ss->cache->vc->ar->winx;
- y /= ss->cache->vc->ar->winy;
+ x *= br->mtex.size[0];
+ y *= br->mtex.size[1];
- if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
- x -= 0.5f;
- y -= 0.5f;
- }
-
- x *= ss->cache->vc->ar->winx / radius;
- y *= ss->cache->vc->ar->winy / radius;
- }
+ x += br->mtex.ofs[0];
+ y += br->mtex.ofs[1];
- /* it is probably worth optimizing for those cases where
- * the texture is not rotated by skipping the calls to
- * atan2, sqrtf, sin, and cos. */
- if (rotation > 0.001f || rotation < -0.001f) {
- const float angle = atan2f(y, x) + rotation;
- const float flen = sqrtf(x * x + y * y);
+ avg = paint_get_tex_pixel(br, x, y, ss->tex_pool);
- x = flen * cosf(angle);
- y = flen * sinf(angle);
+ avg += br->texture_sample_bias;
+ }
+ else {
+ const float point_3d[3] = {point_2d[0], point_2d[1], 0.0f};
+ avg = BKE_brush_sample_tex_3D(scene, br, point_3d, rgba, 0, ss->tex_pool);
}
-
- x *= br->mtex.size[0];
- y *= br->mtex.size[1];
-
- x += br->mtex.ofs[0];
- y += br->mtex.ofs[1];
-
- avg = paint_get_tex_pixel(br, x, y, ss->tex_pool);
}
- avg += br->texture_sample_bias;
-
/* Falloff curve */
avg *= BKE_brush_curve_strength(br, len, ss->cache->radius);
@@ -1203,11 +1188,12 @@ static void calc_local_y(ViewContext *vc, const float center[3], float y[3])
{
Object *ob = vc->obact;
float loc[3], mval_f[2] = {0.0f, 1.0f};
+ float zfac;
mul_v3_m4v3(loc, ob->imat, center);
- initgrabz(vc->rv3d, loc[0], loc[1], loc[2]);
+ zfac = ED_view3d_calc_zfac(vc->rv3d, loc, NULL);
- ED_view3d_win_to_delta(vc->ar, mval_f, y);
+ ED_view3d_win_to_delta(vc->ar, mval_f, y, zfac);
normalize_v3(y);
add_v3_v3(y, ob->loc);
@@ -3173,8 +3159,8 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
if (use_orco) {
if (ss->bm) {
copy_v3_v3(val,
- BM_log_original_vert_co(ss->bm_log,
- vd.bm_vert));
+ BM_log_original_vert_co(ss->bm_log,
+ vd.bm_vert));
}
else
copy_v3_v3(val, orco[vd.i]);
@@ -3342,7 +3328,7 @@ static void sculpt_fix_noise_tear(Sculpt *sd, Object *ob)
}
static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob,
- BrushActionFunc action)
+ BrushActionFunc action)
{
Brush *brush = paint_brush(&sd->paint);
SculptSession *ss = ob->sculpt;
@@ -3480,7 +3466,9 @@ void sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
}
}
}
- else free_sculptsession_deformMats(ss);
+ else {
+ free_sculptsession_deformMats(ss);
+ }
/* if pbvh is deformed, key block is already applied to it */
if (ss->kb && !BKE_pbvh_isDeformed(ss->pbvh)) {
@@ -3673,27 +3661,28 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
Brush *brush = paint_brush(&sd->paint);
ViewContext *vc = paint_stroke_view_context(op->customdata);
Object *ob = CTX_data_active_object(C);
+ float rot[3][3], scale[3], loc[3];
int i;
int mode;
ss->cache = cache;
/* Set scaling adjustment */
- ss->cache->scale[0] = 1.0f / ob->size[0];
- ss->cache->scale[1] = 1.0f / ob->size[1];
- ss->cache->scale[2] = 1.0f / ob->size[2];
+ cache->scale[0] = 1.0f / ob->size[0];
+ cache->scale[1] = 1.0f / ob->size[1];
+ cache->scale[2] = 1.0f / ob->size[2];
- ss->cache->plane_trim_squared = brush->plane_trim * brush->plane_trim;
+ cache->plane_trim_squared = brush->plane_trim * brush->plane_trim;
- ss->cache->flag = 0;
+ cache->flag = 0;
sculpt_init_mirror_clipping(ob, ss);
/* Initial mouse location */
if (mouse)
- copy_v2_v2(ss->cache->initial_mouse, mouse);
+ copy_v2_v2(cache->initial_mouse, mouse);
else
- zero_v2(ss->cache->initial_mouse);
+ zero_v2(cache->initial_mouse);
mode = RNA_enum_get(op->ptr, "mode");
cache->invert = mode == BRUSH_STROKE_INVERT;
@@ -3705,7 +3694,7 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
else brush->flag &= ~BRUSH_INVERTED;
/* Alt-Smooth */
- if (ss->cache->alt_smooth) {
+ if (cache->alt_smooth) {
if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
cache->saved_mask_brush_tool = brush->mask_tool;
brush->mask_tool = BRUSH_MASK_SMOOTH;
@@ -3726,7 +3715,7 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
}
copy_v2_v2(cache->mouse, cache->initial_mouse);
- copy_v2_v2(cache->tex_mouse, cache->initial_mouse);
+ copy_v2_v2(ups->tex_mouse, cache->initial_mouse);
/* Truly temporary data that isn't stored in properties */
@@ -3737,7 +3726,12 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
/* cache projection matrix */
ED_view3d_ob_project_mat_get(cache->vc->rv3d, ob, cache->projection_mat);
+ mat4_to_loc_rot_size(loc, rot, scale, ob->obmat);
+ /* transposing an orthonormal matrix inverts */
+ transpose_m3(rot);
ED_view3d_global_to_vector(cache->vc->rv3d, cache->vc->rv3d->twmat[3], cache->true_view_normal);
+ /* This takes care of rotated mesh. Instead of rotating every normal, we inverse rotate view normal. */
+ mul_m3_v3(rot, cache->true_view_normal);
/* Initialize layer brush displacements and persistent coords */
if (brush->sculpt_tool == SCULPT_TOOL_LAYER) {
/* not supported yet for multires or dynamic topology */
@@ -3748,7 +3742,9 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
ss->layer_co = MEM_mallocN(sizeof(float) * 3 * ss->totvert,
"sculpt mesh vertices copy");
- if (ss->deform_cos) memcpy(ss->layer_co, ss->deform_cos, ss->totvert);
+ if (ss->deform_cos) {
+ memcpy(ss->layer_co, ss->deform_cos, ss->totvert);
+ }
else {
for (i = 0; i < ss->totvert; ++i) {
copy_v3_v3(ss->layer_co[i], ss->mvert[i].co);
@@ -3779,8 +3775,6 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
}
}
- cache->special_rotation = (brush->flag & BRUSH_RAKE) ? ups->last_angle : 0;
-
cache->first_time = 1;
cache->vertex_rotation = 0;
@@ -3793,8 +3787,8 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
SculptSession *ss = ob->sculpt;
StrokeCache *cache = ss->cache;
float mouse[2] = {
- cache->mouse[0] - cache->vc->ar->winrct.xmin,
- cache->mouse[1] - cache->vc->ar->winrct.ymin
+ cache->mouse[0],
+ cache->mouse[1]
};
int tool = brush->sculpt_tool;
@@ -3814,8 +3808,6 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
/* compute 3d coordinate at same z from original location + mouse */
mul_v3_m4v3(loc, ob->obmat, cache->orig_grab_location);
- initgrabz(cache->vc->rv3d, loc[0], loc[1], loc[2]);
-
ED_view3d_win_to_3d(cache->vc->ar, loc, mouse, grab_location);
/* compute delta to move verts by */
@@ -3853,9 +3845,9 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
copy_v3_v3(cache->old_grab_location, grab_location);
if (tool == SCULPT_TOOL_GRAB)
- copy_v3_v3(ups->anchored_location, cache->true_location);
+ copy_v3_v3(cache->anchored_location, cache->true_location);
else if (tool == SCULPT_TOOL_THUMB)
- copy_v3_v3(ups->anchored_location, cache->orig_grab_location);
+ copy_v3_v3(cache->anchored_location, cache->orig_grab_location);
if (ELEM(tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB)) {
/* location stays the same for finding vertices in brush radius */
@@ -3863,7 +3855,7 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
ups->draw_anchored = 1;
copy_v2_v2(ups->anchored_initial_mouse, cache->initial_mouse);
- ups->anchored_size = cache->pixel_radius;
+ ups->anchored_size = ups->pixel_radius;
}
}
}
@@ -3898,18 +3890,11 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob,
* brush coord/pressure/etc.
* It's more an events design issue, which doesn't split coordinate/pressure/angle
* changing events. We should avoid this after events system re-design */
- if (paint_supports_dynamic_size(brush) || cache->first_time) {
+ if (paint_supports_dynamic_size(brush, PAINT_SCULPT) || cache->first_time) {
cache->pressure = RNA_float_get(ptr, "pressure");
}
/* Truly temporary data that isn't stored in properties */
-
- ups->draw_pressure = 1;
- ups->pressure_value = cache->pressure;
-
- cache->previous_pixel_radius = cache->pixel_radius;
- cache->pixel_radius = BKE_brush_size_get(scene, brush);
-
if (cache->first_time) {
if (!BKE_brush_use_locked_size(scene, brush)) {
cache->initial_radius = paint_calc_object_space_radius(cache->vc,
@@ -3922,8 +3907,7 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob,
}
}
- if (BKE_brush_use_size_pressure(scene, brush) && paint_supports_dynamic_size(brush)) {
- cache->pixel_radius *= cache->pressure;
+ if (BKE_brush_use_size_pressure(scene, brush) && paint_supports_dynamic_size(brush, PAINT_SCULPT)) {
cache->radius = cache->initial_radius * cache->pressure;
}
else {
@@ -3932,77 +3916,25 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob,
cache->radius_squared = cache->radius * cache->radius;
- if (!(brush->flag & BRUSH_ANCHORED ||
- ELEM4(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK,
- SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE)))
- {
- copy_v2_v2(cache->tex_mouse, cache->mouse);
-
- if ((brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) &&
- (brush->flag & BRUSH_RANDOM_ROTATION) &&
- !(brush->flag & BRUSH_RAKE))
- {
- cache->special_rotation = 2.0f * (float)M_PI * BLI_frand();
- }
- }
-
if (brush->flag & BRUSH_ANCHORED) {
- int hit = 0;
-
- const float dx = cache->mouse[0] - cache->initial_mouse[0];
- const float dy = cache->mouse[1] - cache->initial_mouse[1];
-
- ups->anchored_size = cache->pixel_radius = sqrt(dx * dx + dy * dy);
-
- cache->special_rotation = atan2(dx, dy) + M_PI;
-
if (brush->flag & BRUSH_EDGE_TO_EDGE) {
float halfway[2];
float out[3];
-
- halfway[0] = dx * 0.5f + cache->initial_mouse[0];
- halfway[1] = dy * 0.5f + cache->initial_mouse[1];
+ halfway[0] = 0.5f * (cache->mouse[0] + cache->initial_mouse[0]);
+ halfway[1] = 0.5f * (cache->mouse[1] + cache->initial_mouse[1]);
if (sculpt_stroke_get_location(C, out, halfway)) {
- copy_v3_v3(ups->anchored_location, out);
- copy_v2_v2(ups->anchored_initial_mouse, halfway);
- copy_v2_v2(cache->tex_mouse, halfway);
- copy_v3_v3(cache->true_location, ups->anchored_location);
- ups->anchored_size /= 2.0f;
- cache->pixel_radius /= 2.0f;
- hit = 1;
+ copy_v3_v3(cache->anchored_location, out);
+ copy_v3_v3(cache->true_location, cache->anchored_location);
}
}
- if (!hit)
- copy_v2_v2(ups->anchored_initial_mouse, cache->initial_mouse);
-
cache->radius = paint_calc_object_space_radius(paint_stroke_view_context(stroke),
cache->true_location,
- cache->pixel_radius);
+ ups->pixel_radius);
cache->radius_squared = cache->radius * cache->radius;
- copy_v3_v3(ups->anchored_location, cache->true_location);
-
- ups->draw_anchored = 1;
- }
- else if (brush->flag & BRUSH_RAKE) {
- const float u = 0.5f;
- const float v = 1 - u;
- const float r = 20;
-
- const float dx = cache->last_rake[0] - cache->mouse[0];
- const float dy = cache->last_rake[1] - cache->mouse[1];
-
- if (cache->first_time) {
- copy_v2_v2(cache->last_rake, cache->mouse);
- }
- else if (dx * dx + dy * dy >= r * r) {
- cache->special_rotation = atan2(dx, dy);
-
- cache->last_rake[0] = u * cache->last_rake[0] + v * cache->mouse[0];
- cache->last_rake[1] = u * cache->last_rake[1] + v * cache->mouse[1];
- }
+ copy_v3_v3(cache->anchored_location, cache->true_location);
}
sculpt_update_brush_delta(ups, ob, brush);
@@ -4015,14 +3947,14 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob,
ups->draw_anchored = 1;
copy_v2_v2(ups->anchored_initial_mouse, cache->initial_mouse);
- copy_v3_v3(ups->anchored_location, cache->true_location);
- ups->anchored_size = cache->pixel_radius;
+ copy_v3_v3(cache->anchored_location, cache->true_location);
+ ups->anchored_size = ups->pixel_radius;
}
- ups->special_rotation = cache->special_rotation;
+ cache->special_rotation = ups->brush_rotation;
}
-/* Returns true iff any of the smoothing modes are active (currently
+/* Returns true if any of the smoothing modes are active (currently
* one of smooth brush, autosmooth, mask smooth, or shift-key
* smooth) */
static int sculpt_any_smooth_mode(const Brush *brush,
@@ -4098,7 +4030,6 @@ int sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2])
StrokeCache *cache;
float ray_start[3], ray_end[3], ray_normal[3], dist;
float obimat[4][4];
- float mval[2];
SculptRaycastData srd;
view3d_set_viewcontext(C, &vc);
@@ -4109,11 +4040,8 @@ int sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2])
sculpt_stroke_modifiers_check(C, ob);
- mval[0] = mouse[0] - vc.ar->winrct.xmin;
- mval[1] = mouse[1] - vc.ar->winrct.ymin;
-
/* TODO: what if the segment is totally clipped? (return == 0) */
- ED_view3d_win_to_segment_clip(vc.ar, vc.v3d, mval, ray_start, ray_end);
+ ED_view3d_win_to_segment_clip(vc.ar, vc.v3d, mouse, ray_start, ray_end);
invert_m4_m4(obimat, ob->obmat);
mul_m4_v3(obimat, ray_start);
@@ -4279,6 +4207,7 @@ static int sculpt_stroke_test_start(bContext *C, struct wmOperator *op,
static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
{
+ UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
@@ -4289,9 +4218,9 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
sculpt_restore_mesh(sd, ob);
BKE_pbvh_bmesh_detail_size_set(ss->pbvh,
- (ss->cache->radius /
- (float)ss->cache->pixel_radius) *
- (float)sd->detail_size);
+ (ss->cache->radius /
+ (float)ups->pixel_radius) *
+ (float)sd->detail_size);
if (sculpt_stroke_dynamic_topology(ss, brush)) {
do_symmetrical_brush_actions(sd, ob, sculpt_topology_update);
@@ -4335,7 +4264,6 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
/* reset values used to draw brush after completing the stroke */
ups->draw_anchored = 0;
ups->draw_pressure = 0;
- ups->special_rotation = 0;
/* Finished */
if (ss->cache) {
@@ -4390,7 +4318,7 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
sculpt_brush_exit_tex(sd);
}
-static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
struct PaintStroke *stroke;
int ignore_background_click;
@@ -4407,8 +4335,7 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *even
op->customdata = stroke;
/* For tablet rotation */
- ignore_background_click = RNA_boolean_get(op->ptr,
- "ignore_background_click");
+ ignore_background_click = RNA_boolean_get(op->ptr, "ignore_background_click");
if (ignore_background_click && !over_mesh(C, op, event->x, event->y)) {
paint_stroke_data_free(op);
@@ -4487,8 +4414,7 @@ static void SCULPT_OT_brush_stroke(wmOperatorType *ot)
/* properties */
- RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement,
- "Stroke", "");
+ RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
RNA_def_enum(ot->srna, "mode", stroke_mode_items, BRUSH_STROKE_NORMAL,
"Sculpt Stroke Mode",
@@ -4570,7 +4496,7 @@ void sculpt_dynamic_topology_enable(bContext *C)
sculpt_pbvh_clear(ob);
ss->bm_smooth_shading = (scene->toolsettings->sculpt->flags &
- SCULPT_DYNTOPO_SMOOTH_SHADING);
+ SCULPT_DYNTOPO_SMOOTH_SHADING);
/* Create triangles-only BMesh */
ss->bm = BM_mesh_create(&bm_mesh_allocsize_default);
@@ -4596,7 +4522,7 @@ void sculpt_dynamic_topology_enable(bContext *C)
* If 'unode' is given, the BMesh's data is copied out to the unode
* before the BMesh is deleted so that it can be restored from */
void sculpt_dynamic_topology_disable(bContext *C,
- SculptUndoNode *unode)
+ SculptUndoNode *unode)
{
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
@@ -4619,13 +4545,13 @@ void sculpt_dynamic_topology_disable(bContext *C,
me->totedge = unode->bm_enter_totedge;
me->totface = 0;
CustomData_copy(&unode->bm_enter_vdata, &me->vdata, CD_MASK_MESH,
- CD_DUPLICATE, unode->bm_enter_totvert);
+ CD_DUPLICATE, unode->bm_enter_totvert);
CustomData_copy(&unode->bm_enter_edata, &me->edata, CD_MASK_MESH,
- CD_DUPLICATE, unode->bm_enter_totedge);
+ CD_DUPLICATE, unode->bm_enter_totedge);
CustomData_copy(&unode->bm_enter_ldata, &me->ldata, CD_MASK_MESH,
- CD_DUPLICATE, unode->bm_enter_totloop);
+ CD_DUPLICATE, unode->bm_enter_totloop);
CustomData_copy(&unode->bm_enter_pdata, &me->pdata, CD_MASK_MESH,
- CD_DUPLICATE, unode->bm_enter_totpoly);
+ CD_DUPLICATE, unode->bm_enter_totpoly);
mesh_update_customdata_pointers(me, FALSE);
}
@@ -4665,28 +4591,23 @@ static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(o
return OPERATOR_FINISHED;
}
-static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op,
- wmEvent *UNUSED(event))
+static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Object *ob = CTX_data_active_object(C);
Mesh *me = ob->data;
SculptSession *ss = ob->sculpt;
- const char *msg = "Dynamic-topology sculpting will not preserve"
- "vertex colors, UVs, or other customdata";
+ const char *msg = TIP_("Dynamic-topology sculpting will not preserve vertex colors, UVs, or other customdata");
if (!ss->bm) {
int i;
for (i = 0; i < CD_NUMTYPES; i++) {
- if (!ELEM7(i, CD_MVERT, CD_MEDGE, CD_MFACE,
- CD_MLOOP, CD_MPOLY, CD_PAINT_MASK,
- CD_ORIGINDEX) &&
+ if (!ELEM7(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->fdata, i)))
{
- /* The mesh has customdata that will be lost, let the
- * user confirm this is OK */
+ /* The mesh has customdata that will be lost, let the user confirm this is OK */
return WM_operator_confirm_message(C, op, msg);
}
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index fa1bdd6ca82..82a07c9e3be 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -62,9 +62,6 @@ int sculpt_poll(struct bContext *C);
void sculpt_update_mesh_elements(struct Scene *scene, struct Sculpt *sd, struct Object *ob,
int need_pmap, int need_mask);
-/* Deformed mesh sculpt */
-void free_sculptsession_deformMats(struct SculptSession *ss);
-
/* Stroke */
int sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2]);
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index 406756f4197..2cc09ea2aa9 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -131,7 +131,9 @@ static int sculpt_undo_restore_coords(bContext *C, DerivedMesh *dm, SculptUndoNo
vertCos = BKE_key_convert_to_vertcos(ob, ss->kb);
for (i = 0; i < unode->totvert; i++) {
- if (ss->modifiers_active) sculpt_undo_restore_deformed(ss, unode, i, index[i], vertCos[index[i]]);
+ if (ss->modifiers_active) {
+ sculpt_undo_restore_deformed(ss, unode, i, index[i], vertCos[index[i]]);
+ }
else {
if (unode->orig_co) swap_v3_v3(vertCos[index[i]], unode->orig_co[i]);
else swap_v3_v3(vertCos[index[i]], unode->co[i]);
@@ -149,7 +151,9 @@ static int sculpt_undo_restore_coords(bContext *C, DerivedMesh *dm, SculptUndoNo
}
else {
for (i = 0; i < unode->totvert; i++) {
- if (ss->modifiers_active) sculpt_undo_restore_deformed(ss, unode, i, index[i], mvert[index[i]].co);
+ if (ss->modifiers_active) {
+ sculpt_undo_restore_deformed(ss, unode, i, index[i], mvert[index[i]].co);
+ }
else {
if (unode->orig_co) swap_v3_v3(mvert[index[i]].co, unode->orig_co[i]);
else swap_v3_v3(mvert[index[i]].co, unode->co[i]);
@@ -263,8 +267,8 @@ static int sculpt_undo_restore_mask(bContext *C, DerivedMesh *dm, SculptUndoNode
}
static void sculpt_undo_bmesh_restore_generic(SculptUndoNode *unode,
- Object *ob,
- SculptSession *ss)
+ Object *ob,
+ SculptSession *ss)
{
if (unode->applied) {
BM_log_undo(ss->bm, ss->bm_log);
@@ -282,7 +286,7 @@ static void sculpt_undo_bmesh_restore_generic(SculptUndoNode *unode,
/* Create empty sculpt BMesh and enable logging */
static void sculpt_undo_bmesh_enable(Object *ob,
- SculptUndoNode *unode)
+ SculptUndoNode *unode)
{
SculptSession *ss = ob->sculpt;
Mesh *me = ob->data;
@@ -296,13 +300,13 @@ static void sculpt_undo_bmesh_enable(Object *ob,
/* Restore the BMLog using saved entries */
ss->bm_log = BM_log_from_existing_entries_create(ss->bm,
- unode->bm_entry);
+ unode->bm_entry);
}
static void sculpt_undo_bmesh_restore_begin(bContext *C,
- SculptUndoNode *unode,
- Object *ob,
- SculptSession *ss)
+ SculptUndoNode *unode,
+ Object *ob,
+ SculptSession *ss)
{
if (unode->applied) {
sculpt_dynamic_topology_disable(C, unode);
@@ -319,9 +323,9 @@ static void sculpt_undo_bmesh_restore_begin(bContext *C,
}
static void sculpt_undo_bmesh_restore_end(bContext *C,
- SculptUndoNode *unode,
- Object *ob,
- SculptSession *ss)
+ SculptUndoNode *unode,
+ Object *ob,
+ SculptSession *ss)
{
if (unode->applied) {
sculpt_undo_bmesh_enable(ob, unode);
@@ -343,9 +347,9 @@ static void sculpt_undo_bmesh_restore_end(bContext *C,
* Returns TRUE if this was a dynamic-topology undo step, otherwise
* returns FALSE to indicate the non-dyntopo code should run. */
static int sculpt_undo_bmesh_restore(bContext *C,
- SculptUndoNode *unode,
- Object *ob,
- SculptSession *ss)
+ SculptUndoNode *unode,
+ Object *ob,
+ SculptSession *ss)
{
switch (unode->type) {
case SCULPT_UNDO_DYNTOPO_BEGIN:
@@ -375,7 +379,6 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb)
DerivedMesh *dm;
SculptSession *ss = ob->sculpt;
SculptUndoNode *unode;
- MultiresModifierData *mmd;
int update = FALSE, rebuild = FALSE;
int need_mask = FALSE;
@@ -446,7 +449,7 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb)
BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb, &rebuild);
BKE_pbvh_update(ss->pbvh, PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw, NULL);
- if ((mmd = sculpt_multires_active(scene, ob))) {
+ if (sculpt_multires_active(scene, ob)) {
if (rebuild)
multires_mark_as_modified(ob, MULTIRES_HIDDEN_MODIFIED);
else
@@ -563,7 +566,7 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node,
if (node) {
BKE_pbvh_node_num_verts(ss->pbvh, node, &totvert, &allvert);
BKE_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid,
- &maxgrid, &gridsize, NULL, NULL);
+ &maxgrid, &gridsize, NULL, NULL);
unode->totvert = totvert;
}
@@ -673,8 +676,8 @@ static void sculpt_undo_store_mask(Object *ob, SculptUndoNode *unode)
}
static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob,
- PBVHNode *node,
- SculptUndoType type)
+ PBVHNode *node,
+ SculptUndoType type)
{
ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_MESH);
SculptUndoNode *unode = lb->first;
@@ -701,13 +704,13 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob,
* (converting polys to triangles) that the BMLog can't
* fully restore from */
CustomData_copy(&me->vdata, &unode->bm_enter_vdata, CD_MASK_MESH,
- CD_DUPLICATE, me->totvert);
+ CD_DUPLICATE, me->totvert);
CustomData_copy(&me->edata, &unode->bm_enter_edata, CD_MASK_MESH,
- CD_DUPLICATE, me->totedge);
+ CD_DUPLICATE, me->totedge);
CustomData_copy(&me->ldata, &unode->bm_enter_ldata, CD_MASK_MESH,
- CD_DUPLICATE, me->totloop);
+ CD_DUPLICATE, me->totloop);
CustomData_copy(&me->pdata, &unode->bm_enter_pdata, CD_MASK_MESH,
- CD_DUPLICATE, me->totpoly);
+ CD_DUPLICATE, me->totpoly);
unode->bm_enter_totvert = me->totvert;
unode->bm_enter_totedge = me->totedge;
unode->bm_enter_totloop = me->totloop;
@@ -756,9 +759,9 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node,
BLI_lock_thread(LOCK_CUSTOM1);
if (ss->bm ||
- ELEM(type,
- SCULPT_UNDO_DYNTOPO_BEGIN,
- SCULPT_UNDO_DYNTOPO_END))
+ ELEM(type,
+ SCULPT_UNDO_DYNTOPO_BEGIN,
+ SCULPT_UNDO_DYNTOPO_END))
{
/* Dynamic topology stores only one undo node per stroke,
* regardless of the number of PBVH nodes modified */
diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c
index 0bcccd9479c..7cdfb6d22b2 100644
--- a/source/blender/editors/sculpt_paint/sculpt_uv.c
+++ b/source/blender/editors/sculpt_paint/sculpt_uv.c
@@ -144,6 +144,69 @@ typedef struct UvSculptData {
char invert;
} UvSculptData;
+
+static Brush *uv_sculpt_brush(bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *settings = scene->toolsettings;
+
+ if (!settings->uvsculpt)
+ return NULL;
+ return paint_brush(&settings->uvsculpt->paint);
+}
+
+
+static int uv_sculpt_brush_poll(bContext *C)
+{
+ BMEditMesh *em;
+ int ret;
+ Object *obedit = CTX_data_edit_object(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *toolsettings = scene->toolsettings;
+
+ if (!uv_sculpt_brush(C) || !obedit || obedit->type != OB_MESH)
+ return 0;
+
+ em = BMEdit_FromObject(obedit);
+ ret = EDBM_mtexpoly_check(em);
+
+ if (ret && sima) {
+ ARegion *ar = CTX_wm_region(C);
+ if ((toolsettings->use_uv_sculpt) && ar->regiontype == RGN_TYPE_WINDOW)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+void ED_space_image_uv_sculpt_update(wmWindowManager *wm, ToolSettings *settings)
+{
+ if (settings->use_uv_sculpt) {
+ if (!settings->uvsculpt) {
+ settings->uvsculpt = MEM_callocN(sizeof(*settings->uvsculpt), "UV Smooth paint");
+ settings->uv_sculpt_tool = UV_SCULPT_TOOL_GRAB;
+ settings->uv_sculpt_settings = UV_SCULPT_LOCK_BORDERS | UV_SCULPT_ALL_ISLANDS;
+ settings->uv_relax_method = UV_SCULPT_TOOL_RELAX_LAPLACIAN;
+ }
+
+ BKE_paint_init(&settings->uvsculpt->paint, PAINT_CURSOR_SCULPT);
+
+ WM_paint_cursor_activate(wm, uv_sculpt_brush_poll,
+ brush_drawcursor_texpaint_uvsculpt, NULL);
+ }
+ else {
+ if (settings->uvsculpt)
+ settings->uvsculpt->paint.flags &= ~PAINT_SHOW_BRUSH;
+ }
+}
+
+int uv_sculpt_poll(bContext *C)
+{
+ return uv_sculpt_brush_poll(C);
+}
+
/*********** Improved Laplacian Relaxation Operator ************************/
/* original code by Raul Fernandez Hernandez "farsthary" *
* adapted to uv smoothing by Antony Riakiatakis *
@@ -294,7 +357,7 @@ static void laplacian_relaxation_iteration_uv(BMEditMesh *em, UvSculptData *scul
}
-static void uv_sculpt_stroke_apply(bContext *C, wmOperator *op, wmEvent *event, Object *obedit)
+static void uv_sculpt_stroke_apply(bContext *C, wmOperator *op, const wmEvent *event, Object *obedit)
{
float co[2], radius, radius_root;
Scene *scene = CTX_data_scene(C);
@@ -464,7 +527,7 @@ static int uv_edge_compare(const void *a, const void *b)
}
-static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, wmEvent *event)
+static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wmEvent *event)
{
Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
@@ -649,7 +712,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, wmEvent
return NULL;
}
/* fill the edges with data */
- for (i = 0; !BLI_ghashIterator_isDone(ghi); BLI_ghashIterator_step(ghi)) {
+ for (i = 0; BLI_ghashIterator_notDone(ghi); BLI_ghashIterator_step(ghi)) {
data->uvedges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(ghi));
}
data->totalUvEdges = BLI_ghash_size(edgeHash);
@@ -731,7 +794,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, wmEvent
return op->customdata;
}
-static int uv_sculpt_stroke_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int uv_sculpt_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
UvSculptData *data;
Object *obedit = CTX_data_edit_object(C);
@@ -754,7 +817,7 @@ static int uv_sculpt_stroke_invoke(bContext *C, wmOperator *op, wmEvent *event)
}
-static int uv_sculpt_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int uv_sculpt_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
UvSculptData *data = (UvSculptData *)op->customdata;
Object *obedit = CTX_data_edit_object(C);
diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c
index eb138bfeeef..d25fd00514c 100644
--- a/source/blender/editors/sound/sound_ops.c
+++ b/source/blender/editors/sound/sound_ops.c
@@ -160,7 +160,7 @@ static int sound_open_exec(bContext *UNUSED(C), wmOperator *op)
#endif
-static int sound_open_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int sound_open_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (RNA_struct_property_is_set(op->ptr, "filepath"))
return sound_open_exec(C, op);
@@ -439,7 +439,7 @@ static int sound_mixdown_check(bContext *UNUSED(C), wmOperator *op)
#endif // WITH_AUDASPACE
-static int sound_mixdown_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int sound_mixdown_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (RNA_struct_property_is_set(op->ptr, "filepath"))
return sound_mixdown_exec(C, op);
@@ -747,7 +747,7 @@ static int sound_unpack_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int sound_unpack_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int sound_unpack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Editing *ed = CTX_data_scene(C)->ed;
bSound *sound;
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index 7e99e6c065d..803e7b71c77 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -742,7 +742,7 @@ static int actkeys_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-static int actkeys_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int actkeys_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
actkeys_duplicate_exec(C, op);
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index 964a6a20c37..b6d2d31f0ad 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -872,7 +872,7 @@ static int actkeys_select_leftright_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int actkeys_select_leftright_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int actkeys_select_leftright_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
bAnimContext ac;
short leftright = RNA_enum_get(op->ptr, "mode");
@@ -1223,7 +1223,7 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_
}
/* handle clicking */
-static int actkeys_clickselect_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int actkeys_clickselect_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
bAnimContext ac;
/* ARegion *ar; */ /* UNUSED */
@@ -1264,16 +1264,17 @@ void ACTION_OT_clickselect(wmOperatorType *ot)
ot->idname = "ACTION_OT_clickselect";
ot->description = "Select keyframes by clicking on them";
- /* api callbacks - absolutely no exec() this yet... */
+ /* callbacks */
ot->invoke = actkeys_clickselect_invoke;
ot->poll = ED_operator_action_active;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO;
/* properties */
prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); // SHIFTKEY
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
prop = RNA_def_boolean(ot->srna, "column", 0, "Column Select", ""); // ALTKEY
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c
index 8b6682ff1c9..dcc61cfa544 100644
--- a/source/blender/editors/space_buttons/buttons_ops.c
+++ b/source/blender/editors/space_buttons/buttons_ops.c
@@ -35,10 +35,10 @@
#include "DNA_userdef_types.h"
+#include "BLI_utildefines.h"
#include "BLI_fileops.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
-#include "BLI_utildefines.h"
#include "BLF_translation.h"
@@ -62,7 +62,7 @@
/********************** toolbox operator *********************/
-static int toolbox_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
+static int toolbox_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
{
bScreen *sc = CTX_wm_screen(C);
SpaceButs *sbuts = CTX_wm_space_buts(C);
@@ -113,7 +113,6 @@ static int file_browse_exec(bContext *C, wmOperator *op)
/* add slash for directories, important for some properties */
if (RNA_property_subtype(fbo->prop) == PROP_DIRPATH) {
- char name[FILE_MAX];
int is_relative = RNA_boolean_get(op->ptr, "relative_path");
id = fbo->ptr.id.data;
@@ -132,8 +131,10 @@ static int file_browse_exec(bContext *C, wmOperator *op)
}
BLI_add_slash(str);
}
- else
- BLI_splitdirstring(str, name);
+ else {
+ char * const lslash = (char *)BLI_last_slash(str);
+ if (lslash) lslash[1] = '\0';
+ }
}
RNA_property_string_set(&fbo->ptr, fbo->prop, str);
@@ -164,7 +165,7 @@ static int file_browse_cancel(bContext *UNUSED(C), wmOperator *op)
return OPERATOR_CANCELLED;
}
-static int file_browse_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
PointerRNA ptr;
PropertyRNA *prop;
@@ -189,7 +190,7 @@ static int file_browse_invoke(bContext *C, wmOperator *op, wmEvent *event)
PointerRNA props_ptr;
if (event->alt) {
- char *lslash = BLI_last_slash(str);
+ char *lslash = (char *)BLI_last_slash(str);
if (lslash)
*lslash = '\0';
}
diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c
index 16d194d0929..1643921e4dd 100644
--- a/source/blender/editors/space_buttons/buttons_texture.c
+++ b/source/blender/editors/space_buttons/buttons_texture.c
@@ -404,7 +404,7 @@ void uiTemplateTextureUser(uiLayout *layout, bContext *C)
}
/* create button */
- BLI_snprintf(name, UI_MAX_NAME_STR, "%s", user->name);
+ BLI_strncpy(name, user->name, UI_MAX_NAME_STR);
if (user->icon) {
but = uiDefIconTextMenuBut(block, template_texture_user_menu, NULL,
diff --git a/source/blender/editors/space_clip/SConscript b/source/blender/editors/space_clip/SConscript
index c65a076186f..840a3b49f2b 100644
--- a/source/blender/editors/space_clip/SConscript
+++ b/source/blender/editors/space_clip/SConscript
@@ -34,5 +34,8 @@ incs += ' ../../makesrna ../../windowmanager #/intern/guardedalloc #/extern/glew
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
+
+if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
+ incs += ' ' + env['BF_PTHREADS_INC']
env.BlenderLib ( 'bf_editors_space_clip', sources, Split(incs), defs, libtype=['core'], priority=[95] )
diff --git a/source/blender/editors/space_clip/clip_dopesheet_ops.c b/source/blender/editors/space_clip/clip_dopesheet_ops.c
index 09f6271b6ef..e5cd7247c43 100644
--- a/source/blender/editors/space_clip/clip_dopesheet_ops.c
+++ b/source/blender/editors/space_clip/clip_dopesheet_ops.c
@@ -59,12 +59,11 @@
#include "clip_intern.h" // own include
-#if 0
-static int ED_space_clip_dopesheet_poll(bContext *C)
+static int space_clip_dopesheet_poll(bContext *C)
{
- SpaceClip *sc = CTX_wm_space_clip(C);
+ if (ED_space_clip_tracking_poll(C)) {
+ SpaceClip *sc = CTX_wm_space_clip(C);
- if (sc && sc->clip) {
if (sc->view == SC_VIEW_DOPESHEET) {
ARegion *ar = CTX_wm_region(C);
@@ -74,7 +73,6 @@ static int ED_space_clip_dopesheet_poll(bContext *C)
return FALSE;
}
-#endif
/********************** select channel operator *********************/
@@ -129,7 +127,7 @@ static int dopesheet_select_channel_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int dopesheet_select_channel_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int dopesheet_select_channel_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
float location[2];
@@ -161,3 +159,54 @@ void CLIP_OT_dopesheet_select_channel(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "extend", 0,
"Extend", "Extend selection rather than clearing the existing selection");
}
+
+/********************** View All operator *********************/
+
+static int dopesheet_view_all_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ ARegion *ar = CTX_wm_region(C);
+ View2D *v2d = &ar->v2d;
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingDopesheet *dopesheet = &tracking->dopesheet;
+ MovieTrackingDopesheetChannel *channel;
+ int frame_min = INT_MAX, frame_max = INT_MIN;
+
+ for (channel = dopesheet->channels.first; channel; channel = channel->next) {
+ frame_min = min_ii(frame_min, channel->segments[0]);
+ frame_max = max_ii(frame_max, channel->segments[channel->tot_segment]);
+ }
+
+ if (frame_min < frame_max) {
+ float extra;
+
+ v2d->cur.xmin = frame_min;
+ v2d->cur.xmax = frame_max;
+
+ /* we need an extra "buffer" factor on either side so that the endpoints are visible */
+ extra = 0.01f * BLI_rctf_size_x(&v2d->cur);
+ v2d->cur.xmin -= extra;
+ v2d->cur.xmax += extra;
+
+ ED_region_tag_redraw(ar);
+ }
+
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_dopesheet_view_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "View All";
+ ot->description = "Reset viewable area to show full keyframe range";
+ ot->idname = "CLIP_OT_dopesheet_view_all";
+
+ /* api callbacks */
+ ot->exec = dopesheet_view_all_exec;
+ ot->poll = space_clip_dopesheet_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c
index 56f2998b047..58626c79363 100644
--- a/source/blender/editors/space_clip/clip_draw.c
+++ b/source/blender/editors/space_clip/clip_draw.c
@@ -944,7 +944,7 @@ static void draw_marker_texts(SpaceClip *sc, MovieTrackingTrack *track, MovieTra
if (state[0])
BLI_snprintf(str, sizeof(str), "%s: %s", track->name, state);
else
- BLI_snprintf(str, sizeof(str), "%s", track->name);
+ BLI_strncpy(str, track->name, sizeof(str));
BLF_position(fontid, pos[0], pos[1], 0.0f);
BLF_draw(fontid, str, sizeof(str));
diff --git a/source/blender/editors/space_clip/clip_graph_ops.c b/source/blender/editors/space_clip/clip_graph_ops.c
index fa235bd2997..edc6ac1ecf7 100644
--- a/source/blender/editors/space_clip/clip_graph_ops.c
+++ b/source/blender/editors/space_clip/clip_graph_ops.c
@@ -276,7 +276,7 @@ static int select_exec(bContext *C, wmOperator *op)
return mouse_select(C, co, extend);
}
-static int select_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
float co[2];
diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h
index 432032e9dbf..cd7da4229d2 100644
--- a/source/blender/editors/space_clip/clip_intern.h
+++ b/source/blender/editors/space_clip/clip_intern.h
@@ -67,6 +67,7 @@ void clip_draw_dopesheet_channels(const struct bContext *C, struct ARegion *ar);
/* clip_dopesheet_ops.c */
void CLIP_OT_dopesheet_select_channel(struct wmOperatorType *ot);
+void CLIP_OT_dopesheet_view_all(struct wmOperatorType *ot);
/* clip_draw.c */
void clip_draw_main(const struct bContext *C, struct SpaceClip *sc, struct ARegion *ar);
@@ -133,7 +134,7 @@ void clip_draw_cfra(struct SpaceClip *sc, struct ARegion *ar, struct Scene *scen
void clip_draw_sfra_efra(struct View2D *v2d, struct Scene *scene);
/* tracking_ops.c */
-struct MovieTrackingTrack *tracking_marker_check_slide(struct bContext *C, struct wmEvent *event,
+struct MovieTrackingTrack *tracking_marker_check_slide(struct bContext *C, const struct wmEvent *event,
int *area_r, int *action_r, int *corner_r);
void CLIP_OT_add_marker(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index dfb69be6f18..914eb9526a8 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -30,16 +30,26 @@
*/
#include <errno.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#ifndef WIN32
+# include <unistd.h>
+#else
+# include <io.h>
+#endif
#include "MEM_guardedalloc.h"
#include "DNA_userdef_types.h"
#include "DNA_scene_types.h" /* min/max frames */
-#include "BLI_path_util.h"
#include "BLI_utildefines.h"
+#include "BLI_fileops.h"
+#include "BLI_path_util.h"
#include "BLI_math.h"
#include "BLI_rect.h"
+#include "BLI_threads.h"
#include "BLF_translation.h"
@@ -113,7 +123,7 @@ static void sclip_zoom_set_factor(const bContext *C, float zoomfac, float locati
sclip_zoom_set(C, sc->zoom * zoomfac, location);
}
-static void sclip_zoom_set_factor_exec(bContext *C, wmEvent *event, float factor)
+static void sclip_zoom_set_factor_exec(bContext *C, const wmEvent *event, float factor)
{
ARegion *ar = CTX_wm_region(C);
@@ -230,7 +240,7 @@ static int open_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int open_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
SpaceClip *sc = CTX_wm_space_clip(C);
char path[FILE_MAX];
@@ -318,7 +328,7 @@ typedef struct ViewPanData {
float *vec;
} ViewPanData;
-static void view_pan_init(bContext *C, wmOperator *op, wmEvent *event)
+static void view_pan_init(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceClip *sc = CTX_wm_space_clip(C);
ViewPanData *vpd;
@@ -377,7 +387,7 @@ static int view_pan_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int view_pan_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int view_pan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (event->type == MOUSEPAN) {
SpaceClip *sc = CTX_wm_space_clip(C);
@@ -399,7 +409,7 @@ static int view_pan_invoke(bContext *C, wmOperator *op, wmEvent *event)
}
}
-static int view_pan_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int view_pan_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceClip *sc = CTX_wm_space_clip(C);
ViewPanData *vpd = op->customdata;
@@ -471,7 +481,7 @@ typedef struct ViewZoomData {
float location[2];
} ViewZoomData;
-static void view_zoom_init(bContext *C, wmOperator *op, wmEvent *event)
+static void view_zoom_init(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceClip *sc = CTX_wm_space_clip(C);
ARegion *ar = CTX_wm_region(C);
@@ -514,7 +524,7 @@ static int view_zoom_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int view_zoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int view_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (event->type == MOUSEZOOM || event->type == MOUSEPAN) {
float delta, factor;
@@ -538,7 +548,7 @@ static int view_zoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
}
}
-static int view_zoom_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int view_zoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewZoomData *vpd = op->customdata;
float delta, factor;
@@ -611,7 +621,7 @@ static int view_zoom_in_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int view_zoom_in_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int view_zoom_in_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceClip *sc = CTX_wm_space_clip(C);
ARegion *ar = CTX_wm_region(C);
@@ -654,7 +664,7 @@ static int view_zoom_out_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int view_zoom_out_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int view_zoom_out_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceClip *sc = CTX_wm_space_clip(C);
ARegion *ar = CTX_wm_region(C);
@@ -844,7 +854,7 @@ static int change_frame_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int frame_from_event(bContext *C, wmEvent *event)
+static int frame_from_event(bContext *C, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
@@ -866,7 +876,7 @@ static int frame_from_event(bContext *C, wmEvent *event)
return framenr;
}
-static int change_frame_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
@@ -885,7 +895,7 @@ static int change_frame_invoke(bContext *C, wmOperator *op, wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
-static int change_frame_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int change_frame_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
switch (event->type) {
case ESCKEY:
@@ -971,46 +981,39 @@ static int proxy_bitflag_to_array(int size_flag, int build_sizes[4], int undisto
return build_count;
}
-/* only this runs inside thread */
-static void proxy_startjob(void *pjv, short *stop, short *do_update, float *progress)
+/* simple case for movies -- handle frame-by-frame, do threading within single frame */
+static void do_movie_proxy(void *pjv, int *UNUSED(build_sizes), int UNUSED(build_count),
+ int *build_undistort_sizes, int build_undistort_count,
+ short *stop, short *do_update, float *progress)
{
ProxyJob *pj = pjv;
Scene *scene = pj->scene;
MovieClip *clip = pj->clip;
struct MovieDistortion *distortion = NULL;
- short size_flag;
int cfra, sfra = SFRA, efra = EFRA;
- int build_sizes[4], build_count = 0;
- int build_undistort_sizes[4], build_undistort_count = 0;
- size_flag = clip->proxy.build_size_flag;
-
- build_count = proxy_bitflag_to_array(size_flag, build_sizes, 0);
- build_undistort_count = proxy_bitflag_to_array(size_flag, build_undistort_sizes, 1);
-
- if (clip->source == MCLIP_SRC_MOVIE) {
- if (pj->index_context)
- IMB_anim_index_rebuild(pj->index_context, stop, do_update, progress);
+ if (pj->index_context)
+ IMB_anim_index_rebuild(pj->index_context, stop, do_update, progress);
- if (!build_undistort_count) {
- if (*stop)
- pj->stop = 1;
+ if (!build_undistort_count) {
+ if (*stop)
+ pj->stop = 1;
- return;
- }
- else {
- sfra = 1;
- efra = IMB_anim_get_duration(clip->anim, IMB_TC_NONE);
- }
+ return;
}
+ else {
+ sfra = 1;
+ efra = IMB_anim_get_duration(clip->anim, IMB_TC_NONE);
+ }
+
+ if (build_undistort_count) {
+ int threads = BLI_system_thread_count();
- if (build_undistort_count)
distortion = BKE_tracking_distortion_new();
+ BKE_tracking_distortion_set_threads(distortion, threads);
+ }
for (cfra = sfra; cfra <= efra; cfra++) {
- if (clip->source != MCLIP_SRC_MOVIE)
- BKE_movieclip_build_proxy_frame(clip, pj->clip_flag, NULL, cfra, build_sizes, build_count, 0);
-
BKE_movieclip_build_proxy_frame(clip, pj->clip_flag, distortion, cfra,
build_undistort_sizes, build_undistort_count, 1);
@@ -1028,6 +1031,193 @@ static void proxy_startjob(void *pjv, short *stop, short *do_update, float *prog
pj->stop = 1;
}
+/* *****
+ * special case for sequences -- handle different frames in different threads,
+ * loading from disk happens in critical section, decoding frame happens from
+ * thread for maximal speed
+ */
+
+typedef struct ProxyQueue {
+ int cfra;
+ int sfra;
+ int efra;
+ SpinLock spin;
+
+ short *stop;
+ short *do_update;
+ float *progress;
+} ProxyQueue;
+
+typedef struct ProxyThread {
+ MovieClip *clip;
+ ProxyQueue *queue;
+
+ struct MovieDistortion *distortion;
+
+ int *build_sizes, build_count;
+ int *build_undistort_sizes, build_undistort_count;
+} ProxyThread;
+
+static unsigned char *proxy_thread_next_frame(ProxyQueue *queue, MovieClip *clip, size_t *size_r, int *cfra_r)
+{
+ unsigned char *mem = NULL;
+
+ BLI_spin_lock(&queue->spin);
+ if (!*queue->stop && queue->cfra <= queue->efra) {
+ char name[FILE_MAX];
+ size_t size;
+ int file;
+
+ BKE_movieclip_filename_for_frame(clip, queue->cfra, name);
+
+ file = open(name, O_BINARY | O_RDONLY, 0);
+ if (file < 0) {
+ BLI_spin_unlock(&queue->spin);
+ return NULL;
+ }
+
+ size = BLI_file_descriptor_size(file);
+ if (size < 1) {
+ close(file);
+ BLI_spin_unlock(&queue->spin);
+ return NULL;
+ }
+
+ mem = MEM_mallocN(size, "movieclip proxy memory file");
+
+ if (read(file, mem, size) != size) {
+ close(file);
+ BLI_spin_unlock(&queue->spin);
+ MEM_freeN(mem);
+ return NULL;
+ }
+
+ *size_r = size;
+ *cfra_r = queue->cfra;
+
+ queue->cfra++;
+ close(file);
+
+ *queue->do_update = 1;
+ *queue->progress = (float)(queue->cfra - queue->sfra) / (queue->efra - queue->sfra);
+ }
+ BLI_spin_unlock(&queue->spin);
+
+ return mem;
+}
+
+static void *do_proxy_thread(void *data_v)
+{
+ ProxyThread *data = (ProxyThread *) data_v;
+ unsigned char *mem;
+ size_t size;
+ int cfra;
+
+ while ((mem = proxy_thread_next_frame(data->queue, data->clip, &size, &cfra))) {
+ ImBuf *ibuf;
+
+ ibuf = IMB_ibImageFromMemory(mem, size, IB_rect | IB_multilayer | IB_alphamode_detect, NULL, "proxy frame");
+
+ BKE_movieclip_build_proxy_frame_for_ibuf(data->clip, ibuf, NULL, cfra,
+ data->build_sizes, data->build_count, FALSE);
+
+ BKE_movieclip_build_proxy_frame_for_ibuf(data->clip, ibuf, data->distortion, cfra,
+ data->build_undistort_sizes, data->build_undistort_count, TRUE);
+
+ IMB_freeImBuf(ibuf);
+
+ MEM_freeN(mem);
+ }
+
+ return NULL;
+}
+
+static void do_sequence_proxy(void *pjv, int *build_sizes, int build_count,
+ int *build_undistort_sizes, int build_undistort_count,
+ short *stop, short *do_update, float *progress)
+{
+ ProxyJob *pj = pjv;
+ MovieClip *clip = pj->clip;
+ Scene *scene = pj->scene;
+ int sfra = SFRA, efra = EFRA;
+ ProxyThread *handles;
+ ListBase threads;
+ int i, tot_thread = BLI_system_thread_count();
+ ProxyQueue queue;
+
+ BLI_spin_init(&queue.spin);
+
+ queue.cfra = sfra;
+ queue.sfra = sfra;
+ queue.efra = efra;
+ queue.stop = stop;
+ queue.do_update = do_update;
+ queue.progress = progress;
+
+ handles = MEM_callocN(sizeof(ProxyThread) * tot_thread, "proxy threaded handles");
+
+ if (tot_thread > 1)
+ BLI_init_threads(&threads, do_proxy_thread, tot_thread);
+
+ for (i = 0; i < tot_thread; i++) {
+ ProxyThread *handle = &handles[i];
+
+ handle->clip = clip;
+ handle->queue = &queue;
+
+ handle->build_count = build_count;
+ handle->build_sizes = build_sizes;
+
+ handle->build_undistort_count = build_undistort_count;
+ handle->build_undistort_sizes = build_undistort_sizes;
+
+ if (build_undistort_count)
+ handle->distortion = BKE_tracking_distortion_new();
+
+ if (tot_thread > 1)
+ BLI_insert_thread(&threads, handle);
+ }
+
+ if (tot_thread > 1)
+ BLI_end_threads(&threads);
+ else
+ do_proxy_thread(handles);
+
+ MEM_freeN(handles);
+
+ if (build_undistort_count) {
+ for (i = 0; i < tot_thread; i++) {
+ ProxyThread *handle = &handles[i];
+
+ BKE_tracking_distortion_free(handle->distortion);
+ }
+ }
+}
+
+static void proxy_startjob(void *pjv, short *stop, short *do_update, float *progress)
+{
+ ProxyJob *pj = pjv;
+ MovieClip *clip = pj->clip;
+
+ short size_flag;
+ int build_sizes[4], build_count = 0;
+ int build_undistort_sizes[4], build_undistort_count = 0;
+
+ size_flag = clip->proxy.build_size_flag;
+
+ build_count = proxy_bitflag_to_array(size_flag, build_sizes, 0);
+ build_undistort_count = proxy_bitflag_to_array(size_flag, build_undistort_sizes, 1);
+
+ if (clip->source == MCLIP_SRC_MOVIE) {
+ do_movie_proxy(pjv, build_sizes, build_count, build_undistort_sizes,
+ build_undistort_count, stop, do_update, progress);
+ }
+ else {
+ do_sequence_proxy(pjv, build_sizes, build_count, build_undistort_sizes,
+ build_undistort_count, stop, do_update, progress);
+ }
+}
+
static void proxy_endjob(void *pjv)
{
ProxyJob *pj = pjv;
@@ -1134,7 +1324,7 @@ void CLIP_OT_mode_set(wmOperatorType *ot)
* that explains the negative signs in the code below
*/
-static int clip_view_ndof_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
+static int clip_view_ndof_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
if (event->type != NDOF_MOTION)
return OPERATOR_CANCELLED;
diff --git a/source/blender/editors/space_clip/clip_toolbar.c b/source/blender/editors/space_clip/clip_toolbar.c
index 7543988b5aa..10175d07300 100644
--- a/source/blender/editors/space_clip/clip_toolbar.c
+++ b/source/blender/editors/space_clip/clip_toolbar.c
@@ -33,8 +33,6 @@
#include "DNA_windowmanager_types.h"
-#include "RNA_access.h"
-
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
@@ -45,12 +43,14 @@
#include "BKE_context.h"
#include "BKE_screen.h"
-#include "ED_screen.h"
-#include "ED_util.h"
+#include "RNA_access.h"
#include "WM_types.h"
#include "WM_api.h"
+#include "ED_screen.h"
+#include "ED_util.h"
+
#include "UI_interface.h"
#include "UI_resources.h"
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index f0c0e7b72fd..4f9757a6640 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -534,6 +534,7 @@ static void clip_operatortypes(void)
/* ** clip_dopesheet_ops.c ** */
WM_operatortype_append(CLIP_OT_dopesheet_select_channel);
+ WM_operatortype_append(CLIP_OT_dopesheet_view_all);
}
static void clip_keymap(struct wmKeyConfig *keyconf)
@@ -768,6 +769,8 @@ static void clip_keymap(struct wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "CLIP_OT_dopesheet_select_channel", ACTIONMOUSE, KM_PRESS, 0, 0);
RNA_boolean_set(kmi->ptr, "extend", TRUE); /* toggle */
+
+ WM_keymap_add_item(keymap, "CLIP_OT_dopesheet_view_all", HOMEKEY, KM_PRESS, 0, 0);
}
const char *clip_context_dir[] = {"edit_movieclip", "edit_mask", NULL};
@@ -796,7 +799,7 @@ static int clip_context(const bContext *C, const char *member, bContextDataResul
}
/* dropboxes */
-static int clip_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event))
+static int clip_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
{
if (drag->type == WM_DRAG_PATH)
if (ELEM3(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_BLANK)) /* rule might not work? */
@@ -1191,6 +1194,9 @@ static void clip_preview_area_init(wmWindowManager *wm, ARegion *ar)
keymap = WM_keymap_find(wm->defaultconf, "Clip Graph Editor", SPACE_CLIP, 0);
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
+
+ keymap = WM_keymap_find(wm->defaultconf, "Clip Dopesheet Editor", SPACE_CLIP, 0);
+ WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
}
static void graph_area_draw(const bContext *C, ARegion *ar)
diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c
index ac7ebd9ddac..a51315d9a16 100644
--- a/source/blender/editors/space_clip/tracking_ops.c
+++ b/source/blender/editors/space_clip/tracking_ops.c
@@ -124,7 +124,7 @@ static int add_marker_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int add_marker_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int add_marker_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceClip *sc = CTX_wm_space_clip(C);
ARegion *ar = CTX_wm_region(C);
@@ -282,7 +282,7 @@ static void slide_marker_tilt_slider(MovieTrackingMarker *marker, float slider[2
}
static SlideMarkerData *create_slide_marker_data(SpaceClip *sc, MovieTrackingTrack *track,
- MovieTrackingMarker *marker, wmEvent *event,
+ MovieTrackingMarker *marker, const wmEvent *event,
int area, int corner, int action, int width, int height)
{
SlideMarkerData *data = MEM_callocN(sizeof(SlideMarkerData), "slide marker data");
@@ -524,7 +524,7 @@ static void show_cursor(bContext *C)
WM_cursor_set(win, CURSOR_STD);
}
-MovieTrackingTrack *tracking_marker_check_slide(bContext *C, wmEvent *event, int *area_r, int *action_r, int *corner_r)
+MovieTrackingTrack *tracking_marker_check_slide(bContext *C, const wmEvent *event, int *area_r, int *action_r, int *corner_r)
{
SpaceClip *sc = CTX_wm_space_clip(C);
ARegion *ar = CTX_wm_region(C);
@@ -623,7 +623,7 @@ MovieTrackingTrack *tracking_marker_check_slide(bContext *C, wmEvent *event, int
return NULL;
}
-static void *slide_marker_customdata(bContext *C, wmEvent *event)
+static void *slide_marker_customdata(bContext *C, const wmEvent *event)
{
SpaceClip *sc = CTX_wm_space_clip(C);
ARegion *ar = CTX_wm_region(C);
@@ -652,7 +652,7 @@ static void *slide_marker_customdata(bContext *C, wmEvent *event)
return customdata;
}
-static int slide_marker_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int slide_marker_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
SlideMarkerData *slidedata = slide_marker_customdata(C, event);
@@ -703,7 +703,7 @@ static void free_slide_data(SlideMarkerData *data)
MEM_freeN(data);
}
-static int slide_marker_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int slide_marker_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceClip *sc = CTX_wm_space_clip(C);
ARegion *ar = CTX_wm_region(C);
@@ -1228,7 +1228,7 @@ static int track_markers_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int track_markers_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int track_markers_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
TrackMarkersJob *tmj;
ScrArea *sa = CTX_wm_area(C);
@@ -1286,7 +1286,7 @@ static int track_markers_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(eve
return OPERATOR_RUNNING_MODAL;
}
-static int track_markers_modal(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
+static int track_markers_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
/* no running tracking, remove handler and pass through */
if (0 == WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C), WM_JOB_TYPE_ANY))
@@ -1457,7 +1457,7 @@ static int solve_camera_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int solve_camera_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int solve_camera_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
SolveCameraJob *scj;
ScrArea *sa = CTX_wm_area(C);
@@ -1507,7 +1507,7 @@ static int solve_camera_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(even
return OPERATOR_RUNNING_MODAL;
}
-static int solve_camera_modal(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
+static int solve_camera_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
/* no running solver, remove handler and pass through */
if (0 == WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C), WM_JOB_TYPE_ANY))
@@ -2334,7 +2334,7 @@ static int set_scale_exec(bContext *C, wmOperator *op)
return do_set_scale(C, op, 0);
}
-static int set_scale_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int set_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
@@ -2390,7 +2390,7 @@ static int set_solution_scale_exec(bContext *C, wmOperator *op)
return do_set_scale(C, op, 1);
}
-static int set_solution_scale_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int set_solution_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
@@ -3258,7 +3258,7 @@ static int clean_tracks_exec(bContext *C, wmOperator *op)
next = track->next;
if ((track->flag & TRACK_HIDDEN) == 0 && (track->flag & TRACK_LOCKED) == 0) {
- int ok = 1;
+ bool ok;
ok = (is_track_clean(track, frames, action == TRACKING_CLEAN_DELETE_SEGMENT)) &&
(error == 0.0f || (track->flag & TRACK_HAS_BUNDLE) == 0 || track->error < error);
@@ -3295,7 +3295,7 @@ static int clean_tracks_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int clean_tracks_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int clean_tracks_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c
index bec50130230..b03209173d8 100644
--- a/source/blender/editors/space_clip/tracking_select.c
+++ b/source/blender/editors/space_clip/tracking_select.c
@@ -268,6 +268,17 @@ static int mouse_select(bContext *C, float co[2], int extend)
return OPERATOR_FINISHED;
}
+static int select_poll(bContext *C)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+
+ if (sc) {
+ return sc->clip && sc->view == SC_VIEW_CLIP;
+ }
+
+ return FALSE;
+}
+
static int select_exec(bContext *C, wmOperator *op)
{
float co[2];
@@ -279,7 +290,7 @@ static int select_exec(bContext *C, wmOperator *op)
return mouse_select(C, co, extend);
}
-static int select_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceClip *sc = CTX_wm_space_clip(C);
ARegion *ar = CTX_wm_region(C);
@@ -317,8 +328,7 @@ void CLIP_OT_select(wmOperatorType *ot)
/* api callbacks */
ot->exec = select_exec;
ot->invoke = select_invoke;
- //ot->poll = ED_space_clip_tracking_poll; // so mask view can Ctrl+RMB markers
- ot->poll = ED_space_clip_view_clip_poll;
+ ot->poll = select_poll;
/* flags */
ot->flag = OPTYPE_UNDO;
diff --git a/source/blender/editors/space_console/console_draw.c b/source/blender/editors/space_console/console_draw.c
index 73747239255..cb191d0b15e 100644
--- a/source/blender/editors/space_console/console_draw.c
+++ b/source/blender/editors/space_console/console_draw.c
@@ -150,6 +150,26 @@ static int console_textview_line_get(struct TextViewContext *tvc, const char **l
return 1;
}
+static void console_cursor_wrap_offset(const char *str, int width, int *row, int *column, const char *end)
+{
+ int col;
+
+ for (; *str; str += BLI_str_utf8_size_safe(str)) {
+ col = BLI_str_utf8_char_width_safe(str);
+
+ if (*column + col > width) {
+ (*row)++;
+ *column = 0;
+ }
+
+ if (end && str >= end)
+ break;
+
+ *column += col;
+ }
+ return;
+}
+
static int console_textview_line_color(struct TextViewContext *tvc, unsigned char fg[3], unsigned char UNUSED(bg[3]))
{
ConsoleLine *cl_iter = (ConsoleLine *)tvc->iter;
@@ -158,24 +178,18 @@ static int console_textview_line_color(struct TextViewContext *tvc, unsigned cha
if (tvc->iter_index == 0) {
const SpaceConsole *sc = (SpaceConsole *)tvc->arg1;
const ConsoleLine *cl = (ConsoleLine *)sc->history.last;
- const int prompt_len = BLI_strlen_utf8(sc->prompt);
- const int cursor_loc = BLI_strnlen_utf8(cl->line, cl->cursor) + prompt_len;
- const int line_len = BLI_strlen_utf8(cl->line) + prompt_len;
+ int offl = 0, offc = 0;
int xy[2] = {CONSOLE_DRAW_MARGIN, CONSOLE_DRAW_MARGIN};
int pen[2];
xy[1] += tvc->lheight / 6;
- /* account for wrapping */
- if (line_len < tvc->console_width) {
- /* simple case, no wrapping */
- pen[0] = tvc->cwidth * cursor_loc;
- pen[1] = -2;
- }
- else {
- /* wrap */
- pen[0] = tvc->cwidth * (cursor_loc % tvc->console_width);
- pen[1] = -2 + (((line_len / tvc->console_width) - (cursor_loc / tvc->console_width)) * tvc->lheight);
- }
+ console_cursor_wrap_offset(sc->prompt, tvc->console_width, &offl, &offc, NULL);
+ console_cursor_wrap_offset(cl->line, tvc->console_width, &offl, &offc, cl->line + cl->cursor);
+ pen[0] = tvc->cwidth * offc;
+ pen[1] = -2 - tvc->lheight * offl;
+
+ console_cursor_wrap_offset(cl->line + cl->cursor, tvc->console_width, &offl, &offc, NULL);
+ pen[1] += tvc->lheight * offl;
/* cursor */
UI_GetThemeColor3ubv(TH_CONSOLE_CURSOR, fg);
diff --git a/source/blender/editors/space_console/console_ops.c b/source/blender/editors/space_console/console_ops.c
index 1242d123a41..b735dee5bdf 100644
--- a/source/blender/editors/space_console/console_ops.c
+++ b/source/blender/editors/space_console/console_ops.c
@@ -390,7 +390,7 @@ static int console_insert_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int console_insert_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int console_insert_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
// if (!RNA_struct_property_is_set(op->ptr, "text")) { /* always set from keymap XXX */
if (!RNA_string_length(op->ptr, "text")) {
@@ -1042,7 +1042,7 @@ static void console_cursor_set_to_pos(SpaceConsole *sc, ARegion *ar, SetConsoleC
}
}
-static void console_modal_select_apply(bContext *C, wmOperator *op, wmEvent *event)
+static void console_modal_select_apply(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceConsole *sc = CTX_wm_space_console(C);
ARegion *ar = CTX_wm_region(C);
@@ -1080,7 +1080,7 @@ static void console_cursor_set_exit(bContext *UNUSED(C), wmOperator *op)
MEM_freeN(scu);
}
-static int console_modal_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int console_modal_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceConsole *sc = CTX_wm_space_console(C);
// ARegion *ar = CTX_wm_region(C);
@@ -1101,7 +1101,7 @@ static int console_modal_select_invoke(bContext *C, wmOperator *op, wmEvent *eve
return OPERATOR_RUNNING_MODAL;
}
-static int console_modal_select(bContext *C, wmOperator *op, wmEvent *event)
+static int console_modal_select(bContext *C, wmOperator *op, const wmEvent *event)
{
switch (event->type) {
case LEFTMOUSE:
diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c
index eed269ff70f..4243ae4e2df 100644
--- a/source/blender/editors/space_console/space_console.c
+++ b/source/blender/editors/space_console/space_console.c
@@ -160,7 +160,7 @@ static void console_main_area_init(wmWindowManager *wm, ARegion *ar)
/* ************* dropboxes ************* */
-static int id_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event))
+static int id_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
{
// SpaceConsole *sc = CTX_wm_space_console(C);
if (drag->type == WM_DRAG_ID)
@@ -179,7 +179,7 @@ static void id_drop_copy(wmDrag *drag, wmDropBox *drop)
MEM_freeN(text);
}
-static int path_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event))
+static int path_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
{
// SpaceConsole *sc = CTX_wm_space_console(C);
if (drag->type == WM_DRAG_PATH)
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index afe32ec0b85..5b6b8656072 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -35,6 +35,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_dynstr.h"
+#include "BLI_fileops_types.h"
#ifdef WIN32
# include "BLI_winstuff.h"
@@ -55,6 +56,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_userdef_types.h"
+#include "DNA_windowmanager_types.h"
#include "RNA_access.h"
@@ -374,7 +376,7 @@ static void file_draw_preview(uiBlock *block, struct direntry *file, int sx, int
/* the image */
glColor4f(1.0, 1.0, 1.0, 1.0);
- glaDrawPixelsTexScaled((float)xco, (float)yco, imb->x, imb->y, GL_UNSIGNED_BYTE, imb->rect, scale, scale);
+ glaDrawPixelsTexScaled((float)xco, (float)yco, imb->x, imb->y, GL_UNSIGNED_BYTE, GL_NEAREST, imb->rect, scale, scale);
/* border */
if (dropshadow) {
@@ -396,6 +398,7 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname)
char newname[FILE_MAX + 12];
char orgname[FILE_MAX + 12];
char filename[FILE_MAX + 12];
+ wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C);
ARegion *ar = CTX_wm_region(C);
@@ -407,7 +410,7 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname)
if (!BLI_exists(newname)) {
BLI_rename(orgname, newname);
/* to make sure we show what is on disk */
- ED_fileselect_clear(C, sfile);
+ ED_fileselect_clear(wm, sfile);
}
ED_region_tag_redraw(ar);
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index 79a578a86d1..f705831c715 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -30,6 +30,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_fileops_types.h"
#include "BKE_context.h"
#include "BKE_screen.h"
@@ -227,7 +228,7 @@ static FileSelect file_select(bContext *C, const rcti *rect, FileSelType select,
return retval;
}
-static int file_border_select_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int file_border_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
SpaceFile *sfile = CTX_wm_space_file(C);
@@ -310,7 +311,7 @@ void FILE_OT_select_border(wmOperatorType *ot)
WM_operator_properties_gesture_border(ot, 1);
}
-static int file_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
SpaceFile *sfile = CTX_wm_space_file(C);
@@ -584,7 +585,7 @@ int file_highlight_set(SpaceFile *sfile, ARegion *ar, int mx, int my)
return (params->active_file != origfile);
}
-static int file_highlight_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
+static int file_highlight_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
SpaceFile *sfile = CTX_wm_space_file(C);
@@ -611,12 +612,13 @@ void FILE_OT_highlight(struct wmOperatorType *ot)
int file_cancel_exec(bContext *C, wmOperator *UNUSED(unused))
{
+ wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
wmOperator *op = sfile->op;
sfile->op = NULL;
- WM_event_fileselect_event(C, op, EVT_FILESELECT_CANCEL);
+ WM_event_fileselect_event(wm, op, EVT_FILESELECT_CANCEL);
return OPERATOR_FINISHED;
}
@@ -779,6 +781,7 @@ int file_draw_check_exists(SpaceFile *sfile)
/* sends events now, so things get handled on windowqueue level */
int file_exec(bContext *C, wmOperator *exec_op)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
char filepath[FILE_MAX];
@@ -810,7 +813,7 @@ int file_exec(bContext *C, wmOperator *exec_op)
BLI_make_file_string(G.main->name, filepath, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
fsmenu_write_file(fsmenu_get(), filepath);
- WM_event_fileselect_event(C, op, EVT_FILESELECT_EXEC);
+ WM_event_fileselect_event(wm, op, EVT_FILESELECT_EXEC);
}
@@ -870,10 +873,11 @@ void FILE_OT_parent(struct wmOperatorType *ot)
static int file_refresh_exec(bContext *C, wmOperator *UNUSED(unused))
{
+ wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
struct FSMenu *fsmenu = fsmenu_get();
- ED_fileselect_clear(C, sfile);
+ ED_fileselect_clear(wm, sfile);
/* refresh system directory menu */
fsmenu_refresh_system_category(fsmenu);
@@ -949,7 +953,7 @@ int file_next_exec(bContext *C, wmOperator *UNUSED(unused))
/* only meant for timer usage */
-static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
+static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
ScrArea *sa = CTX_wm_area(C);
SpaceFile *sfile = CTX_wm_space_file(C);
@@ -1087,6 +1091,7 @@ int file_directory_new_exec(bContext *C, wmOperator *op)
char path[FILE_MAX];
int generate_name = 1;
+ wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
if (!sfile->params) {
@@ -1125,7 +1130,7 @@ int file_directory_new_exec(bContext *C, wmOperator *op)
sfile->scroll_offset = 0;
/* reload dir to make sure we're seeing what's in the directory */
- ED_fileselect_clear(C, sfile);
+ ED_fileselect_clear(wm, sfile);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
return OPERATOR_FINISHED;
@@ -1189,7 +1194,7 @@ static void file_expand_directory(bContext *C)
}
}
-static int file_directory_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int file_directory_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
SpaceFile *sfile = CTX_wm_space_file(C);
@@ -1227,7 +1232,6 @@ int file_directory_exec(bContext *C, wmOperator *UNUSED(unused))
}
BLI_cleanup_dir(G.main->name, sfile->params->dir);
- BLI_add_slash(sfile->params->dir);
file_change_dir(C, 1);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@@ -1291,11 +1295,12 @@ void FILE_OT_refresh(struct wmOperatorType *ot)
static int file_hidedot_exec(bContext *C, wmOperator *UNUSED(unused))
{
+ wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
if (sfile->params) {
sfile->params->flag ^= FILE_HIDE_DOT;
- ED_fileselect_clear(C, sfile);
+ ED_fileselect_clear(wm, sfile);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
@@ -1477,14 +1482,15 @@ static int file_delete_poll(bContext *C)
int file_delete_exec(bContext *C, wmOperator *UNUSED(op))
{
char str[FILE_MAX];
+ wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
struct direntry *file;
file = filelist_file(sfile->files, sfile->params->active_file);
BLI_make_file_string(G.main->name, str, sfile->params->dir, file->relname);
- BLI_delete(str, 0, 0);
- ED_fileselect_clear(C, sfile);
+ BLI_delete(str, false, false);
+ ED_fileselect_clear(wm, sfile);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 142eb2214a1..f1e707f8802 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -48,6 +48,7 @@
#include "BLI_linklist.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
+#include "BLI_fileops_types.h"
#ifdef WIN32
# include "BLI_winstuff.h"
@@ -545,8 +546,6 @@ FileList *filelist_new(short type)
void filelist_free(struct FileList *filelist)
{
- int i;
-
if (!filelist) {
printf("Attempting to delete empty filelist.\n");
return;
@@ -557,23 +556,8 @@ void filelist_free(struct FileList *filelist)
filelist->fidx = NULL;
}
- for (i = 0; i < filelist->numfiles; ++i) {
- if (filelist->filelist[i].image) {
- IMB_freeImBuf(filelist->filelist[i].image);
- }
- filelist->filelist[i].image = NULL;
- if (filelist->filelist[i].relname)
- MEM_freeN(filelist->filelist[i].relname);
- if (filelist->filelist[i].path)
- MEM_freeN(filelist->filelist[i].path);
- filelist->filelist[i].relname = NULL;
- if (filelist->filelist[i].string)
- MEM_freeN(filelist->filelist[i].string);
- filelist->filelist[i].string = NULL;
- }
-
+ BLI_free_filelist(filelist->filelist, filelist->numfiles);
filelist->numfiles = 0;
- free(filelist->filelist);
filelist->filelist = NULL;
filelist->filter = 0;
filelist->filter_glob[0] = '\0';
@@ -874,18 +858,14 @@ static void filelist_setfiletypes(struct FileList *filelist)
static void filelist_read_dir(struct FileList *filelist)
{
- char wdir[FILE_MAX] = "";
if (!filelist) return;
filelist->fidx = NULL;
filelist->filelist = NULL;
- BLI_current_working_dir(wdir, sizeof(wdir)); /* backup cwd to restore after */
-
BLI_cleanup_dir(G.main->name, filelist->dir);
filelist->numfiles = BLI_dir_contents(filelist->dir, &(filelist->filelist));
- if (!chdir(wdir)) {} /* fix warning about not checking return value */
filelist_setfiletypes(filelist);
filelist_filter(filelist);
}
@@ -1033,7 +1013,7 @@ static int groupname_to_code(const char *group)
char *lslash;
BLI_strncpy(buf, group, sizeof(buf));
- lslash = BLI_last_slash(buf);
+ lslash = (char *)BLI_last_slash(buf);
if (lslash)
lslash[0] = '\0';
@@ -1364,7 +1344,7 @@ static void thumbnails_free(void *tjv)
}
-void thumbnails_start(struct FileList *filelist, const struct bContext *C)
+void thumbnails_start(FileList *filelist, const bContext *C)
{
wmJob *wm_job;
ThumbnailJob *tj;
@@ -1376,7 +1356,7 @@ void thumbnails_start(struct FileList *filelist, const struct bContext *C)
for (idx = 0; idx < filelist->numfiles; idx++) {
if (!filelist->filelist[idx].image) {
if ( (filelist->filelist[idx].flags & (IMAGEFILE | MOVIEFILE | BLENDERFILE | BLENDERFILE_BACKUP)) ) {
- FileImage *limg = MEM_callocN(sizeof(struct FileImage), "loadimage");
+ FileImage *limg = MEM_callocN(sizeof(FileImage), "loadimage");
BLI_strncpy(limg->path, filelist->filelist[idx].path, FILE_MAX);
limg->index = idx;
limg->flags = filelist->filelist[idx].flags;
@@ -1398,12 +1378,12 @@ void thumbnails_start(struct FileList *filelist, const struct bContext *C)
WM_jobs_start(CTX_wm_manager(C), wm_job);
}
-void thumbnails_stop(struct FileList *filelist, const struct bContext *C)
+void thumbnails_stop(wmWindowManager *wm, FileList *filelist)
{
- WM_jobs_kill(CTX_wm_manager(C), filelist, NULL);
+ WM_jobs_kill(wm, filelist, NULL);
}
-int thumbnails_running(struct FileList *filelist, const struct bContext *C)
+int thumbnails_running(wmWindowManager *wm, FileList *filelist)
{
- return WM_jobs_test(CTX_wm_manager(C), filelist, WM_JOB_TYPE_FILESEL_THUMBNAIL);
+ return WM_jobs_test(wm, filelist, WM_JOB_TYPE_FILESEL_THUMBNAIL);
}
diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h
index 32a31c51229..d093d427eae 100644
--- a/source/blender/editors/space_file/filelist.h
+++ b/source/blender/editors/space_file/filelist.h
@@ -37,15 +37,16 @@
extern "C" {
#endif
+struct BlendHandle;
struct FileList;
+struct FileSelection;
struct FolderList;
-struct direntry;
-struct BlendHandle;
-struct Scene;
struct Main;
-struct rcti;
struct ReportList;
-struct FileSelection;
+struct Scene;
+struct direntry;
+struct rcti;
+struct wmWindowManager;
typedef enum FileSelType {
FILE_SEL_REMOVE = 0,
@@ -99,9 +100,9 @@ void folderlist_popdir(struct ListBase *folderlist, char *dir);
void folderlist_pushdir(struct ListBase *folderlist, const char *dir);
int folderlist_clear_next(struct SpaceFile *sfile);
-void thumbnails_stop(struct FileList *filelist, const struct bContext *C);
void thumbnails_start(struct FileList *filelist, const struct bContext *C);
-int thumbnails_running(struct FileList *filelist, const struct bContext *C);
+void thumbnails_stop(struct wmWindowManager *wm, struct FileList *filelist);
+int thumbnails_running(struct wmWindowManager *wm, struct FileList *filelist);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 3c6f6358171..b8db7dc97b7 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -58,6 +58,7 @@
#include "BLI_linklist.h"
#include "BLI_dynstr.h"
#include "BLI_utildefines.h"
+#include "BLI_fileops_types.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -577,13 +578,14 @@ FileLayout *ED_fileselect_get_layout(struct SpaceFile *sfile, ARegion *ar)
void file_change_dir(bContext *C, int checkdir)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
if (sfile->params) {
- ED_fileselect_clear(C, sfile);
+ ED_fileselect_clear(wm, sfile);
- if (checkdir && BLI_is_dir(sfile->params->dir) == 0) {
+ if (checkdir && !BLI_is_dir(sfile->params->dir)) {
BLI_strncpy(sfile->params->dir, filelist_dir(sfile->files), sizeof(sfile->params->dir));
/* could return but just refresh the current dir */
}
@@ -690,24 +692,24 @@ void autocomplete_file(struct bContext *C, char *str, void *UNUSED(arg_v))
}
}
-void ED_fileselect_clear(struct bContext *C, struct SpaceFile *sfile)
+void ED_fileselect_clear(struct wmWindowManager *wm, struct SpaceFile *sfile)
{
/* only NULL in rare cases - [#29734] */
if (sfile->files) {
- thumbnails_stop(sfile->files, C);
+ thumbnails_stop(wm, sfile->files);
filelist_freelib(sfile->files);
filelist_free(sfile->files);
}
sfile->params->active_file = -1;
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
-void ED_fileselect_exit(struct bContext *C, struct SpaceFile *sfile)
+void ED_fileselect_exit(struct wmWindowManager *wm, struct SpaceFile *sfile)
{
if (!sfile) return;
if (sfile->op) {
- WM_event_fileselect_event(C, sfile->op, EVT_FILESELECT_EXTERNAL_CANCEL);
+ WM_event_fileselect_event(wm, sfile->op, EVT_FILESELECT_EXTERNAL_CANCEL);
sfile->op = NULL;
}
@@ -715,7 +717,7 @@ void ED_fileselect_exit(struct bContext *C, struct SpaceFile *sfile)
folderlist_free(sfile->folders_next);
if (sfile->files) {
- ED_fileselect_clear(C, sfile);
+ ED_fileselect_clear(wm, sfile);
MEM_freeN(sfile->files);
sfile->files = NULL;
}
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index 5f1f9a3ab22..04c68e5ea68 100644
--- a/source/blender/editors/space_file/fsmenu.c
+++ b/source/blender/editors/space_file/fsmenu.c
@@ -281,14 +281,14 @@ void fsmenu_write_file(struct FSMenu *fsmenu, const char *filename)
void fsmenu_read_bookmarks(struct FSMenu *fsmenu, const char *filename)
{
- char line[256];
+ char line[FILE_MAXDIR];
FSMenuCategory category = FS_CATEGORY_BOOKMARKS;
FILE *fp;
fp = BLI_fopen(filename, "r");
if (!fp) return;
- while (fgets(line, 256, fp) != NULL) { /* read a line */
+ while (fgets(line, sizeof(line), fp) != NULL) { /* read a line */
if (strncmp(line, "[Bookmarks]", 11) == 0) {
category = FS_CATEGORY_BOOKMARKS;
}
@@ -318,7 +318,7 @@ void fsmenu_read_bookmarks(struct FSMenu *fsmenu, const char *filename)
void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
{
- char line[256];
+ char line[FILE_MAXDIR];
#ifdef WIN32
/* Add the drive names to the listing */
{
@@ -376,25 +376,25 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
* TODO : replace hardcoded paths with proper BLI_get_folder calls */
home = getenv("HOME");
if (read_bookmarks && home) {
- BLI_snprintf(line, 256, "%s/", home);
+ BLI_snprintf(line, sizeof(line), "%s/", home);
fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, FS_INSERT_SORTED);
- BLI_snprintf(line, 256, "%s/Desktop/", home);
+ BLI_snprintf(line, sizeof(line), "%s/Desktop/", home);
if (BLI_exists(line)) {
fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, FS_INSERT_SORTED);
}
- BLI_snprintf(line, 256, "%s/Documents/", home);
+ BLI_snprintf(line, sizeof(line), "%s/Documents/", home);
if (BLI_exists(line)) {
fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, FS_INSERT_SORTED);
}
- BLI_snprintf(line, 256, "%s/Pictures/", home);
+ BLI_snprintf(line, sizeof(line), "%s/Pictures/", home);
if (BLI_exists(line)) {
fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, FS_INSERT_SORTED);
}
- BLI_snprintf(line, 256, "%s/Music/", home);
+ BLI_snprintf(line, sizeof(line), "%s/Music/", home);
if (BLI_exists(line)) {
fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, FS_INSERT_SORTED);
}
- BLI_snprintf(line, 256, "%s/Movies/", home);
+ BLI_snprintf(line, sizeof(line), "%s/Movies/", home);
if (BLI_exists(line)) {
fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, FS_INSERT_SORTED);
}
@@ -427,7 +427,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
pathString = CFURLCopyFileSystemPath(cfURL, kCFURLPOSIXPathStyle);
- if (!CFStringGetCString(pathString, line, 256, kCFStringEncodingASCII))
+ if (!CFStringGetCString(pathString, line, sizeof(line), kCFStringEncodingASCII))
continue;
fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, line, FS_INSERT_SORTED);
@@ -480,7 +480,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
pathString = CFURLCopyFileSystemPath(cfURL, kCFURLPOSIXPathStyle);
- if (!CFStringGetCString(pathString, line, 256, kCFStringEncodingASCII))
+ if (!CFStringGetCString(pathString, line, sizeof(line), kCFStringEncodingASCII))
continue;
fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, FS_INSERT_SORTED);
@@ -499,9 +499,9 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
const char *home = getenv("HOME");
if (read_bookmarks && home) {
- BLI_snprintf(line, FILE_MAXDIR, "%s/", home);
+ BLI_snprintf(line, sizeof(line), "%s/", home);
fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, FS_INSERT_SORTED);
- BLI_snprintf(line, FILE_MAXDIR, "%s/Desktop/", home);
+ BLI_snprintf(line, sizeof(line), "%s/Desktop/", home);
if (BLI_exists(line)) {
fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, FS_INSERT_SORTED);
}
@@ -527,7 +527,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
len = strlen(mnt->mnt_dir);
if (len && mnt->mnt_dir[len - 1] != '/') {
- BLI_snprintf(line, FILE_MAXDIR, "%s/", mnt->mnt_dir);
+ BLI_snprintf(line, sizeof(line), "%s/", mnt->mnt_dir);
fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, line, FS_INSERT_SORTED);
}
else {
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index 0a4b922bb38..698c355fad3 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -28,13 +28,9 @@
* \ingroup spfile
*/
-
#include <string.h>
#include <stdio.h>
-
-#include "RNA_access.h"
-
#include "MEM_guardedalloc.h"
#include "BIF_gl.h"
@@ -45,11 +41,17 @@
#include "BLI_math.h"
#include "BLI_rand.h"
#include "BLI_utildefines.h"
+#include "BLI_fileops_types.h"
#include "BKE_context.h"
#include "BKE_screen.h"
#include "BKE_global.h"
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
#include "ED_space_api.h"
#include "ED_screen.h"
#include "ED_fileselect.h"
@@ -57,9 +59,6 @@
#include "IMB_imbuf_types.h"
#include "IMB_thumbs.h"
-#include "WM_api.h"
-#include "WM_types.h"
-
#include "UI_resources.h"
#include "UI_view2d.h"
@@ -147,7 +146,7 @@ static void file_free(SpaceLink *sl)
/* spacetype; init callback, area size changes, screen set, etc */
-static void file_init(struct wmWindowManager *UNUSED(wm), ScrArea *sa)
+static void file_init(wmWindowManager *UNUSED(wm), ScrArea *sa)
{
SpaceFile *sfile = (SpaceFile *)sa->spacedata.first;
//printf("file_init\n");
@@ -158,6 +157,12 @@ static void file_init(struct wmWindowManager *UNUSED(wm), ScrArea *sa)
if (sfile->layout) sfile->layout->dirty = TRUE;
}
+static void file_exit(wmWindowManager *wm, ScrArea *sa)
+{
+ SpaceFile *sfile = (SpaceFile *)sa->spacedata.first;
+
+ ED_fileselect_exit(wm, sfile);
+}
static SpaceLink *file_duplicate(SpaceLink *sl)
{
@@ -187,6 +192,7 @@ static SpaceLink *file_duplicate(SpaceLink *sl)
static void file_refresh(const bContext *C, ScrArea *UNUSED(sa))
{
+ wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
FileSelectParams *params = ED_fileselect_get_params(sfile);
@@ -202,7 +208,7 @@ static void file_refresh(const bContext *C, ScrArea *UNUSED(sa))
filelist_setfilter_types(sfile->files, params->filter_glob);
if (filelist_empty(sfile->files)) {
- thumbnails_stop(sfile->files, C);
+ thumbnails_stop(wm, sfile->files);
filelist_readdir(sfile->files);
if (params->sort != FILE_SORT_NONE) {
filelist_sort(sfile->files, params->sort);
@@ -214,7 +220,7 @@ static void file_refresh(const bContext *C, ScrArea *UNUSED(sa))
}
else {
if (params->sort != FILE_SORT_NONE) {
- thumbnails_stop(sfile->files, C);
+ thumbnails_stop(wm, sfile->files);
filelist_sort(sfile->files, params->sort);
if (params->display == FILE_IMGDISPLAY) {
thumbnails_start(sfile->files, C);
@@ -222,14 +228,14 @@ static void file_refresh(const bContext *C, ScrArea *UNUSED(sa))
}
else {
if (params->display == FILE_IMGDISPLAY) {
- if (!thumbnails_running(sfile->files, C)) {
+ if (!thumbnails_running(wm, sfile->files)) {
thumbnails_start(sfile->files, C);
}
}
else {
/* stop any running thumbnail jobs if we're not
* displaying them - speedup for NFS */
- thumbnails_stop(sfile->files, C);
+ thumbnails_stop(wm, sfile->files);
}
filelist_filter(sfile->files);
}
@@ -577,6 +583,7 @@ void ED_spacetype_file(void)
st->new = file_new;
st->free = file_free;
st->init = file_init;
+ st->exit = file_exit;
st->duplicate = file_duplicate;
st->refresh = file_refresh;
st->listener = file_listener;
@@ -629,7 +636,7 @@ void ED_spacetype_file(void)
void ED_file_init(void)
{
- char *cfgdir = BLI_get_folder(BLENDER_USER_CONFIG, NULL);
+ const char * const cfgdir = BLI_get_folder(BLENDER_USER_CONFIG, NULL);
fsmenu_read_system(fsmenu_get(), TRUE);
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index b92430ce0e9..a51fef6c692 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -609,7 +609,7 @@ static int graphkeys_click_insert_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int graphkeys_click_insert_invoke(bContext *C, wmOperator *op, wmEvent *evt)
+static int graphkeys_click_insert_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
bAnimContext ac;
ARegion *ar;
@@ -625,8 +625,8 @@ static int graphkeys_click_insert_invoke(bContext *C, wmOperator *op, wmEvent *e
ar = ac.ar;
v2d = &ar->v2d;
- mval[0] = (evt->x - ar->winrct.xmin);
- mval[1] = (evt->y - ar->winrct.ymin);
+ mval[0] = (event->x - ar->winrct.xmin);
+ mval[1] = (event->y - ar->winrct.ymin);
UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
@@ -835,7 +835,7 @@ static int graphkeys_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-static int graphkeys_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int graphkeys_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
graphkeys_duplicate_exec(C, op);
@@ -1190,7 +1190,7 @@ static int graphkeys_sound_bake_exec(bContext *UNUSED(C), wmOperator *op)
#endif //WITH_AUDASPACE
-static int graphkeys_sound_bake_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int graphkeys_sound_bake_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
bAnimContext ac;
@@ -2132,7 +2132,7 @@ void GRAPH_OT_smooth(wmOperatorType *ot)
/* ******************** Add F-Modifier Operator *********************** */
/* present a special customised popup menu for this, with some filtering */
-static int graph_fmodifier_add_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int graph_fmodifier_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
wmOperatorType *ot = WM_operatortype_find("GRAPH_OT_fmodifier_add", 1);
uiPopupMenu *pup;
@@ -2196,8 +2196,9 @@ static int graph_fmodifier_add_exec(bContext *C, wmOperator *op)
/* add F-Modifier of specified type to active F-Curve, and make it the active one */
fcm = add_fmodifier(&fcu->modifiers, type);
- if (fcm)
+ if (fcm) {
set_active_fmodifier(&fcu->modifiers, fcm);
+ }
else {
BKE_report(op->reports, RPT_ERROR, "Modifier could not be added (see console for details)");
break;
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index 54b417e740a..acb9e42d91b 100644
--- a/source/blender/editors/space_graph/graph_ops.c
+++ b/source/blender/editors/space_graph/graph_ops.c
@@ -109,7 +109,7 @@ static int graphview_cursor_exec(bContext *C, wmOperator *op)
/* ... */
/* set the operator properties from the initial event */
-static void graphview_cursor_setprops(bContext *C, wmOperator *op, wmEvent *event)
+static void graphview_cursor_setprops(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
float viewx, viewy;
@@ -128,7 +128,7 @@ static void graphview_cursor_setprops(bContext *C, wmOperator *op, wmEvent *even
}
/* Modal Operator init */
-static int graphview_cursor_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int graphview_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
/* Change to frame that mouse is over before adding modal handler,
* as user could click on a single frame (jump to frame) as well as
@@ -145,7 +145,7 @@ static int graphview_cursor_invoke(bContext *C, wmOperator *op, wmEvent *event)
}
/* Modal event handling of cursor changing */
-static int graphview_cursor_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int graphview_cursor_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
/* execute the events */
switch (event->type) {
diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c
index 978b3224850..cbec3072c44 100644
--- a/source/blender/editors/space_graph/graph_select.c
+++ b/source/blender/editors/space_graph/graph_select.c
@@ -815,7 +815,7 @@ static int graphkeys_select_leftright_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int graphkeys_select_leftright_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int graphkeys_select_leftright_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
bAnimContext ac;
short leftright = RNA_enum_get(op->ptr, "mode");
@@ -1297,7 +1297,7 @@ static void graphkeys_mselect_column(bAnimContext *ac, const int mval[2], short
/* ------------------- */
/* handle clicking */
-static int graphkeys_clickselect_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int graphkeys_clickselect_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
bAnimContext ac;
short selectmode;
@@ -1342,10 +1342,13 @@ void GRAPH_OT_clickselect(wmOperatorType *ot)
ot->idname = "GRAPH_OT_clickselect";
ot->description = "Select keyframes by clicking on them";
- /* api callbacks */
+ /* callbacks */
ot->invoke = graphkeys_clickselect_invoke;
ot->poll = graphop_visible_keyframes_poll;
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
/* properties */
prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); // SHIFTKEY
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
diff --git a/source/blender/editors/space_image/SConscript b/source/blender/editors/space_image/SConscript
index 6e7c5982d6e..68f747270a3 100644
--- a/source/blender/editors/space_image/SConscript
+++ b/source/blender/editors/space_image/SConscript
@@ -44,7 +44,7 @@ if env['WITH_BF_OPENJPEG']:
if env['WITH_BF_TIFF']:
defs.append('WITH_TIFF')
if env['WITH_BF_CINEON']:
- defs.append('WITH_CINEON')
+ defs.append('WITH_CINEON')
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
incs += ' ' + env['BF_PTHREADS_INC']
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index 6237958e723..70001b59528 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -73,51 +73,55 @@
/* proto */
-static void image_info(Scene *scene, ImageUser *iuser, Image *ima, ImBuf *ibuf, char *str)
+static void image_info(Scene *scene, ImageUser *iuser, Image *ima, ImBuf *ibuf, char *str, size_t len)
{
- int ofs = 0;
+ size_t ofs = 0;
str[0] = 0;
-
- if (ima == NULL) return;
+ if (ima == NULL)
+ return;
if (ibuf == NULL) {
- ofs += sprintf(str, IFACE_("Can't Load Image"));
+ ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Can't Load Image"), len - ofs);
}
else {
if (ima->source == IMA_SRC_MOVIE) {
- ofs += sprintf(str, IFACE_("Movie"));
+ ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Movie"), len - ofs);
if (ima->anim)
- ofs += sprintf(str + ofs, IFACE_(" %d frs"), IMB_anim_get_duration(ima->anim, IMB_TC_RECORD_RUN));
+ ofs += BLI_snprintf(str + ofs, len - ofs, IFACE_(" %d frs"),
+ IMB_anim_get_duration(ima->anim, IMB_TC_RECORD_RUN));
+ }
+ else {
+ ofs += BLI_strncpy_rlen(str, IFACE_("Image"), len - ofs);
}
- else
- ofs += sprintf(str, IFACE_("Image"));
- ofs += sprintf(str + ofs, IFACE_(": size %d x %d,"), ibuf->x, ibuf->y);
+ ofs += BLI_snprintf(str + ofs, len - ofs, IFACE_(": size %d x %d,"), ibuf->x, ibuf->y);
if (ibuf->rect_float) {
if (ibuf->channels != 4) {
- ofs += sprintf(str + ofs, IFACE_("%d float channel(s)"), ibuf->channels);
+ ofs += BLI_snprintf(str + ofs, len - ofs, IFACE_("%d float channel(s)"), ibuf->channels);
}
else if (ibuf->planes == R_IMF_PLANES_RGBA)
- ofs += sprintf(str + ofs, IFACE_(" RGBA float"));
+ ofs += BLI_strncpy_rlen(str + ofs, IFACE_(" RGBA float"), len - ofs);
else
- ofs += sprintf(str + ofs, IFACE_(" RGB float"));
+ ofs += BLI_strncpy_rlen(str + ofs, IFACE_(" RGB float"), len - ofs);
}
else {
if (ibuf->planes == R_IMF_PLANES_RGBA)
- ofs += sprintf(str + ofs, IFACE_(" RGBA byte"));
+ ofs += BLI_strncpy_rlen(str + ofs, IFACE_(" RGBA byte"), len - ofs);
else
- ofs += sprintf(str + ofs, IFACE_(" RGB byte"));
+ ofs += BLI_strncpy_rlen(str + ofs, IFACE_(" RGB byte"), len - ofs);
}
if (ibuf->zbuf || ibuf->zbuf_float)
- ofs += sprintf(str + ofs, IFACE_(" + Z"));
+ ofs += BLI_strncpy_rlen(str + ofs, IFACE_(" + Z"), len - ofs);
if (ima->source == IMA_SRC_SEQUENCE) {
- char *file = BLI_last_slash(ibuf->name);
- if (file == NULL) file = ibuf->name;
- else file++;
- ofs += sprintf(str + ofs, ", %s", file);
+ const char *file = BLI_last_slash(ibuf->name);
+ if (file == NULL)
+ file = ibuf->name;
+ else
+ file++;
+ ofs += BLI_snprintf(str + ofs, len - ofs, ", %s", file);
}
}
@@ -125,10 +129,8 @@ static void image_info(Scene *scene, ImageUser *iuser, Image *ima, ImBuf *ibuf,
if (ima->source == IMA_SRC_SEQUENCE) {
/* don't use iuser->framenr directly because it may not be updated if auto-refresh is off */
const int framenr = BKE_image_user_frame_get(iuser, CFRA, 0, NULL);
- ofs += sprintf(str + ofs, IFACE_(", Frame: %d"), framenr);
+ ofs += BLI_snprintf(str + ofs, len - ofs, IFACE_(", Frame: %d"), framenr);
}
-
- (void)ofs;
}
/* gets active viewer user */
@@ -539,16 +541,17 @@ static void rna_update_cb(bContext *C, void *arg_cb, void *UNUSED(arg))
void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, PointerRNA *userptr, int compact)
{
+#define MAX_INFO_LEN 128
+
PropertyRNA *prop;
PointerRNA imaptr;
RNAUpdateCb *cb;
Image *ima;
ImageUser *iuser;
- ImBuf *ibuf;
Scene *scene = CTX_data_scene(C);
uiLayout *row, *split, *col;
uiBlock *block;
- char str[128];
+ char str[MAX_INFO_LEN];
void *lock;
@@ -591,8 +594,8 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
uiBlockSetNFunc(block, rna_update_cb, MEM_dupallocN(cb), NULL);
if (ima->source == IMA_SRC_VIEWER) {
- ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
- image_info(scene, iuser, ima, ibuf, str);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
+ image_info(scene, iuser, ima, ibuf, str, MAX_INFO_LEN);
BKE_image_release_ibuf(ima, ibuf, lock);
uiItemL(layout, ima->id.name + 2, ICON_NONE);
@@ -661,8 +664,8 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
}
else if (ima->source != IMA_SRC_GENERATED) {
if (compact == 0) {
- ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
- image_info(scene, iuser, ima, ibuf, str);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
+ image_info(scene, iuser, ima, ibuf, str, MAX_INFO_LEN);
BKE_image_release_ibuf(ima, ibuf, lock);
uiItemL(layout, str, ICON_NONE);
}
@@ -750,6 +753,8 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
}
MEM_freeN(cb);
+
+#undef MAX_INFO_LEN
}
void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, int color_management)
diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c
index cae71885b87..e69ce56c9d9 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -491,6 +491,8 @@ static void draw_image_buffer(const bContext *C, SpaceImage *sima, ARegion *ar,
/* set zoom */
glPixelZoom(zoomx, zoomy);
+ glaDefine2DArea(&ar->winrct);
+
/* find window pixel coordinates of origin */
UI_view2d_to_region_no_clip(&ar->v2d, fx, fy, &x, &y);
@@ -523,11 +525,7 @@ static void draw_image_buffer(const bContext *C, SpaceImage *sima, ARegion *ar,
display_buffer = IMB_display_buffer_acquire_ctx(C, ibuf, &cache_handle);
if (display_buffer)
- glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, display_buffer);
-#if 0
- else
- glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_FLOAT, ibuf->rect_float);
-#endif
+ glaDrawPixelsAuto(x, y, ibuf->x, ibuf->y, GL_UNSIGNED_BYTE, GL_NEAREST, display_buffer);
IMB_display_buffer_release(cache_handle);
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index b913b3528ac..54230d35312 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -162,7 +162,7 @@ static int space_image_file_exists_poll(bContext *C)
if (BLI_exists(name) == FALSE) {
CTX_wm_operator_poll_msg_set(C, "image file not found");
}
- else if (BLI_file_is_writable(name) == FALSE) {
+ else if (!BLI_file_is_writable(name)) {
CTX_wm_operator_poll_msg_set(C, "image path can't be written to");
}
else {
@@ -238,7 +238,7 @@ typedef struct ViewPanData {
int event_type;
} ViewPanData;
-static void image_view_pan_init(bContext *C, wmOperator *op, wmEvent *event)
+static void image_view_pan_init(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceImage *sima = CTX_wm_space_image(C);
ViewPanData *vpd;
@@ -293,7 +293,7 @@ static int image_view_pan_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int image_view_pan_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int image_view_pan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (event->type == MOUSEPAN) {
SpaceImage *sima = CTX_wm_space_image(C);
@@ -312,7 +312,7 @@ static int image_view_pan_invoke(bContext *C, wmOperator *op, wmEvent *event)
}
}
-static int image_view_pan_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int image_view_pan_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceImage *sima = CTX_wm_space_image(C);
ViewPanData *vpd = op->customdata;
@@ -383,7 +383,7 @@ typedef struct ViewZoomData {
ARegion *ar;
} ViewZoomData;
-static void image_view_zoom_init(bContext *C, wmOperator *op, wmEvent *event)
+static void image_view_zoom_init(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceImage *sima = CTX_wm_space_image(C);
ARegion *ar = CTX_wm_region(C);
@@ -455,7 +455,7 @@ enum {
VIEW_CONFIRM
};
-static int image_view_zoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int image_view_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (event->type == MOUSEZOOM || event->type == MOUSEPAN) {
SpaceImage *sima = CTX_wm_space_image(C);
@@ -525,7 +525,7 @@ static void image_zoom_apply(ViewZoomData *vpd, wmOperator *op, const int x, con
ED_region_tag_redraw(vpd->ar);
}
-static int image_view_zoom_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int image_view_zoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewZoomData *vpd = op->customdata;
short event_code = VIEW_PASS;
@@ -589,7 +589,7 @@ void IMAGE_OT_view_zoom(wmOperatorType *ot)
* that explains the negative signs in the code below
*/
-static int image_view_ndof_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
+static int image_view_ndof_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
if (event->type != NDOF_MOTION)
return OPERATOR_CANCELLED;
@@ -773,7 +773,7 @@ static int image_view_zoom_in_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int image_view_zoom_in_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int image_view_zoom_in_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
float location[2];
@@ -815,7 +815,7 @@ static int image_view_zoom_out_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int image_view_zoom_out_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int image_view_zoom_out_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
float location[2];
@@ -978,7 +978,7 @@ static int image_open_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int image_open_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int image_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
SpaceImage *sima = CTX_wm_space_image(C); /* XXX other space types can call */
char *path = U.textudir;
@@ -1128,7 +1128,7 @@ static int image_replace_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int image_replace_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int image_replace_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
SpaceImage *sima = CTX_wm_space_image(C);
@@ -1442,7 +1442,7 @@ static int image_save_as_check(bContext *UNUSED(C), wmOperator *op)
return WM_operator_filesel_ensure_ext_imtype(op, imf);
}
-static int image_save_as_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int image_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = ED_space_image(sima);
@@ -1603,7 +1603,7 @@ static int image_save_sequence_exec(bContext *C, wmOperator *op)
SpaceImage *sima = CTX_wm_space_image(C);
ImBuf *ibuf;
int tot = 0;
- char di[FILE_MAX], fi[FILE_MAX];
+ char di[FILE_MAX];
if (sima->image == NULL)
return OPERATOR_CANCELLED;
@@ -1632,10 +1632,8 @@ static int image_save_sequence_exec(bContext *C, wmOperator *op)
for (ibuf = sima->image->ibufs.first; ibuf; ibuf = ibuf->next)
if (ibuf->userflags & IB_BITMAPDIRTY)
break;
-
- BLI_strncpy(di, ibuf->name, FILE_MAX);
- BLI_splitdirstring(di, fi);
-
+
+ BLI_split_dir_part(ibuf->name, di, sizeof(di));
BKE_reportf(op->reports, RPT_INFO, "%d image(s) will be saved in %s", tot, di);
for (ibuf = sima->image->ibufs.first; ibuf; ibuf = ibuf->next) {
@@ -1775,7 +1773,7 @@ static int image_new_exec(bContext *C, wmOperator *op)
/* XXX, Ton is not a fan of OK buttons but using this function to avoid undo/redo bug while in mesh-editmode, - campbell */
/* XXX Note: the WM_operator_props_dialog_popup() doesn't work for uiIDContextProperty(), image is not being that way */
-static int image_new_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int image_new_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
return WM_operator_props_dialog_popup(C, op, 15 * UI_UNIT_X, 5 * UI_UNIT_Y);
@@ -1945,7 +1943,7 @@ static int image_pack_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int image_pack_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int image_pack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Image *ima = CTX_data_edit_image(C);
ImBuf *ibuf;
@@ -2029,7 +2027,7 @@ static int image_unpack_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int image_unpack_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int image_unpack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Image *ima = CTX_data_edit_image(C);
@@ -2145,7 +2143,7 @@ int ED_space_image_color_sample(SpaceImage *sima, ARegion *ar, int mval[2], floa
return ret;
}
-static void image_sample_apply(bContext *C, wmOperator *op, wmEvent *event)
+static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceImage *sima = CTX_wm_space_image(C);
ARegion *ar = CTX_wm_region(C);
@@ -2271,7 +2269,7 @@ static void image_sample_exit(bContext *C, wmOperator *op)
MEM_freeN(info);
}
-static int image_sample_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int image_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceImage *sima = CTX_wm_space_image(C);
ARegion *ar = CTX_wm_region(C);
@@ -2292,7 +2290,7 @@ static int image_sample_invoke(bContext *C, wmOperator *op, wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
-static int image_sample_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int image_sample_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
switch (event->type) {
case LEFTMOUSE:
@@ -2378,7 +2376,7 @@ static int image_sample_line_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int image_sample_line_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int image_sample_line_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceImage *sima = CTX_wm_space_image(C);
@@ -2533,7 +2531,7 @@ static int image_record_composite_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int image_record_composite_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int image_record_composite_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
RecordCompositeData *rcd;
@@ -2550,7 +2548,7 @@ static int image_record_composite_invoke(bContext *C, wmOperator *op, wmEvent *U
return OPERATOR_RUNNING_MODAL;
}
-static int image_record_composite_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int image_record_composite_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
RecordCompositeData *rcd = op->customdata;
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index d82a46e9578..761becdbf8e 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -337,7 +337,7 @@ static void image_keymap(struct wmKeyConfig *keyconf)
}
/* dropboxes */
-static int image_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event))
+static int image_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
{
if (drag->type == WM_DRAG_PATH)
if (ELEM3(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_BLANK)) /* rule might not work? */
diff --git a/source/blender/editors/space_info/info_ops.c b/source/blender/editors/space_info/info_ops.c
index 04f6a5152e6..c68473820e3 100644
--- a/source/blender/editors/space_info/info_ops.c
+++ b/source/blender/editors/space_info/info_ops.c
@@ -104,7 +104,7 @@ static int unpack_libraries_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int unpack_libraries_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int unpack_libraries_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
return WM_operator_confirm_message(C, op, "Unpack Blender Libraries - creates directories, all new paths should work");
}
@@ -137,7 +137,7 @@ static int pack_all_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int pack_all_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int pack_all_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Main *bmain = CTX_data_main(C);
Image *ima;
@@ -203,7 +203,7 @@ static int unpack_all_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int unpack_all_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int unpack_all_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Main *bmain = CTX_data_main(C);
uiPopupMenu *pup;
@@ -288,7 +288,7 @@ static int unpack_item_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int unpack_item_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int unpack_item_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
uiPopupMenu *pup;
uiLayout *layout;
@@ -429,7 +429,7 @@ static int find_missing_files_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int find_missing_files_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int find_missing_files_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
/* XXX file open button text "Find Missing Files" */
WM_event_add_fileselect(C, op);
@@ -469,7 +469,7 @@ void FILE_OT_find_missing_files(wmOperatorType *ot)
#define ERROR_TIMEOUT 10.0f
#define ERROR_COLOR_TIMEOUT 6.0f
#define COLLAPSE_TIMEOUT 0.25f
-static int update_reports_display_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
+static int update_reports_display_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
wmWindowManager *wm = CTX_wm_manager(C);
ReportList *reports = CTX_wm_reports(C);
diff --git a/source/blender/editors/space_info/info_report.c b/source/blender/editors/space_info/info_report.c
index 3050563e538..b096b8f3e2b 100644
--- a/source/blender/editors/space_info/info_report.c
+++ b/source/blender/editors/space_info/info_report.c
@@ -127,7 +127,7 @@ static int select_report_pick_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int select_report_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int select_report_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceInfo *sinfo = CTX_wm_space_info(C);
ARegion *ar = CTX_wm_region(C);
diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c
index 976769752f9..b2e9427c799 100644
--- a/source/blender/editors/space_info/info_stats.c
+++ b/source/blender/editors/space_info/info_stats.c
@@ -38,8 +38,9 @@
#include "DNA_meta_types.h"
#include "DNA_scene_types.h"
-#include "BLI_utildefines.h"
#include "BLI_math.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
#include "BLF_translation.h"
@@ -58,6 +59,7 @@
#include "ED_armature.h"
#include "ED_mesh.h"
+#define MAX_INFO_LEN 512
typedef struct SceneStats {
int totvert, totvertsel;
@@ -68,7 +70,7 @@ typedef struct SceneStats {
int totlamp, totlampsel;
int tottri, totmesh;
- char infostr[512];
+ char infostr[MAX_INFO_LEN];
} SceneStats;
static void stats_object(Object *ob, int sel, int totob, SceneStats *stats)
@@ -357,60 +359,70 @@ static void stats_update(Scene *scene)
static void stats_string(Scene *scene)
{
+#define MAX_INFO_MEM_LEN 64
SceneStats *stats = scene->stats;
Object *ob = (scene->basact) ? scene->basact->object : NULL;
uintptr_t mem_in_use, mmap_in_use;
- char memstr[64];
+ char memstr[MAX_INFO_MEM_LEN];
char *s;
+ size_t ofs = 0;
mem_in_use = MEM_get_memory_in_use();
mmap_in_use = MEM_get_mapped_memory_in_use();
/* get memory statistics */
- s = memstr + sprintf(memstr, IFACE_(" | Mem:%.2fM"), (double)((mem_in_use - mmap_in_use) >> 10) / 1024.0);
+ s = memstr;
+ ofs += BLI_snprintf(s + ofs, MAX_INFO_MEM_LEN - ofs, IFACE_(" | Mem:%.2fM"),
+ (double)((mem_in_use - mmap_in_use) >> 10) / 1024.0);
if (mmap_in_use)
- sprintf(s, IFACE_(" (%.2fM)"), (double)((mmap_in_use) >> 10) / 1024.0);
+ BLI_snprintf(s + ofs, MAX_INFO_MEM_LEN - ofs, IFACE_(" (%.2fM)"), (double)((mmap_in_use) >> 10) / 1024.0);
s = stats->infostr;
-
- s += sprintf(s, "%s | ", versionstr);
+ ofs = 0;
+
+ ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, "%s | ", versionstr);
if (scene->obedit) {
if (BKE_keyblock_from_object(scene->obedit))
- s += sprintf(s, IFACE_("(Key) "));
+ ofs += BLI_strncpy_rlen(s + ofs, IFACE_("(Key) "), MAX_INFO_LEN - ofs);
if (scene->obedit->type == OB_MESH) {
- s += sprintf(s, IFACE_("Verts:%d/%d | Edges:%d/%d | Faces:%d/%d | Tris:%d"),
- stats->totvertsel, stats->totvert, stats->totedgesel, stats->totedge, stats->totfacesel,
- stats->totface, stats->tottri);
+ ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs,
+ IFACE_("Verts:%d/%d | Edges:%d/%d | Faces:%d/%d | Tris:%d"),
+ stats->totvertsel, stats->totvert, stats->totedgesel, stats->totedge,
+ stats->totfacesel, stats->totface, stats->tottri);
}
else if (scene->obedit->type == OB_ARMATURE) {
- s += sprintf(s, IFACE_("Verts:%d/%d | Bones:%d/%d"), stats->totvertsel, stats->totvert, stats->totbonesel,
- stats->totbone);
+ ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%d/%d | Bones:%d/%d"), stats->totvertsel,
+ stats->totvert, stats->totbonesel, stats->totbone);
}
else {
- s += sprintf(s, IFACE_("Verts:%d/%d"), stats->totvertsel, stats->totvert);
+ ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%d/%d"), stats->totvertsel, stats->totvert);
}
- strcat(s, memstr);
+ ofs += BLI_strncpy_rlen(s + ofs, memstr, MAX_INFO_LEN - ofs);
}
else if (ob && (ob->mode & OB_MODE_POSE)) {
- s += sprintf(s, IFACE_("Bones:%d/%d %s"),
- stats->totbonesel, stats->totbone, memstr);
+ ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Bones:%d/%d %s"),
+ stats->totbonesel, stats->totbone, memstr);
}
else if (stats_is_object_dynamic_topology_sculpt(ob)) {
- s += sprintf(s, IFACE_("Verts:%d | Tris:%d"), stats->totvert, stats->tottri);
+ ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%d | Tris:%d"), stats->totvert, stats->tottri);
}
else {
- s += sprintf(s, IFACE_("Verts:%d | Faces:%d | Tris:%d | Objects:%d/%d | Lamps:%d/%d%s"),
- stats->totvert, stats->totface, stats->tottri, stats->totobjsel, stats->totobj, stats->totlampsel,
- stats->totlamp, memstr);
+ ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs,
+ IFACE_("Verts:%d | Faces:%d | Tris:%d | Objects:%d/%d | Lamps:%d/%d%s"), stats->totvert,
+ stats->totface, stats->tottri, stats->totobjsel, stats->totobj, stats->totlampsel,
+ stats->totlamp, memstr);
}
if (ob)
- sprintf(s, " | %s", ob->id.name + 2);
+ BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, " | %s", ob->id.name + 2);
+#undef MAX_INFO_MEM_LEN
}
+#undef MAX_INFO_LEN
+
void ED_info_stats_clear(Scene *scene)
{
if (scene->stats) {
diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c
index 66f4904c340..e53cbdd04af 100644
--- a/source/blender/editors/space_info/textview.c
+++ b/source/blender/editors/space_info/textview.c
@@ -31,14 +31,19 @@
#include <limits.h>
#include <assert.h>
+#include "MEM_guardedalloc.h"
+
#include "BLF_api.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLI_string_utf8.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "BKE_text.h"
+
#include "ED_datafiles.h"
#include "textview.h"
@@ -68,12 +73,12 @@ BLI_INLINE void console_step_sel(ConsoleDrawContext *cdc, const int step)
cdc->sel[1] += step;
}
-static void console_draw_sel(const int sel[2], const int xy[2], const int str_len_draw, int cwidth, int lheight,
- const unsigned char bg_sel[4])
+static void console_draw_sel(const char *str, const int sel[2], const int xy[2], const int str_len_draw,
+ int cwidth, int lheight, const unsigned char bg_sel[4])
{
if (sel[0] <= str_len_draw && sel[1] >= 0) {
- const int sta = max_ii(sel[0], 0);
- const int end = min_ii(sel[1], str_len_draw);
+ const int sta = txt_utf8_offset_to_column(str, max_ii(sel[0], 0));
+ const int end = txt_utf8_offset_to_column(str, min_ii(sel[1], str_len_draw));
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -85,38 +90,72 @@ static void console_draw_sel(const int sel[2], const int xy[2], const int str_le
}
}
+/* warning: allocated memory for 'offsets' must be freed by caller */
+static int console_wrap_offsets(const char *str, int len, int width, int *lines, int **offsets)
+{
+ int i, end; /* column */
+ int j; /* mem */
+
+ *lines = 1;
+
+ *offsets = MEM_callocN(sizeof(**offsets) * (len * BLI_UTF8_WIDTH_MAX / MAX2(1, width - (BLI_UTF8_WIDTH_MAX - 1)) + 1),
+ "console_wrap_offsets");
+ (*offsets)[0] = 0;
+
+ for (i = 0, end = width, j = 0; j < len && str[j]; j += BLI_str_utf8_size_safe(str + j)) {
+ int columns = BLI_str_utf8_char_width_safe(str + j);
+
+ if (i + columns > end) {
+ (*offsets)[*lines] = j;
+ (*lines)++;
+
+ end = i + width;
+ }
+ i += columns;
+ }
+ return j; /* return actual length */
+}
+
/* return 0 if the last line is off the screen
* should be able to use this for any string type */
-static int console_draw_string(ConsoleDrawContext *cdc, const char *str, const int str_len,
+static int console_draw_string(ConsoleDrawContext *cdc, const char *str, int str_len,
const unsigned char fg[3], const unsigned char bg[3], const unsigned char bg_sel[4])
{
int rct_ofs = cdc->lheight / 4;
- int tot_lines = (str_len / cdc->console_width) + 1; /* total number of lines for wrapping */
- int y_next = (str_len > cdc->console_width) ? cdc->xy[1] + cdc->lheight * tot_lines : cdc->xy[1] + cdc->lheight;
+ int tot_lines; /* total number of lines for wrapping */
+ int *offsets; /* offsets of line beginnings for wrapping */
+ int y_next;
const int mono = blf_mono_font;
+ str_len = console_wrap_offsets(str, str_len, cdc->console_width, &tot_lines, &offsets);
+ y_next = cdc->xy[1] + cdc->lheight * tot_lines;
+
/* just advance the height */
if (cdc->draw == 0) {
- if (cdc->pos_pick && (cdc->mval[1] != INT_MAX)) {
- if (cdc->xy[1] <= cdc->mval[1]) {
- if ((y_next >= cdc->mval[1])) {
- int ofs = (int)floor(((float)cdc->mval[0] / (float)cdc->cwidth));
-
- /* wrap */
- if (str_len > cdc->console_width)
- ofs += cdc->console_width * ((int)((((float)(y_next - cdc->mval[1]) /
- (float)(y_next - cdc->xy[1])) * tot_lines)));
-
- CLAMP(ofs, 0, str_len);
- *cdc->pos_pick += str_len - ofs;
+ if (cdc->pos_pick && cdc->mval[1] != INT_MAX && cdc->xy[1] <= cdc->mval[1]) {
+ if (y_next >= cdc->mval[1]) {
+ int ofs = 0;
+
+ /* wrap */
+ if (tot_lines > 1) {
+ int iofs = (int)((float)(y_next - cdc->mval[1]) / cdc->lheight);
+ ofs += offsets[MIN2(iofs, tot_lines - 1)];
}
- else
- *cdc->pos_pick += str_len + 1;
+
+ /* last part */
+ ofs += txt_utf8_column_to_offset(str + ofs,
+ (int)floor((float)cdc->mval[0] / cdc->cwidth));
+
+ CLAMP(ofs, 0, str_len);
+ *cdc->pos_pick += str_len - ofs;
}
+ else
+ *cdc->pos_pick += str_len + 1;
}
cdc->xy[1] = y_next;
+ MEM_freeN(offsets);
return 1;
}
else if (y_next - cdc->lheight < cdc->ymin) {
@@ -128,12 +167,15 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, const i
console_step_sel(cdc, -(str_len + 1));
}
+ MEM_freeN(offsets);
return 1;
}
if (tot_lines > 1) { /* wrap? */
- const int initial_offset = ((tot_lines - 1) * cdc->console_width);
- const char *line_stride = str + initial_offset; /* advance to the last line and draw it first */
+ const int initial_offset = offsets[tot_lines - 1];
+ size_t len = str_len - initial_offset;
+ const char *s = str + initial_offset;
+ int i;
int sel_orig[2];
copy_v2_v2_int(sel_orig, cdc->sel);
@@ -151,36 +193,38 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, const i
/* last part needs no clipping */
BLF_position(mono, cdc->xy[0], cdc->xy[1], 0);
- BLF_draw(mono, line_stride, str_len - initial_offset);
+ BLF_draw_mono(mono, s, len, cdc->cwidth);
if (cdc->sel[0] != cdc->sel[1]) {
console_step_sel(cdc, -initial_offset);
// glColor4ub(255, 0, 0, 96); // debug
- console_draw_sel(cdc->sel, cdc->xy, str_len % cdc->console_width, cdc->cwidth, cdc->lheight, bg_sel);
- console_step_sel(cdc, cdc->console_width);
+ console_draw_sel(s, cdc->sel, cdc->xy, len, cdc->cwidth, cdc->lheight, bg_sel);
glColor3ubv(fg);
}
cdc->xy[1] += cdc->lheight;
- line_stride -= cdc->console_width;
-
- for (; line_stride >= str; line_stride -= cdc->console_width) {
+ for (i = tot_lines - 1; i > 0; i--) {
+ len = offsets[i] - offsets[i - 1];
+ s = str + offsets[i - 1];
+
BLF_position(mono, cdc->xy[0], cdc->xy[1], 0);
- BLF_draw(mono, line_stride, cdc->console_width);
+ BLF_draw_mono(mono, s, len, cdc->cwidth);
if (cdc->sel[0] != cdc->sel[1]) {
+ console_step_sel(cdc, len);
// glColor4ub(0, 255, 0, 96); // debug
- console_draw_sel(cdc->sel, cdc->xy, cdc->console_width, cdc->cwidth, cdc->lheight, bg_sel);
- console_step_sel(cdc, cdc->console_width);
+ console_draw_sel(s, cdc->sel, cdc->xy, len, cdc->cwidth, cdc->lheight, bg_sel);
glColor3ubv(fg);
}
cdc->xy[1] += cdc->lheight;
/* check if were out of view bounds */
- if (cdc->xy[1] > cdc->ymax)
+ if (cdc->xy[1] > cdc->ymax) {
+ MEM_freeN(offsets);
return 0;
+ }
}
copy_v2_v2_int(cdc->sel, sel_orig);
@@ -196,7 +240,7 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, const i
glColor3ubv(fg);
BLF_position(mono, cdc->xy[0], cdc->xy[1], 0);
- BLF_draw(mono, str, str_len);
+ BLF_draw_mono(mono, str, str_len, cdc->cwidth);
if (cdc->sel[0] != cdc->sel[1]) {
int isel[2];
@@ -205,16 +249,19 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, const i
isel[1] = str_len - cdc->sel[0];
// glColor4ub(255, 255, 0, 96); // debug
- console_draw_sel(isel, cdc->xy, str_len, cdc->cwidth, cdc->lheight, bg_sel);
+ console_draw_sel(str, isel, cdc->xy, str_len, cdc->cwidth, cdc->lheight, bg_sel);
console_step_sel(cdc, -(str_len + 1));
}
cdc->xy[1] += cdc->lheight;
- if (cdc->xy[1] > cdc->ymax)
+ if (cdc->xy[1] > cdc->ymax) {
+ MEM_freeN(offsets);
return 0;
+ }
}
+ MEM_freeN(offsets);
return 1;
}
diff --git a/source/blender/editors/space_logic/logic_ops.c b/source/blender/editors/space_logic/logic_ops.c
index 2313885dbaf..5f2ecbf1b2b 100644
--- a/source/blender/editors/space_logic/logic_ops.c
+++ b/source/blender/editors/space_logic/logic_ops.c
@@ -122,7 +122,7 @@ static Object *edit_object_property_get(bContext *C, wmOperator *op)
/* if ob_name is valid try to find the object with this name
* otherwise gets the active object */
- if (BLI_strnlen(ob_name, MAX_NAME) > 0)
+ if (*ob_name)
ob = BLI_findstring(&(CTX_data_main(C)->object), ob_name, offsetof(ID, name) + 2);
else
ob = ED_object_active_context(C);
@@ -250,7 +250,7 @@ static int sensor_remove_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int sensor_remove_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int sensor_remove_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (edit_sensor_invoke_properties(C, op))
return sensor_remove_exec(C, op);
@@ -295,12 +295,13 @@ static int sensor_add_exec(bContext *C, wmOperator *op)
prop = RNA_struct_find_property(&sens_ptr, "type");
RNA_string_get(op->ptr, "name", name);
- if (BLI_strnlen(name, MAX_NAME) < 1) {
+ if (*name) {
+ BLI_strncpy(sens->name, name, sizeof(sens->name));
+ }
+ else {
RNA_property_enum_name(C, &sens_ptr, prop, RNA_property_enum_get(&sens_ptr, prop), &sens_name);
BLI_strncpy(sens->name, sens_name, sizeof(sens->name));
}
- else
- BLI_strncpy(sens->name, name, sizeof(sens->name));
make_unique_prop_names(C, sens->name);
ob->scaflag |= OB_SHOWSENS;
@@ -355,7 +356,7 @@ static int controller_remove_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int controller_remove_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int controller_remove_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (edit_controller_invoke_properties(C, op))
return controller_remove_exec(C, op);
@@ -401,12 +402,13 @@ static int controller_add_exec(bContext *C, wmOperator *op)
prop = RNA_struct_find_property(&cont_ptr, "type");
RNA_string_get(op->ptr, "name", name);
- if (BLI_strnlen(name, MAX_NAME) < 1) {
+ if (*name) {
+ BLI_strncpy(cont->name, name, sizeof(cont->name));
+ }
+ else {
RNA_property_enum_name(C, &cont_ptr, prop, RNA_property_enum_get(&cont_ptr, prop), &cont_name);
BLI_strncpy(cont->name, cont_name, sizeof(cont->name));
}
- else
- BLI_strncpy(cont->name, name, sizeof(cont->name));
make_unique_prop_names(C, cont->name);
/* set the controller state mask from the current object state.
@@ -473,7 +475,7 @@ static int actuator_remove_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int actuator_remove_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int actuator_remove_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (edit_actuator_invoke_properties(C, op))
return actuator_remove_exec(C, op);
@@ -518,12 +520,13 @@ static int actuator_add_exec(bContext *C, wmOperator *op)
prop = RNA_struct_find_property(&act_ptr, "type");
RNA_string_get(op->ptr, "name", name);
- if (BLI_strnlen(name, MAX_NAME) < 1) {
+ if (*name) {
+ BLI_strncpy(act->name, name, sizeof(act->name));
+ }
+ else {
RNA_property_enum_name(C, &act_ptr, prop, RNA_property_enum_get(&act_ptr, prop), &act_name);
BLI_strncpy(act->name, act_name, sizeof(act->name));
}
- else
- BLI_strncpy(act->name, name, sizeof(act->name));
make_unique_prop_names(C, act->name);
ob->scaflag |= OB_SHOWACT;
@@ -583,7 +586,7 @@ static int sensor_move_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int sensor_move_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int sensor_move_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (edit_sensor_invoke_properties(C, op)) {
return sensor_move_exec(C, op);
@@ -628,7 +631,7 @@ static int controller_move_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int controller_move_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int controller_move_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (edit_controller_invoke_properties(C, op)) {
return controller_move_exec(C, op);
@@ -673,7 +676,7 @@ static int actuator_move_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int actuator_move_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int actuator_move_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (edit_actuator_invoke_properties(C, op)) {
return actuator_move_exec(C, op);
@@ -711,7 +714,7 @@ static int texface_convert_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-static int texface_convert_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int texface_convert_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
return texface_convert_exec(C, op);
}
diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c
index 31c773e613e..b2cae8e5496 100644
--- a/source/blender/editors/space_nla/nla_buttons.c
+++ b/source/blender/editors/space_nla/nla_buttons.c
@@ -131,7 +131,6 @@ static int nla_panel_context(const bContext *C, PointerRNA *adt_ptr, PointerRNA
case ANIMTYPE_SCENE: /* Top-Level Widgets doubling up as datablocks */
case ANIMTYPE_OBJECT:
- case ANIMTYPE_FILLACTD: /* Action Expander */
case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
case ANIMTYPE_DSLAM:
case ANIMTYPE_DSCAM:
@@ -142,22 +141,34 @@ static int nla_panel_context(const bContext *C, PointerRNA *adt_ptr, PointerRNA
case ANIMTYPE_DSPART:
case ANIMTYPE_DSMBALL:
case ANIMTYPE_DSARM:
+ case ANIMTYPE_DSMESH:
+ case ANIMTYPE_DSTEX:
+ case ANIMTYPE_DSLAT:
#ifdef WITH_FREESTYLE
case ANIMTYPE_DSLINESTYLE:
#endif
case ANIMTYPE_DSSPK:
{
/* for these channels, we only do AnimData */
- if (ale->id && ale->adt) {
- if (adt_ptr) {
- /* AnimData pointer */
- RNA_pointer_create(ale->id, &RNA_AnimData, ale->adt, adt_ptr);
-
- /* set found status to -1, since setting to 1 would break the loop
- * and potentially skip an active NLA-Track in some cases...
- */
- found = -1;
+ if (ale->adt && adt_ptr) {
+ ID *id;
+
+ if ((ale->data == NULL) || (ale->type == ANIMTYPE_OBJECT)) {
+ /* ale->data is not an ID block! */
+ id = ale->id;
}
+ else {
+ /* ale->data is always the proper ID block we need, but ale->id may not be (i.e. for textures) */
+ id = (ID *)ale->data;
+ }
+
+ /* AnimData pointer */
+ RNA_pointer_create(id, &RNA_AnimData, ale->adt, adt_ptr);
+
+ /* set found status to -1, since setting to 1 would break the loop
+ * and potentially skip an active NLA-Track in some cases...
+ */
+ found = -1;
}
}
break;
@@ -250,6 +261,28 @@ static void nla_panel_animdata(const bContext *C, Panel *pa)
block = uiLayoutGetBlock(layout);
uiBlockSetHandleFunc(block, do_nla_region_buttons, NULL);
+ /* AnimData Source Properties ----------------------------------- */
+
+ /* icon + id-block name of block where AnimData came from to prevent
+ * accidentally changing the properties of the wrong action
+ */
+ if (adt_ptr.id.data) {
+ ID *id = adt_ptr.id.data;
+ PointerRNA id_ptr;
+
+ RNA_id_pointer_create(id, &id_ptr);
+
+ /* ID-block name > AnimData */
+ row = uiLayoutRow(layout, TRUE);
+ uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_LEFT);
+
+ uiItemL(row, id->name + 2, RNA_struct_ui_icon(id_ptr.type)); /* id-block (src) */
+ uiItemL(row, "", VICO_SMALL_TRI_RIGHT_VEC); /* expander */
+ uiItemL(row, IFACE_("Animation Data"), ICON_ANIM_DATA); /* animdata */
+
+ uiItemS(layout);
+ }
+
/* Active Action Properties ------------------------------------- */
/* action */
row = uiLayoutRow(layout, TRUE);
diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c
index 97581cefc2b..6d091e3c7c4 100644
--- a/source/blender/editors/space_nla/nla_channels.c
+++ b/source/blender/editors/space_nla/nla_channels.c
@@ -48,6 +48,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_screen.h"
+#include "BKE_report.h"
#include "ED_anim_api.h"
#include "ED_keyframes_edit.h"
@@ -140,7 +141,7 @@ static int mouse_nla_channels(bAnimContext *ac, float x, int channel_index, shor
}
else {
Base *b;
-
+
/* deselect all */
/* TODO: should this deselect all other types of channels too? */
for (b = sce->base.first; b; b = b->next) {
@@ -268,6 +269,7 @@ static int mouse_nla_channels(bAnimContext *ac, float x, int channel_index, shor
{
AnimData *adt = BKE_animdata_from_id(ale->id);
+ /* button area... */
if (x >= (v2d->cur.xmax - NLACHANNEL_BUTTON_WIDTH)) {
if (nlaedit_is_tweakmode_on(ac) == 0) {
/* 'push-down' action - only usable when not in TweakMode */
@@ -283,6 +285,30 @@ static int mouse_nla_channels(bAnimContext *ac, float x, int channel_index, shor
/* changes to NLA-Action occurred */
notifierFlags |= ND_NLA_ACTCHANGE;
}
+ /* OR rest of name... */
+ else {
+ /* NOTE: rest of NLA-Action name doubles for operating on the AnimData block
+ * - this is useful when there's no clear divider, and makes more sense in
+ * the case of users trying to use this to change actions
+ */
+
+ /* select/deselect */
+ if (selectmode == SELECT_INVERT) {
+ /* inverse selection status of this AnimData block only */
+ adt->flag ^= ADT_UI_SELECTED;
+ }
+ else {
+ /* select AnimData block by itself */
+ ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+ adt->flag |= ADT_UI_SELECTED;
+ }
+
+ /* set active? */
+ if (adt->flag & ADT_UI_SELECTED)
+ adt->flag |= ADT_UI_ACTIVE;
+
+ notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
+ }
}
break;
@@ -301,7 +327,7 @@ static int mouse_nla_channels(bAnimContext *ac, float x, int channel_index, shor
/* ------------------- */
/* handle clicking */
-static int nlachannels_mouseclick_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int nlachannels_mouseclick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
bAnimContext ac;
SpaceNla *snla;
@@ -358,7 +384,7 @@ void NLA_OT_channels_click(wmOperatorType *ot)
ot->poll = ED_operator_nla_active;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO;
/* props */
prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); // SHIFTKEY
@@ -371,24 +397,18 @@ void NLA_OT_channels_click(wmOperatorType *ot)
/* ******************** Add Tracks Operator ***************************** */
/* Add NLA Tracks to the same AnimData block as a selected track, or above the selected tracks */
-static int nlaedit_add_tracks_exec(bContext *C, wmOperator *op)
+/* helper - add NLA Tracks alongside existing ones */
+static bool nlaedit_add_tracks_existing(bAnimContext *ac, bool above_sel)
{
- bAnimContext ac;
-
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter;
-
AnimData *lastAdt = NULL;
- short above_sel = RNA_boolean_get(op->ptr, "above_selected");
+ bool added = false;
- /* get editor data */
- if (ANIM_animdata_get_context(C, &ac) == 0)
- return OPERATOR_CANCELLED;
-
- /* get a list of the AnimData blocks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL);
- ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+ /* get a list of the (selected) NLA Tracks being shown in the NLA */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
+ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* add tracks... */
for (ale = anim_data.first; ale; ale = ale->next) {
@@ -402,11 +422,13 @@ static int nlaedit_add_tracks_exec(bContext *C, wmOperator *op)
if (above_sel) {
/* just add a new one above this one */
add_nlatrack(adt, nlt);
+ added = true;
}
else if ((lastAdt == NULL) || (adt != lastAdt)) {
/* add one track to the top of the owning AnimData's stack, then don't add anymore to this stack */
add_nlatrack(adt, NULL);
lastAdt = adt;
+ added = true;
}
}
}
@@ -414,17 +436,80 @@ static int nlaedit_add_tracks_exec(bContext *C, wmOperator *op)
/* free temp data */
BLI_freelistN(&anim_data);
- /* set notifier that things have changed */
- WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
+ return added;
+}
+
+/* helper - add NLA Tracks to empty (and selected) AnimData blocks */
+static bool nlaedit_add_tracks_empty(bAnimContext *ac)
+{
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+ bool added = false;
- /* done */
- return OPERATOR_FINISHED;
+ /* get a list of the selected AnimData blocks in the NLA */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
+ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+
+ /* check if selected AnimData blocks are empty, and add tracks if so... */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt = ale->adt;
+
+ /* sanity check */
+ BLI_assert(adt->flag & ADT_UI_SELECTED);
+
+ /* ensure it is empty */
+ if (adt->nla_tracks.first == NULL) {
+ /* add new track to this AnimData block then */
+ add_nlatrack(adt, NULL);
+ added = true;
+ }
+ }
+
+ /* cleanup */
+ BLI_freelistN(&anim_data);
+
+ return added;
+}
+
+/* ----- */
+
+static int nlaedit_add_tracks_exec(bContext *C, wmOperator *op)
+{
+ bAnimContext ac;
+ bool above_sel = RNA_boolean_get(op->ptr, "above_selected");
+ bool op_done = false;
+
+ /* get editor data */
+ if (ANIM_animdata_get_context(C, &ac) == 0)
+ return OPERATOR_CANCELLED;
+
+ /* perform adding in two passes - existing first so that we don't double up for empty */
+ op_done |= nlaedit_add_tracks_existing(&ac, above_sel);
+ op_done |= nlaedit_add_tracks_empty(&ac);
+
+ /* done? */
+ if (op_done) {
+ /* set notifier that things have changed */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
+
+ /* done */
+ return OPERATOR_FINISHED;
+ }
+ else {
+ /* failed to add any tracks */
+ BKE_report(op->reports, RPT_WARNING,
+ "Select an existing NLA Track or an empty action line first");
+
+ /* not done */
+ return OPERATOR_CANCELLED;
+ }
}
void NLA_OT_tracks_add(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Add Track(s)";
+ ot->name = "Add Tracks";
ot->idname = "NLA_OT_tracks_add";
ot->description = "Add NLA-Tracks above/after the selected tracks";
@@ -485,11 +570,11 @@ static int nlaedit_delete_tracks_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-void NLA_OT_delete_tracks(wmOperatorType *ot)
+void NLA_OT_tracks_delete(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Delete Tracks";
- ot->idname = "NLA_OT_delete_tracks";
+ ot->idname = "NLA_OT_tracks_delete";
ot->description = "Delete selected NLA-Tracks and the strips they contain";
/* api callbacks */
@@ -501,3 +586,59 @@ void NLA_OT_delete_tracks(wmOperatorType *ot)
}
/* *********************************************** */
+/* AnimData Related Operators */
+
+/* ******************** Include Objects Operator ***************************** */
+/* Include selected objects in NLA Editor, by giving them AnimData blocks
+ * NOTE: This doesn't help for non-object AnimData, where we do not have any effective
+ * selection mechanism in place. Unfortunately, this means that non-object AnimData
+ * once again becomes a second-class citizen here. However, at least for the most
+ * common use case, we now have a nice shortcut again.
+ */
+
+static int nlaedit_objects_add_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bAnimContext ac;
+ SpaceNla *snla;
+
+ /* get editor data */
+ if (ANIM_animdata_get_context(C, &ac) == 0)
+ return OPERATOR_CANCELLED;
+
+ /* ensure that filters are set so that the effect will be immediately visible */
+ snla = (SpaceNla *)ac.sl;
+ if (snla && snla->ads) {
+ snla->ads->filterflag &= ~ADS_FILTER_NLA_NOACT;
+ }
+
+ /* operate on selected objects... */
+ CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
+ {
+ /* ensure that object has AnimData... that's all */
+ BKE_id_add_animdata(&ob->id);
+ }
+ CTX_DATA_END;
+
+ /* set notifier that things have changed */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
+
+ /* done */
+ return OPERATOR_FINISHED;
+}
+
+void NLA_OT_selected_objects_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Include Selected Objects";
+ ot->idname = "NLA_OT_selected_objects_add";
+ ot->description = "Make selected objects appear in NLA Editor by adding Animation Data";
+
+ /* api callbacks */
+ ot->exec = nlaedit_objects_add_exec;
+ ot->poll = nlaop_poll_tweakmode_off;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* *********************************************** */
diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c
index acfb4a51b14..56f2ec9ebe1 100644
--- a/source/blender/editors/space_nla/nla_draw.c
+++ b/source/blender/editors/space_nla/nla_draw.c
@@ -695,11 +695,8 @@ static void draw_nla_channel_list_gl(bAnimContext *ac, ListBase *anim_data, View
special = ICON_ACTION;
- if (act)
- BLI_snprintf(name, sizeof(name), "%s", act->id.name + 2);
- else
- BLI_strncpy(name, "<No Action>", sizeof(name));
-
+ BLI_strncpy(name, act ? act->id.name + 2 : "<No Action>", sizeof(name));
+
/* draw manually still */
do_draw = TRUE;
}
@@ -759,7 +756,6 @@ static void draw_nla_channel_list_gl(bAnimContext *ac, ListBase *anim_data, View
glEnable(GL_BLEND);
/* draw backing strip behind channel name */
- // FIXME: hardcoded colors!!!
if (group == 5) {
float color[4];
diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c
index 484eb47fa8e..17d403789cf 100644
--- a/source/blender/editors/space_nla/nla_edit.c
+++ b/source/blender/editors/space_nla/nla_edit.c
@@ -200,7 +200,7 @@ static int nlaedit_disable_tweakmode_exec(bContext *C, wmOperator *op)
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt = ale->data;
- /* try entering tweakmode if valid */
+ /* to be sure, just exit tweakmode... */
BKE_nla_tweakmode_exit(adt);
}
@@ -891,7 +891,7 @@ static int nlaedit_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
}
-static int nlaedit_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int nlaedit_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
nlaedit_duplicate_exec(C, op);
@@ -1627,7 +1627,7 @@ void NLA_OT_action_sync_length(wmOperatorType *ot)
/* api callbacks */
ot->exec = nlaedit_sync_actlen_exec;
- ot->poll = ED_operator_nla_active; // XXX: is this satisfactory... probably requires a check for active strip...
+ ot->poll = nlaop_poll_tweakmode_off;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1801,7 +1801,7 @@ void NLA_OT_clear_scale(wmOperatorType *ot)
/* defines for snap keyframes tool */
static EnumPropertyItem prop_nlaedit_snap_types[] = {
- {NLAEDIT_SNAP_CFRA, "CFRA", 0, "Current frame", ""},
+ {NLAEDIT_SNAP_CFRA, "CFRA", 0, "Current Frame", ""},
{NLAEDIT_SNAP_NEAREST_FRAME, "NEAREST_FRAME", 0, "Nearest Frame", ""}, // XXX as single entry?
{NLAEDIT_SNAP_NEAREST_SECOND, "NEAREST_SECOND", 0, "Nearest Second", ""}, // XXX as single entry?
{NLAEDIT_SNAP_NEAREST_MARKER, "NEAREST_MARKER", 0, "Nearest Marker", ""},
@@ -1947,7 +1947,7 @@ void NLA_OT_snap(wmOperatorType *ot)
/* ******************** Add F-Modifier Operator *********************** */
/* present a special customised popup menu for this, with some filtering */
-static int nla_fmodifier_add_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
+static int nla_fmodifier_add_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
{
uiPopupMenu *pup;
uiLayout *layout;
@@ -2021,8 +2021,9 @@ static int nla_fmodifier_add_exec(bContext *C, wmOperator *op)
/* add F-Modifier of specified type to selected, and make it the active one */
fcm = add_fmodifier(&strip->modifiers, type);
- if (fcm)
+ if (fcm) {
set_active_fmodifier(&strip->modifiers, fcm);
+ }
else {
BKE_reportf(op->reports, RPT_ERROR,
"Modifier could not be added to (%s : %s) (see console for details)",
@@ -2101,8 +2102,10 @@ static int nla_fmodifier_copy_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_ERROR, "No F-Modifiers available to be copied");
return OPERATOR_CANCELLED;
}
- else
+ else {
+ /* no updates needed - copy is non-destructive operation */
return OPERATOR_FINISHED;
+ }
}
void NLA_OT_fmodifier_copy(wmOperatorType *ot)
@@ -2156,8 +2159,6 @@ static int nla_fmodifier_paste_exec(bContext *C, wmOperator *op)
/* successful or not? */
if (ok) {
- /* set notifier that things have changed */
- /* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_nla/nla_intern.h b/source/blender/editors/space_nla/nla_intern.h
index 398d2d5f1f4..450b85738ad 100644
--- a/source/blender/editors/space_nla/nla_intern.h
+++ b/source/blender/editors/space_nla/nla_intern.h
@@ -125,7 +125,9 @@ void NLA_OT_fmodifier_paste(wmOperatorType *ot);
void NLA_OT_channels_click(wmOperatorType *ot);
void NLA_OT_tracks_add(wmOperatorType *ot);
-void NLA_OT_delete_tracks(wmOperatorType *ot);
+void NLA_OT_tracks_delete(wmOperatorType *ot);
+
+void NLA_OT_selected_objects_add(wmOperatorType *ot);
/* **************************************** */
/* nla_ops.c */
diff --git a/source/blender/editors/space_nla/nla_ops.c b/source/blender/editors/space_nla/nla_ops.c
index 54ade829c0d..fb0f11ffd87 100644
--- a/source/blender/editors/space_nla/nla_ops.c
+++ b/source/blender/editors/space_nla/nla_ops.c
@@ -120,7 +120,9 @@ void nla_operatortypes(void)
WM_operatortype_append(NLA_OT_channels_click);
WM_operatortype_append(NLA_OT_tracks_add);
- WM_operatortype_append(NLA_OT_delete_tracks);
+ WM_operatortype_append(NLA_OT_tracks_delete);
+
+ WM_operatortype_append(NLA_OT_selected_objects_add);
/* select */
WM_operatortype_append(NLA_OT_click_select);
@@ -188,8 +190,8 @@ static void nla_keymap_channels(wmKeyMap *keymap)
RNA_boolean_set(kmi->ptr, "above_selected", TRUE);
/* delete tracks */
- WM_keymap_add_item(keymap, "NLA_OT_delete_tracks", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "NLA_OT_delete_tracks", DELKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "NLA_OT_tracks_delete", XKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "NLA_OT_tracks_delete", DELKEY, KM_PRESS, 0, 0);
}
static void nla_keymap_main(wmKeyConfig *keyconf, wmKeyMap *keymap)
diff --git a/source/blender/editors/space_nla/nla_select.c b/source/blender/editors/space_nla/nla_select.c
index 97553b7aa56..3e414233add 100644
--- a/source/blender/editors/space_nla/nla_select.c
+++ b/source/blender/editors/space_nla/nla_select.c
@@ -451,7 +451,7 @@ static int nlaedit_select_leftright_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int nlaedit_select_leftright_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int nlaedit_select_leftright_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
bAnimContext ac;
short leftright = RNA_enum_get(op->ptr, "mode");
@@ -613,7 +613,7 @@ static void mouse_nla_strips(bContext *C, bAnimContext *ac, const int mval[2], s
/* ------------------- */
/* handle clicking */
-static int nlaedit_clickselect_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int nlaedit_clickselect_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
bAnimContext ac;
/* Scene *scene; */ /* UNUSED */
@@ -660,7 +660,7 @@ void NLA_OT_click_select(wmOperatorType *ot)
ot->poll = ED_operator_nla_active;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO;
/* properties */
prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); // SHIFTKEY
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 8a2e03f2660..4a14d6ba6fd 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -687,14 +687,14 @@ static void draw_group_socket_name(SpaceNode *snode, bNode *gnode, bNodeSocket *
static void draw_group_socket(const bContext *C, SpaceNode *snode, bNodeTree *ntree, bNode *gnode,
bNodeSocket *sock, bNodeSocket *gsock, int index, int in_out)
{
- const float dpi_fac = 1.0f;
+ const float dpi_fac = UI_DPI_FAC;
bNodeTree *ngroup = (bNodeTree *)gnode->id;
bNodeSocketType *stype = ntreeGetSocketType(gsock ? gsock->type : sock->type);
uiBut *bt;
float offset;
int draw_value;
const float node_group_frame = NODE_GROUP_FRAME * dpi_fac;
- const float socket_size = NODE_SOCKSIZE * dpi_fac;
+ const float socket_size = NODE_SOCKSIZE;
const float arrowbutw = 0.8f * UI_UNIT_X;
const short co_text_w = 72 * dpi_fac;
const float co_margin = 6.0f * dpi_fac;
@@ -799,12 +799,12 @@ static void node_draw_group(const bContext *C, ARegion *ar, SpaceNode *snode, bN
uiLayout *layout;
PointerRNA ptr;
rctf rect = gnode->totr;
- const float dpi_fac = 1.0f;
+ const float dpi_fac = UI_DPI_FAC;
const float node_group_frame = NODE_GROUP_FRAME * dpi_fac;
const float group_header = 26 * dpi_fac;
int index;
-
+
/* backdrop header */
glEnable(GL_BLEND);
uiSetRoundBox(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT);
@@ -1296,11 +1296,11 @@ static void node_shader_buts_mapping(uiLayout *layout, bContext *UNUSED(C), Poin
uiItemR(row, ptr, "scale", 0, "", ICON_NONE);
row = uiLayoutRow(layout, TRUE);
- uiItemR(row, ptr, "use_min", 0, "Min", ICON_NONE);
+ uiItemR(row, ptr, "use_min", 0, IFACE_("Min"), ICON_NONE);
uiItemR(row, ptr, "min", 0, "", ICON_NONE);
row = uiLayoutRow(layout, TRUE);
- uiItemR(row, ptr, "use_max", 0, "Max", ICON_NONE);
+ uiItemR(row, ptr, "use_max", 0, IFACE_("Max"), ICON_NONE);
uiItemR(row, ptr, "max", 0, "", ICON_NONE);
}
@@ -3301,7 +3301,7 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glPixelZoom(snode->zoom, snode->zoom);
- glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, display_buffer);
+ glaDrawPixelsAuto(x, y, ibuf->x, ibuf->y, GL_UNSIGNED_BYTE, GL_LINEAR, display_buffer);
glPixelZoom(1.0f, 1.0f);
glDisable(GL_BLEND);
@@ -3309,7 +3309,7 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode)
else {
glPixelZoom(snode->zoom, snode->zoom);
- glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, display_buffer);
+ glaDrawPixelsAuto(x, y, ibuf->x, ibuf->y, GL_UNSIGNED_BYTE, GL_LINEAR, display_buffer);
glPixelZoom(1.0f, 1.0f);
}
@@ -3320,6 +3320,7 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode)
/** @note draw selected info on backdrop */
if (snode->edittree) {
bNode *node = snode->edittree->nodes.first;
+ rctf *viewer_border = &snode->edittree->viewer_border;
while (node) {
if (node->flag & NODE_SELECT) {
if (node->typeinfo->uibackdropfunc) {
@@ -3328,6 +3329,23 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode)
}
node = node->next;
}
+
+ if ((snode->edittree->flag & NTREE_VIEWER_BORDER) &&
+ viewer_border->xmin < viewer_border->xmax &&
+ viewer_border->ymin < viewer_border->ymax)
+ {
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ setlinestyle(3);
+ cpack(0x4040FF);
+
+ glRectf(x + snode->zoom * viewer_border->xmin * ibuf->x,
+ y + snode->zoom * viewer_border->ymin * ibuf->y,
+ x + snode->zoom * viewer_border->xmax * ibuf->x,
+ y + snode->zoom * viewer_border->ymax * ibuf->y);
+
+ setlinestyle(0);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ }
}
glMatrixMode(GL_PROJECTION);
@@ -3340,57 +3358,6 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode)
}
}
-#if 0
-/* note: needs to be userpref or opengl profile option */
-static void draw_nodespace_back_tex(ScrArea *sa, SpaceNode *snode)
-{
-
- draw_nodespace_grid(snode);
-
- if (snode->flag & SNODE_BACKDRAW) {
- Image *ima = BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
- if (ibuf) {
- int x, y;
- float zoom = 1.0;
-
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
-
- glaDefine2DArea(&sa->winrct);
-
- if (ibuf->x > sa->winx || ibuf->y > sa->winy) {
- float zoomx, zoomy;
- zoomx = (float)sa->winx / ibuf->x;
- zoomy = (float)sa->winy / ibuf->y;
- zoom = min_ff(zoomx, zoomy);
- }
-
- x = (sa->winx - zoom * ibuf->x) / 2 + snode->xof;
- y = (sa->winy - zoom * ibuf->y) / 2 + snode->yof;
-
- glPixelZoom(zoom, zoom);
-
- glColor4f(1.0, 1.0, 1.0, 1.0);
- if (ibuf->rect)
- glaDrawPixelsTex(x, y, ibuf->x, ibuf->y, GL_UNSIGNED_BYTE, ibuf->rect);
- else if (ibuf->channels == 4)
- glaDrawPixelsTex(x, y, ibuf->x, ibuf->y, GL_FLOAT, ibuf->rect_float);
-
- glPixelZoom(1.0, 1.0);
-
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
-
- BKE_image_release_ibuf(ima, ibuf, NULL);
- }
- }
-}
-#endif
/* if v2d not NULL, it clips and returns 0 if not visible */
int node_link_bezier_points(View2D *v2d, SpaceNode *snode, bNodeLink *link, float coord_array[][2], int resol)
diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c
index 4943bb45113..235d91ecd92 100644
--- a/source/blender/editors/space_node/node_add.c
+++ b/source/blender/editors/space_node/node_add.c
@@ -400,7 +400,7 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int node_add_file_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int node_add_file_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
SpaceNode *snode = CTX_wm_space_node(C);
diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c
index 34f7799d47c..d6a3a6a6a3f 100644
--- a/source/blender/editors/space_node/node_draw.c
+++ b/source/blender/editors/space_node/node_draw.c
@@ -629,7 +629,7 @@ static void node_draw_preview(bNodePreview *preview, rctf *prv)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); /* premul graphics */
glColor4f(1.0, 1.0, 1.0, 1.0);
- glaDrawPixelsTex(prv->xmin, prv->ymin, preview->xsize, preview->ysize, GL_UNSIGNED_BYTE, preview->rect);
+ glaDrawPixelsTex(prv->xmin, prv->ymin, preview->xsize, preview->ysize, GL_UNSIGNED_BYTE, GL_LINEAR, preview->rect);
glDisable(GL_BLEND);
glPixelZoom(1.0f, 1.0f);
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index fb4e4f62e52..941bd783c39 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -73,6 +73,8 @@
#include "GPU_material.h"
+#include "IMB_imbuf_types.h"
+
#include "node_intern.h" /* own include */
#define USE_ESC_COMPO
@@ -835,7 +837,7 @@ typedef struct NodeSizeWidget {
int directions;
} NodeSizeWidget;
-static void node_resize_init(bContext *C, wmOperator *op, wmEvent *UNUSED(event), bNode *node, int dir)
+static void node_resize_init(bContext *C, wmOperator *op, const wmEvent *UNUSED(event), bNode *node, int dir)
{
SpaceNode *snode = CTX_wm_space_node(C);
@@ -868,7 +870,7 @@ static void node_resize_exit(bContext *C, wmOperator *op, int UNUSED(cancel))
op->customdata = NULL;
}
-static int node_resize_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int node_resize_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceNode *snode = CTX_wm_space_node(C);
ARegion *ar = CTX_wm_region(C);
@@ -971,7 +973,7 @@ static int node_resize_modal(bContext *C, wmOperator *op, wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
-static int node_resize_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int node_resize_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceNode *snode = CTX_wm_space_node(C);
ARegion *ar = CTX_wm_region(C);
@@ -1055,7 +1057,7 @@ void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set)
}
/* return 0, nothing done */
-static int UNUSED_FUNCTION(node_mouse_groupheader) (SpaceNode * snode)
+static int UNUSED_FUNCTION(node_mouse_groupheader) (SpaceNode *snode)
{
bNode *gnode;
float mx = 0, my = 0;
@@ -2138,7 +2140,7 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int node_clipboard_paste_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int node_clipboard_paste_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
SpaceNode *snode = CTX_wm_space_node(C);
@@ -2281,3 +2283,105 @@ void NODE_OT_shader_script_update(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/* ********************** Viewer border ******************/
+
+static void viewer_border_corner_to_backdrop(SpaceNode *snode, ARegion *ar, int x, int y,
+ int backdrop_width, int backdrop_height,
+ float *fx, float *fy)
+{
+ float bufx, bufy;
+
+ bufx = backdrop_width * snode->zoom;
+ bufy = backdrop_height * snode->zoom;
+
+ *fx = (bufx > 0.0f ? ((float) x - 0.5f * ar->winx - snode->xof) / bufx + 0.5f : 0.0f);
+ *fy = (bufy > 0.0f ? ((float) y - 0.5f * ar->winy - snode->yof) / bufy + 0.5f : 0.0f);
+}
+
+static int viewer_border_exec(bContext *C, wmOperator *op)
+{
+ Image *ima;
+ void *lock;
+ ImBuf *ibuf;
+
+ ED_preview_kill_jobs(C);
+
+ ima = BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
+ ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
+
+ if (ibuf) {
+ ARegion *ar = CTX_wm_region(C);
+ SpaceNode *snode = CTX_wm_space_node(C);
+ bNodeTree *btree = snode->edittree;
+ rcti rect;
+ rctf rectf;
+
+ /* get border from operator */
+ WM_operator_properties_border_to_rcti(op, &rect);
+
+ /* convert border to unified space within backdrop image */
+ viewer_border_corner_to_backdrop(snode, ar, rect.xmin, rect.ymin, ibuf->x, ibuf->y,
+ &rectf.xmin, &rectf.ymin);
+
+ viewer_border_corner_to_backdrop(snode, ar, rect.xmax, rect.ymax, ibuf->x, ibuf->y,
+ &rectf.xmax, &rectf.ymax);
+
+ /* clamp coordinates */
+ rectf.xmin = max_ff(rectf.xmin, 0.0f);
+ rectf.ymin = max_ff(rectf.ymin, 0.0f);
+ rectf.xmax = min_ff(rectf.xmax, 1.0f);
+ rectf.ymax = min_ff(rectf.ymax, 1.0f);
+
+ if (rectf.xmin < rectf.xmax && rectf.ymin < rectf.ymax) {
+ btree->viewer_border = rectf;
+
+ if (rectf.xmin == 0.0f && rectf.ymin == 0.0f &&
+ rectf.xmax == 1.0f && rectf.ymax == 1.0f)
+ {
+ btree->flag &= ~NTREE_VIEWER_BORDER;
+ }
+ else {
+ if (ibuf->rect)
+ memset(ibuf->rect, 0, 4 * ibuf->x * ibuf->y);
+
+ if (ibuf->rect_float)
+ memset(ibuf->rect_float, 0, 4 * ibuf->x * ibuf->y * sizeof(float));
+
+ ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
+
+ btree->flag |= NTREE_VIEWER_BORDER;
+ }
+
+ snode_notify(C, snode);
+ WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL);
+ }
+ else {
+ btree->flag &= ~NTREE_VIEWER_BORDER;
+ }
+ }
+
+ BKE_image_release_ibuf(ima, ibuf, lock);
+
+ return OPERATOR_FINISHED;
+}
+
+void NODE_OT_viewer_border(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Viewer Border";
+ ot->description = "Set the boundaries for viewer operations";
+ ot->idname = "NODE_OT_viewer_border";
+
+ /* api callbacks */
+ ot->invoke = WM_border_select_invoke;
+ ot->exec = viewer_border_exec;
+ ot->modal = WM_border_select_modal;
+ ot->cancel = WM_border_select_cancel;
+ ot->poll = composite_node_active;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ WM_operator_properties_gesture_border(ot, TRUE);
+}
diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c
index 7b7b98f132c..6696284b169 100644
--- a/source/blender/editors/space_node/node_group.c
+++ b/source/blender/editors/space_node/node_group.c
@@ -133,7 +133,7 @@ static int node_group_edit_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-static int node_group_edit_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int node_group_edit_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
SpaceNode *snode = CTX_wm_space_node(C);
bNode *gnode;
@@ -789,7 +789,7 @@ static int node_group_separate_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int node_group_separate_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
+static int node_group_separate_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
{
uiPopupMenu *pup = uiPupMenuBegin(C, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Separate"), ICON_NONE);
uiLayout *layout = uiPupMenuLayout(pup);
@@ -1146,7 +1146,7 @@ static int node_group_make_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int node_group_make_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
+static int node_group_make_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
{
SpaceNode *snode = CTX_wm_space_node(C);
bNode *act = nodeGetActive(snode->edittree);
diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h
index e8dd1cf1528..cbf7101a101 100644
--- a/source/blender/editors/space_node/node_intern.h
+++ b/source/blender/editors/space_node/node_intern.h
@@ -217,6 +217,8 @@ void NODE_OT_clipboard_paste(struct wmOperatorType *ot);
void NODE_OT_shader_script_update(struct wmOperatorType *ot);
+void NODE_OT_viewer_border(struct wmOperatorType *ot);
+
extern const char *node_context_dir[];
// XXXXXX
diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c
index 8adccd9e6c4..d16c6627d3f 100644
--- a/source/blender/editors/space_node/node_ops.c
+++ b/source/blender/editors/space_node/node_ops.c
@@ -120,6 +120,8 @@ void node_operatortypes(void)
WM_operatortype_append(NODE_OT_clipboard_paste);
WM_operatortype_append(NODE_OT_shader_script_update);
+
+ WM_operatortype_append(NODE_OT_viewer_border);
}
void ED_operatormacros_node(void)
@@ -298,5 +300,7 @@ void node_keymap(struct wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "NODE_OT_clipboard_copy", CKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "NODE_OT_clipboard_paste", VKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "NODE_OT_viewer_border", BKEY, KM_PRESS, KM_CTRL, 0);
+
transform_keymap_for_space(keyconf, keymap, SPACE_NODE);
}
diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c
index 8d7eef22822..097e4f418e0 100644
--- a/source/blender/editors/space_node/node_relationships.c
+++ b/source/blender/editors/space_node/node_relationships.c
@@ -448,7 +448,7 @@ static int outside_group_rect(SpaceNode *snode)
/* loop that adds a nodelink, called by function below */
/* in_out = starting socket */
-static int node_link_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceNode *snode = CTX_wm_space_node(C);
ARegion *ar = CTX_wm_region(C);
@@ -702,7 +702,7 @@ static bNodeLinkDrag *node_link_init(SpaceNode *snode, int detach)
return nldrag;
}
-static int node_link_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceNode *snode = CTX_wm_space_node(C);
ARegion *ar = CTX_wm_region(C);
@@ -840,7 +840,9 @@ static int cut_links_exec(bContext *C, wmOperator *op)
if (i > 1) {
int found = FALSE;
bNodeLink *link, *next;
-
+
+ ED_preview_kill_jobs(C);
+
for (link = snode->edittree->links.first; link; link = next) {
next = link->next;
@@ -1181,7 +1183,7 @@ static int node_attach_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-static int node_attach_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int node_attach_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
SpaceNode *snode = CTX_wm_space_node(C);
diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c
index 7d2b80d50ba..c917b8ee756 100644
--- a/source/blender/editors/space_node/node_select.c
+++ b/source/blender/editors/space_node/node_select.c
@@ -429,7 +429,7 @@ static int node_select_exec(bContext *C, wmOperator *op)
}
}
-static int node_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int node_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
RNA_int_set(op->ptr, "mouse_x", event->mval[0]);
RNA_int_set(op->ptr, "mouse_y", event->mval[1]);
@@ -494,7 +494,7 @@ static int node_borderselect_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int node_border_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int node_border_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
int tweak = RNA_boolean_get(op->ptr, "tweak");
diff --git a/source/blender/editors/space_node/node_view.c b/source/blender/editors/space_node/node_view.c
index a69e73c1489..a8e84e0a0e5 100644
--- a/source/blender/editors/space_node/node_view.c
+++ b/source/blender/editors/space_node/node_view.c
@@ -196,7 +196,7 @@ typedef struct NodeViewMove {
int xmin, ymin, xmax, ymax;
} NodeViewMove;
-static int snode_bg_viewmove_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int snode_bg_viewmove_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceNode *snode = CTX_wm_space_node(C);
ARegion *ar = CTX_wm_region(C);
@@ -231,7 +231,7 @@ static int snode_bg_viewmove_modal(bContext *C, wmOperator *op, wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
-static int snode_bg_viewmove_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int snode_bg_viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceNode *snode = CTX_wm_space_node(C);
ARegion *ar = CTX_wm_region(C);
@@ -413,7 +413,7 @@ int ED_space_node_color_sample(SpaceNode *snode, ARegion *ar, int mval[2], float
return ret;
}
-static void sample_apply(bContext *C, wmOperator *op, wmEvent *event)
+static void sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceNode *snode = CTX_wm_space_node(C);
ARegion *ar = CTX_wm_region(C);
@@ -513,7 +513,7 @@ static void sample_exit(bContext *C, wmOperator *op)
MEM_freeN(info);
}
-static int sample_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceNode *snode = CTX_wm_space_node(C);
ARegion *ar = CTX_wm_region(C);
@@ -534,7 +534,7 @@ static int sample_invoke(bContext *C, wmOperator *op, wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
-static int sample_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int sample_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
switch (event->type) {
case LEFTMOUSE:
diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c
index 264bea5f871..75f28baf558 100644
--- a/source/blender/editors/space_node/space_node.c
+++ b/source/blender/editors/space_node/space_node.c
@@ -423,7 +423,7 @@ static void node_main_area_draw(const bContext *C, ARegion *ar)
/* ************* dropboxes ************* */
-static int node_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event))
+static int node_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
{
if (drag->type == WM_DRAG_ID) {
ID *id = (ID *)drag->poin;
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index cacbc6d6268..26a0d0a2fa8 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -41,6 +41,8 @@
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
+#include "BLF_translation.h"
+
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_depsgraph.h"
@@ -50,6 +52,7 @@
#include "BKE_modifier.h"
#include "BKE_report.h"
#include "BKE_scene.h"
+#include "BKE_object.h"
#include "ED_armature.h"
#include "ED_object.h"
@@ -129,11 +132,66 @@ static void outliner_rna_width(SpaceOops *soops, ListBase *lb, int *w, int start
/* ****************************************************** */
+static void restrictbutton_recursive_ebone(bContext *C, EditBone *ebone_parent, int flag, bool set_flag)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ bArmature *arm = obedit->data;
+ EditBone *ebone;
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (ED_armature_ebone_is_child_recursive(ebone_parent, ebone)) {
+ if (set_flag) {
+ ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ ebone->flag |= flag;
+ }
+ else {
+ ebone->flag &= ~flag;
+ }
+ }
+ }
+}
+
+static void restrictbutton_recursive_bone(bContext *C, bArmature *arm, Bone *bone_parent, int flag, bool set_flag)
+{
+ Bone *bone;
+ for (bone = bone_parent->childbase.first; bone; bone = bone->next) {
+ if (set_flag) {
+ bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ bone->flag |= flag;
+ }
+ else {
+ bone->flag &= ~flag;
+ }
+ restrictbutton_recursive_bone(C, arm, bone, flag, set_flag);
+ }
+
+}
+
+static void restrictbutton_recursive_child(bContext *C, Scene *scene, Object *ob_parent, char flag,
+ bool state, bool deselect)
+{
+ Main *bmain = CTX_data_main(C);
+ Object *ob;
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
+ if (BKE_object_is_child_recursive(ob_parent, ob)) {
+ if (state) {
+ ob->restrictflag |= flag;
+ if (deselect) {
+ ED_base_object_select(BKE_scene_base_find(scene, ob), BA_DESELECT);
+ }
+ }
+ else {
+ ob->restrictflag &= ~flag;
+ }
+ }
+ }
+}
+
static void restrictbutton_view_cb(bContext *C, void *poin, void *poin2)
{
Scene *scene = (Scene *)poin;
Object *ob = (Object *)poin2;
-
+
if (!common_restrict_check(C, ob)) return;
/* deselect objects that are invisible */
@@ -142,6 +200,12 @@ static void restrictbutton_view_cb(bContext *C, void *poin, void *poin2)
* so have to do loop to find it. */
ED_base_object_select(BKE_scene_base_find(scene, ob), BA_DESELECT);
}
+
+ if (CTX_wm_window(C)->eventstate->ctrl) {
+ restrictbutton_recursive_child(C, scene, ob, OB_RESTRICT_VIEW,
+ (ob->restrictflag & OB_RESTRICT_VIEW) != 0, true);
+ }
+
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
@@ -159,12 +223,25 @@ static void restrictbutton_sel_cb(bContext *C, void *poin, void *poin2)
* so have to do loop to find it. */
ED_base_object_select(BKE_scene_base_find(scene, ob), BA_DESELECT);
}
+
+ if (CTX_wm_window(C)->eventstate->ctrl) {
+ restrictbutton_recursive_child(C, scene, ob, OB_RESTRICT_SELECT,
+ (ob->restrictflag & OB_RESTRICT_SELECT) != 0, true);
+ }
+
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
-static void restrictbutton_rend_cb(bContext *C, void *poin, void *UNUSED(poin2))
+static void restrictbutton_rend_cb(bContext *C, void *poin, void *poin2)
{
+ Object *ob = (Object *)poin2;
+
+ if (CTX_wm_window(C)->eventstate->ctrl) {
+ restrictbutton_recursive_child(C, (Scene *)poin, ob, OB_RESTRICT_RENDER,
+ (ob->restrictflag & OB_RESTRICT_RENDER) != 0, false);
+ }
+
WM_event_add_notifier(C, NC_SCENE | ND_OB_RENDER, poin);
}
@@ -182,19 +259,59 @@ static void restrictbutton_modifier_cb(bContext *C, void *UNUSED(poin), void *po
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
}
-static void restrictbutton_bone_cb(bContext *C, void *UNUSED(poin), void *poin2)
+static void restrictbutton_bone_visibility_cb(bContext *C, void *poin, void *poin2)
{
+ bArmature *arm = (bArmature *)poin;
Bone *bone = (Bone *)poin2;
if (bone && (bone->flag & BONE_HIDDEN_P))
bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+
+ if (CTX_wm_window(C)->eventstate->ctrl) {
+ restrictbutton_recursive_bone(C, arm, bone, BONE_HIDDEN_P, (bone->flag & BONE_HIDDEN_P) != 0);
+ }
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+}
+
+static void restrictbutton_bone_select_cb(bContext *C, void *poin, void *poin2)
+{
+ bArmature *arm = (bArmature *)poin;
+ Bone *bone = (Bone *)poin2;
+ if (bone && (bone->flag & BONE_UNSELECTABLE))
+ bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+
+ if (CTX_wm_window(C)->eventstate->ctrl) {
+ restrictbutton_recursive_bone(C, arm, bone, BONE_UNSELECTABLE, (bone->flag & BONE_UNSELECTABLE) != 0);
+ }
+
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
}
-static void restrictbutton_ebone_cb(bContext *C, void *UNUSED(poin), void *poin2)
+static void restrictbutton_ebone_select_cb(bContext *C, void *UNUSED(poin), void *poin2)
{
EditBone *ebone = (EditBone *)poin2;
- if (ebone && (ebone->flag & BONE_HIDDEN_A))
+
+ if (ebone->flag & BONE_UNSELECTABLE) {
ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+
+ if (CTX_wm_window(C)->eventstate->ctrl) {
+ restrictbutton_recursive_ebone(C, ebone, BONE_UNSELECTABLE, (ebone->flag & BONE_UNSELECTABLE) != 0);
+ }
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+}
+
+static void restrictbutton_ebone_visibility_cb(bContext *C, void *UNUSED(poin), void *poin2)
+{
+ EditBone *ebone = (EditBone *)poin2;
+ if (ebone->flag & BONE_HIDDEN_A) {
+ ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+
+ if (CTX_wm_window(C)->eventstate->ctrl) {
+ restrictbutton_recursive_ebone(C, ebone, BONE_HIDDEN_A, (ebone->flag & BONE_HIDDEN_A) != 0);
+ }
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
}
@@ -238,7 +355,7 @@ static int group_select_flag(Group *gr)
}
void restrictbutton_gr_restrict_flag(void *poin, void *poin2, int flag)
-{
+{
Scene *scene = (Scene *)poin;
GroupObject *gob;
Group *gr = (Group *)poin2;
@@ -297,7 +414,7 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
TreeElement *te = outliner_find_tse(soops, tselem);
if (tselem->type == 0) {
- test_idbutton(tselem->id->name + 2); // library.c, unique name and alpha sort
+ test_idbutton(tselem->id->name); // library.c, unique name and alpha sort
switch (GS(tselem->id->name)) {
case ID_MA:
@@ -332,7 +449,7 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
defgroup_unique_name(te->directdata, (Object *)tselem->id); // id = object
break;
case TSE_NLA_ACTION:
- test_idbutton(tselem->id->name + 2);
+ test_idbutton(tselem->id->name);
break;
case TSE_EBONE:
{
@@ -389,7 +506,8 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
Object *ob = (Object *)tselem->id; // id = object
bActionGroup *grp = te->directdata;
- BLI_uniquename(&ob->pose->agroups, grp, "Group", '.', offsetof(bActionGroup, name), sizeof(grp->name));
+ BLI_uniquename(&ob->pose->agroups, grp, "Group", '.', offsetof(bActionGroup, name),
+ sizeof(grp->name));
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
}
break;
@@ -422,17 +540,20 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar
uiBlockSetEmboss(block, UI_EMBOSSN);
bt = uiDefIconButR(block, ICONTOG, 0, ICON_RESTRICT_VIEW_OFF,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
- &ptr, "hide", -1, 0, 0, -1, -1, NULL);
+ &ptr, "hide", -1, 0, 0, -1, -1,
+ TIP_("Restrict viewport visibility (Ctrl - Recursive)"));
uiButSetFunc(bt, restrictbutton_view_cb, scene, ob);
bt = uiDefIconButR(block, ICONTOG, 0, ICON_RESTRICT_SELECT_OFF,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
- &ptr, "hide_select", -1, 0, 0, -1, -1, NULL);
+ &ptr, "hide_select", -1, 0, 0, -1, -1,
+ TIP_("Restrict viewport selection (Ctrl - Recursive)"));
uiButSetFunc(bt, restrictbutton_sel_cb, scene, ob);
bt = uiDefIconButR(block, ICONTOG, 0, ICON_RESTRICT_RENDER_OFF,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
- &ptr, "hide_render", -1, 0, 0, -1, -1, NULL);
+ &ptr, "hide_render", -1, 0, 0, -1, -1,
+ TIP_("Restrict rendering (Ctrl - Recursive)"));
uiButSetFunc(bt, restrictbutton_rend_cb, scene, ob);
uiBlockSetEmboss(block, UI_EMBOSS);
@@ -447,19 +568,19 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar
restrict_bool = group_restrict_flag(gr, OB_RESTRICT_VIEW);
bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_VIEW_ON : ICON_RESTRICT_VIEW_OFF,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
- NULL, 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View");
+ NULL, 0, 0, 0, 0, TIP_("Restrict/Allow visibility in the 3D View"));
uiButSetFunc(bt, restrictbutton_gr_restrict_view, scene, gr);
restrict_bool = group_restrict_flag(gr, OB_RESTRICT_SELECT);
bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_SELECT_ON : ICON_RESTRICT_SELECT_OFF,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
- NULL, 0, 0, 0, 0, "Restrict/Allow selection in the 3D View");
+ NULL, 0, 0, 0, 0, TIP_("Restrict/Allow selection in the 3D View"));
uiButSetFunc(bt, restrictbutton_gr_restrict_select, scene, gr);
restrict_bool = group_restrict_flag(gr, OB_RESTRICT_RENDER);
bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_RENDER_ON : ICON_RESTRICT_RENDER_OFF,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
- NULL, 0, 0, 0, 0, "Restrict/Allow renderability");
+ NULL, 0, 0, 0, 0, TIP_("Restrict/Allow renderability"));
uiButSetFunc(bt, restrictbutton_gr_restrict_render, scene, gr);
uiBlockSetEmboss(block, UI_EMBOSS);
@@ -469,8 +590,8 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar
uiBlockSetEmboss(block, UI_EMBOSSN);
bt = uiDefIconButBitI(block, ICONTOGN, SCE_LAY_DISABLE, 0, ICON_CHECKBOX_HLT - 1,
- (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
- te->directdata, 0, 0, 0, 0, "Render this RenderLayer");
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X,
+ UI_UNIT_Y, te->directdata, 0, 0, 0, 0, TIP_("Render this RenderLayer"));
uiButSetFunc(bt, restrictbutton_r_lay_cb, tselem->id, NULL);
uiBlockSetEmboss(block, UI_EMBOSS);
@@ -483,8 +604,8 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar
bt = uiDefIconButBitI(block, ICONTOG, passflag, 0, ICON_CHECKBOX_HLT - 1,
- (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
- layflag, 0, 0, 0, 0, "Render this Pass");
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X,
+ UI_UNIT_Y, layflag, 0, 0, 0, 0, TIP_("Render this Pass"));
uiButSetFunc(bt, restrictbutton_r_lay_cb, tselem->id, NULL);
layflag++; /* is lay_xor */
@@ -492,8 +613,8 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar
SCE_PASS_INDIRECT, SCE_PASS_EMIT, SCE_PASS_ENVIRONMENT))
{
bt = uiDefIconButBitI(block, TOG, passflag, 0, (*layflag & passflag) ? ICON_DOT : ICON_BLANK1,
- (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
- layflag, 0, 0, 0, 0, "Exclude this Pass from Combined");
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X,
+ UI_UNIT_Y, layflag, 0, 0, 0, 0, TIP_("Exclude this Pass from Combined"));
}
uiButSetFunc(bt, restrictbutton_r_lay_cb, tselem->id, NULL);
@@ -505,43 +626,49 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar
uiBlockSetEmboss(block, UI_EMBOSSN);
bt = uiDefIconButBitI(block, ICONTOGN, eModifierMode_Realtime, 0, ICON_RESTRICT_VIEW_OFF,
- (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
- &(md->mode), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View");
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X,
+ UI_UNIT_Y, &(md->mode), 0, 0, 0, 0,
+ TIP_("Restrict/Allow visibility in the 3D View"));
uiButSetFunc(bt, restrictbutton_modifier_cb, scene, ob);
bt = uiDefIconButBitI(block, ICONTOGN, eModifierMode_Render, 0, ICON_RESTRICT_RENDER_OFF,
- (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
- &(md->mode), 0, 0, 0, 0, "Restrict/Allow renderability");
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)te->ys, UI_UNIT_X,
+ UI_UNIT_Y, &(md->mode), 0, 0, 0, 0, TIP_("Restrict/Allow renderability"));
uiButSetFunc(bt, restrictbutton_modifier_cb, scene, ob);
}
else if (tselem->type == TSE_POSE_CHANNEL) {
bPoseChannel *pchan = (bPoseChannel *)te->directdata;
Bone *bone = pchan->bone;
+ ob = (Object *)tselem->id;
uiBlockSetEmboss(block, UI_EMBOSSN);
bt = uiDefIconButBitI(block, ICONTOG, BONE_HIDDEN_P, 0, ICON_RESTRICT_VIEW_OFF,
- (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
- &(bone->flag), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View");
- uiButSetFunc(bt, restrictbutton_bone_cb, NULL, bone);
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X,
+ UI_UNIT_Y, &(bone->flag), 0, 0, 0, 0,
+ TIP_("Restrict/Allow visibility in the 3D View"));
+ uiButSetFunc(bt, restrictbutton_bone_visibility_cb, ob->data, bone);
bt = uiDefIconButBitI(block, ICONTOG, BONE_UNSELECTABLE, 0, ICON_RESTRICT_SELECT_OFF,
- (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
- &(bone->flag), 0, 0, 0, 0, "Restrict/Allow selection in the 3D View");
- uiButSetFunc(bt, restrictbutton_bone_cb, NULL, NULL);
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X,
+ UI_UNIT_Y, &(bone->flag), 0, 0, 0, 0,
+ TIP_("Restrict/Allow selection in the 3D View"));
+ uiButSetFunc(bt, restrictbutton_bone_select_cb, ob->data, bone);
}
else if (tselem->type == TSE_EBONE) {
EditBone *ebone = (EditBone *)te->directdata;
uiBlockSetEmboss(block, UI_EMBOSSN);
bt = uiDefIconButBitI(block, ICONTOG, BONE_HIDDEN_A, 0, ICON_RESTRICT_VIEW_OFF,
- (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
- &(ebone->flag), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View");
- uiButSetFunc(bt, restrictbutton_ebone_cb, NULL, ebone);
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X,
+ UI_UNIT_Y, &(ebone->flag), 0, 0, 0, 0,
+ TIP_("Restrict/Allow visibility in the 3D View"));
+ uiButSetFunc(bt, restrictbutton_ebone_visibility_cb, NULL, ebone);
bt = uiDefIconButBitI(block, ICONTOG, BONE_UNSELECTABLE, 0, ICON_RESTRICT_SELECT_OFF,
- (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
- &(ebone->flag), 0, 0, 0, 0, "Restrict/Allow selection in the 3D View");
- uiButSetFunc(bt, restrictbutton_ebone_cb, NULL, NULL);
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X,
+ UI_UNIT_Y, &(ebone->flag), 0, 0, 0, 0,
+ TIP_("Restrict/Allow selection in the 3D View"));
+ uiButSetFunc(bt, restrictbutton_ebone_select_cb, NULL, ebone);
}
}
@@ -571,7 +698,7 @@ static void outliner_draw_rnacols(ARegion *ar, int sizex)
}
static void outliner_draw_rnabuts(uiBlock *block, Scene *scene, ARegion *ar, SpaceOops *soops, int sizex, ListBase *lb)
-{
+{
TreeElement *te;
TreeStoreElem *tselem;
PointerRNA *ptr;
@@ -586,14 +713,17 @@ static void outliner_draw_rnabuts(uiBlock *block, Scene *scene, ARegion *ar, Spa
ptr = &te->rnaptr;
prop = te->directdata;
- if (!(RNA_property_type(prop) == PROP_POINTER && (TSELEM_OPEN(tselem, soops))) )
- uiDefAutoButR(block, ptr, prop, -1, "", ICON_NONE, sizex, (int)te->ys, OL_RNA_COL_SIZEX, UI_UNIT_Y - 1);
+ if (!(RNA_property_type(prop) == PROP_POINTER && (TSELEM_OPEN(tselem, soops)))) {
+ uiDefAutoButR(block, ptr, prop, -1, "", ICON_NONE, sizex, (int)te->ys, OL_RNA_COL_SIZEX,
+ UI_UNIT_Y - 1);
+ }
}
else if (tselem->type == TSE_RNA_ARRAY_ELEM) {
ptr = &te->rnaptr;
prop = te->directdata;
- uiDefAutoButR(block, ptr, prop, te->index, "", ICON_NONE, sizex, (int)te->ys, OL_RNA_COL_SIZEX, UI_UNIT_Y - 1);
+ uiDefAutoButR(block, ptr, prop, te->index, "", ICON_NONE, sizex, (int)te->ys, OL_RNA_COL_SIZEX,
+ UI_UNIT_Y - 1);
}
}
@@ -615,7 +745,7 @@ static void operator_search_cb(const struct bContext *UNUSED(C), void *UNUSED(ar
{
GHashIterator *iter = WM_operatortype_iter();
- for (; !BLI_ghashIterator_isDone(iter); BLI_ghashIterator_step(iter)) {
+ for (; BLI_ghashIterator_notDone(iter); BLI_ghashIterator_step(iter)) {
wmOperatorType *ot = BLI_ghashIterator_getValue(iter);
if (BLI_strcasestr(ot->idname, str)) {
@@ -806,7 +936,8 @@ static void outliner_draw_keymapbuts(uiBlock *block, ARegion *ar, SpaceOops *soo
/* pass */
}
else {
- uiDefBlockBut(block, operator_search_menu, kmi, "", xstart, (int)te->ys + 1, butw1, UI_UNIT_Y - 1, "Assign new Operator");
+ uiDefBlockBut(block, operator_search_menu, kmi, "", xstart, (int)te->ys + 1, butw1, UI_UNIT_Y - 1,
+ TIP_("Assign new Operator"));
}
xstart += butw1 + 10;
@@ -814,43 +945,58 @@ static void outliner_draw_keymapbuts(uiBlock *block, ARegion *ar, SpaceOops *soo
kmi->maptype = keymap_menu_type(kmi->type);
str = keymap_type_menu();
- but = uiDefButS(block, MENU, 0, str, xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, &kmi->maptype, 0, 0, 0, 0, "Event type");
+ but = uiDefButS(block, MENU, 0, str, xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, &kmi->maptype,
+ 0, 0, 0, 0, TIP_("Event type"));
uiButSetFunc(but, keymap_type_cb, kmi, NULL);
xstart += butw2 + 5;
/* edit actual event */
switch (kmi->maptype) {
case OL_KM_KEYBOARD:
- uiDefKeyevtButS(block, 0, "", xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, &kmi->type, "Key code");
+ uiDefKeyevtButS(block, 0, "", xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, &kmi->type,
+ TIP_("Key code"));
xstart += butw2 + 5;
break;
case OL_KM_MOUSE:
str = keymap_mouse_menu();
- uiDefButS(block, MENU, 0, str, xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, &kmi->type, 0, 0, 0, 0, "Mouse button");
+ uiDefButS(block, MENU, 0, str, xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, &kmi->type,
+ 0, 0, 0, 0, TIP_("Mouse button"));
xstart += butw2 + 5;
break;
case OL_KM_TWEAK:
str = keymap_tweak_menu();
- uiDefButS(block, MENU, 0, str, xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, &kmi->type, 0, 0, 0, 0, "Tweak gesture");
+ uiDefButS(block, MENU, 0, str, xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, &kmi->type,
+ 0, 0, 0, 0, TIP_("Tweak gesture"));
xstart += butw2 + 5;
str = keymap_tweak_dir_menu();
- uiDefButS(block, MENU, 0, str, xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, &kmi->val, 0, 0, 0, 0, "Tweak gesture direction");
+ uiDefButS(block, MENU, 0, str, xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, &kmi->val,
+ 0, 0, 0, 0, TIP_("Tweak gesture direction"));
xstart += butw2 + 5;
break;
}
/* modifiers */
- uiDefButS(block, OPTION, 0, "Shift", xstart, (int)te->ys + 1, butw3 + 5, UI_UNIT_Y - 1, &kmi->shift, 0, 0, 0, 0, "Modifier"); xstart += butw3 + 5;
- uiDefButS(block, OPTION, 0, "Ctrl", xstart, (int)te->ys + 1, butw3, UI_UNIT_Y - 1, &kmi->ctrl, 0, 0, 0, 0, "Modifier"); xstart += butw3;
- uiDefButS(block, OPTION, 0, "Alt", xstart, (int)te->ys + 1, butw3, UI_UNIT_Y - 1, &kmi->alt, 0, 0, 0, 0, "Modifier"); xstart += butw3;
- uiDefButS(block, OPTION, 0, "OS", xstart, (int)te->ys + 1, butw3, UI_UNIT_Y - 1, &kmi->oskey, 0, 0, 0, 0, "Modifier"); xstart += butw3;
- xstart += 5;
- uiDefKeyevtButS(block, 0, "", xstart, (int)te->ys + 1, butw3, UI_UNIT_Y - 1, &kmi->keymodifier, "Key Modifier code");
+ uiDefButS(block, OPTION, 0, IFACE_("Shift"), xstart, (int)te->ys + 1, butw3 + 5, UI_UNIT_Y - 1,
+ &kmi->shift, 0, 0, 0, 0, TIP_("Modifier"));
+ xstart += butw3 + 5;
+ uiDefButS(block, OPTION, 0, IFACE_("Ctrl"), xstart, (int)te->ys + 1, butw3, UI_UNIT_Y - 1, &kmi->ctrl,
+ 0, 0, 0, 0, TIP_("Modifier"));
+ xstart += butw3;
+ uiDefButS(block, OPTION, 0, IFACE_("Alt"), xstart, (int)te->ys + 1, butw3, UI_UNIT_Y - 1, &kmi->alt,
+ 0, 0, 0, 0, TIP_("Modifier"));
+ xstart += butw3;
+ uiDefButS(block, OPTION, 0, IFACE_("OS"), xstart, (int)te->ys + 1, butw3, UI_UNIT_Y - 1, &kmi->oskey,
+ 0, 0, 0, 0, TIP_("Modifier"));
+ xstart += butw3 + 5;
+ uiDefKeyevtButS(block, 0, "", xstart, (int)te->ys + 1, butw3, UI_UNIT_Y - 1, &kmi->keymodifier,
+ TIP_("Key Modifier code"));
xstart += butw3 + 5;
/* rna property */
if (kmi->ptr && kmi->ptr->data) {
- uiDefBut(block, LABEL, 0, "(RNA property)", xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, NULL, 0, 0, 0, 0, ""); xstart += butw2;
+ uiDefBut(block, LABEL, 0, IFACE_("(RNA property)"), xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1,
+ NULL, 0, 0, 0, 0, "");
+ xstart += butw2;
}
(void)xstart;
@@ -878,7 +1024,8 @@ static void outliner_buttons(const bContext *C, uiBlock *block, ARegion *ar, Spa
/* If we add support to rename Sequence.
* need change this.
*/
- if (tselem->type == TSE_POSE_BASE) continue; // prevent crash when trying to rename 'pose' entry of armature
+ // prevent crash when trying to rename 'pose' entry of armature
+ if (tselem->type == TSE_POSE_BASE) continue;
if (tselem->type == TSE_EBONE) len = sizeof(((EditBone *) 0)->name);
else if (tselem->type == TSE_MODIFIER) len = sizeof(((ModifierData *) 0)->name);
@@ -891,7 +1038,8 @@ static void outliner_buttons(const bContext *C, uiBlock *block, ARegion *ar, Spa
spx = te->xs + 2 * UI_UNIT_X - 4;
if (spx + dx + 10 > ar->v2d.cur.xmax) dx = ar->v2d.cur.xmax - spx - 10;
- bt = uiDefBut(block, TEX, OL_NAMEBUTTON, "", spx, (int)te->ys, dx + 10, UI_UNIT_Y - 1, (void *)te->name, 1.0, (float)len, 0, 0, "");
+ bt = uiDefBut(block, TEX, OL_NAMEBUTTON, "", spx, (int)te->ys, dx + 10, UI_UNIT_Y - 1, (void *)te->name,
+ 1.0, (float)len, 0, 0, "");
uiButSetRenameFunc(bt, namebutton_cb, tselem);
/* returns false if button got removed */
@@ -924,7 +1072,8 @@ static void tselem_draw_icon_uibut(struct DrawIconArg *arg, int icon)
glDisable(GL_BLEND);
}
else {
- uiBut *but = uiDefIconBut(arg->block, LABEL, 0, icon, arg->xb, arg->yb, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 1.0, arg->alpha, (arg->id && arg->id->lib) ? arg->id->lib->name : "");
+ uiBut *but = uiDefIconBut(arg->block, LABEL, 0, icon, arg->xb, arg->yb, UI_UNIT_X, UI_UNIT_Y, NULL,
+ 0.0, 0.0, 1.0, arg->alpha, (arg->id && arg->id->lib) ? arg->id->lib->name : "");
if (arg->id)
uiButSetDragID(but, arg->id);
@@ -932,7 +1081,8 @@ static void tselem_draw_icon_uibut(struct DrawIconArg *arg, int icon)
}
-static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeStoreElem *tselem, TreeElement *te, float alpha)
+static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeStoreElem *tselem, TreeElement *te,
+ float alpha)
{
struct DrawIconArg arg;
float aspect;
@@ -1217,7 +1367,8 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
}
}
-static void outliner_draw_iconrow(bContext *C, uiBlock *block, Scene *scene, SpaceOops *soops, ListBase *lb, int level, int xmax, int *offsx, int ys)
+static void outliner_draw_iconrow(bContext *C, uiBlock *block, Scene *scene, SpaceOops *soops, ListBase *lb, int level,
+ int xmax, int *offsx, int ys)
{
TreeElement *te;
TreeStoreElem *tselem;
@@ -1236,12 +1387,20 @@ static void outliner_draw_iconrow(bContext *C, uiBlock *block, Scene *scene, Spa
/* active blocks get white circle */
if (tselem->type == 0) {
- if (te->idcode == ID_OB) active = (OBACT == (Object *)tselem->id);
- else if (scene->obedit && scene->obedit->data == tselem->id) active = 1; // XXX use context?
- else active = tree_element_active(C, scene, soops, te, 0);
+ if (te->idcode == ID_OB) {
+ active = (OBACT == (Object *)tselem->id);
+ }
+ else if (scene->obedit && scene->obedit->data == tselem->id) {
+ active = 1; // XXX use context?
+ }
+ else {
+ active = tree_element_active(C, scene, soops, te, 0);
+ }
}
- else active = tree_element_type_active(NULL, scene, soops, te, tselem, 0);
-
+ else {
+ active = tree_element_type_active(NULL, scene, soops, te, tselem, 0, false);
+ }
+
if (active) {
float ufac = UI_UNIT_X / 20.0f;
@@ -1286,7 +1445,8 @@ static void outliner_set_coord_tree_element(SpaceOops *soops, TreeElement *te, i
}
-static void outliner_draw_tree_element(bContext *C, uiBlock *block, Scene *scene, ARegion *ar, SpaceOops *soops, TreeElement *te, int startx, int *starty)
+static void outliner_draw_tree_element(bContext *C, uiBlock *block, Scene *scene, ARegion *ar, SpaceOops *soops,
+ TreeElement *te, int startx, int *starty)
{
TreeElement *ten;
TreeStoreElem *tselem;
@@ -1377,7 +1537,7 @@ static void outliner_draw_tree_element(bContext *C, uiBlock *block, Scene *scene
}
}
else {
- if (tree_element_type_active(NULL, scene, soops, te, tselem, 0) ) active = 2;
+ if (tree_element_type_active(NULL, scene, soops, te, tselem, 0, false) ) active = 2;
glColor4ub(220, 220, 255, alpha);
}
@@ -1685,15 +1845,17 @@ void draw_outliner(const bContext *C)
sizex_rna = max_ii(OL_RNA_COLX, sizex_rna + OL_RNA_COL_SPACEX);
/* get width of data (for setting 'tot' rect, this is column 1 + column 2 + a bit extra) */
- if (soops->outlinevis == SO_KEYMAP)
- sizex = sizex_rna + OL_RNA_COL_SIZEX * 3 + 50; // XXX this is only really a quick hack to make this wide enough...
+ if (soops->outlinevis == SO_KEYMAP)
+ // XXX this is only really a quick hack to make this wide enough...
+ sizex = sizex_rna + OL_RNA_COL_SIZEX * 3 + 50;
else
sizex = sizex_rna + OL_RNA_COL_SIZEX + 50;
}
else {
/* width must take into account restriction columns (if visible) so that entries will still be visible */
//outliner_width(soops, &soops->tree, &sizex);
- outliner_rna_width(soops, &soops->tree, &sizex, 0); // XXX should use outliner_width instead when te->xend will be set correctly...
+ // XXX should use outliner_width instead when te->xend will be set correctly...
+ outliner_rna_width(soops, &soops->tree, &sizex, 0);
/* constant offset for restriction columns */
// XXX this isn't that great yet...
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 9a1b3628196..1e67e099508 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -146,7 +146,7 @@ static int do_outliner_item_openclose(bContext *C, SpaceOops *soops, TreeElement
}
/* event can enterkey, then it opens/closes */
-static int outliner_item_openclose(bContext *C, wmOperator *op, wmEvent *event)
+static int outliner_item_openclose(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
@@ -222,12 +222,12 @@ static int do_outliner_item_rename(bContext *C, ARegion *ar, SpaceOops *soops, T
if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
TreeStoreElem *tselem = TREESTORE(te);
- /* name and first icon */
- if (mval[0] > te->xs + UI_UNIT_X && mval[0] < te->xend) {
-
+ /* click on name */
+ if (mval[0] > te->xs + UI_UNIT_X * 2 && mval[0] < te->xend) {
do_item_rename(ar, te, tselem, reports);
+ return 1;
}
- return 1;
+ return 0;
}
for (te = te->subtree.first; te; te = te->next) {
@@ -236,20 +236,24 @@ static int do_outliner_item_rename(bContext *C, ARegion *ar, SpaceOops *soops, T
return 0;
}
-static int outliner_item_rename(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
+static int outliner_item_rename(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
TreeElement *te;
float fmval[2];
+ bool change = false;
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], fmval, fmval + 1);
for (te = soops->tree.first; te; te = te->next) {
- if (do_outliner_item_rename(C, ar, soops, te, fmval)) break;
+ if (do_outliner_item_rename(C, ar, soops, te, fmval)) {
+ change = true;
+ break;
+ }
}
- return OPERATOR_FINISHED;
+ return change ? OPERATOR_FINISHED : OPERATOR_PASS_THROUGH;
}
@@ -890,9 +894,13 @@ static void tree_element_show_hierarchy(Scene *scene, SpaceOops *soops, ListBase
else tselem->flag |= TSE_CLOSED;
}
}
- else tselem->flag |= TSE_CLOSED;
-
- if (TSELEM_OPEN(tselem, soops)) tree_element_show_hierarchy(scene, soops, &te->subtree);
+ else {
+ tselem->flag |= TSE_CLOSED;
+ }
+
+ if (TSELEM_OPEN(tselem, soops)) {
+ tree_element_show_hierarchy(scene, soops, &te->subtree);
+ }
}
}
@@ -1440,7 +1448,7 @@ static int parent_drop_exec(bContext *C, wmOperator *op)
}
/* Used for drag and drop parenting */
-TreeElement *outliner_dropzone_parent(bContext *C, wmEvent *event, TreeElement *te, float *fmval)
+TreeElement *outliner_dropzone_parent(bContext *C, const wmEvent *event, TreeElement *te, const float fmval[2])
{
SpaceOops *soops = CTX_wm_space_outliner(C);
TreeStoreElem *tselem = TREESTORE(te);
@@ -1469,7 +1477,7 @@ TreeElement *outliner_dropzone_parent(bContext *C, wmEvent *event, TreeElement *
return NULL;
}
-static int parent_drop_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Object *par = NULL;
Object *ob = NULL;
@@ -1643,7 +1651,7 @@ void OUTLINER_OT_parent_drop(wmOperatorType *ot)
RNA_def_enum(ot->srna, "type", prop_make_parent_types, 0, "Type", "");
}
-int outliner_dropzone_parent_clear(bContext *C, wmEvent *event, TreeElement *te, float *fmval)
+int outliner_dropzone_parent_clear(bContext *C, const wmEvent *event, TreeElement *te, const float fmval[2])
{
SpaceOops *soops = CTX_wm_space_outliner(C);
TreeStoreElem *tselem = TREESTORE(te);
@@ -1681,7 +1689,7 @@ int outliner_dropzone_parent_clear(bContext *C, wmEvent *event, TreeElement *te,
return 0;
}
-static int parent_clear_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int parent_clear_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Main *bmain = CTX_data_main(C);
Scene *scene = NULL;
@@ -1730,7 +1738,7 @@ void OUTLINER_OT_parent_clear(wmOperatorType *ot)
RNA_def_enum(ot->srna, "type", prop_clear_parent_types, 0, "Type", "");
}
-TreeElement *outliner_dropzone_scene(bContext *C, wmEvent *UNUSED(event), TreeElement *te, float *fmval)
+TreeElement *outliner_dropzone_scene(bContext *C, const wmEvent *UNUSED(event), TreeElement *te, const float fmval[2])
{
SpaceOops *soops = CTX_wm_space_outliner(C);
TreeStoreElem *tselem = TREESTORE(te);
@@ -1746,7 +1754,7 @@ TreeElement *outliner_dropzone_scene(bContext *C, wmEvent *UNUSED(event), TreeEl
return NULL;
}
-static int scene_drop_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int scene_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Scene *scene = NULL;
Object *ob = NULL;
@@ -1822,7 +1830,7 @@ void OUTLINER_OT_scene_drop(wmOperatorType *ot)
RNA_def_string(ot->srna, "scene", "Scene", MAX_ID_NAME, "Scene", "Target Scene");
}
-static int material_drop_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int material_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Material *ma = NULL;
Object *ob = NULL;
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index 63452de18d0..a918357ced2 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -165,8 +165,9 @@ void draw_outliner(const struct bContext *C);
void restrictbutton_gr_restrict_flag(void *poin, void *poin2, int flag);
/* outliner_select.c -------------------------------------------- */
-int tree_element_type_active(struct bContext *C, struct Scene *scene, struct SpaceOops *soops, TreeElement *te, TreeStoreElem *tselem, int set);
+int tree_element_type_active(struct bContext *C, struct Scene *scene, struct SpaceOops *soops, TreeElement *te, TreeStoreElem *tselem, int set, bool recursive);
int tree_element_active(struct bContext *C, struct Scene *scene, SpaceOops *soops, TreeElement *te, int set);
+int outliner_item_do_activate(struct bContext *C, int x, int y, bool extend, bool recursive);
/* outliner_edit.c ---------------------------------------------- */
@@ -189,9 +190,9 @@ void group_toggle_renderability_cb(struct bContext *C, struct Scene *scene, Tree
void item_rename_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem);
-TreeElement *outliner_dropzone_parent(struct bContext *C, struct wmEvent *event, struct TreeElement *te, float *fmval);
-int outliner_dropzone_parent_clear(struct bContext *C, struct wmEvent *event, struct TreeElement *te, float *fmval);
-TreeElement *outliner_dropzone_scene(struct bContext *C, struct wmEvent *event, struct TreeElement *te, float *fmval);
+TreeElement *outliner_dropzone_parent(struct bContext *C, const struct wmEvent *event, struct TreeElement *te, const float fmval[2]);
+int outliner_dropzone_parent_clear(struct bContext *C, const struct wmEvent *event, struct TreeElement *te, const float fmval[2]);
+TreeElement *outliner_dropzone_scene(struct bContext *C, const struct wmEvent *event, struct TreeElement *te, const float fmval[2]);
/* ...................................................... */
void OUTLINER_OT_item_activate(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c
index 1dd043409a5..b9e3942a7ce 100644
--- a/source/blender/editors/space_outliner/outliner_ops.c
+++ b/source/blender/editors/space_outliner/outliner_ops.c
@@ -30,12 +30,12 @@
#include "DNA_space_types.h"
-#include "WM_api.h"
-#include "WM_types.h"
+#include "BLI_utildefines.h"
#include "RNA_access.h"
-#include "BLI_utildefines.h"
+#include "WM_api.h"
+#include "WM_types.h"
#include "outliner_intern.h"
@@ -88,10 +88,22 @@ void outliner_keymap(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "OUTLINER_OT_item_rename", LEFTMOUSE, KM_DBL_CLICK, 0, 0);
kmi = WM_keymap_add_item(keymap, "OUTLINER_OT_item_activate", LEFTMOUSE, KM_CLICK, 0, 0);
+ RNA_boolean_set(kmi->ptr, "recursive", FALSE);
RNA_boolean_set(kmi->ptr, "extend", FALSE);
+
kmi = WM_keymap_add_item(keymap, "OUTLINER_OT_item_activate", LEFTMOUSE, KM_CLICK, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "recursive", FALSE);
+ RNA_boolean_set(kmi->ptr, "extend", TRUE);
+
+ kmi = WM_keymap_add_item(keymap, "OUTLINER_OT_item_activate", LEFTMOUSE, KM_CLICK, KM_CTRL, 0);
+ RNA_boolean_set(kmi->ptr, "recursive", TRUE);
+ RNA_boolean_set(kmi->ptr, "extend", FALSE);
+
+ kmi = WM_keymap_add_item(keymap, "OUTLINER_OT_item_activate", LEFTMOUSE, KM_CLICK, KM_CTRL | KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "recursive", TRUE);
RNA_boolean_set(kmi->ptr, "extend", TRUE);
+
WM_keymap_add_item(keymap, "OUTLINER_OT_select_border", BKEY, KM_PRESS, 0, 0);
kmi = WM_keymap_add_item(keymap, "OUTLINER_OT_item_openclose", RETKEY, KM_PRESS, 0, 0);
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index fa337ba7af1..6fcfb457615 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -47,8 +47,11 @@
#include "BKE_context.h"
#include "BKE_depsgraph.h"
+#include "BKE_main.h"
+#include "BKE_object.h"
#include "BKE_scene.h"
#include "BKE_sequencer.h"
+#include "BKE_armature.h"
#include "ED_armature.h"
#include "ED_object.h"
@@ -140,7 +143,50 @@ static int tree_element_active_renderlayer(bContext *C, TreeElement *te, TreeSto
return 0;
}
-static int tree_element_set_active_object(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te, int set)
+/**
+ * Select object tree:
+ * CTRL+LMB: Select/Deselect object and all cildren
+ * CTRL+SHIFT+LMB: Add/Remove object and all children
+ */
+static void do_outliner_object_select_recursive(Scene *scene, Object *ob_parent, bool select)
+{
+ Base *base;
+
+ for (base = FIRSTBASE; base; base = base->next) {
+ Object *ob = base->object;
+ if ((((ob->restrictflag & OB_RESTRICT_VIEW) == 0) && BKE_object_is_child_recursive(ob_parent, ob))) {
+ ED_base_object_select(base, select ? BA_SELECT : BA_DESELECT);
+ }
+ }
+}
+
+static void do_outliner_bone_select_recursive(bArmature *arm, Bone *bone_parent, bool select)
+{
+ Bone *bone;
+ for (bone = bone_parent->childbase.first; bone; bone = bone->next) {
+ if (select && PBONE_SELECTABLE(arm, bone))
+ bone->flag |= BONE_SELECTED;
+ else
+ bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ do_outliner_bone_select_recursive(arm, bone, select);
+ }
+}
+
+static void do_outliner_ebone_select_recursive(bArmature *arm, EditBone *ebone_parent, bool select)
+{
+ EditBone *ebone;
+ for (ebone = ebone_parent->next; ebone; ebone = ebone->next) {
+ if (ED_armature_ebone_is_child_recursive(ebone_parent, ebone)) {
+ if (select && EBONE_SELECTABLE(arm, ebone))
+ ebone->flag |= BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL;
+ else
+ ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ }
+ }
+}
+
+static int tree_element_set_active_object(bContext *C, Scene *scene, SpaceOops *soops,
+ TreeElement *te, int set, bool recursive)
{
TreeStoreElem *tselem = TREESTORE(te);
Scene *sce;
@@ -148,7 +194,9 @@ static int tree_element_set_active_object(bContext *C, Scene *scene, SpaceOops
Object *ob = NULL;
/* if id is not object, we search back */
- if (te->idcode == ID_OB) ob = (Object *)tselem->id;
+ if (te->idcode == ID_OB) {
+ ob = (Object *)tselem->id;
+ }
else {
ob = (Object *)outliner_search_back(soops, te, ID_OB);
if (ob == OBACT) return 0;
@@ -176,6 +224,12 @@ static int tree_element_set_active_object(bContext *C, Scene *scene, SpaceOops
BKE_scene_base_deselect_all(scene);
ED_base_object_select(base, BA_SELECT);
}
+
+ if (recursive) {
+ /* Recursive select/deselect for Object hierarchies */
+ do_outliner_object_select_recursive(scene, ob, (ob->flag & SELECT) != 0);
+ }
+
if (C) {
ED_base_object_activate(C, base); /* adds notifier */
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
@@ -312,7 +366,9 @@ static int tree_element_active_lamp(bContext *UNUSED(C), Scene *scene, SpaceOops
if (set) {
// XXX extern_set_butspace(F5KEY, 0);
}
- else return 1;
+ else {
+ return 1;
+ }
return 0;
}
@@ -395,7 +451,7 @@ static int tree_element_active_posegroup(bContext *C, Scene *scene, TreeElement
return 0;
}
-static int tree_element_active_posechannel(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, int set)
+static int tree_element_active_posechannel(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, int set, bool recursive)
{
Object *ob = (Object *)tselem->id;
bArmature *arm = ob->data;
@@ -404,9 +460,13 @@ static int tree_element_active_posechannel(bContext *C, Scene *scene, TreeElemen
if (set) {
if (!(pchan->bone->flag & BONE_HIDDEN_P)) {
- if (set == 2) ED_pose_deselectall(ob, 2); // 2 = clear active tag
- else ED_pose_deselectall(ob, 0); // 0 = deselect
-
+ if (set != 2) {
+ bPoseChannel *pchannel;
+ /* single select forces all other bones to get unselected */
+ for (pchannel = ob->pose->chanbase.first; pchannel; pchannel = pchannel->next)
+ pchannel->bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ }
+
if (set == 2 && (pchan->bone->flag & BONE_SELECTED)) {
pchan->bone->flag &= ~BONE_SELECTED;
}
@@ -414,7 +474,12 @@ static int tree_element_active_posechannel(bContext *C, Scene *scene, TreeElemen
pchan->bone->flag |= BONE_SELECTED;
arm->act_bone = pchan->bone;
}
-
+
+ if (recursive) {
+ /* Recursive select/deselect */
+ do_outliner_bone_select_recursive(arm, pchan->bone, (pchan->bone->flag & BONE_SELECTED) != 0);
+ }
+
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_ACTIVE, ob);
}
@@ -427,7 +492,7 @@ static int tree_element_active_posechannel(bContext *C, Scene *scene, TreeElemen
return 0;
}
-static int tree_element_active_bone(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, int set)
+static int tree_element_active_bone(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, int set, bool recursive)
{
bArmature *arm = (bArmature *)tselem->id;
Bone *bone = te->directdata;
@@ -436,8 +501,12 @@ static int tree_element_active_bone(bContext *C, Scene *scene, TreeElement *te,
if (!(bone->flag & BONE_HIDDEN_P)) {
Object *ob = OBACT;
if (ob) {
- if (set == 2) ED_pose_deselectall(ob, 2); // 2 is clear active tag
- else ED_pose_deselectall(ob, 0);
+ if (set != 2) {
+ bPoseChannel *pchannel;
+ /* single select forces all other bones to get unselected */
+ for (pchannel = ob->pose->chanbase.first; pchannel; pchannel = pchannel->next)
+ pchannel->bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ }
}
if (set == 2 && (bone->flag & BONE_SELECTED)) {
@@ -447,6 +516,12 @@ static int tree_element_active_bone(bContext *C, Scene *scene, TreeElement *te,
bone->flag |= BONE_SELECTED;
arm->act_bone = bone;
}
+
+ if (recursive) {
+ /* Recursive select/deselect */
+ do_outliner_bone_select_recursive(arm, bone, (bone->flag & BONE_SELECTED) != 0);
+ }
+
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_ACTIVE, ob);
}
@@ -479,35 +554,42 @@ static void tree_element_active_ebone__sel(bContext *C, Scene *scene, bArmature
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_ACTIVE, scene->obedit);
}
-static int tree_element_active_ebone(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tselem), int set)
+static int tree_element_active_ebone(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tselem), int set, bool recursive)
{
bArmature *arm = scene->obedit->data;
EditBone *ebone = te->directdata;
-
- if (set == 1) {
- if (!(ebone->flag & BONE_HIDDEN_A)) {
- ED_armature_deselect_all(scene->obedit, 0); // deselect
- tree_element_active_ebone__sel(C, scene, arm, ebone, TRUE);
- return 1;
- }
- }
- else if (set == 2) {
- if (!(ebone->flag & BONE_HIDDEN_A)) {
- if (!(ebone->flag & BONE_SELECTED)) {
+ int status = 0;
+ if (set) {
+ if (set == 1) {
+ if (!(ebone->flag & BONE_HIDDEN_A)) {
+ ED_armature_deselect_all(scene->obedit, 0); // deselect
tree_element_active_ebone__sel(C, scene, arm, ebone, TRUE);
- return 1;
+ status = 1;
}
- else {
- /* entirely selected, so de-select */
- tree_element_active_ebone__sel(C, scene, arm, ebone, FALSE);
- return 0;
+ }
+ else if (set == 2) {
+ if (!(ebone->flag & BONE_HIDDEN_A)) {
+ if (!(ebone->flag & BONE_SELECTED)) {
+ tree_element_active_ebone__sel(C, scene, arm, ebone, TRUE);
+ status = 1;
+ }
+ else {
+ /* entirely selected, so de-select */
+ tree_element_active_ebone__sel(C, scene, arm, ebone, FALSE);
+ status = 0;
+ }
}
}
+
+ if (recursive) {
+ /* Recursive select/deselect */
+ do_outliner_ebone_select_recursive(arm, ebone, (ebone->flag & BONE_SELECTED) != 0);
+ }
}
else if (ebone->flag & BONE_SELECTED) {
- return 1;
+ status = 1;
}
- return 0;
+ return status;
}
static int tree_element_active_modifier(bContext *C, TreeElement *UNUSED(te), TreeStoreElem *tselem, int set)
@@ -675,19 +757,19 @@ int tree_element_active(bContext *C, Scene *scene, SpaceOops *soops, TreeElement
/* generic call for non-id data to make/check active in UI */
/* Context can be NULL when set==0 */
int tree_element_type_active(bContext *C, Scene *scene, SpaceOops *soops,
- TreeElement *te, TreeStoreElem *tselem, int set)
+ TreeElement *te, TreeStoreElem *tselem, int set, bool recursive)
{
switch (tselem->type) {
case TSE_DEFGROUP:
return tree_element_active_defgroup(C, scene, te, tselem, set);
case TSE_BONE:
- return tree_element_active_bone(C, scene, te, tselem, set);
+ return tree_element_active_bone(C, scene, te, tselem, set, recursive);
case TSE_EBONE:
- return tree_element_active_ebone(C, scene, te, tselem, set);
+ return tree_element_active_ebone(C, scene, te, tselem, set, recursive);
case TSE_MODIFIER:
return tree_element_active_modifier(C, te, tselem, set);
case TSE_LINKED_OB:
- if (set) tree_element_set_active_object(C, scene, soops, te, set);
+ if (set) tree_element_set_active_object(C, scene, soops, te, set, FALSE);
else if (tselem->id == (ID *)OBACT) return 1;
break;
case TSE_LINKED_PSYS:
@@ -695,7 +777,7 @@ int tree_element_type_active(bContext *C, Scene *scene, SpaceOops *soops,
case TSE_POSE_BASE:
return tree_element_active_pose(C, scene, te, tselem, set);
case TSE_POSE_CHANNEL:
- return tree_element_active_posechannel(C, scene, te, tselem, set);
+ return tree_element_active_posechannel(C, scene, te, tselem, set, recursive);
case TSE_CONSTRAINT:
return tree_element_active_constraint(C, te, tselem, set);
case TSE_R_LAYER:
@@ -716,7 +798,7 @@ int tree_element_type_active(bContext *C, Scene *scene, SpaceOops *soops,
/* ================================================ */
static int do_outliner_item_activate(bContext *C, Scene *scene, ARegion *ar, SpaceOops *soops,
- TreeElement *te, int extend, const float mval[2])
+ TreeElement *te, bool extend, bool recursive, const float mval[2])
{
if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
@@ -748,7 +830,9 @@ static int do_outliner_item_activate(bContext *C, Scene *scene, ARegion *ar, Spa
/* always makes active object */
if (tselem->type != TSE_SEQUENCE && tselem->type != TSE_SEQ_STRIP && tselem->type != TSE_SEQUENCE_DUP)
- tree_element_set_active_object(C, scene, soops, te, 1 + (extend != 0 && tselem->type == 0));
+ tree_element_set_active_object(C, scene, soops, te,
+ 1 + (extend != 0 && tselem->type == 0),
+ recursive && tselem->type == 0 );
if (tselem->type == 0) { // the lib blocks
/* editmode? */
@@ -791,31 +875,31 @@ static int do_outliner_item_activate(bContext *C, Scene *scene, ARegion *ar, Spa
else { // rest of types
tree_element_active(C, scene, soops, te, 1);
}
-
+
+ }
+ else {
+ tree_element_type_active(C, scene, soops, te, tselem, 1 + (extend != 0), recursive);
}
- else tree_element_type_active(C, scene, soops, te, tselem, 1 + (extend != 0));
return 1;
}
}
for (te = te->subtree.first; te; te = te->next) {
- if (do_outliner_item_activate(C, scene, ar, soops, te, extend, mval)) return 1;
+ if (do_outliner_item_activate(C, scene, ar, soops, te, extend, recursive, mval)) return 1;
}
return 0;
}
-/* event can enterkey, then it opens/closes */
-static int outliner_item_activate(bContext *C, wmOperator *op, wmEvent *event)
+int outliner_item_do_activate(bContext *C, int x, int y, bool extend, bool recursive)
{
Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
TreeElement *te;
float fmval[2];
- int extend = RNA_boolean_get(op->ptr, "extend");
- UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], fmval, fmval + 1);
+ UI_view2d_region_to_view(&ar->v2d, x, y, fmval, fmval + 1);
if (!ELEM3(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF, SO_KEYMAP) &&
!(soops->flag & SO_HIDE_RESTRICTCOLS) &&
@@ -825,7 +909,7 @@ static int outliner_item_activate(bContext *C, wmOperator *op, wmEvent *event)
}
for (te = soops->tree.first; te; te = te->next) {
- if (do_outliner_item_activate(C, scene, ar, soops, te, extend, fmval)) break;
+ if (do_outliner_item_activate(C, scene, ar, soops, te, extend, recursive, fmval)) break;
}
if (te) {
@@ -855,6 +939,16 @@ static int outliner_item_activate(bContext *C, wmOperator *op, wmEvent *event)
return OPERATOR_FINISHED;
}
+/* event can enterkey, then it opens/closes */
+static int outliner_item_activate(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ bool extend = RNA_boolean_get(op->ptr, "extend");
+ bool recursive = RNA_boolean_get(op->ptr, "recursive");
+ int x = event->mval[0];
+ int y = event->mval[1];
+ return outliner_item_do_activate(C, x, y, extend, recursive);
+}
+
void OUTLINER_OT_item_activate(wmOperatorType *ot)
{
ot->name = "Activate Item";
@@ -865,7 +959,8 @@ void OUTLINER_OT_item_activate(wmOperatorType *ot)
ot->poll = ED_operator_outliner_active;
- RNA_def_boolean(ot->srna, "extend", 1, "Extend", "Extend selection for activation");
+ RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection for activation");
+ RNA_def_boolean(ot->srna, "recursive", false, "Recursive", "Select Objects and their children");
}
/* ****************************************************** */
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index cd04c8c6bd1..258f0338d1e 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -75,6 +75,7 @@
#include "outliner_intern.h"
+
/* ****************************************************** */
/* ************ SELECTION OPERATIONS ********* */
@@ -190,8 +191,10 @@ static void unlink_texture_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeEle
World *wrld = (World *)tsep->id;
mtex = wrld->mtex;
}
- else return;
-
+ else {
+ return;
+ }
+
for (a = 0; a < MAX_MTEX; a++) {
if (a == te->index && mtex[a]) {
if (mtex[a]->tex) {
@@ -264,6 +267,17 @@ 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))
+{
+ /* From where do i get the x,y coordinate of the mouse event ? */
+ wmWindow *win = CTX_wm_window(C);
+ int x = win->eventstate->mval[0];
+ int y = win->eventstate->mval[1];
+ outliner_item_do_activate(C, x, y, true, true);
+}
+
+
static void object_deselect_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te,
TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
{
@@ -300,7 +314,7 @@ static void id_local_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(t
if (tselem->id->lib && (tselem->id->flag & LIB_EXTERN)) {
/* if the ID type has no special local function,
* just clear the lib */
- if (id_make_local(tselem->id, FALSE) == FALSE) {
+ if (id_make_local(tselem->id, false) == false) {
Main *bmain = CTX_data_main(C);
id_clear_lib_data(bmain, tselem->id);
}
@@ -526,9 +540,9 @@ static void sequence_cb(int event, TreeElement *te, TreeStoreElem *tselem, void
Sequence *seq = (Sequence *)te->directdata;
if (event == 1) {
Scene *scene = (Scene *)scene_ptr;
- Editing *ed = BKE_sequencer_editing_get(scene, FALSE);
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
if (BLI_findindex(ed->seqbasep, seq) != -1) {
- ED_sequencer_select_sequence_single(scene, seq, TRUE);
+ ED_sequencer_select_sequence_single(scene, seq, true);
}
}
@@ -569,15 +583,29 @@ static void outliner_do_data_operation(SpaceOops *soops, int type, int event, Li
/* **************************************** */
+enum {
+ OL_OP_ENDMARKER = 0,
+ OL_OP_SELECT,
+ OL_OP_DESELECT,
+ OL_OP_SELECT_HIERARCHY,
+ OL_OP_DELETE,
+ OL_OP_LOCALIZED, /* disabled, see below */
+ OL_OP_TOGVIS,
+ OL_OP_TOGSEL,
+ OL_OP_TOGREN,
+ OL_OP_RENAME
+};
+
static EnumPropertyItem prop_object_op_types[] = {
- {1, "SELECT", 0, "Select", ""},
- {2, "DESELECT", 0, "Deselect", ""},
- {4, "DELETE", 0, "Delete", ""},
- {6, "TOGVIS", 0, "Toggle Visible", ""},
- {7, "TOGSEL", 0, "Toggle Selectable", ""},
- {8, "TOGREN", 0, "Toggle Renderable", ""},
- {9, "RENAME", 0, "Rename", ""},
- {0, NULL, 0, NULL, NULL}
+ {OL_OP_SELECT, "SELECT", 0, "Select", ""},
+ {OL_OP_DESELECT, "DESELECT", 0, "Deselect", ""},
+ {OL_OP_SELECT_HIERARCHY, "SELECT_HIERARCHY", 0, "Select Hierarchy", ""},
+ {OL_OP_DELETE, "DELETE", 0, "Delete", ""},
+ {OL_OP_TOGVIS, "TOGVIS", 0, "Toggle Visible", ""},
+ {OL_OP_TOGSEL, "TOGSEL", 0, "Toggle Selectable", ""},
+ {OL_OP_TOGREN, "TOGREN", 0, "Toggle Renderable", ""},
+ {OL_OP_RENAME, "RENAME", 0, "Rename", ""},
+ {OL_OP_ENDMARKER, NULL, 0, NULL, NULL}
};
static int outliner_object_operation_exec(bContext *C, wmOperator *op)
@@ -594,7 +622,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
event = RNA_enum_get(op->ptr, "type");
- if (event == 1) {
+ 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);
if (scene != sce) {
@@ -604,12 +632,21 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
str = "Select Objects";
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
- else if (event == 2) {
+ else if (event == OL_OP_SELECT_HIERARCHY) {
+ Scene *sce = scene; // to be able to delete, scenes are set...
+ outliner_do_object_operation(C, scene, soops, &soops->tree, object_select_hierarchy_cb);
+ if (scene != sce) {
+ ED_screen_set_scene(C, CTX_wm_screen(C), sce);
+ }
+ str = "Select Object Hierarchy";
+ 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);
str = "Deselect Objects";
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
- else if (event == 4) {
+ else if (event == OL_OP_DELETE) {
outliner_do_object_operation(C, scene, soops, &soops->tree, object_delete_cb);
/* XXX: tree management normally happens from draw_outliner(), but when
@@ -623,26 +660,26 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
str = "Delete Objects";
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
}
- else if (event == 5) { /* disabled, see above enum (ton) */
+ else if (event == OL_OP_LOCALIZED) { /* disabled, see above enum (ton) */
outliner_do_object_operation(C, scene, soops, &soops->tree, id_local_cb);
str = "Localized Objects";
}
- else if (event == 6) {
+ else if (event == OL_OP_TOGVIS) {
outliner_do_object_operation(C, 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 == 7) {
+ else if (event == OL_OP_TOGSEL) {
outliner_do_object_operation(C, 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 == 8) {
+ else if (event == OL_OP_TOGREN) {
outliner_do_object_operation(C, 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 == 9) {
+ else if (event == OL_OP_RENAME) {
outliner_do_object_operation(C, scene, soops, &soops->tree, item_rename_cb);
str = "Rename Object";
}
@@ -1229,7 +1266,7 @@ void OUTLINER_OT_data_operation(wmOperatorType *ot)
static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, SpaceOops *soops,
- TreeElement *te, wmEvent *event, const float mval[2])
+ TreeElement *te, const wmEvent *event, const float mval[2])
{
ReportList *reports = CTX_wm_reports(C); // XXX...
@@ -1259,7 +1296,9 @@ static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, S
WM_operator_name_call(C, "OUTLINER_OT_object_operation", WM_OP_INVOKE_REGION_WIN, NULL);
}
else if (idlevel) {
- if (idlevel == -1 || datalevel) BKE_report(reports, RPT_WARNING, "Mixed selection");
+ if (idlevel == -1 || datalevel) {
+ BKE_report(reports, RPT_WARNING, "Mixed selection");
+ }
else {
if (idlevel == ID_GR)
WM_operator_name_call(C, "OUTLINER_OT_group_operation", WM_OP_INVOKE_REGION_WIN, NULL);
@@ -1268,7 +1307,9 @@ static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, S
}
}
else if (datalevel) {
- if (datalevel == -1) BKE_report(reports, RPT_WARNING, "Mixed selection");
+ if (datalevel == -1) {
+ BKE_report(reports, RPT_WARNING, "Mixed selection");
+ }
else {
if (datalevel == TSE_ANIM_DATA)
WM_operator_name_call(C, "OUTLINER_OT_animdata_operation", WM_OP_INVOKE_REGION_WIN, NULL);
@@ -1295,7 +1336,7 @@ static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, S
}
-static int outliner_operation(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
+static int outliner_operation(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index f723fbedc7b..19bc1db2b5d 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -64,6 +64,8 @@
#include "BLI_utildefines.h"
#include "BLI_math.h"
+#include "BLF_translation.h"
+
#include "BKE_fcurve.h"
#include "BKE_main.h"
#include "BKE_library.h"
@@ -322,7 +324,7 @@ static void outliner_add_passes(SpaceOops *soops, TreeElement *tenla, ID *id, Sc
* in order to not overflow short tselem->nr */
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_COMBINED));
- te->name = "Combined";
+ te->name = IFACE_("Combined");
te->directdata = &srl->passflag;
/* save cpu cycles, but we add the first to invoke an open/close triangle */
@@ -331,71 +333,71 @@ static void outliner_add_passes(SpaceOops *soops, TreeElement *tenla, ID *id, Sc
return;
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_Z));
- te->name = "Z";
+ te->name = IFACE_("Z");
te->directdata = &srl->passflag;
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_VECTOR));
- te->name = "Vector";
+ te->name = IFACE_("Vector");
te->directdata = &srl->passflag;
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_NORMAL));
- te->name = "Normal";
+ te->name = IFACE_("Normal");
te->directdata = &srl->passflag;
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_UV));
- te->name = "UV";
+ te->name = IFACE_("UV");
te->directdata = &srl->passflag;
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_MIST));
- te->name = "Mist";
+ te->name = IFACE_("Mist");
te->directdata = &srl->passflag;
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_INDEXOB));
- te->name = "Index Object";
+ te->name = IFACE_("Index Object");
te->directdata = &srl->passflag;
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_INDEXMA));
- te->name = "Index Material";
+ te->name = IFACE_("Index Material");
te->directdata = &srl->passflag;
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_RGBA));
- te->name = "Color";
+ te->name = IFACE_("Color");
te->directdata = &srl->passflag;
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_DIFFUSE));
- te->name = "Diffuse";
+ te->name = IFACE_("Diffuse");
te->directdata = &srl->passflag;
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_SPEC));
- te->name = "Specular";
+ te->name = IFACE_("Specular");
te->directdata = &srl->passflag;
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_SHADOW));
- te->name = "Shadow";
+ te->name = IFACE_("Shadow");
te->directdata = &srl->passflag;
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_AO));
- te->name = "AO";
+ te->name = IFACE_("AO");
te->directdata = &srl->passflag;
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_REFLECT));
- te->name = "Reflection";
+ te->name = IFACE_("Reflection");
te->directdata = &srl->passflag;
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_REFRACT));
- te->name = "Refraction";
+ te->name = IFACE_("Refraction");
te->directdata = &srl->passflag;
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_INDIRECT));
- te->name = "Indirect";
+ te->name = IFACE_("Indirect");
te->directdata = &srl->passflag;
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_ENVIRONMENT));
- te->name = "Environment";
+ te->name = IFACE_("Environment");
te->directdata = &srl->passflag;
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_EMIT));
- te->name = "Emit";
+ te->name = IFACE_("Emit");
te->directdata = &srl->passflag;
}
@@ -407,7 +409,7 @@ static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *s
TreeElement *tenla = outliner_add_element(soops, lb, sce, te, TSE_R_LAYER_BASE, 0);
int a;
- tenla->name = "RenderLayers";
+ tenla->name = IFACE_("RenderLayers");
for (a = 0, srl = sce->r.layers.first; srl; srl = srl->next, a++) {
TreeElement *tenlay = outliner_add_element(soops, &tenla->subtree, sce, te, TSE_R_LAYER, a);
tenlay->name = srl->name;
@@ -449,7 +451,7 @@ static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, Tree
TreeElement *ten;
TreeElement *tenla = outliner_add_element(soops, &te->subtree, ob, te, TSE_POSE_BASE, 0);
- tenla->name = "Pose";
+ tenla->name = IFACE_("Pose");
/* channels undefined in editmode, but we want the 'tenla' pose icon itself */
if ((arm->edbo == NULL) && (ob->mode & OB_MODE_POSE)) {
@@ -468,7 +470,7 @@ static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, Tree
TreeElement *tenla1 = outliner_add_element(soops, &ten->subtree, ob, ten, TSE_CONSTRAINT_BASE, 0);
//char *str;
- tenla1->name = "Constraints";
+ tenla1->name = IFACE_("Constraints");
for (con = pchan->constraints.first; con; con = con->next, const_index++) {
ten1 = outliner_add_element(soops, &tenla1->subtree, ob, tenla1, TSE_CONSTRAINT, const_index);
#if 0 /* disabled as it needs to be reworked for recoded constraints system */
@@ -508,7 +510,7 @@ static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, Tree
TreeElement *tenla = outliner_add_element(soops, &te->subtree, ob, te, TSE_POSEGRP_BASE, 0);
int a = 0;
- tenla->name = "Bone Groups";
+ tenla->name = IFACE_("Bone Groups");
for (agrp = ob->pose->agroups.first; agrp; agrp = agrp->next, a++) {
ten = outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_POSEGRP, a);
ten->name = agrp->name;
@@ -527,7 +529,7 @@ static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, Tree
TreeElement *tenla = outliner_add_element(soops, &te->subtree, ob, te, TSE_CONSTRAINT_BASE, 0);
//char *str;
- tenla->name = "Constraints";
+ tenla->name = IFACE_("Constraints");
for (con = ob->constraints.first, a = 0; con; con = con->next, a++) {
ten = outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_CONSTRAINT, a);
#if 0 /* disabled due to constraints system targets recode... code here needs review */
@@ -547,7 +549,7 @@ static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, Tree
TreeElement *temod = outliner_add_element(soops, &te->subtree, ob, te, TSE_MODIFIER_BASE, 0);
int index;
- temod->name = "Modifiers";
+ temod->name = IFACE_("Modifiers");
for (index = 0, md = ob->modifiers.first; md; index++, md = md->next) {
TreeElement *te = outliner_add_element(soops, &temod->subtree, ob, temod, TSE_MODIFIER, index);
te->name = md->name;
@@ -582,7 +584,7 @@ static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, Tree
TreeElement *ten;
TreeElement *tenla = outliner_add_element(soops, &te->subtree, ob, te, TSE_DEFGROUP_BASE, 0);
- tenla->name = "Vertex Groups";
+ tenla->name = IFACE_("Vertex Groups");
for (defgroup = ob->defbase.first, a = 0; defgroup; defgroup = defgroup->next, a++) {
ten = outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_DEFGROUP, a);
ten->name = defgroup->name;
@@ -856,7 +858,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
AnimData *adt = (AnimData *)iat->adt;
/* this element's info */
- te->name = "Animation";
+ te->name = IFACE_("Animation");
te->directdata = adt;
/* Action */
@@ -868,7 +870,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
ID *lastadded = NULL;
FCurve *fcu;
- ted->name = "Drivers";
+ ted->name = IFACE_("Drivers");
for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
if (fcu->driver && fcu->driver->variables.first) {
@@ -897,7 +899,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
NlaTrack *nlt;
int a = 0;
- tenla->name = "NLA Tracks";
+ tenla->name = IFACE_("NLA Tracks");
for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
TreeElement *tenlt = outliner_add_element(soops, &tenla->subtree, nlt, tenla, TSE_NLA_TRACK, a);
@@ -951,7 +953,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
if (strip->dir)
te->name = strip->dir;
else
- te->name = "Strip None";
+ te->name = IFACE_("Strip None");
te->directdata = strip;
}
else if (type == TSE_SEQUENCE_DUP) {
@@ -970,7 +972,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
/* we do lazy build, for speed and to avoid infinite recusion */
if (ptr->data == NULL) {
- te->name = "(empty)";
+ te->name = IFACE_("(empty)");
}
else if (type == TSE_RNA_STRUCT) {
/* struct */
@@ -1096,7 +1098,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
ten->directdata = kmi;
if (kmi->propvalue) {
- ten->name = "Modal map, not yet";
+ ten->name = IFACE_("Modal map, not yet");
}
else {
WM_operator_py_idname(opname, ot->idname);
@@ -1257,19 +1259,23 @@ static int treesort_obtype_alpha(const void *v1, const void *v2)
const tTreeSort *x1 = v1, *x2 = v2;
/* first put objects last (hierarchy) */
- if (x1->idcode == ID_OB && x2->idcode != ID_OB) return 1;
- else if (x2->idcode == ID_OB && x1->idcode != ID_OB) return -1;
+ if (x1->idcode == ID_OB && x2->idcode != ID_OB) {
+ return 1;
+ }
+ else if (x2->idcode == ID_OB && x1->idcode != ID_OB) {
+ return -1;
+ }
else {
/* 2nd we check ob type */
if (x1->idcode == ID_OB && x2->idcode == ID_OB) {
- if (((Object *)x1->id)->type > ((Object *)x2->id)->type) return 1;
+ if (((Object *)x1->id)->type > ((Object *)x2->id)->type) return 1;
else if (((Object *)x1->id)->type > ((Object *)x2->id)->type) return -1;
else return 0;
}
else {
int comp = strcmp(x1->name, x2->name);
- if (comp > 0) return 1;
+ if (comp > 0) return 1;
else if (comp < 0) return -1;
return 0;
}
@@ -1502,7 +1508,7 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
/* current file first - mainvar provides tselem with unique pointer - not used */
ten = outliner_add_element(soops, &soops->tree, mainvar, NULL, TSE_ID_BASE, 0);
- ten->name = "Current File";
+ ten->name = IFACE_("Current File");
tselem = TREESTORE(ten);
if (!tselem->used)
diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c
index 4bf88376b74..3849aaf78c1 100644
--- a/source/blender/editors/space_outliner/space_outliner.c
+++ b/source/blender/editors/space_outliner/space_outliner.c
@@ -90,7 +90,7 @@ static void outliner_main_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_dropbox_handler(&ar->handlers, lb);
}
-static int outliner_parent_drop_poll(bContext *C, wmDrag *drag, wmEvent *event)
+static int outliner_parent_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
@@ -135,7 +135,7 @@ static void outliner_parent_drop_copy(wmDrag *drag, wmDropBox *drop)
RNA_string_set(drop->ptr, "child", id->name + 2);
}
-static int outliner_parent_clear_poll(bContext *C, wmDrag *drag, wmEvent *event)
+static int outliner_parent_clear_poll(bContext *C, wmDrag *drag, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
@@ -176,7 +176,7 @@ static void outliner_parent_clear_copy(wmDrag *drag, wmDropBox *drop)
RNA_enum_set(drop->ptr, "type", 0);
}
-static int outliner_scene_drop_poll(bContext *C, wmDrag *drag, wmEvent *event)
+static int outliner_scene_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
@@ -205,7 +205,7 @@ static void outliner_scene_drop_copy(wmDrag *drag, wmDropBox *drop)
RNA_string_set(drop->ptr, "object", id->name + 2);
}
-static int outliner_material_drop_poll(bContext *C, wmDrag *drag, wmEvent *event)
+static int outliner_material_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
@@ -316,6 +316,10 @@ static void outliner_main_area_listener(ARegion *ar, wmNotifier *wmn)
/* all modifier actions now */
ED_region_tag_redraw(ar);
break;
+ default:
+ /* Trigger update for NC_OBJECT itself */
+ ED_region_tag_redraw(ar);
+ break;
}
break;
case NC_GROUP:
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index 78a76532487..571779a7524 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -294,7 +294,7 @@ static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op)
}
-static int sequencer_add_scene_strip_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int sequencer_add_scene_strip_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (!ED_operator_sequencer_active(C)) {
BKE_report(op->reports, RPT_ERROR, "Sequencer area not active");
@@ -392,7 +392,7 @@ static int sequencer_add_movieclip_strip_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int sequencer_add_movieclip_strip_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int sequencer_add_movieclip_strip_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (!ED_operator_sequencer_active(C)) {
BKE_report(op->reports, RPT_ERROR, "Sequencer area not active");
@@ -489,7 +489,7 @@ static int sequencer_add_mask_strip_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int sequencer_add_mask_strip_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int sequencer_add_mask_strip_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (!ED_operator_sequencer_active(C)) {
BKE_report(op->reports, RPT_ERROR, "Sequencer area not active");
@@ -602,7 +602,7 @@ static int sequencer_add_movie_strip_exec(bContext *C, wmOperator *op)
}
-static int sequencer_add_movie_strip_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int sequencer_add_movie_strip_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (!ED_operator_sequencer_active(C)) {
@@ -657,7 +657,7 @@ static int sequencer_add_sound_strip_exec(bContext *C, wmOperator *op)
return sequencer_add_generic_strip_exec(C, op, BKE_sequencer_add_sound_strip);
}
-static int sequencer_add_sound_strip_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int sequencer_add_sound_strip_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (!ED_operator_sequencer_active(C)) {
@@ -769,7 +769,7 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int sequencer_add_image_strip_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int sequencer_add_image_strip_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (!ED_operator_sequencer_active(C)) {
@@ -921,7 +921,7 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op)
/* add color */
-static int sequencer_add_effect_strip_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int sequencer_add_effect_strip_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
short is_type_set = RNA_struct_property_is_set(op->ptr, "type");
int type = -1;
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 396878cbfeb..7ebe04f666b 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -813,7 +813,9 @@ static void UNUSED_FUNCTION(set_special_seq_update) (int val)
if (val) {
// XXX special_seq_update = find_nearest_seq(&x);
}
- else special_seq_update = NULL;
+ else {
+ special_seq_update = NULL;
+ }
}
ImBuf *sequencer_ibuf_get(struct Main *bmain, Scene *scene, SpaceSeq *sseq, int cfra, int frame_ofs)
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 7be2d51a3c0..f0ed8d4107d 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -520,7 +520,7 @@ int seq_effect_find_selected(Scene *scene, Sequence *activeseq, int type, Sequen
return 0;
}
if ((seq != activeseq) && (seq != seq2)) {
- if (seq2 == NULL) seq2 = seq;
+ if (seq2 == NULL) seq2 = seq;
else if (seq1 == NULL) seq1 = seq;
else if (seq3 == NULL) seq3 = seq;
else {
@@ -889,7 +889,7 @@ static int insert_gap(Scene *scene, int gap, int cfra)
return done;
}
-static void UNUSED_FUNCTION(touch_seq_files) (Scene * scene)
+static void UNUSED_FUNCTION(touch_seq_files) (Scene *scene)
{
Sequence *seq;
Editing *ed = BKE_sequencer_editing_get(scene, FALSE);
@@ -946,7 +946,7 @@ static void set_filter_seq(Scene *scene)
}
#endif
-static void UNUSED_FUNCTION(seq_remap_paths) (Scene * scene)
+static void UNUSED_FUNCTION(seq_remap_paths) (Scene *scene)
{
Sequence *seq, *last_seq = BKE_sequencer_active_get(scene);
Editing *ed = BKE_sequencer_editing_get(scene, FALSE);
@@ -988,7 +988,7 @@ static void UNUSED_FUNCTION(seq_remap_paths) (Scene * scene)
}
-static void UNUSED_FUNCTION(no_gaps) (Scene * scene)
+static void UNUSED_FUNCTION(no_gaps) (Scene *scene)
{
Editing *ed = BKE_sequencer_editing_get(scene, FALSE);
int cfra, first = 0, done;
@@ -1121,7 +1121,7 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int sequencer_snap_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int sequencer_snap_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Scene *scene = CTX_data_scene(C);
@@ -1546,7 +1546,7 @@ static int sequencer_cut_exec(bContext *C, wmOperator *op)
}
-static int sequencer_cut_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int sequencer_cut_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Scene *scene = CTX_data_scene(C);
View2D *v2d = UI_view2d_fromcontext(C);
@@ -1695,7 +1695,7 @@ static int sequencer_delete_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-static int sequencer_delete_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int sequencer_delete_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
@@ -3105,7 +3105,7 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int sequencer_change_path_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int sequencer_change_path_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Scene *scene = CTX_data_scene(C);
Sequence *seq = BKE_sequencer_active_get(scene);
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index 0d1ecb76d0e..3269e772be6 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -162,7 +162,7 @@ void select_surround_from_last(Scene *scene)
}
#endif
-void ED_sequencer_select_sequence_single(Scene * scene, Sequence * seq, int deselect_all)
+void ED_sequencer_select_sequence_single(Scene *scene, Sequence *seq, bool deselect_all)
{
Editing *ed = BKE_sequencer_editing_get(scene, FALSE);
@@ -315,7 +315,7 @@ void SEQUENCER_OT_select_inverse(struct wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-static int sequencer_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
View2D *v2d = UI_view2d_fromcontext(C);
Scene *scene = CTX_data_scene(C);
@@ -552,8 +552,6 @@ void SEQUENCER_OT_select(wmOperatorType *ot)
}
-
-
/* run recursively to select linked */
static int select_more_less_seq__internal(Scene *scene, int sel, int linked)
{
@@ -670,7 +668,7 @@ void SEQUENCER_OT_select_less(wmOperatorType *ot)
/* select pick linked operator (uses the mouse) */
-static int sequencer_select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int sequencer_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Scene *scene = CTX_data_scene(C);
View2D *v2d = UI_view2d_fromcontext(C);
diff --git a/source/blender/editors/space_sequencer/sequencer_view.c b/source/blender/editors/space_sequencer/sequencer_view.c
index 92b17393114..7dcd3a70870 100644
--- a/source/blender/editors/space_sequencer/sequencer_view.c
+++ b/source/blender/editors/space_sequencer/sequencer_view.c
@@ -85,7 +85,7 @@ static void sample_draw(const bContext *C, ARegion *ar, void *arg_info)
}
}
-static void sample_apply(bContext *C, wmOperator *op, wmEvent *event)
+static void sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
@@ -168,7 +168,7 @@ static void sample_exit(bContext *C, wmOperator *op)
MEM_freeN(info);
}
-static int sample_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
SpaceSeq *sseq = CTX_wm_space_seq(C);
@@ -189,7 +189,7 @@ static int sample_invoke(bContext *C, wmOperator *op, wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
-static int sample_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int sample_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
switch (event->type) {
case LEFTMOUSE:
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index 4c6b909882c..ffe89407715 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -373,7 +373,7 @@ static void sequencer_main_area_draw(const bContext *C, ARegion *ar)
/* ************* dropboxes ************* */
-static int image_drop_poll(bContext *C, wmDrag *drag, wmEvent *event)
+static int image_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
@@ -387,7 +387,7 @@ static int image_drop_poll(bContext *C, wmDrag *drag, wmEvent *event)
return 0;
}
-static int movie_drop_poll(bContext *C, wmDrag *drag, wmEvent *event)
+static int movie_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
@@ -400,7 +400,7 @@ static int movie_drop_poll(bContext *C, wmDrag *drag, wmEvent *event)
return 0;
}
-static int sound_drop_poll(bContext *C, wmDrag *drag, wmEvent *event)
+static int sound_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c
index ff9d1329721..110e0ab5bc4 100644
--- a/source/blender/editors/space_text/space_text.c
+++ b/source/blender/editors/space_text/space_text.c
@@ -458,7 +458,7 @@ static void text_cursor(wmWindow *win, ScrArea *UNUSED(sa), ARegion *UNUSED(ar))
/* ************* dropboxes ************* */
-static int text_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event))
+static int text_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
{
if (drag->type == WM_DRAG_PATH)
if (ELEM(drag->icon, ICON_FILE_SCRIPT, ICON_FILE_BLANK)) /* rule might not work? */
diff --git a/source/blender/editors/space_text/text_autocomplete.c b/source/blender/editors/space_text/text_autocomplete.c
index 7c18b5c283a..838ffb948b1 100644
--- a/source/blender/editors/space_text/text_autocomplete.c
+++ b/source/blender/editors/space_text/text_autocomplete.c
@@ -220,7 +220,7 @@ static GHash *text_autocomplete_build(Text *text)
TextFormatType *tft;
tft = ED_text_format_get(text);
- for (; !BLI_ghashIterator_isDone(iter); BLI_ghashIterator_step(iter)) {
+ for (; BLI_ghashIterator_notDone(iter); BLI_ghashIterator_step(iter)) {
const char *s = BLI_ghashIterator_getValue(iter);
texttool_suggest_add(s, tft->format_identifier(s));
}
@@ -282,7 +282,7 @@ static void confirm_suggestion(Text *text)
/* -- */
-static int text_autocomplete_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int text_autocomplete_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
SpaceText *st = CTX_wm_space_text(C);
Text *text = CTX_data_edit_text(C);
@@ -313,7 +313,7 @@ static int text_autocomplete_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED
static int doc_scroll = 0;
-static int text_autocomplete_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceText *st = CTX_wm_space_text(C);
ScrArea *sa = CTX_wm_area(C);
diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c
index c264368e714..95fd7fce878 100644
--- a/source/blender/editors/space_text/text_draw.c
+++ b/source/blender/editors/space_text/text_draw.c
@@ -67,12 +67,14 @@ static void text_font_end(SpaceText *UNUSED(st))
{
}
-static int text_font_draw(SpaceText *UNUSED(st), int x, int y, const char *str)
+static int text_font_draw(SpaceText *st, int x, int y, const char *str)
{
+ int columns;
+
BLF_position(mono, x, y, 0);
- BLF_draw(mono, str, BLF_DRAW_STR_DUMMY_MAX);
+ columns = BLF_draw_mono(mono, str, BLF_DRAW_STR_DUMMY_MAX, st->cwidth);
- return BLF_width(mono, str);
+ return st->cwidth * columns;
}
static int text_font_draw_character(SpaceText *st, int x, int y, char c)
@@ -85,10 +87,13 @@ static int text_font_draw_character(SpaceText *st, int x, int y, char c)
static int text_font_draw_character_utf8(SpaceText *st, int x, int y, const char *c)
{
+ int columns;
+
const size_t len = BLI_str_utf8_size_safe(c);
BLF_position(mono, x, y, 0);
- BLF_draw(mono, c, len);
- return st->cwidth;
+ columns = BLF_draw_mono(mono, c, len, st->cwidth);
+
+ return st->cwidth * columns;
}
#if 0
@@ -216,7 +221,7 @@ void wrap_offset(SpaceText *st, ARegion *ar, TextLine *linein, int cursin, int *
}
max = wrap_width(st, ar);
- cursin = txt_utf8_offset_to_index(linein->line, cursin);
+ cursin = txt_utf8_offset_to_column(linein->line, cursin);
while (linep) {
start = 0;
@@ -225,6 +230,7 @@ void wrap_offset(SpaceText *st, ARegion *ar, TextLine *linein, int cursin, int *
*offc = 0;
for (i = 0, j = 0; linep->line[j]; j += BLI_str_utf8_size_safe(linep->line + j)) {
int chars;
+ int columns = BLI_str_utf8_char_width_safe(linep->line + j); /* = 1 for tab */
/* Mimic replacement of tabs */
ch = linep->line[j];
@@ -238,7 +244,9 @@ void wrap_offset(SpaceText *st, ARegion *ar, TextLine *linein, int cursin, int *
}
while (chars--) {
- if (i - start >= max) {
+ if (i + columns - start > max) {
+ end = MIN2(end, i);
+
if (chop && linep == linein && i >= cursin) {
if (i == cursin) {
(*offl)++;
@@ -261,7 +269,7 @@ void wrap_offset(SpaceText *st, ARegion *ar, TextLine *linein, int cursin, int *
if (linep == linein && i >= cursin)
return;
}
- i++;
+ i += columns;
}
}
if (linep == linein) break;
@@ -286,9 +294,10 @@ void wrap_offset_in_line(SpaceText *st, ARegion *ar, TextLine *linein, int cursi
end = max;
chop = 1;
*offc = 0;
- cursin = txt_utf8_offset_to_index(linein->line, cursin);
+ cursin = txt_utf8_offset_to_column(linein->line, cursin);
for (i = 0, j = 0; linein->line[j]; j += BLI_str_utf8_size_safe(linein->line + j)) {
+ int columns = BLI_str_utf8_char_width_safe(linein->line + j); /* = 1 for tab */
/* Mimic replacement of tabs */
ch = linein->line[j];
@@ -301,7 +310,9 @@ void wrap_offset_in_line(SpaceText *st, ARegion *ar, TextLine *linein, int cursi
chars = 1;
while (chars--) {
- if (i - start >= max) {
+ if (i + columns - start > max) {
+ end = MIN2(end, i);
+
if (chop && i >= cursin) {
if (i == cursin) {
(*offl)++;
@@ -324,7 +335,7 @@ void wrap_offset_in_line(SpaceText *st, ARegion *ar, TextLine *linein, int cursi
if (i >= cursin)
return;
}
- i++;
+ i += columns;
}
}
}
@@ -337,24 +348,35 @@ int text_get_char_pos(SpaceText *st, const char *line, int cur)
if (line[i] == '\t')
a += st->tabnumber - a % st->tabnumber;
else
- a++;
+ a += BLI_str_utf8_char_width_safe(line + i);
}
return a;
}
-static const char *txt_utf8_get_nth(const char *str, int n)
+static const char *txt_utf8_forward_columns(const char *str, int columns, int *padding)
{
- int pos = 0;
- while (str[pos] && n--) {
- pos += BLI_str_utf8_size_safe(str + pos);
+ int col;
+ const char *p = str;
+ while (*p) {
+ col = BLI_str_utf8_char_width(p);
+ if (columns - col < 0)
+ break;
+ columns -= col;
+ p += BLI_str_utf8_size_safe(p);
+ if (columns == 0)
+ break;
}
- return str + pos;
+ if (padding)
+ *padding = *p ? columns : 0;
+ return p;
}
static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w, const char *format, int skip)
{
FlattenString fs;
- int basex, i, a, start, end, max, lines; /* view */
+ int basex, lines;
+ int i, wrap, end, max, columns, padding; /* column */
+ int a, fstart, fpos; /* utf8 chars */
int mi, ma, mstart, mend; /* mem */
char fmt_prev = 0xff;
@@ -365,41 +387,46 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w
basex = x;
lines = 1;
- start = 0; mstart = 0;
- end = max; mend = txt_utf8_get_nth(str, max) - str;
+ fpos = fstart = 0; mstart = 0;
+ mend = txt_utf8_forward_columns(str, max, &padding) - str;
+ end = wrap = max - padding;
- for (i = 0, mi = 0; str[mi]; i++, mi += BLI_str_utf8_size_safe(str + mi)) {
- if (i - start >= max) {
+ for (i = 0, mi = 0; str[mi]; i += columns, mi += BLI_str_utf8_size_safe(str + mi)) {
+ columns = BLI_str_utf8_char_width_safe(str + mi);
+ if (i + columns > end) {
/* skip hidden part of line */
if (skip) {
skip--;
- start = end; mstart = mend;
- end += max; mend = txt_utf8_get_nth(str + mend, max) - str;
+ fstart = fpos; mstart = mend;
+ mend = txt_utf8_forward_columns(str + mend, max, &padding) - str;
+ end = (wrap += max - padding);
continue;
}
/* Draw the visible portion of text on the overshot line */
- for (a = start, ma = mstart; a < end; a++, ma += BLI_str_utf8_size_safe(str + ma)) {
+ for (a = fstart, ma = mstart; ma < mend; a++, ma += BLI_str_utf8_size_safe(str + ma)) {
if (st->showsyntax && format) {
if (fmt_prev != format[a]) format_draw_color(fmt_prev = format[a]);
}
x += text_font_draw_character_utf8(st, x, y, str + ma);
+ fpos++;
}
y -= st->lheight_dpi + TXT_LINE_SPACING;
x = basex;
lines++;
- start = end; mstart = mend;
- end += max; mend = txt_utf8_get_nth(str + mend, max) - str;
+ fstart = fpos; mstart = mend;
+ mend = txt_utf8_forward_columns(str + mend, max, &padding) - str;
+ end = (wrap += max - padding);
if (y <= 0) break;
}
else if (str[mi] == ' ' || str[mi] == '-') {
- end = i + 1; mend = mi + 1;
+ wrap = i + 1; mend = mi + 1;
}
}
/* Draw the remaining text */
- for (a = start, ma = mstart; str[ma] && y > 0; a++, ma += BLI_str_utf8_size_safe(str + ma)) {
+ for (a = fstart, ma = mstart; str[ma] && y > 0; a++, ma += BLI_str_utf8_size_safe(str + ma)) {
if (st->showsyntax && format) {
if (fmt_prev != format[a]) format_draw_color(fmt_prev = format[a]);
}
@@ -412,53 +439,55 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w
return lines;
}
-static int text_draw(SpaceText *st, char *str, int cshift, int maxwidth, int draw, int x, int y, const char *format)
+static void text_draw(SpaceText *st, char *str, int cshift, int maxwidth, int x, int y, const char *format)
{
FlattenString fs;
- int *acc, r = 0;
- const char *in;
+ int columns, size, n, w = 0, padding, amount = 0;
+ const char *in = NULL;
- int w = flatten_string(st, &fs, str);
- if (w < cshift) {
- flatten_string_free(&fs);
- return 0; /* String is shorter than shift */
- }
-
- in = txt_utf8_get_nth(fs.buf, cshift);
- acc = fs.accum + cshift;
- w = w - cshift;
+ for (n = flatten_string(st, &fs, str), str = fs.buf; n > 0; n--) {
+ columns = BLI_str_utf8_char_width_safe(str);
+ size = BLI_str_utf8_size_safe(str);
- if (draw) {
- int amount = maxwidth ? MIN2(w, maxwidth) : w;
-
- if (st->showsyntax && format) {
- int a, str_shift = 0;
- char fmt_prev = 0xff;
- format = format + cshift;
-
- for (a = 0; a < amount; a++) {
- if (format[a] != fmt_prev) format_draw_color(fmt_prev = format[a]);
- x += text_font_draw_character_utf8(st, x, y, in + str_shift);
- str_shift += BLI_str_utf8_size_safe(in + str_shift);
+ if (!in) {
+ if (w >= cshift) {
+ padding = w - cshift;
+ in = str;
}
+ else if (format)
+ format++;
}
- else {
- text_font_draw(st, x, y, in);
+ if (in) {
+ if (maxwidth && w + columns > cshift + maxwidth)
+ break;
+ amount++;
+ }
+
+ w += columns;
+ str += size;
+ }
+ if (!in) {
+ flatten_string_free(&fs);
+ return; /* String is shorter than shift or ends with a padding */
+ }
+
+ x += st->cwidth * padding;
+
+ if (st->showsyntax && format) {
+ int a, str_shift = 0;
+ char fmt_prev = 0xff;
+
+ for (a = 0; a < amount; a++) {
+ if (format[a] != fmt_prev) format_draw_color(fmt_prev = format[a]);
+ x += text_font_draw_character_utf8(st, x, y, in + str_shift);
+ str_shift += BLI_str_utf8_size_safe(in + str_shift);
}
}
else {
- while (w-- && *acc++ < maxwidth)
- r += st->cwidth;
+ text_font_draw(st, x, y, in);
}
flatten_string_free(&fs);
-
- if (cshift && r == 0)
- return 0;
- else if (st->showlinenrs)
- return r + TXT_OFFSET + TEXTXLOC;
- else
- return r + TXT_OFFSET;
}
/************************ cache utilities *****************************/
@@ -672,25 +701,29 @@ int text_get_visible_lines(SpaceText *st, ARegion *ar, const char *str)
start = 0;
end = max;
for (i = 0, j = 0; str[j]; j += BLI_str_utf8_size_safe(str + j)) {
+ int columns = BLI_str_utf8_char_width_safe(str + j); /* = 1 for tab */
+
/* Mimic replacement of tabs */
ch = str[j];
if (ch == '\t') {
chars = st->tabnumber - i % st->tabnumber;
ch = ' ';
}
- else chars = 1;
+ else {
+ chars = 1;
+ }
while (chars--) {
- if (i - start >= max) {
+ if (i + columns - start > max) {
lines++;
- start = end;
+ start = MIN2(end, i);
end += max;
}
else if (ch == ' ' || ch == '-') {
end = i + 1;
}
- i++;
+ i += columns;
}
}
@@ -712,7 +745,9 @@ int text_get_span_wrap(SpaceText *st, ARegion *ar, TextLine *from, TextLine *to)
return ret;
}
- else return txt_get_span(from, to);
+ else {
+ return txt_get_span(from, to);
+ }
}
int text_get_total_lines(SpaceText *st, ARegion *ar)
@@ -927,7 +962,7 @@ static void draw_documentation(SpaceText *st, ARegion *ar)
buf[i] = '\0';
if (lines >= 0) {
y -= st->lheight_dpi;
- text_draw(st, buf, 0, 0, 1, x + 4, y - 3, NULL);
+ text_draw(st, buf, 0, 0, x + 4, y - 3, NULL);
}
i = 0; br = DOC_WIDTH; lines++;
}
@@ -936,7 +971,7 @@ static void draw_documentation(SpaceText *st, ARegion *ar)
buf[br] = '\0';
if (lines >= 0) {
y -= st->lheight_dpi;
- text_draw(st, buf, 0, 0, 1, x + 4, y - 3, NULL);
+ text_draw(st, buf, 0, 0, x + 4, y - 3, NULL);
}
p -= i - br - 1; /* Rewind pointer to last break */
i = 0; br = DOC_WIDTH; lines++;
@@ -955,9 +990,9 @@ static void draw_documentation(SpaceText *st, ARegion *ar)
static void draw_suggestion_list(SpaceText *st, ARegion *ar)
{
SuggItem *item, *first, *last, *sel;
- TextLine *tmp;
- char str[SUGG_LIST_WIDTH + 1];
- int w, boxw = 0, boxh, i, l, x, y, *top;
+ char str[SUGG_LIST_WIDTH * BLI_UTF8_MAX + 1];
+ int offl, offc, vcurl, vcurc;
+ int w, boxw = 0, boxh, i, x, y, *top;
const int lheight = st->lheight_dpi + TXT_LINE_SPACING;
const int margin_x = 2;
@@ -973,24 +1008,24 @@ static void draw_suggestion_list(SpaceText *st, ARegion *ar)
sel = texttool_suggest_selected();
top = texttool_suggest_top();
- /* Count the visible lines to the cursor */
- for (tmp = st->text->curl, l = -st->top; tmp; tmp = tmp->prev, l++) ;
- if (l < 0) return;
-
- if (st->showlinenrs) {
- x = st->cwidth * (st->text->curc - st->left) + TXT_OFFSET + TEXTXLOC - 4;
- }
- else {
- x = st->cwidth * (st->text->curc - st->left) + TXT_OFFSET - 4;
- }
+ wrap_offset(st, ar, st->text->curl, st->text->curc, &offl, &offc);
+ vcurl = txt_get_span(st->text->lines.first, st->text->curl) - st->top + offl;
+ vcurc = text_get_char_pos(st, st->text->curl->line, st->text->curc) - st->left + offc;
+
+ x = st->showlinenrs ? TXT_OFFSET + TEXTXLOC : TXT_OFFSET;
+ x += vcurc * st->cwidth - 4;
+ y = ar->winy - (vcurl + 1) * lheight - 2;
+
/* offset back so the start of the text lines up with the suggestions,
* not essential but makes suggestions easier to follow */
x -= st->cwidth * (st->text->curc - text_find_identifier_start(st->text->curl->line, st->text->curc));
- y = ar->winy - lheight * l - 2;
boxw = SUGG_LIST_WIDTH * st->cwidth + 20;
boxh = SUGG_LIST_SIZE * lheight + 8;
+ if (x + boxw > ar->winx)
+ x = MAX2(0, ar->winx - boxw);
+
/* not needed but stands out nicer */
uiDrawBoxShadow(220, x, y - boxh, x + boxw, y);
@@ -1003,12 +1038,13 @@ static void draw_suggestion_list(SpaceText *st, ARegion *ar)
for (i = 0, item = first; i < *top && item->next; i++, item = item->next) ;
for (i = 0; i < SUGG_LIST_SIZE && item; i++, item = item->next) {
+ int len = txt_utf8_forward_columns(item->name, SUGG_LIST_WIDTH, NULL) - item->name;
y -= lheight;
- BLI_strncpy(str, item->name, SUGG_LIST_WIDTH);
+ BLI_strncpy(str, item->name, len + 1);
- w = BLF_width(mono, str);
+ w = st->cwidth * text_get_char_pos(st, str, len);
if (item == sel) {
UI_ThemeColor(TH_SHADE2);
@@ -1016,7 +1052,7 @@ static void draw_suggestion_list(SpaceText *st, ARegion *ar)
}
format_draw_color(item->type);
- text_draw(st, str, 0, 0, 1, x + margin_x, y - 1, NULL);
+ text_draw(st, str, 0, 0, x + margin_x, y - 1, NULL);
if (item == last) break;
}
@@ -1378,7 +1414,7 @@ void draw_text_main(SpaceText *st, ARegion *ar)
}
else {
/* draw unwrapped text */
- text_draw(st, tmp->line, st->left, ar->winx / st->cwidth, 1, x, y, tmp->format);
+ text_draw(st, tmp->line, st->left, ar->winx / st->cwidth, x, y, tmp->format);
y -= st->lheight_dpi + TXT_LINE_SPACING;
}
@@ -1435,8 +1471,6 @@ void text_scroll_to_cursor(SpaceText *st, ScrArea *sa)
winx = ar->winx;
break;
}
-
- winx -= TXT_SCROLL_WIDTH;
text_update_character_width(st);
@@ -1454,10 +1488,11 @@ void text_scroll_to_cursor(SpaceText *st, ScrArea *sa)
st->left = 0;
}
else {
- x = text_draw(st, text->sell->line, st->left, text->selc, 0, 0, 0, NULL);
+ x = st->cwidth * (text_get_char_pos(st, text->sell->line, text->selc) - st->left);
+ winx -= TXT_OFFSET + (st->showlinenrs ? TEXTXLOC : 0) + TXT_SCROLL_WIDTH;
- if (x == 0 || x > winx)
- st->left = text->curc - 0.5 * winx / st->cwidth;
+ if (x <= 0 || x > winx)
+ st->left += (x - winx / 2) / st->cwidth;
}
if (st->top < 0) st->top = 0;
diff --git a/source/blender/editors/space_text/text_format.c b/source/blender/editors/space_text/text_format.c
index 3c7897200ed..b29c6420d60 100644
--- a/source/blender/editors/space_text/text_format.c
+++ b/source/blender/editors/space_text/text_format.c
@@ -144,7 +144,7 @@ int text_check_format_len(TextLine *line, unsigned int len)
* Fill the string with formatting constant,
* advancing \a str_p and \a fmt_p
*
- * \param len length in bytes
+ * \param len length in bytes of \a fmt_p to fill.
*/
void text_format_fill(const char **str_p, char **fmt_p, const char type, const int len)
{
diff --git a/source/blender/editors/space_text/text_format_lua.c b/source/blender/editors/space_text/text_format_lua.c
index 6c72e043930..f74d1cf8e8b 100644
--- a/source/blender/editors/space_text/text_format_lua.c
+++ b/source/blender/editors/space_text/text_format_lua.c
@@ -237,7 +237,7 @@ static void txtfmt_lua_format_line(SpaceText *st, TextLine *line, const int do_n
}
/* Single line comment */
else if (*str == '-' && *(str + 1) == '-') {
- text_format_fill(&str, &fmt, FMT_TYPE_COMMENT, len - (int)(str - fs.buf));
+ text_format_fill(&str, &fmt, FMT_TYPE_COMMENT, len - (int)(fmt - line->format));
}
else if (*str == '"' || *str == '\'') {
/* Strings */
diff --git a/source/blender/editors/space_text/text_format_osl.c b/source/blender/editors/space_text/text_format_osl.c
index 7d493eb1f62..c95929a720f 100644
--- a/source/blender/editors/space_text/text_format_osl.c
+++ b/source/blender/editors/space_text/text_format_osl.c
@@ -141,10 +141,10 @@ static int txtfmt_osl_find_specialvar(const char *string)
int i, len;
/* OSL shader types */
- if (STR_LITERAL_STARTSWITH(string, "shader", len)) i = len;
- else if (STR_LITERAL_STARTSWITH(string, "surface", len)) i = len;
- else if (STR_LITERAL_STARTSWITH(string, "volume", len)) i = len;
- else if (STR_LITERAL_STARTSWITH(string, "displacement", len)) i = len;
+ if (STR_LITERAL_STARTSWITH(string, "shader", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "surface", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "volume", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "displacement", len)) i = len;
else i = 0;
/* If next source char is an identifier (eg. 'i' in "definate") no match */
@@ -252,7 +252,7 @@ static void txtfmt_osl_format_line(SpaceText *st, TextLine *line, const int do_n
/* Deal with comments first */
if (*str == '/' && *(str + 1) == '/') {
/* fill the remaining line */
- text_format_fill(&str, &fmt, FMT_TYPE_COMMENT, len - (int)(str - fs.buf));
+ text_format_fill(&str, &fmt, FMT_TYPE_COMMENT, len - (int)(fmt - line->format));
}
/* C-Style (multi-line) comments */
else if (*str == '/' && *(str + 1) == '*') {
diff --git a/source/blender/editors/space_text/text_format_py.c b/source/blender/editors/space_text/text_format_py.c
index 902d60dcb3e..9562d57041f 100644
--- a/source/blender/editors/space_text/text_format_py.c
+++ b/source/blender/editors/space_text/text_format_py.c
@@ -233,7 +233,7 @@ static void txtfmt_py_format_line(SpaceText *st, TextLine *line, const int do_ne
/* Deal with comments first */
if (*str == '#') {
/* fill the remaining line */
- text_format_fill(&str, &fmt, FMT_TYPE_COMMENT, len - (int)(str - fs.buf));
+ text_format_fill(&str, &fmt, FMT_TYPE_COMMENT, len - (int)(fmt - line->format));
}
else if (*str == '"' || *str == '\'') {
/* Strings */
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index b45961bff11..cdbb3e7c600 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -72,7 +72,7 @@
/************************ poll ***************************/
-BLI_INLINE int text_pixel_x_to_index(SpaceText *st, const int x)
+BLI_INLINE int text_pixel_x_to_column(SpaceText *st, const int x)
{
/* add half the char width so mouse cursor selection is inbetween letters */
return (x + (st->cwidth / 2)) / st->cwidth;
@@ -278,7 +278,7 @@ static int text_open_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int text_open_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int text_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Text *text = CTX_data_edit_text(C);
char *path = (text && text->name) ? text->name : G.main->name;
@@ -539,7 +539,7 @@ static int text_save_as_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int text_save_as_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int text_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Text *text = CTX_data_edit_text(C);
char *str;
@@ -1011,7 +1011,7 @@ static int text_line_break_exec(bContext *C, wmOperator *UNUSED(op))
text_drawcache_tag_update(st, 0);
// double check tabs/spaces before splitting the line
- curts = setcurr_tab_spaces(text, space);
+ curts = txt_setcurr_tab_spaces(text, space);
txt_split_curline(text);
for (a = 0; a < curts; a++) {
@@ -1407,25 +1407,31 @@ static int text_get_cursor_rel(SpaceText *st, ARegion *ar, TextLine *linein, int
for (i = 0, j = 0; loop; j += BLI_str_utf8_size_safe(linein->line + j)) {
int chars;
+ int columns = BLI_str_utf8_char_width_safe(linein->line + j); /* = 1 for tab */
+
/* Mimic replacement of tabs */
ch = linein->line[j];
if (ch == '\t') {
chars = st->tabnumber - i % st->tabnumber;
ch = ' ';
}
- else chars = 1;
+ else {
+ chars = 1;
+ }
while (chars--) {
- if (rell == 0 && i - start == relc) {
+ if (rell == 0 && i - start <= relc && i + columns - start > relc) {
/* current position could be wrapped to next line */
/* this should be checked when end of current line would be reached */
selc = j;
found = 1;
}
- else if (i - end == relc) {
+ else if (i - end <= relc && i + columns - end > relc) {
curs = j;
}
- if (i - start >= max) {
+ if (i + columns - start > max) {
+ end = MIN2(end, i);
+
if (found) {
/* exact cursor position was found, check if it's */
/* still on needed line (hasn't been wrapped) */
@@ -1441,7 +1447,7 @@ static int text_get_cursor_rel(SpaceText *st, ARegion *ar, TextLine *linein, int
chop = 1;
rell--;
- if (rell == 0 && i - start >= relc) {
+ if (rell == 0 && i + columns - start > relc) {
selc = curs;
loop = 0;
break;
@@ -1458,7 +1464,7 @@ static int text_get_cursor_rel(SpaceText *st, ARegion *ar, TextLine *linein, int
break;
}
- if (rell == 0 && i - start >= relc) {
+ if (rell == 0 && i + columns - start > relc) {
selc = curs;
loop = 0;
break;
@@ -1467,7 +1473,7 @@ static int text_get_cursor_rel(SpaceText *st, ARegion *ar, TextLine *linein, int
endj = j;
chop = 0;
}
- i++;
+ i += columns;
}
}
@@ -1585,20 +1591,26 @@ static void txt_wrap_move_bol(SpaceText *st, ARegion *ar, short sel)
for (i = 0, j = 0; loop; j += BLI_str_utf8_size_safe((*linep)->line + j)) {
int chars;
+ int columns = BLI_str_utf8_char_width_safe((*linep)->line + j); /* = 1 for tab */
+
/* Mimic replacement of tabs */
ch = (*linep)->line[j];
if (ch == '\t') {
chars = st->tabnumber - i % st->tabnumber;
ch = ' ';
}
- else chars = 1;
+ else {
+ chars = 1;
+ }
while (chars--) {
- if (i - start >= max) {
+ if (i + columns - start > max) {
+ end = MIN2(end, i);
+
*charp = endj;
if (j >= oldc) {
- if (ch == '\0') *charp = txt_utf8_index_to_offset((*linep)->line, start);
+ if (ch == '\0') *charp = txt_utf8_column_to_offset((*linep)->line, start);
loop = 0;
break;
}
@@ -1611,7 +1623,7 @@ static void txt_wrap_move_bol(SpaceText *st, ARegion *ar, short sel)
}
else if (ch == ' ' || ch == '-' || ch == '\0') {
if (j >= oldc) {
- *charp = txt_utf8_index_to_offset((*linep)->line, start);
+ *charp = txt_utf8_column_to_offset((*linep)->line, start);
loop = 0;
break;
}
@@ -1620,7 +1632,7 @@ static void txt_wrap_move_bol(SpaceText *st, ARegion *ar, short sel)
endj = j + 1;
chop = 0;
}
- i++;
+ i += columns;
}
}
@@ -1651,16 +1663,22 @@ static void txt_wrap_move_eol(SpaceText *st, ARegion *ar, short sel)
for (i = 0, j = 0; loop; j += BLI_str_utf8_size_safe((*linep)->line + j)) {
int chars;
+ int columns = BLI_str_utf8_char_width_safe((*linep)->line + j); /* = 1 for tab */
+
/* Mimic replacement of tabs */
ch = (*linep)->line[j];
if (ch == '\t') {
chars = st->tabnumber - i % st->tabnumber;
ch = ' ';
}
- else chars = 1;
+ else {
+ chars = 1;
+ }
while (chars--) {
- if (i - start >= max) {
+ if (i + columns - start > max) {
+ end = MIN2(end, i);
+
if (chop) endj = BLI_str_prev_char_utf8((*linep)->line + j) - (*linep)->line;
if (endj >= oldc) {
@@ -1684,7 +1702,7 @@ static void txt_wrap_move_eol(SpaceText *st, ARegion *ar, short sel)
endj = j;
chop = 0;
}
- i++;
+ i += columns;
}
}
@@ -1716,7 +1734,9 @@ static void txt_wrap_move_up(SpaceText *st, ARegion *ar, short sel)
visible_lines = text_get_visible_lines(st, ar, (*linep)->line);
*charp = text_get_cursor_rel(st, ar, *linep, visible_lines - 1, col);
}
- else *charp = 0;
+ else {
+ *charp = 0;
+ }
}
if (!sel) txt_pop_sel(text);
@@ -1745,7 +1765,9 @@ static void txt_wrap_move_down(SpaceText *st, ARegion *ar, short sel)
*linep = (*linep)->next;
*charp = text_get_cursor_rel(st, ar, *linep, 0, col);
}
- else *charp = (*linep)->len;
+ else {
+ *charp = (*linep)->len;
+ }
}
if (!sel) txt_pop_sel(text);
@@ -1927,7 +1949,7 @@ static int text_jump_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int text_jump_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int text_jump_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
return WM_operator_props_dialog_popup(C, op, 10 * UI_UNIT_X, 5 * UI_UNIT_Y);
@@ -2085,7 +2107,7 @@ static int text_scroll_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static void text_scroll_apply(bContext *C, wmOperator *op, wmEvent *event)
+static void text_scroll_apply(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceText *st = CTX_wm_space_text(C);
ARegion *ar = CTX_wm_region(C);
@@ -2142,7 +2164,7 @@ static void scroll_exit(bContext *C, wmOperator *op)
MEM_freeN(op->customdata);
}
-static int text_scroll_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int text_scroll_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
TextScroll *tsc = op->customdata;
SpaceText *st = CTX_wm_space_text(C);
@@ -2182,7 +2204,7 @@ static int text_scroll_cancel(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
-static int text_scroll_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int text_scroll_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceText *st = CTX_wm_space_text(C);
TextScroll *tsc;
@@ -2259,7 +2281,7 @@ static int text_region_scroll_poll(bContext *C)
return 1;
}
-static int text_scroll_bar_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int text_scroll_bar_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceText *st = CTX_wm_space_text(C);
ARegion *ar = CTX_wm_region(C);
@@ -2342,7 +2364,7 @@ typedef struct SetSelection {
short old[2];
} SetSelection;
-static int flatten_len(SpaceText *st, const char *str)
+static int flatten_width(SpaceText *st, const char *str)
{
int i, total = 0;
@@ -2350,20 +2372,30 @@ static int flatten_len(SpaceText *st, const char *str)
if (str[i] == '\t') {
total += st->tabnumber - total % st->tabnumber;
}
- else total++;
+ else {
+ total += BLI_str_utf8_char_width_safe(str + i);
+ }
}
return total;
}
-static int flatten_index_to_offset(SpaceText *st, const char *str, int index)
+static int flatten_column_to_offset(SpaceText *st, const char *str, int index)
{
- int i, j;
- for (i = 0, j = 0; i < index; j += BLI_str_utf8_size_safe(str + j))
+ int i = 0, j = 0, col;
+
+ while (*(str + j)) {
if (str[j] == '\t')
- i += st->tabnumber - i % st->tabnumber;
+ col = st->tabnumber - i % st->tabnumber;
else
- i++;
+ col = BLI_str_utf8_char_width_safe(str + j);
+
+ if (i + col > index)
+ break;
+
+ i += col;
+ j += BLI_str_utf8_size_safe(str + j);
+ }
return j;
}
@@ -2390,7 +2422,7 @@ static TextLine *get_first_visible_line(SpaceText *st, ARegion *ar, int *y)
static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, int y, int sel)
{
Text *text = st->text;
- int max = wrap_width(st, ar); /* view */
+ int max = wrap_width(st, ar); /* column */
int charp = -1; /* mem */
int loop = 1, found = 0; /* flags */
char ch;
@@ -2399,12 +2431,13 @@ static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, in
TextLine *linep = get_first_visible_line(st, ar, &y);
while (loop && linep) {
- int i = 0, start = 0, end = max; /* view */
+ int i = 0, start = 0, end = max; /* column */
int j = 0, curs = 0, endj = 0; /* mem */
int chop = 1; /* flags */
for (; loop; j += BLI_str_utf8_size_safe(linep->line + j)) {
int chars;
+ int columns = BLI_str_utf8_char_width_safe(linep->line + j); /* = 1 for tab */
/* Mimic replacement of tabs */
ch = linep->line[j];
@@ -2412,7 +2445,9 @@ static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, in
chars = st->tabnumber - i % st->tabnumber;
ch = ' ';
}
- else chars = 1;
+ else {
+ chars = 1;
+ }
while (chars--) {
/* Gone too far, go back to last wrap point */
@@ -2422,17 +2457,19 @@ static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, in
break;
/* Exactly at the cursor */
}
- else if (y == 0 && i - start == x) {
+ else if (y == 0 && i - start <= x && i + columns - start > x) {
/* current position could be wrapped to next line */
/* this should be checked when end of current line would be reached */
charp = curs = j;
found = 1;
/* Prepare curs for next wrap */
}
- else if (i - end == x) {
+ else if (i - end <= x && i + columns - end > x) {
curs = j;
}
- if (i - start >= max) {
+ if (i + columns - start > max) {
+ end = MIN2(end, i);
+
if (found) {
/* exact cursor position was found, check if it's */
/* still on needed line (hasn't been wrapped) */
@@ -2449,7 +2486,7 @@ static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, in
y--;
chop = 1;
- if (y == 0 && i - start >= x) {
+ if (y == 0 && i + columns - start > x) {
charp = curs;
loop = 0;
break;
@@ -2461,7 +2498,7 @@ static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, in
break;
}
- if (y == 0 && i - start >= x) {
+ if (y == 0 && i + columns - start > x) {
charp = curs;
loop = 0;
break;
@@ -2470,7 +2507,7 @@ static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, in
endj = j;
chop = 0;
}
- i++;
+ i += columns;
}
if (ch == '\0') break;
@@ -2509,7 +2546,7 @@ static void text_cursor_set_to_pos(SpaceText *st, ARegion *ar, int x, int y, int
else x -= TXT_OFFSET;
if (x < 0) x = 0;
- x = text_pixel_x_to_index(st, x) + st->left;
+ x = text_pixel_x_to_column(st, x) + st->left;
if (st->wordwrap) {
text_cursor_set_to_pos_wrapped(st, ar, x, y, sel);
@@ -2532,14 +2569,14 @@ static void text_cursor_set_to_pos(SpaceText *st, ARegion *ar, int x, int y, int
}
- w = flatten_len(st, (*linep)->line);
- if (x < w) *charp = flatten_index_to_offset(st, (*linep)->line, x);
+ w = flatten_width(st, (*linep)->line);
+ if (x < w) *charp = flatten_column_to_offset(st, (*linep)->line, x);
else *charp = (*linep)->len;
}
if (!sel) txt_pop_sel(text);
}
-static void text_cursor_set_apply(bContext *C, wmOperator *op, wmEvent *event)
+static void text_cursor_set_apply(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceText *st = CTX_wm_space_text(C);
ARegion *ar = CTX_wm_region(C);
@@ -2594,7 +2631,7 @@ static void text_cursor_set_exit(bContext *C, wmOperator *op)
MEM_freeN(ssel);
}
-static int text_set_selection_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int text_set_selection_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceText *st = CTX_wm_space_text(C);
SetSelection *ssel;
@@ -2619,7 +2656,7 @@ static int text_set_selection_invoke(bContext *C, wmOperator *op, wmEvent *event
return OPERATOR_RUNNING_MODAL;
}
-static int text_set_selection_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int text_set_selection_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
switch (event->type) {
case LEFTMOUSE:
@@ -2675,7 +2712,7 @@ static int text_cursor_set_exec(bContext *C, wmOperator *op)
return OPERATOR_PASS_THROUGH;
}
-static int text_cursor_set_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int text_cursor_set_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceText *st = CTX_wm_space_text(C);
@@ -2707,7 +2744,7 @@ void TEXT_OT_cursor_set(wmOperatorType *ot)
/******************* line number operator **********************/
-static int text_line_number_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
+static int text_line_number_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
SpaceText *st = CTX_wm_space_text(C);
Text *text = CTX_data_edit_text(C);
@@ -2797,7 +2834,7 @@ static int text_insert_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int text_insert_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int text_insert_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
int ret;
@@ -3100,7 +3137,7 @@ static int text_resolve_conflict_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
-static int text_resolve_conflict_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int text_resolve_conflict_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Text *text = CTX_data_edit_text(C);
uiPopupMenu *pup;
diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt
index 462619a7e8b..a04371a5ed9 100644
--- a/source/blender/editors/space_view3d/CMakeLists.txt
+++ b/source/blender/editors/space_view3d/CMakeLists.txt
@@ -54,6 +54,7 @@ set(SRC
view3d_iterators.c
view3d_ops.c
view3d_project.c
+ view3d_ruler.c
view3d_select.c
view3d_snap.c
view3d_toolbar.c
diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c
index 2cef10e1981..9000ccbf324 100644
--- a/source/blender/editors/space_view3d/drawmesh.c
+++ b/source/blender/editors/space_view3d/drawmesh.c
@@ -428,7 +428,9 @@ static DMDrawOption draw_tface__set_draw_legacy(MTFace *tface, int has_mcol, int
return DM_DRAW_OPTION_NO_MCOL; /* Don't set color */
}
else if (!has_mcol) {
- if (tface) glColor3f(1.0, 1.0, 1.0);
+ if (tface) {
+ glColor3f(1.0, 1.0, 1.0);
+ }
else {
if (ma) {
float col[3];
@@ -437,7 +439,9 @@ static DMDrawOption draw_tface__set_draw_legacy(MTFace *tface, int has_mcol, int
glColor3fv(col);
}
- else glColor3f(1.0, 1.0, 1.0);
+ else {
+ glColor3f(1.0, 1.0, 1.0);
+ }
}
return DM_DRAW_OPTION_NO_MCOL; /* Don't set color */
}
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 158b75c494a..743b53ce16c 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -615,7 +615,7 @@ static void draw_empty_image(Object *ob, const short dflag, const unsigned char
glColor4fv(ob->col);
/* Draw the Image on the screen */
- glaDrawPixelsTex(ofs_x, ofs_y, ima_x, ima_y, GL_UNSIGNED_BYTE, ibuf->rect);
+ glaDrawPixelsTex(ofs_x, ofs_y, ima_x, ima_y, GL_UNSIGNED_BYTE, GL_LINEAR, ibuf->rect);
glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
glDisable(GL_BLEND);
@@ -812,17 +812,6 @@ void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, int depth_write, floa
}
for (vos = strings->first; vos; vos = vos->next) {
- /* too slow, reading opengl info while drawing is very bad,
- * better to see if we can use the zbuffer while in pixel space - campbell */
-#if 0
- if (v3d->zbuf && (vos->flag & V3D_CACHE_TEXT_ZBUF)) {
- gluProject(vos->vec[0], vos->vec[1], vos->vec[2], mats.modelview, mats.projection, (GLint *)mats.viewport, &ux, &uy, &uz);
- glReadPixels(ar->winrct.xmin + vos->mval[0] + vos->xoffs, ar->winrct.ymin + vos->mval[1], 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
-
- if (uz > depth)
- continue;
- }
-#endif
if (vos->sco[0] != IS_CLIPPED) {
const char *str = (char *)(vos + 1);
@@ -3862,7 +3851,7 @@ static int drawDispList(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *bas
if (v3d->flag2 & V3D_BACKFACE_CULLING) {
/* not all displists use same in/out normal direction convention */
glEnable(GL_CULL_FACE);
- glCullFace((base->object->type == OB_MBALL) ? GL_BACK : GL_FRONT);
+ glCullFace((base->object->type == OB_MBALL || base->object->derivedFinal) ? GL_BACK : GL_FRONT);
}
retval = drawDispList_nobackface(scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
@@ -3968,7 +3957,9 @@ static void draw_particle(ParticleKey *state, int draw_as, short draw, float pix
if (draw_as == PART_DRAW_AXIS) {
copy_v3_v3(vec2, state->co);
}
- else sub_v3_v3v3(vec2, state->co, vec);
+ else {
+ sub_v3_v3v3(vec2, state->co, vec);
+ }
add_v3_v3(vec, state->co);
copy_v3_v3(pdd->vd, vec); pdd->vd += 3;
@@ -3980,7 +3971,9 @@ static void draw_particle(ParticleKey *state, int draw_as, short draw, float pix
if (draw_as == PART_DRAW_AXIS) {
copy_v3_v3(vec2, state->co);
}
- else sub_v3_v3v3(vec2, state->co, vec);
+ else {
+ sub_v3_v3v3(vec2, state->co, vec);
+ }
add_v3_v3(vec, state->co);
@@ -6055,8 +6048,10 @@ static void drawtexspace(Object *ob)
copy_v3_v3(size, mb->size);
copy_v3_v3(loc, mb->loc);
}
- else return;
-
+ else {
+ return;
+ }
+
vec[0][0] = vec[1][0] = vec[2][0] = vec[3][0] = loc[0] - size[0];
vec[4][0] = vec[5][0] = vec[6][0] = vec[7][0] = loc[0] + size[0];
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 57755231240..d332fb9f8b3 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -48,10 +48,12 @@
#include "BKE_object.h"
#include "BKE_screen.h"
+#include "ED_render.h"
#include "ED_space_api.h"
#include "ED_screen.h"
#include "ED_object.h"
+#include "GPU_extensions.h"
#include "GPU_material.h"
#include "BIF_gl.h"
@@ -350,7 +352,7 @@ static void view3d_free(SpaceLink *sl)
/* spacetype; init callback */
-static void view3d_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
+static void view3d_init(wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
{
}
@@ -469,7 +471,22 @@ static void view3d_main_area_init(wmWindowManager *wm, ARegion *ar)
}
-static int view3d_ob_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event))
+static void view3d_main_area_exit(wmWindowManager *UNUSED(wm), ARegion *ar)
+{
+ RegionView3D *rv3d = ar->regiondata;
+
+ if (rv3d->render_engine) {
+ RE_engine_free(rv3d->render_engine);
+ rv3d->render_engine = NULL;
+ }
+
+ if (rv3d->gpuoffscreen) {
+ GPU_offscreen_free(rv3d->gpuoffscreen);
+ rv3d->gpuoffscreen = NULL;
+ }
+}
+
+static int view3d_ob_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
{
if (drag->type == WM_DRAG_ID) {
ID *id = (ID *)drag->poin;
@@ -479,7 +496,7 @@ static int view3d_ob_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSE
return 0;
}
-static int view3d_group_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event))
+static int view3d_group_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
{
if (drag->type == WM_DRAG_ID) {
ID *id = (ID *)drag->poin;
@@ -489,7 +506,7 @@ static int view3d_group_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UN
return 0;
}
-static int view3d_mat_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event))
+static int view3d_mat_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
{
if (drag->type == WM_DRAG_ID) {
ID *id = (ID *)drag->poin;
@@ -499,7 +516,7 @@ static int view3d_mat_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUS
return 0;
}
-static int view3d_ima_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event))
+static int view3d_ima_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
{
if (drag->type == WM_DRAG_ID) {
ID *id = (ID *)drag->poin;
@@ -513,7 +530,7 @@ static int view3d_ima_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUS
return 0;
}
-static int view3d_ima_bg_drop_poll(bContext *C, wmDrag *drag, wmEvent *event)
+static int view3d_ima_bg_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
{
if (event->ctrl)
return false;
@@ -524,7 +541,7 @@ static int view3d_ima_bg_drop_poll(bContext *C, wmDrag *drag, wmEvent *event)
return 0;
}
-static int view3d_ima_empty_drop_poll(bContext *C, wmDrag *drag, wmEvent *event)
+static int view3d_ima_empty_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
{
Base *base = ED_view3d_give_base_under_cursor(C, event->mval);
@@ -535,7 +552,7 @@ static int view3d_ima_empty_drop_poll(bContext *C, wmDrag *drag, wmEvent *event)
return 0;
}
-static int view3d_ima_mesh_drop_poll(bContext *C, wmDrag *drag, wmEvent *event)
+static int view3d_ima_mesh_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
{
Base *base = ED_view3d_give_base_under_cursor(C, event->mval);
@@ -615,6 +632,10 @@ static void view3d_main_area_free(ARegion *ar)
if (rv3d->sms) {
MEM_freeN(rv3d->sms);
}
+ if (rv3d->gpuoffscreen) {
+ GPU_offscreen_free(rv3d->gpuoffscreen);
+ }
+
MEM_freeN(rv3d);
ar->regiondata = NULL;
}
@@ -633,6 +654,7 @@ static void *view3d_main_area_duplicate(void *poin)
new->clipbb = MEM_dupallocN(rv3d->clipbb);
new->depths = NULL;
+ new->gpuoffscreen = NULL;
new->ri = NULL;
new->render_engine = NULL;
new->gpd = NULL;
@@ -1216,6 +1238,7 @@ void ED_spacetype_view3d(void)
art->keymapflag = ED_KEYMAP_GPENCIL;
art->draw = view3d_main_area_draw;
art->init = view3d_main_area_init;
+ art->exit = view3d_main_area_exit;
art->free = view3d_main_area_free;
art->duplicate = view3d_main_area_duplicate;
art->listener = view3d_main_area_listener;
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 4aaa3332252..8fdc9416513 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -219,15 +219,12 @@ void ED_view3d_clipping_enable(void)
}
}
-static int view3d_clipping_test(const float vec[3], float clip[6][4])
+static int view3d_clipping_test(const float co[3], float clip[6][4])
{
- float view[3];
- copy_v3_v3(view, vec);
-
- if (0.0f < clip[0][3] + dot_v3v3(view, clip[0]))
- if (0.0f < clip[1][3] + dot_v3v3(view, clip[1]))
- if (0.0f < clip[2][3] + dot_v3v3(view, clip[2]))
- if (0.0f < clip[3][3] + dot_v3v3(view, clip[3]))
+ if (0.0f < clip[0][3] + dot_v3v3(co, clip[0]))
+ if (0.0f < clip[1][3] + dot_v3v3(co, clip[1]))
+ if (0.0f < clip[2][3] + dot_v3v3(co, clip[2]))
+ if (0.0f < clip[3][3] + dot_v3v3(co, clip[3]))
return 0;
return 1;
@@ -235,9 +232,9 @@ static int view3d_clipping_test(const float vec[3], float clip[6][4])
/* for 'local' ED_view3d_clipping_local must run first
* then all comparisons can be done in localspace */
-int ED_view3d_clipping_test(RegionView3D *rv3d, const float vec[3], const int is_local)
+int ED_view3d_clipping_test(RegionView3D *rv3d, const float co[3], const bool is_local)
{
- return view3d_clipping_test(vec, is_local ? rv3d->clip_local : rv3d->clip);
+ return view3d_clipping_test(co, is_local ? rv3d->clip_local : rv3d->clip);
}
/* ********* end custom clipping *********** */
@@ -971,7 +968,7 @@ static void draw_selected_name(Scene *scene, Object *ob, rcti *rect)
}
static void view3d_camera_border(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d,
- rctf *viewborder_r, short no_shift, short no_zoom)
+ rctf *r_viewborder, const bool no_shift, const bool no_zoom)
{
CameraParams params;
rctf rect_view, rect_camera;
@@ -995,25 +992,25 @@ static void view3d_camera_border(Scene *scene, ARegion *ar, View3D *v3d, RegionV
rect_camera = params.viewplane;
/* get camera border within viewport */
- viewborder_r->xmin = ((rect_camera.xmin - rect_view.xmin) / BLI_rctf_size_x(&rect_view)) * ar->winx;
- viewborder_r->xmax = ((rect_camera.xmax - rect_view.xmin) / BLI_rctf_size_x(&rect_view)) * ar->winx;
- viewborder_r->ymin = ((rect_camera.ymin - rect_view.ymin) / BLI_rctf_size_y(&rect_view)) * ar->winy;
- viewborder_r->ymax = ((rect_camera.ymax - rect_view.ymin) / BLI_rctf_size_y(&rect_view)) * ar->winy;
+ r_viewborder->xmin = ((rect_camera.xmin - rect_view.xmin) / BLI_rctf_size_x(&rect_view)) * ar->winx;
+ r_viewborder->xmax = ((rect_camera.xmax - rect_view.xmin) / BLI_rctf_size_x(&rect_view)) * ar->winx;
+ r_viewborder->ymin = ((rect_camera.ymin - rect_view.ymin) / BLI_rctf_size_y(&rect_view)) * ar->winy;
+ r_viewborder->ymax = ((rect_camera.ymax - rect_view.ymin) / BLI_rctf_size_y(&rect_view)) * ar->winy;
}
-void ED_view3d_calc_camera_border_size(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, float size_r[2])
+void ED_view3d_calc_camera_border_size(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, float r_size[2])
{
rctf viewborder;
view3d_camera_border(scene, ar, v3d, rv3d, &viewborder, TRUE, TRUE);
- size_r[0] = BLI_rctf_size_x(&viewborder);
- size_r[1] = BLI_rctf_size_y(&viewborder);
+ r_size[0] = BLI_rctf_size_x(&viewborder);
+ r_size[1] = BLI_rctf_size_y(&viewborder);
}
void ED_view3d_calc_camera_border(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d,
- rctf *viewborder_r, short no_shift)
+ rctf *viewborder_r, const bool no_shift)
{
- view3d_camera_border(scene, ar, v3d, rv3d, viewborder_r, no_shift, FALSE);
+ view3d_camera_border(scene, ar, v3d, rv3d, viewborder_r, no_shift, false);
}
static void drawviewborder_grid3(float x1, float x2, float y1, float y2, float fac)
@@ -1316,11 +1313,6 @@ static void backdrawview3d(Scene *scene, ARegion *ar, View3D *v3d)
{
/* do nothing */
}
- else if ((base && (base->object->mode & OB_MODE_TEXTURE_PAINT)) &&
- scene->toolsettings && (scene->toolsettings->imapaint.flag & IMAGEPAINT_PROJECT_DISABLE))
- {
- /* do nothing */
- }
else if ((base && (base->object->mode & OB_MODE_PARTICLE_EDIT)) &&
v3d->drawtype > OB_WIRE && (v3d->flag & V3D_ZBUF_SELECT))
{
@@ -1356,7 +1348,35 @@ static void backdrawview3d(Scene *scene, ARegion *ar, View3D *v3d)
if (multisample_enabled)
glDisable(GL_MULTISAMPLE_ARB);
- glScissor(ar->winrct.xmin, ar->winrct.ymin, BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct));
+ if (U.ogl_multisamples != USER_MULTISAMPLE_NONE) {
+ /* for multisample we use an offscreen FBO. multisample drawing can fail
+ * with color coded selection drawing, and reading back depths from such
+ * a buffer can also cause a few seconds freeze on OS X / NVidia. */
+ int w = BLI_rcti_size_x(&ar->winrct);
+ int h = BLI_rcti_size_y(&ar->winrct);
+ char error[256];
+
+ if (rv3d->gpuoffscreen) {
+ if (GPU_offscreen_width(rv3d->gpuoffscreen) != w ||
+ GPU_offscreen_height(rv3d->gpuoffscreen) != h)
+ {
+ GPU_offscreen_free(rv3d->gpuoffscreen);
+ rv3d->gpuoffscreen = NULL;
+ }
+ }
+
+ if (!rv3d->gpuoffscreen) {
+ rv3d->gpuoffscreen = GPU_offscreen_create(w, h, error);
+
+ if (!rv3d->gpuoffscreen)
+ fprintf(stderr, "Failed to create offscreen selection buffer for multisample: %s\n", error);
+ }
+ }
+
+ if (rv3d->gpuoffscreen)
+ GPU_offscreen_bind(rv3d->gpuoffscreen);
+ else
+ glScissor(ar->winrct.xmin, ar->winrct.ymin, BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct));
glClearColor(0.0, 0.0, 0.0, 0.0);
if (v3d->zbuf) {
@@ -1375,9 +1395,13 @@ static void backdrawview3d(Scene *scene, ARegion *ar, View3D *v3d)
if (base && (base->lay & v3d->lay))
draw_object_backbufsel(scene, v3d, rv3d, base->object);
+
+ if (rv3d->gpuoffscreen)
+ GPU_offscreen_unbind(rv3d->gpuoffscreen);
+ else
+ ar->swap = 0; /* mark invalid backbuf for wm draw */
v3d->flag &= ~V3D_INVALID_BACKBUF;
- ar->swap = 0; /* mark invalid backbuf for wm draw */
G.f &= ~G_BACKBUFSEL;
v3d->zbuf = FALSE;
@@ -1394,6 +1418,21 @@ static void backdrawview3d(Scene *scene, ARegion *ar, View3D *v3d)
}
+void view3d_opengl_read_pixels(ARegion *ar, int x, int y, int w, int h, int format, int type, void *data)
+{
+ RegionView3D *rv3d = ar->regiondata;
+
+ if (rv3d->gpuoffscreen) {
+ GPU_offscreen_bind(rv3d->gpuoffscreen);
+ glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
+ glReadPixels(x, y, w, h, format, type, data);
+ GPU_offscreen_unbind(rv3d->gpuoffscreen);
+ }
+ else {
+ glReadPixels(ar->winrct.xmin + x, ar->winrct.ymin + y, w, h, format, type, data);
+ }
+}
+
void view3d_validate_backbuf(ViewContext *vc)
{
if (vc->v3d->flag & V3D_INVALID_BACKBUF)
@@ -1409,12 +1448,9 @@ unsigned int view3d_sample_backbuf(ViewContext *vc, int x, int y)
return 0;
}
- x += vc->ar->winrct.xmin;
- y += vc->ar->winrct.ymin;
-
view3d_validate_backbuf(vc);
- glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
+ view3d_opengl_read_pixels(vc->ar, x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
glReadBuffer(GL_BACK);
if (ENDIAN_ORDER == B_ENDIAN) {
@@ -1445,8 +1481,8 @@ ImBuf *view3d_read_backbuf(ViewContext *vc, short xmin, short ymin, short xmax,
view3d_validate_backbuf(vc);
- glReadPixels(vc->ar->winrct.xmin + xminc,
- vc->ar->winrct.ymin + yminc,
+ view3d_opengl_read_pixels(vc->ar,
+ xminc, yminc,
(xmaxc - xminc + 1),
(ymaxc - yminc + 1),
GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
@@ -1573,7 +1609,7 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
float fac, asp, zoomx, zoomy;
float x1, y1, x2, y2;
- ImBuf *ibuf = NULL, *freeibuf;
+ ImBuf *ibuf = NULL, *freeibuf, *releaseibuf;
Image *ima;
MovieClip *clip;
@@ -1583,6 +1619,7 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
continue;
freeibuf = NULL;
+ releaseibuf = NULL;
if (bgpic->source == V3D_BGPIC_IMAGE) {
ima = bgpic->ima;
if (ima == NULL)
@@ -1593,7 +1630,7 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
}
else {
ibuf = BKE_image_acquire_ibuf(ima, &bgpic->iuser, NULL);
- freeibuf = ibuf;
+ releaseibuf = ibuf;
}
image_aspect[0] = ima->aspx;
@@ -1608,7 +1645,9 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
if (scene->camera)
clip = BKE_object_movieclip_get(scene, scene->camera, 1);
}
- else clip = bgpic->clip;
+ else {
+ clip = bgpic->clip;
+ }
if (clip == NULL)
continue;
@@ -1636,6 +1675,8 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
if ((ibuf->rect == NULL && ibuf->rect_float == NULL) || ibuf->channels != 4) { /* invalid image format */
if (freeibuf)
IMB_freeImBuf(freeibuf);
+ if (releaseibuf)
+ BKE_image_release_ibuf(ima, releaseibuf, NULL);
continue;
}
@@ -1708,10 +1749,12 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
float tvec[3];
float sco[2];
const float mval_f[2] = {1.0f, 0.0f};
+ const float co_zero[3] = {0};
+ float zfac;
/* calc window coord */
- initgrabz(rv3d, 0.0, 0.0, 0.0);
- ED_view3d_win_to_delta(ar, mval_f, tvec);
+ zfac = ED_view3d_calc_zfac(rv3d, co_zero, NULL);
+ ED_view3d_win_to_delta(ar, mval_f, tvec, zfac);
fac = max_ff(fabsf(tvec[0]), max_ff(fabsf(tvec[1]), fabsf(tvec[2]))); /* largest abs axis */
fac = 1.0f / fac;
@@ -1731,6 +1774,8 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
if (x2 < 0 || y2 < 0 || x1 > ar->winx || y1 > ar->winy) {
if (freeibuf)
IMB_freeImBuf(freeibuf);
+ if (releaseibuf)
+ BKE_image_release_ibuf(ima, releaseibuf, NULL);
continue;
}
@@ -1774,7 +1819,7 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
glPixelZoom(zoomx, zoomy);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f - bgpic->blend);
- glaDrawPixelsTex(x1, y1, ibuf->x, ibuf->y, GL_UNSIGNED_BYTE, ibuf->rect);
+ glaDrawPixelsAuto(x1, y1, ibuf->x, ibuf->y, GL_UNSIGNED_BYTE, GL_LINEAR, ibuf->rect);
glPixelZoom(1.0, 1.0);
glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
@@ -1789,9 +1834,10 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
glDepthMask(1);
if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
- if (freeibuf) {
+ if (freeibuf)
IMB_freeImBuf(freeibuf);
- }
+ if (releaseibuf)
+ BKE_image_release_ibuf(ima, releaseibuf, NULL);
}
}
}
@@ -2102,7 +2148,7 @@ void view3d_update_depths_rect(ARegion *ar, ViewDepths *d, rcti *rect)
}
if (d->damaged) {
- glReadPixels(ar->winrct.xmin + d->x, ar->winrct.ymin + d->y, d->w, d->h, GL_DEPTH_COMPONENT, GL_FLOAT, d->depths);
+ view3d_opengl_read_pixels(ar, d->x, d->y, d->w, d->h, GL_DEPTH_COMPONENT, GL_FLOAT, d->depths);
glGetDoublev(GL_DEPTH_RANGE, d->depth_range);
d->damaged = FALSE;
}
@@ -2130,9 +2176,7 @@ void ED_view3d_depth_update(ARegion *ar)
}
if (d->damaged) {
- glReadPixels(ar->winrct.xmin, ar->winrct.ymin, d->w, d->h,
- GL_DEPTH_COMPONENT, GL_FLOAT, d->depths);
-
+ view3d_opengl_read_pixels(ar, 0, 0, d->w, d->h, GL_DEPTH_COMPONENT, GL_FLOAT, d->depths);
glGetDoublev(GL_DEPTH_RANGE, d->depth_range);
d->damaged = 0;
@@ -2999,7 +3043,7 @@ static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar)
#define VIEWGRAD_RES_Y 16
GLubyte grid_col[VIEWGRAD_RES_X][VIEWGRAD_RES_Y][4];
- static float grid_pos[VIEWGRAD_RES_X][VIEWGRAD_RES_Y][2];
+ static float grid_pos[VIEWGRAD_RES_X][VIEWGRAD_RES_Y][3];
static GLushort indices[VIEWGRAD_RES_X - 1][VIEWGRAD_RES_X - 1][4];
static char buf_calculated = FALSE;
@@ -3008,8 +3052,6 @@ static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar)
IMB_colormanagement_pixel_to_display_space_v3(col_zen, &scene->world->zenr, &scene->view_settings,
&scene->display_settings);
- glClear(GL_DEPTH_BUFFER_BIT);
-
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
@@ -3029,6 +3071,7 @@ static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar)
/* -1..1 range */
grid_pos[x][y][0] = (xf - 0.5f) * 2.0f;
grid_pos[x][y][1] = (yf - 0.5f) * 2.0f;
+ grid_pos[x][y][2] = 1.0;
}
}
@@ -3082,15 +3125,22 @@ static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar)
}
}
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_ALWAYS);
+
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
- glVertexPointer(2, GL_FLOAT, 0, grid_pos);
+ glVertexPointer(3, GL_FLOAT, 0, grid_pos);
glColorPointer(4, GL_UNSIGNED_BYTE, 0, grid_col);
glDrawElements(GL_QUADS, (VIEWGRAD_RES_X - 1) * (VIEWGRAD_RES_Y - 1) * 4, GL_UNSIGNED_SHORT, indices);
+
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
+ glDepthFunc(GL_LEQUAL);
+ glDisable(GL_DEPTH_TEST);
+
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
@@ -3112,9 +3162,6 @@ static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar)
}
else {
if (UI_GetThemeValue(TH_SHOW_BACK_GRAD)) {
- /* only clear depth buffer here */
- glClear(GL_DEPTH_BUFFER_BIT);
-
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
@@ -3122,17 +3169,22 @@ static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar)
glPushMatrix();
glLoadIdentity();
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_ALWAYS);
glShadeModel(GL_SMOOTH);
glBegin(GL_QUADS);
UI_ThemeColor(TH_LOW_GRAD);
- glVertex2f(-1.0, -1.0);
- glVertex2f(1.0, -1.0);
+ glVertex3f(-1.0, -1.0, 1.0);
+ glVertex3f(1.0, -1.0, 1.0);
UI_ThemeColor(TH_HIGH_GRAD);
- glVertex2f(1.0, 1.0);
- glVertex2f(-1.0, 1.0);
+ 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);
+
glMatrixMode(GL_PROJECTION);
glPopMatrix();
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 5f54f0dcfc8..8c8332075a2 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -368,6 +368,7 @@ typedef struct ViewOpsData {
float reverse, dist0, camzoom0;
float grid, far;
short axis_snap; /* view rotate only */
+ float zfac;
/* use for orbit selection and auto-dist */
float ofs[3], dyn_ofs[3];
@@ -407,7 +408,7 @@ static void calctrackballvec(const rcti *rect, int mx, int my, float vec[3])
}
-static void viewops_data_create(bContext *C, wmOperator *op, wmEvent *event)
+static void viewops_data_create(bContext *C, wmOperator *op, const wmEvent *event)
{
static float lastofs[3] = {0, 0, 0};
RegionView3D *rv3d;
@@ -504,7 +505,11 @@ static void viewops_data_create(bContext *C, wmOperator *op, wmEvent *event)
calctrackballvec(&vod->ar->winrct, event->x, event->y, vod->trackvec);
- initgrabz(rv3d, -rv3d->ofs[0], -rv3d->ofs[1], -rv3d->ofs[2]);
+ {
+ float tvec[3];
+ negate_v3_v3(tvec, rv3d->ofs);
+ vod->zfac = ED_view3d_calc_zfac(rv3d, tvec, NULL);
+ }
vod->reverse = 1.0f;
if (rv3d->persmat[2][1] < 0.0f)
@@ -836,7 +841,7 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y)
ED_region_tag_redraw(vod->ar);
}
-static int viewrotate_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewOpsData *vod = op->customdata;
short event_code = VIEW_PASS;
@@ -885,7 +890,7 @@ static int viewrotate_modal(bContext *C, wmOperator *op, wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
-static int viewrotate_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewOpsData *vod;
RegionView3D *rv3d;
@@ -1092,7 +1097,7 @@ static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof, RegionView3D
* -- zooming
* -- panning in rotationally-locked views
*/
-static int ndof_orbit_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (event->type != NDOF_MOTION)
@@ -1174,7 +1179,7 @@ void VIEW3D_OT_ndof_orbit(struct wmOperatorType *ot)
}
-static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (event->type != NDOF_MOTION)
@@ -1272,7 +1277,7 @@ void VIEW3D_OT_ndof_orbit_zoom(struct wmOperatorType *ot)
/* -- "pan" navigation
* -- zoom or dolly?
*/
-static int ndof_pan_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
+static int ndof_pan_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
if (event->type != NDOF_MOTION)
return OPERATOR_CANCELLED;
@@ -1366,7 +1371,7 @@ void VIEW3D_OT_ndof_pan(struct wmOperatorType *ot)
/*
* this is basically just the pan only code + the rotate only code crammed into one function that does both
*/
-static int ndof_all_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int ndof_all_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (event->type != NDOF_MOTION) {
return OPERATOR_CANCELLED;
@@ -1508,7 +1513,7 @@ static void viewmove_apply(ViewOpsData *vod, int x, int y)
mval_f[0] = x - vod->oldx;
mval_f[1] = y - vod->oldy;
- ED_view3d_win_to_delta(vod->ar, mval_f, dvec);
+ ED_view3d_win_to_delta(vod->ar, mval_f, dvec, vod->zfac);
add_v3_v3(vod->rv3d->ofs, dvec);
@@ -1525,7 +1530,7 @@ static void viewmove_apply(ViewOpsData *vod, int x, int y)
}
-static int viewmove_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int viewmove_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewOpsData *vod = op->customdata;
@@ -1568,7 +1573,7 @@ static int viewmove_modal(bContext *C, wmOperator *op, wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
-static int viewmove_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewOpsData *vod;
@@ -1665,15 +1670,16 @@ static void view_zoom_mouseloc(ARegion *ar, float dfac, int mx, int my)
float tpos[3];
float mval_f[2];
float new_dist;
+ float zfac;
negate_v3_v3(tpos, rv3d->ofs);
- /* Project cursor position into 3D space */
- initgrabz(rv3d, tpos[0], tpos[1], tpos[2]);
-
mval_f[0] = (float)(((mx - ar->winrct.xmin) * 2) - ar->winx) / 2.0f;
mval_f[1] = (float)(((my - ar->winrct.ymin) * 2) - ar->winy) / 2.0f;
- ED_view3d_win_to_delta(ar, mval_f, dvec);
+
+ /* Project cursor position into 3D space */
+ zfac = ED_view3d_calc_zfac(rv3d, tpos, NULL);
+ ED_view3d_win_to_delta(ar, mval_f, dvec, zfac);
/* Calculate view target position for dolly */
add_v3_v3v3(tvec, tpos, dvec);
@@ -1788,7 +1794,7 @@ static void viewzoom_apply(ViewOpsData *vod, const int x, const int y, const sho
}
-static int viewzoom_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewOpsData *vod = op->customdata;
short event_code = VIEW_PASS;
@@ -1933,7 +1939,7 @@ void viewdolly_modal_keymap(wmKeyConfig *keyconf)
}
/* viewdolly_invoke() copied this function, changes here may apply there */
-static int viewzoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewOpsData *vod;
@@ -2053,7 +2059,7 @@ static void viewdolly_apply(ViewOpsData *vod, int x, int y, const short zoom_inv
}
-static int viewdolly_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int viewdolly_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewOpsData *vod = op->customdata;
short event_code = VIEW_PASS;
@@ -2145,7 +2151,7 @@ static int viewdolly_exec(bContext *C, wmOperator *op)
}
/* copied from viewzoom_invoke(), changes here may apply there */
-static int viewdolly_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewOpsData *vod;
@@ -2957,14 +2963,20 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
}
else {
float mval_f[2];
+ float zfac;
+
/* We cant use the depth, fallback to the old way that dosnt set the center depth */
copy_v3_v3(new_ofs, rv3d->ofs);
- initgrabz(rv3d, -new_ofs[0], -new_ofs[1], -new_ofs[2]);
+ {
+ float tvec[3];
+ negate_v3_v3(tvec, new_ofs);
+ zfac = ED_view3d_calc_zfac(rv3d, tvec, NULL);
+ }
mval_f[0] = (rect.xmin + rect.xmax - vb[0]) / 2.0f;
mval_f[1] = (rect.ymin + rect.ymax - vb[1]) / 2.0f;
- ED_view3d_win_to_delta(ar, mval_f, dvec);
+ ED_view3d_win_to_delta(ar, mval_f, dvec, zfac);
/* center the view to the center of the rectangle */
sub_v3_v3(new_ofs, dvec);
}
@@ -2997,7 +3009,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int view3d_zoom_border_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int view3d_zoom_border_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
View3D *v3d = CTX_wm_view3d(C);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
@@ -3415,16 +3427,19 @@ static int viewpan_exec(bContext *C, wmOperator *op)
ARegion *ar = CTX_wm_region(C);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
float vec[3];
+ const float co_zero[3] = {0.0f};
float mval_f[2] = {0.0f, 0.0f};
+ float zfac;
int pandir;
pandir = RNA_enum_get(op->ptr, "type");
- initgrabz(rv3d, 0.0, 0.0, 0.0);
- if (pandir == V3D_VIEW_PANRIGHT) { mval_f[0] = -32.0f; ED_view3d_win_to_delta(ar, mval_f, vec); }
- else if (pandir == V3D_VIEW_PANLEFT) { mval_f[0] = 32.0f; ED_view3d_win_to_delta(ar, mval_f, vec); }
- else if (pandir == V3D_VIEW_PANUP) { mval_f[1] = -25.0f; ED_view3d_win_to_delta(ar, mval_f, vec); }
- else if (pandir == V3D_VIEW_PANDOWN) { mval_f[1] = 25.0f; ED_view3d_win_to_delta(ar, mval_f, vec); }
+ zfac = ED_view3d_calc_zfac(rv3d, co_zero, NULL);
+ if (pandir == V3D_VIEW_PANRIGHT) { mval_f[0] = -32.0f; }
+ else if (pandir == V3D_VIEW_PANLEFT) { mval_f[0] = 32.0f; }
+ else if (pandir == V3D_VIEW_PANUP) { mval_f[1] = -25.0f; }
+ else if (pandir == V3D_VIEW_PANDOWN) { mval_f[1] = 25.0f; }
+ ED_view3d_win_to_delta(ar, mval_f, vec, zfac);
add_v3_v3(rv3d->ofs, vec);
if (rv3d->viewlock & RV3D_BOXVIEW)
@@ -3506,7 +3521,7 @@ static int background_image_add_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-static int background_image_add_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int background_image_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
View3D *v3d = CTX_wm_view3d(C);
Image *ima = NULL;
@@ -3661,7 +3676,7 @@ static int view3d_clipping_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int view3d_clipping_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int view3d_clipping_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
RegionView3D *rv3d = CTX_wm_region_view3d(C);
ARegion *ar = CTX_wm_region(C);
@@ -3713,15 +3728,16 @@ void ED_view3d_cursor3d_position(bContext *C, float fp[3], const int mval[2])
View3D *v3d = CTX_wm_view3d(C);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
float mval_fl[2];
- int flip;
+ float zfac;
+ bool flip;
- flip = initgrabz(rv3d, fp[0], fp[1], fp[2]);
+ zfac = ED_view3d_calc_zfac(rv3d, fp, &flip);
/* reset the depth based on the view offset (we _know_ the offset is infront of us) */
if (flip) {
negate_v3_v3(fp, rv3d->ofs);
/* re initialize, no need to check flip again */
- /* flip = */ initgrabz(rv3d, fp[0], fp[1], fp[2]);
+ zfac = ED_view3d_calc_zfac(rv3d, fp, NULL /* &flip */ );
}
if (ED_view3d_project_float_global(ar, fp, mval_fl, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
@@ -3736,17 +3752,17 @@ void ED_view3d_cursor3d_position(bContext *C, float fp[3], const int mval[2])
if (depth_used == FALSE) {
float dvec[3];
VECSUB2D(mval_fl, mval_fl, mval);
- ED_view3d_win_to_delta(ar, mval_fl, dvec);
+ ED_view3d_win_to_delta(ar, mval_fl, dvec, zfac);
sub_v3_v3(fp, dvec);
}
}
else {
- const float dx = ((float)(mval[0] - (ar->winx / 2))) * rv3d->zfac / (ar->winx / 2);
- const float dy = ((float)(mval[1] - (ar->winy / 2))) * rv3d->zfac / (ar->winy / 2);
+ const float dx = ((float)(mval[0] - (ar->winx / 2))) * zfac / (ar->winx / 2);
+ const float dy = ((float)(mval[1] - (ar->winy / 2))) * zfac / (ar->winy / 2);
const float fz = (rv3d->persmat[0][3] * fp[0] +
rv3d->persmat[1][3] * fp[1] +
rv3d->persmat[2][3] * fp[2] +
- rv3d->persmat[3][3]) / rv3d->zfac;
+ rv3d->persmat[3][3]) / zfac;
fp[0] = (rv3d->persinv[0][0] * dx + rv3d->persinv[1][0] * dy + rv3d->persinv[2][0] * fz) - rv3d->ofs[0];
fp[1] = (rv3d->persinv[0][1] * dx + rv3d->persinv[1][1] * dy + rv3d->persinv[2][1] * fz) - rv3d->ofs[1];
@@ -3755,7 +3771,7 @@ void ED_view3d_cursor3d_position(bContext *C, float fp[3], const int mval[2])
}
-static int view3d_cursor3d_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
+static int view3d_cursor3d_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
@@ -3794,7 +3810,7 @@ void VIEW3D_OT_cursor3d(wmOperatorType *ot)
/* ***************** manipulator op ******************* */
-static int manipulator_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int manipulator_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
View3D *v3d = CTX_wm_view3d(C);
@@ -3830,7 +3846,7 @@ void VIEW3D_OT_manipulator(wmOperatorType *ot)
Transform_Properties(ot, P_CONSTRAINT);
}
-static int enable_manipulator_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int enable_manipulator_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
View3D *v3d = CTX_wm_view3d(C);
diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c
index c2e75a1c5d9..700027d62a2 100644
--- a/source/blender/editors/space_view3d/view3d_fly.c
+++ b/source/blender/editors/space_view3d/view3d_fly.c
@@ -272,7 +272,7 @@ static void drawFlyPixel(const struct bContext *UNUSED(C), ARegion *UNUSED(ar),
#define FLY_CANCEL 1
#define FLY_CONFIRM 2
-static int initFlyInfo(bContext *C, FlyInfo *fly, wmOperator *op, wmEvent *event)
+static int initFlyInfo(bContext *C, FlyInfo *fly, wmOperator *op, const wmEvent *event)
{
wmWindow *win = CTX_wm_window(C);
float upvec[3]; /* tmp */
@@ -486,7 +486,7 @@ static int flyEnd(bContext *C, FlyInfo *fly)
return OPERATOR_CANCELLED;
}
-static void flyEvent(FlyInfo *fly, wmEvent *event)
+static void flyEvent(FlyInfo *fly, const wmEvent *event)
{
if (event->type == TIMER && event->customdata == fly->timer) {
fly->redraw = 1;
@@ -1179,7 +1179,7 @@ static int flyApply_ndof(bContext *C, FlyInfo *fly)
return OPERATOR_FINISHED;
}
-static int fly_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int fly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
RegionView3D *rv3d = CTX_wm_region_view3d(C);
FlyInfo *fly;
@@ -1214,7 +1214,7 @@ static int fly_cancel(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
-static int fly_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int fly_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
int exit_code;
short do_draw = FALSE;
diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c
index e078fa8eda1..430ed8698d7 100644
--- a/source/blender/editors/space_view3d/view3d_header.c
+++ b/source/blender/editors/space_view3d/view3d_header.c
@@ -28,7 +28,6 @@
* \ingroup spview3d
*/
-
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
@@ -37,8 +36,6 @@
#include "DNA_object_types.h"
#include "DNA_mesh_types.h"
-#include "RNA_access.h"
-
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
@@ -57,18 +54,19 @@
#include "BKE_screen.h"
#include "BKE_tessmesh.h"
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
#include "ED_mesh.h"
#include "ED_util.h"
#include "ED_screen.h"
#include "ED_transform.h"
#include "ED_types.h"
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "RNA_define.h"
-#include "RNA_enum_types.h"
-
#include "UI_interface.h"
#include "UI_resources.h"
@@ -209,7 +207,7 @@ static int view3d_layers_exec(bContext *C, wmOperator *op)
/* applies shift and alt, lazy coding or ok? :) */
/* the local per-keymap-entry keymap will solve it */
-static int view3d_layers_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int view3d_layers_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (event->ctrl || event->oskey)
return OPERATOR_PASS_THROUGH;
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index d4cfa9076a6..26ed8e1885c 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -108,6 +108,9 @@ float ndof_to_axis_angle(const struct wmNDOFMotionData *ndof, float axis[3]);
void view3d_keymap(struct wmKeyConfig *keyconf);
void VIEW3D_OT_fly(struct wmOperatorType *ot);
+/* view3d_ruler.c */
+void VIEW3D_OT_ruler(struct wmOperatorType *ot);
+
/* drawanim.c */
void draw_motion_paths_init(View3D *v3d, struct ARegion *ar);
void draw_motion_path_instance(Scene *scene,
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index bf1c5404c0e..e567ebda4b7 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -166,6 +166,7 @@ void view3d_operatortypes(void)
WM_operatortype_append(VIEW3D_OT_localview);
WM_operatortype_append(VIEW3D_OT_game_start);
WM_operatortype_append(VIEW3D_OT_fly);
+ WM_operatortype_append(VIEW3D_OT_ruler);
WM_operatortype_append(VIEW3D_OT_layers);
WM_operatortype_append(VIEW3D_OT_copybuffer);
WM_operatortype_append(VIEW3D_OT_pastebuffer);
diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c
index bc1656ff7c6..30a100283cc 100644
--- a/source/blender/editors/space_view3d/view3d_project.c
+++ b/source/blender/editors/space_view3d/view3d_project.c
@@ -73,7 +73,7 @@ void ED_view3d_project_float_v2_m4(const ARegion *ar, const float co[3], float r
/**
* \note use #ED_view3d_ob_project_mat_get to get projecting mat
*/
-void ED_view3d_project_float_v3_m4(ARegion *ar, const float vec[3], float r_co[3], float mat[4][4])
+void ED_view3d_project_float_v3_m4(const ARegion *ar, const float vec[3], float r_co[3], float mat[4][4])
{
float vec4[4];
@@ -97,7 +97,7 @@ void ED_view3d_project_float_v3_m4(ARegion *ar, const float vec[3], float r_co[3
/* Clipping Projection Functions
* ***************************** */
-eV3DProjStatus ED_view3d_project_base(struct ARegion *ar, struct Base *base)
+eV3DProjStatus ED_view3d_project_base(const struct ARegion *ar, struct Base *base)
{
eV3DProjStatus ret = ED_view3d_project_short_global(ar, base->object->obmat[3], &base->sx, V3D_PROJ_TEST_CLIP_DEFAULT);
@@ -113,8 +113,8 @@ eV3DProjStatus ED_view3d_project_base(struct ARegion *ar, struct Base *base)
* - 'rv3d->perspmat', is_local == FALSE
* - 'rv3d->persmatob', is_local == TRUE
*/
-static eV3DProjStatus ed_view3d_project__internal(ARegion *ar,
- float perspmat[4][4], const int is_local, /* normally hidden */
+static eV3DProjStatus ed_view3d_project__internal(const ARegion *ar,
+ float perspmat[4][4], const bool is_local, /* normally hidden */
const float co[3], float r_co[2], const eV3DProjTest flag)
{
float vec4[4];
@@ -171,7 +171,7 @@ static eV3DProjStatus ed_view3d_project__internal(ARegion *ar,
return V3D_PROJ_RET_OK;
}
-eV3DProjStatus ED_view3d_project_short_ex(ARegion *ar, float perspmat[4][4], const int is_local,
+eV3DProjStatus ED_view3d_project_short_ex(const ARegion *ar, float perspmat[4][4], const bool is_local,
const float co[3], short r_co[2], const eV3DProjTest flag)
{
float tvec[2];
@@ -190,7 +190,7 @@ eV3DProjStatus ED_view3d_project_short_ex(ARegion *ar, float perspmat[4][4], con
return ret;
}
-eV3DProjStatus ED_view3d_project_int_ex(ARegion *ar, float perspmat[4][4], const int is_local,
+eV3DProjStatus ED_view3d_project_int_ex(const ARegion *ar, float perspmat[4][4], const bool is_local,
const float co[3], int r_co[2], const eV3DProjTest flag)
{
float tvec[2];
@@ -209,7 +209,7 @@ eV3DProjStatus ED_view3d_project_int_ex(ARegion *ar, float perspmat[4][4], const
return ret;
}
-eV3DProjStatus ED_view3d_project_float_ex(ARegion *ar, float perspmat[4][4], const int is_local,
+eV3DProjStatus ED_view3d_project_float_ex(const ARegion *ar, float perspmat[4][4], const bool is_local,
const float co[3], float r_co[2], const eV3DProjTest flag)
{
float tvec[2];
@@ -228,39 +228,39 @@ eV3DProjStatus ED_view3d_project_float_ex(ARegion *ar, float perspmat[4][4], con
}
/* --- short --- */
-eV3DProjStatus ED_view3d_project_short_global(ARegion *ar, const float co[3], short r_co[2], const eV3DProjTest flag)
+eV3DProjStatus ED_view3d_project_short_global(const ARegion *ar, const float co[3], short r_co[2], const eV3DProjTest flag)
{
RegionView3D *rv3d = ar->regiondata;
return ED_view3d_project_short_ex(ar, rv3d->persmat, FALSE, co, r_co, flag);
}
/* object space, use ED_view3d_init_mats_rv3d before calling */
-eV3DProjStatus ED_view3d_project_short_object(ARegion *ar, const float co[3], short r_co[2], const eV3DProjTest flag)
+eV3DProjStatus ED_view3d_project_short_object(const ARegion *ar, const float co[3], short r_co[2], const eV3DProjTest flag)
{
RegionView3D *rv3d = ar->regiondata;
return ED_view3d_project_short_ex(ar, rv3d->persmatob, TRUE, co, r_co, flag);
}
/* --- int --- */
-eV3DProjStatus ED_view3d_project_int_global(ARegion *ar, const float co[3], int r_co[2], const eV3DProjTest flag)
+eV3DProjStatus ED_view3d_project_int_global(const ARegion *ar, const float co[3], int r_co[2], const eV3DProjTest flag)
{
RegionView3D *rv3d = ar->regiondata;
return ED_view3d_project_int_ex(ar, rv3d->persmat, FALSE, co, r_co, flag);
}
/* object space, use ED_view3d_init_mats_rv3d before calling */
-eV3DProjStatus ED_view3d_project_int_object(ARegion *ar, const float co[3], int r_co[2], const eV3DProjTest flag)
+eV3DProjStatus ED_view3d_project_int_object(const ARegion *ar, const float co[3], int r_co[2], const eV3DProjTest flag)
{
RegionView3D *rv3d = ar->regiondata;
return ED_view3d_project_int_ex(ar, rv3d->persmatob, TRUE, co, r_co, flag);
}
/* --- float --- */
-eV3DProjStatus ED_view3d_project_float_global(ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag)
+eV3DProjStatus ED_view3d_project_float_global(const ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag)
{
RegionView3D *rv3d = ar->regiondata;
return ED_view3d_project_float_ex(ar, rv3d->persmat, FALSE, co, r_co, flag);
}
/* object space, use ED_view3d_init_mats_rv3d before calling */
-eV3DProjStatus ED_view3d_project_float_object(ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag)
+eV3DProjStatus ED_view3d_project_float_object(const ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag)
{
RegionView3D *rv3d = ar->regiondata;
return ED_view3d_project_float_ex(ar, rv3d->persmatob, TRUE, co, r_co, flag);
@@ -271,28 +271,30 @@ eV3DProjStatus ED_view3d_project_float_object(ARegion *ar, const float co[3], fl
/* More Generic Window/Ray/Vector projection functions
* *************************************************** */
-/* odd function, need to document better */
-int initgrabz(RegionView3D *rv3d, float x, float y, float z)
+/**
+ * Caculate a depth value from \a co, use with #ED_view3d_win_to_delta
+ */
+float ED_view3d_calc_zfac(const RegionView3D *rv3d, const float co[3], bool *r_flip)
{
- int flip = FALSE;
- if (rv3d == NULL) return flip;
- rv3d->zfac = rv3d->persmat[0][3] * x + rv3d->persmat[1][3] * y + rv3d->persmat[2][3] * z + rv3d->persmat[3][3];
- if (rv3d->zfac < 0.0f)
- flip = TRUE;
+ float zfac = mul_project_m4_v3_zfac((float (*)[4])rv3d->persmat, co);
+
+ if (r_flip) {
+ *r_flip = (zfac < 0.0f);
+ }
+
/* if x,y,z is exactly the viewport offset, zfac is 0 and we don't want that
- * (accounting for near zero values)
- */
- if (rv3d->zfac < 1.e-6f && rv3d->zfac > -1.e-6f) rv3d->zfac = 1.0f;
+ * (accounting for near zero values) */
+ if (zfac < 1.e-6f && zfac > -1.e-6f) {
+ zfac = 1.0f;
+ }
/* Negative zfac means x, y, z was behind the camera (in perspective).
- * This gives flipped directions, so revert back to ok default case.
- */
- /* NOTE: I've changed this to flip zfac to be positive again for now so that GPencil draws ok
- * Aligorith, 2009Aug31 */
- //if (rv3d->zfac < 0.0f) rv3d->zfac = 1.0f;
- if (rv3d->zfac < 0.0f) rv3d->zfac = -rv3d->zfac;
-
- return flip;
+ * This gives flipped directions, so revert back to ok default case. */
+ if (zfac < 0.0f) {
+ zfac = -zfac;
+ }
+
+ return zfac;
}
/**
@@ -306,7 +308,7 @@ int initgrabz(RegionView3D *rv3d, float x, float y, float z)
* \param ray_start The world-space starting point of the segment.
* \param ray_normal The normalized world-space direction of towards mval.
*/
-void ED_view3d_win_to_ray(ARegion *ar, View3D *v3d, const float mval[2], float ray_start[3], float ray_normal[3])
+void ED_view3d_win_to_ray(const ARegion *ar, View3D *v3d, const float mval[2], float ray_start[3], float ray_normal[3])
{
float ray_end[3];
@@ -322,7 +324,7 @@ void ED_view3d_win_to_ray(ARegion *ar, View3D *v3d, const float mval[2], float r
* \param coord The world-space location.
* \param vec The resulting normalized vector.
*/
-void ED_view3d_global_to_vector(RegionView3D *rv3d, const float coord[3], float vec[3])
+void ED_view3d_global_to_vector(const RegionView3D *rv3d, const float coord[3], float vec[3])
{
if (rv3d->is_persp) {
float p1[4], p2[4];
@@ -331,11 +333,11 @@ void ED_view3d_global_to_vector(RegionView3D *rv3d, const float coord[3], float
p1[3] = 1.0f;
copy_v3_v3(p2, p1);
p2[3] = 1.0f;
- mul_m4_v4(rv3d->viewmat, p2);
+ mul_m4_v4((float (*)[4])rv3d->viewmat, p2);
mul_v3_fl(p2, 2.0f);
- mul_m4_v4(rv3d->viewinv, p2);
+ mul_m4_v4((float (*)[4])rv3d->viewinv, p2);
sub_v3_v3v3(vec, p1, p2);
}
@@ -352,7 +354,7 @@ void ED_view3d_global_to_vector(RegionView3D *rv3d, const float coord[3], float
* \param mval The area relative location (such as event->mval converted to floats).
* \param out The resulting world-space location.
*/
-void ED_view3d_win_to_3d(ARegion *ar, const float depth_pt[3], const float mval[2], float out[3])
+void ED_view3d_win_to_3d(const ARegion *ar, const float depth_pt[3], const float mval[2], float out[3])
{
RegionView3D *rv3d = ar->regiondata;
@@ -384,19 +386,19 @@ void ED_view3d_win_to_3d(ARegion *ar, const float depth_pt[3], const float mval[
/**
* Calculate a 3d difference vector from 2d window offset.
- * note that initgrabz() must be called first to determine
+ * note that ED_view3d_calc_zfac() must be called first to determine
* the depth used to calculate the delta.
* \param ar The region (used for the window width and height).
* \param mval The area relative 2d difference (such as event->mval[0] - other_x).
* \param out The resulting world-space delta.
*/
-void ED_view3d_win_to_delta(ARegion *ar, const float mval[2], float out[3])
+void ED_view3d_win_to_delta(const ARegion *ar, const float mval[2], float out[3], const float zfac)
{
RegionView3D *rv3d = ar->regiondata;
float dx, dy;
- dx = 2.0f * mval[0] * rv3d->zfac / ar->winx;
- dy = 2.0f * mval[1] * rv3d->zfac / ar->winy;
+ dx = 2.0f * mval[0] * zfac / ar->winx;
+ dy = 2.0f * mval[1] * zfac / ar->winy;
out[0] = (rv3d->persinv[0][0] * dx + rv3d->persinv[1][0] * dy);
out[1] = (rv3d->persinv[0][1] * dx + rv3d->persinv[1][1] * dy);
@@ -408,7 +410,7 @@ void ED_view3d_win_to_delta(ARegion *ar, const float mval[2], float out[3])
* This direction vector starts and the view in the direction of the 2d window coordinates.
* In orthographic view all window coordinates yield the same vector.
*
- * \note doesn't rely on initgrabz
+ * \note doesn't rely on ED_view3d_calc_zfac
* for perspective view, get the vector direction to
* the mouse cursor as a normalized vector.
*
@@ -416,7 +418,7 @@ void ED_view3d_win_to_delta(ARegion *ar, const float mval[2], float out[3])
* \param mval The area relative 2d location (such as event->mval converted to floats).
* \param out The resulting normalized world-space direction vector.
*/
-void ED_view3d_win_to_vector(ARegion *ar, const float mval[2], float out[3])
+void ED_view3d_win_to_vector(const ARegion *ar, const float mval[2], float out[3])
{
RegionView3D *rv3d = ar->regiondata;
@@ -433,7 +435,7 @@ void ED_view3d_win_to_vector(ARegion *ar, const float mval[2], float out[3])
normalize_v3(out);
}
-void ED_view3d_win_to_segment(ARegion *ar, View3D *v3d, const float mval[2], float ray_start[3], float ray_end[3])
+void ED_view3d_win_to_segment(const ARegion *ar, View3D *v3d, const float mval[2], float ray_start[3], float ray_end[3])
{
RegionView3D *rv3d = ar->regiondata;
@@ -472,7 +474,7 @@ void ED_view3d_win_to_segment(ARegion *ar, View3D *v3d, const float mval[2], flo
* \param ray_end The world-space end point of the segment.
* \return success, FALSE if the segment is totally clipped.
*/
-int ED_view3d_win_to_segment_clip(ARegion *ar, View3D *v3d, const float mval[2], float ray_start[3], float ray_end[3])
+int ED_view3d_win_to_segment_clip(const ARegion *ar, View3D *v3d, const float mval[2], float ray_start[3], float ray_end[3])
{
RegionView3D *rv3d = ar->regiondata;
ED_view3d_win_to_segment(ar, v3d, mval, ray_start, ray_end);
@@ -503,12 +505,12 @@ int ED_view3d_win_to_segment_clip(ARegion *ar, View3D *v3d, const float mval[2],
/* Utility functions for projection
* ******************************** */
-void ED_view3d_ob_project_mat_get(RegionView3D *rv3d, Object *ob, float pmat[4][4])
+void ED_view3d_ob_project_mat_get(const RegionView3D *rv3d, Object *ob, float pmat[4][4])
{
float vmat[4][4];
- mult_m4_m4m4(vmat, rv3d->viewmat, ob->obmat);
- mult_m4_m4m4(pmat, rv3d->winmat, vmat);
+ mult_m4_m4m4(vmat, (float (*)[4])rv3d->viewmat, ob->obmat);
+ mult_m4_m4m4(pmat, (float (*)[4])rv3d->winmat, vmat);
}
/**
diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c
new file mode 100644
index 00000000000..410d20a1dc0
--- /dev/null
+++ b/source/blender/editors/space_view3d/view3d_ruler.c
@@ -0,0 +1,939 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_view3d/view3d_ruler.c
+ * \ingroup spview3d
+ */
+
+/* defines VIEW3D_OT_ruler modal operator */
+
+#include "DNA_scene_types.h"
+#include "DNA_gpencil_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+
+#include "BKE_context.h"
+#include "BKE_unit.h"
+#include "BKE_gpencil.h"
+
+#include "BIF_gl.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_screen.h"
+#include "ED_space_api.h"
+
+#include "BLF_api.h"
+#include "BIF_glutil.h"
+
+#include "UI_resources.h"
+#include "UI_interface.h"
+
+#include "view3d_intern.h" /* own include */
+
+
+/* -------------------------------------------------------------------- */
+/* Snapping (could be own function) */
+/* NOTE - this is not very nice use of transform snapping */
+#include "ED_transform.h"
+#include "../transform/transform.h"
+
+static bool ED_view3d_snap_co(bContext *C, float r_co[3], const float co_ss[2],
+ bool use_vert, bool use_edge, bool use_face)
+{
+ TransInfo t = {0};
+ int dist = 12; /* snap dist */
+ float r_no_dummy[3];
+ bool ret = false;
+ char backup_snap_mode;
+ Base *backup_baseact;
+
+ t.scene = CTX_data_scene(C);
+ t.view = CTX_wm_view3d(C);
+ t.ar = CTX_wm_region(C);
+ t.obedit = CTX_data_edit_object(C);
+
+ backup_snap_mode = t.scene->toolsettings->snap_mode;
+ backup_baseact = t.scene->basact;
+ t.scene->basact = NULL;
+
+ /* try snap edge, then face if it fails */
+ if (use_vert) {
+ t.scene->toolsettings->snap_mode = SCE_SNAP_MODE_VERTEX;
+ ret = snapObjectsTransform(&t, co_ss, &dist, r_co, r_no_dummy, SNAP_ALL);
+ }
+ if (use_edge && (ret == false)) {
+ t.scene->toolsettings->snap_mode = SCE_SNAP_MODE_EDGE;
+ ret = snapObjectsTransform(&t, co_ss, &dist, r_co, r_no_dummy, SNAP_ALL);
+ }
+ if (use_face && (ret == false)) {
+ t.scene->toolsettings->snap_mode = SCE_SNAP_MODE_FACE;
+ ret = snapObjectsTransform(&t, co_ss, &dist, r_co, r_no_dummy, SNAP_ALL);
+ }
+
+ t.scene->toolsettings->snap_mode = backup_snap_mode;
+ t.scene->basact = backup_baseact;
+
+ return ret;
+}
+/* done snapping */
+
+
+/* -------------------------------------------------------------------- */
+/* Ruler Item (we can have many) */
+enum {
+ RULERITEM_USE_ANGLE = (1 << 0), /* use protractor */
+ RULERITEM_USE_RAYCAST = (1 << 1)
+};
+
+enum {
+ RULERITEM_DIRECTION_IN = 0,
+ RULERITEM_DIRECTION_OUT
+};
+
+#define RULER_PICK_DIST 75.0f
+#define RULER_PICK_DIST_SQ (RULER_PICK_DIST * RULER_PICK_DIST)
+
+typedef struct RulerItem {
+ struct RulerItem *next, *prev;
+
+ /* worldspace coords, middle being optional */
+ float co[3][3];
+
+ /* selected coord */
+ char co_index; /* 0 -> 2*/
+
+ int flag;
+ int raycast_dir; /* RULER_DIRECTION_* */
+} RulerItem;
+
+enum {
+ RULER_STATE_NORMAL = 0,
+ RULER_STATE_DRAG
+};
+
+
+/* -------------------------------------------------------------------- */
+/* Ruler Info (one per session) */
+
+typedef struct RulerInfo {
+ ListBase items;
+ int item_active;
+ int flag;
+ int snap_flag;
+ int state;
+
+ /* --- */
+ ARegion *ar;
+ void *draw_handle_pixel;
+} RulerInfo;
+
+/* -------------------------------------------------------------------- */
+/* local functions */
+static RulerItem *ruler_item_add(RulerInfo *ruler_info)
+{
+ RulerItem *ruler_item = MEM_callocN(sizeof(RulerItem), "RulerItem");
+ BLI_addtail(&ruler_info->items, ruler_item);
+ return ruler_item;
+}
+
+static void ruler_item_remove(RulerInfo *ruler_info, RulerItem *ruler_item)
+{
+ BLI_remlink(&ruler_info->items, ruler_item);
+ MEM_freeN(ruler_item);
+}
+
+static RulerItem *ruler_item_active_get(RulerInfo *ruler_info)
+{
+ return BLI_findlink(&ruler_info->items, ruler_info->item_active);
+}
+
+static void ruler_item_active_set(RulerInfo *ruler_info, RulerItem *ruler_item)
+{
+ ruler_info->item_active = BLI_findindex(&ruler_info->items, ruler_item);
+}
+
+static void ruler_item_as_string(RulerItem *ruler_item, UnitSettings *unit,
+ char *numstr, size_t numstr_size, int prec)
+{
+ const int do_split = unit->flag & USER_UNIT_OPT_SPLIT;
+
+ if (ruler_item->flag & RULERITEM_USE_ANGLE) {
+ const float ruler_angle = angle_v3v3v3(ruler_item->co[0],
+ ruler_item->co[1],
+ ruler_item->co[2]);
+
+ if (unit->system == USER_UNIT_NONE) {
+ BLI_snprintf(numstr, numstr_size, "%.*f°", prec, RAD2DEGF(ruler_angle));
+ }
+ else {
+ bUnit_AsString(numstr, numstr_size,
+ (double)ruler_angle,
+ prec, unit->system, B_UNIT_ROTATION, do_split, false);
+ }
+ }
+ else {
+ const float ruler_len = len_v3v3(ruler_item->co[0],
+ ruler_item->co[2]);
+
+ if (unit->system == USER_UNIT_NONE) {
+ BLI_snprintf(numstr, numstr_size, "%.*f", prec, ruler_len);
+ }
+ else {
+ bUnit_AsString(numstr, numstr_size,
+ (double)(ruler_len * unit->scale_length),
+ prec, unit->system, B_UNIT_LENGTH, do_split, false);
+ }
+ }
+
+}
+
+static bool view3d_ruler_pick(RulerInfo *ruler_info, const float mval[2],
+ RulerItem **r_ruler_item, int *r_co_index)
+{
+ ARegion *ar = ruler_info->ar;
+ RulerItem *ruler_item;
+
+ float dist_best = RULER_PICK_DIST_SQ;
+ RulerItem *ruler_item_best = NULL;
+ int co_index_best = -1;
+
+ for (ruler_item = ruler_info->items.first; ruler_item; ruler_item = ruler_item->next) {
+ float co_ss[3][2];
+ float dist;
+ int j;
+
+ /* should these be checked? - ok for now not to */
+ for (j = 0; j < 3; j++) {
+ ED_view3d_project_float_global(ar, ruler_item->co[j], co_ss[j], V3D_PROJ_TEST_NOP);
+ }
+
+ if (ruler_item->flag & RULERITEM_USE_ANGLE) {
+ dist = min_ff(dist_squared_to_line_segment_v2(mval, co_ss[0], co_ss[1]),
+ dist_squared_to_line_segment_v2(mval, co_ss[1], co_ss[2]));
+ if (dist < dist_best) {
+ dist_best = dist;
+ ruler_item_best = ruler_item;
+
+ {
+ float dist_points[3] = {len_squared_v2v2(co_ss[0], mval),
+ len_squared_v2v2(co_ss[1], mval),
+ len_squared_v2v2(co_ss[2], mval)};
+ if (min_fff(UNPACK3(dist_points)) < RULER_PICK_DIST_SQ) {
+ co_index_best = min_axis_v3(dist_points);
+ }
+ else {
+ co_index_best = -1;
+ }
+ }
+ }
+ }
+ else {
+ dist = dist_squared_to_line_segment_v2(mval, co_ss[0], co_ss[2]);
+ if (dist < dist_best) {
+ dist_best = dist;
+ ruler_item_best = ruler_item;
+
+ {
+ float dist_points[2] = {len_squared_v2v2(co_ss[0], mval),
+ len_squared_v2v2(co_ss[2], mval)};
+ if (min_ff(UNPACK2(dist_points)) < RULER_PICK_DIST_SQ) {
+ co_index_best = (dist_points[0] < dist_points[1]) ? 0 : 2;
+ }
+ else {
+ co_index_best = -1;
+ }
+ }
+ }
+ }
+ }
+
+ if (ruler_item_best) {
+ *r_ruler_item = ruler_item_best;
+ *r_co_index = co_index_best;
+ return true;
+ }
+ else {
+ *r_ruler_item = NULL;
+ *r_co_index = -1;
+ return false;
+ }
+}
+
+#define RULER_ID "RulerData3D"
+static bool view3d_ruler_to_gpencil(bContext *C, RulerInfo *ruler_info)
+{
+ Scene *scene = CTX_data_scene(C);
+ bGPDlayer *gpl;
+ bGPDframe *gpf;
+ bGPDstroke *gps;
+ RulerItem *ruler_item;
+ const char *ruler_name = RULER_ID;
+ bool change = false;
+
+ if (scene->gpd == NULL) {
+ scene->gpd = gpencil_data_addnew("GPencil");
+ }
+
+ gpl = BLI_findstring(&scene->gpd->layers, ruler_name, offsetof(bGPDlayer, info));
+ if (gpl == NULL) {
+ gpl = gpencil_layer_addnew(scene->gpd, ruler_name, false);
+ gpl->thickness = 1;
+ gpl->flag |= GP_LAYER_HIDE;
+ }
+
+ gpf = gpencil_layer_getframe(gpl, CFRA, true);
+ free_gpencil_strokes(gpf);
+
+ for (ruler_item = ruler_info->items.first; ruler_item; ruler_item = ruler_item->next) {
+ bGPDspoint *pt;
+ int j;
+
+ /* allocate memory for a new stroke */
+ gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
+ if (ruler_item->flag & RULERITEM_USE_ANGLE) {
+ gps->totpoints = 3;
+ pt = gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+ for (j = 0; j < 3; j++) {
+ copy_v3_v3(&pt->x, ruler_item->co[j]);
+ pt->pressure = 1.0f;
+ pt++;
+ }
+ }
+ else {
+ gps->totpoints = 2;
+ pt = gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+ for (j = 0; j < 3; j += 2) {
+ copy_v3_v3(&pt->x, ruler_item->co[j]);
+ pt->pressure = 1.0f;
+ pt++;
+ }
+ }
+ gps->flag = GP_STROKE_3DSPACE;
+ BLI_addtail(&gpf->strokes, gps);
+ change = true;
+ }
+
+ return change;
+}
+
+static bool view3d_ruler_from_gpencil(bContext *C, RulerInfo *ruler_info)
+{
+ Scene *scene = CTX_data_scene(C);
+ bool change = false;
+
+ if (scene->gpd) {
+ bGPDlayer *gpl;
+ const char *ruler_name = RULER_ID;
+ gpl = BLI_findstring(&scene->gpd->layers, ruler_name, offsetof(bGPDlayer, info));
+ if (gpl) {
+ bGPDframe *gpf;
+ gpf = gpencil_layer_getframe(gpl, CFRA, false);
+ if (gpf) {
+ bGPDstroke *gps;
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ bGPDspoint *pt = gps->points;
+ int j;
+ if (gps->totpoints == 3) {
+ RulerItem *ruler_item = ruler_item_add(ruler_info);
+ for (j = 0; j < 3; j++) {
+ copy_v3_v3(ruler_item->co[j], &pt->x);
+ pt++;
+ }
+ ruler_item->flag |= RULERITEM_USE_ANGLE;
+ change = true;
+ }
+ else if (gps->totpoints == 2) {
+ RulerItem *ruler_item = ruler_item_add(ruler_info);
+ for (j = 0; j < 3; j += 2) {
+ copy_v3_v3(ruler_item->co[j], &pt->x);
+ pt++;
+ }
+ change = true;
+ }
+ }
+ }
+ }
+ }
+
+ return change;
+}
+
+/* -------------------------------------------------------------------- */
+/* local callbacks */
+
+static void ruler_info_draw_pixel(const struct bContext *C, ARegion *ar, void *arg)
+{
+ Scene *scene = CTX_data_scene(C);
+ UnitSettings *unit = &scene->unit;
+ RulerItem *ruler_item;
+ RulerInfo *ruler_info = arg;
+ RegionView3D *rv3d = ruler_info->ar->regiondata;
+// ARegion *ar = ruler_info->ar;
+ const float cap_size = 4.0f;
+ const float bg_margin = 4.0f * U.pixelsize;
+ const float bg_radius = 4.0f * U.pixelsize;
+ const float arc_size = 64.0f * U.pixelsize;
+#define ARC_STEPS 24
+ const int arc_steps = ARC_STEPS;
+ int i;
+ //unsigned int color_act = 0x666600;
+ unsigned int color_act = 0xffffff;
+ unsigned int color_base = 0x0;
+ unsigned char color_back[4] = {0xff, 0xff, 0xff, 0x80};
+ unsigned char color_text[3];
+ unsigned char color_wire[3];
+
+ /* anti-aliased lines for more consistent appearance */
+ glEnable(GL_LINE_SMOOTH);
+
+ BLF_enable(blf_mono_font, BLF_ROTATION);
+ BLF_size(blf_mono_font, 14 * U.pixelsize, U.dpi);
+ BLF_rotation(blf_mono_font, 0.0f);
+
+ UI_GetThemeColor3ubv(TH_TEXT, color_text);
+ UI_GetThemeColor3ubv(TH_WIRE, color_wire);
+
+ for (ruler_item = ruler_info->items.first, i = 0; ruler_item; ruler_item = ruler_item->next, i++) {
+ const bool is_act = (i == ruler_info->item_active);
+ float dir_ruler[2];
+ float co_ss[3][2];
+ int j;
+
+ /* should these be checked? - ok for now not to */
+ for (j = 0; j < 3; j++) {
+ ED_view3d_project_float_global(ar, ruler_item->co[j], co_ss[j], V3D_PROJ_TEST_NOP);
+ }
+
+ glEnable(GL_BLEND);
+
+ cpack(is_act ? color_act : color_base);
+
+ if (ruler_item->flag & RULERITEM_USE_ANGLE) {
+ glBegin(GL_LINE_STRIP);
+ for (j = 0; j < 3; j++) {
+ glVertex2fv(co_ss[j]);
+ }
+ glEnd();
+ cpack(0xaaaaaa);
+ setlinestyle(3);
+ glBegin(GL_LINE_STRIP);
+ for (j = 0; j < 3; j++) {
+ glVertex2fv(co_ss[j]);
+ }
+ glEnd();
+ setlinestyle(0);
+
+ /* arc */
+ {
+ float dir_tmp[3];
+ float co_tmp[3];
+ float arc_ss_coords[ARC_STEPS + 1][2];
+
+ float dir_a[3];
+ float dir_b[3];
+ float quat[4];
+ float axis[3];
+ float angle;
+ const float px_scale = (ED_view3d_pixel_size(rv3d, ruler_item->co[1]) *
+ min_fff(arc_size,
+ len_v2v2(co_ss[0], co_ss[1]) / 2.0f,
+ len_v2v2(co_ss[2], co_ss[1]) / 2.0f));
+
+ sub_v3_v3v3(dir_a, ruler_item->co[0], ruler_item->co[1]);
+ sub_v3_v3v3(dir_b, ruler_item->co[2], ruler_item->co[1]);
+ normalize_v3(dir_a);
+ normalize_v3(dir_b);
+
+ cross_v3_v3v3(axis, dir_a, dir_b);
+ angle = angle_normalized_v3v3(dir_a, dir_b);
+
+ axis_angle_to_quat(quat, axis, angle / arc_steps);
+
+ copy_v3_v3(dir_tmp, dir_a);
+
+ glColor3ubv(color_wire);
+
+ for (j = 0; j <= arc_steps; j++) {
+ madd_v3_v3v3fl(co_tmp, ruler_item->co[1], dir_tmp, px_scale);
+ ED_view3d_project_float_global(ar, co_tmp, arc_ss_coords[j], V3D_PROJ_TEST_NOP);
+ mul_qt_v3(quat, dir_tmp);
+ }
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(2, GL_FLOAT, 0, arc_ss_coords);
+ glDrawArrays(GL_LINE_STRIP, 0, arc_steps + 1);
+ glDisableClientState(GL_VERTEX_ARRAY);
+ }
+
+ /* text */
+ {
+ char numstr[256];
+ float numstr_size[2];
+ float pos[2];
+ const int prec = 2; /* XXX, todo, make optional */
+
+ ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec);
+
+ BLF_width_and_height(blf_mono_font, numstr, &numstr_size[0], &numstr_size[1]);
+
+ pos[0] = co_ss[1][0] + (cap_size * 2.0f);
+ pos[1] = co_ss[1][1] - (numstr_size[1] / 2.0f);
+
+ /* draw text (bg) */
+ glColor4ubv(color_back);
+ uiSetRoundBox(UI_CNR_ALL);
+ uiRoundBox(pos[0] - bg_margin, pos[1] - bg_margin,
+ pos[0] + bg_margin + numstr_size[0], pos[1] + bg_margin + numstr_size[1],
+ bg_radius);
+ /* draw text */
+ glColor3ubv(color_text);
+ BLF_position(blf_mono_font, pos[0], pos[1], 0.0f);
+ BLF_rotation(blf_mono_font, 0.0f);
+ BLF_draw(blf_mono_font, numstr, sizeof(numstr));
+ }
+
+ /* capping */
+ {
+ float rot_90_vec_a[2];
+ float rot_90_vec_b[2];
+ float cap[2];
+
+ sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[1]);
+ rot_90_vec_a[0] = -dir_ruler[1];
+ rot_90_vec_a[1] = dir_ruler[0];
+ normalize_v2(rot_90_vec_a);
+
+ sub_v2_v2v2(dir_ruler, co_ss[1], co_ss[2]);
+ rot_90_vec_b[0] = -dir_ruler[1];
+ rot_90_vec_b[1] = dir_ruler[0];
+ normalize_v2(rot_90_vec_b);
+
+ glEnable(GL_BLEND);
+
+ glColor3ubv(color_wire);
+
+ glBegin(GL_LINES);
+
+ madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, cap_size);
+ glVertex2fv(cap);
+ madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, -cap_size);
+ glVertex2fv(cap);
+
+ madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, cap_size);
+ glVertex2fv(cap);
+ madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, -cap_size);
+ glVertex2fv(cap);
+
+ /* angle vertex */
+ glVertex2f(co_ss[1][0] - cap_size, co_ss[1][1] - cap_size);
+ glVertex2f(co_ss[1][0] + cap_size, co_ss[1][1] + cap_size);
+ glVertex2f(co_ss[1][0] - cap_size, co_ss[1][1] + cap_size);
+ glVertex2f(co_ss[1][0] + cap_size, co_ss[1][1] - cap_size);
+ glEnd();
+
+ glDisable(GL_BLEND);
+ }
+ }
+ else {
+ glBegin(GL_LINE_STRIP);
+ for (j = 0; j < 3; j += 2) {
+ glVertex2fv(co_ss[j]);
+ }
+ glEnd();
+ cpack(0xaaaaaa);
+ setlinestyle(3);
+ glBegin(GL_LINE_STRIP);
+ for (j = 0; j < 3; j += 2) {
+ glVertex2fv(co_ss[j]);
+ }
+ glEnd();
+ setlinestyle(0);
+
+ sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[2]);
+
+ /* text */
+ {
+ char numstr[256];
+ float numstr_size[2];
+ const int prec = 6; /* XXX, todo, make optional */
+ float pos[2];
+
+ ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec);
+
+ BLF_width_and_height(blf_mono_font, numstr, &numstr_size[0], &numstr_size[1]);
+
+ mid_v2_v2v2(pos, co_ss[0], co_ss[2]);
+
+ /* center text */
+ pos[0] -= numstr_size[0] / 2.0f;
+ pos[1] -= numstr_size[1] / 2.0f;
+
+ /* draw text (bg) */
+ glColor4ubv(color_back);
+ uiSetRoundBox(UI_CNR_ALL);
+ uiRoundBox(pos[0] - bg_margin, pos[1] - bg_margin,
+ pos[0] + bg_margin + numstr_size[0], pos[1] + bg_margin + numstr_size[1],
+ bg_radius);
+ /* draw text */
+ glColor3ubv(color_text);
+ BLF_position(blf_mono_font, pos[0], pos[1], 0.0f);
+ BLF_draw(blf_mono_font, numstr, sizeof(numstr));
+ }
+
+ /* capping */
+ {
+ float rot_90_vec[2] = {-dir_ruler[1], dir_ruler[0]};
+ float cap[2];
+
+ normalize_v2(rot_90_vec);
+
+ glEnable(GL_BLEND);
+ glColor3ubv(color_wire);
+
+ glBegin(GL_LINES);
+ madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, cap_size);
+ glVertex2fv(cap);
+ madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, -cap_size);
+ glVertex2fv(cap);
+
+ madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, cap_size);
+ glVertex2fv(cap);
+ madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, -cap_size);
+ glVertex2fv(cap);
+ glEnd();
+
+ glDisable(GL_BLEND);
+ }
+ }
+ }
+
+ glDisable(GL_LINE_SMOOTH);
+
+ BLF_disable(blf_mono_font, BLF_ROTATION);
+
+#undef ARC_STEPS
+}
+
+/* free, use for both cancel and finish */
+static void view3d_ruler_end(const struct bContext *UNUSED(C), RulerInfo *ruler_info)
+{
+ ED_region_draw_cb_exit(ruler_info->ar->type, ruler_info->draw_handle_pixel);
+}
+
+static void view3d_ruler_free(RulerInfo *ruler_info)
+{
+ BLI_freelistN(&ruler_info->items);
+ MEM_freeN(ruler_info);
+}
+
+static void view3d_ruler_item_project(RulerInfo *ruler_info, float r_co[3],
+ const int xy[2])
+{
+ view3d_get_view_aligned_coordinate(ruler_info->ar, r_co, xy, true);
+}
+
+/* use for mousemove events */
+static bool view3d_ruler_item_mousemove(bContext *C, RulerInfo *ruler_info, const int mval[2], const bool do_snap)
+{
+ RulerItem *ruler_item = ruler_item_active_get(ruler_info);
+
+ if (ruler_item) {
+ float *co = ruler_item->co[ruler_item->co_index];
+ view3d_ruler_item_project(ruler_info, co, mval);
+ if (do_snap) {
+ const float mval_fl[2] = {UNPACK2(mval)};
+ ED_view3d_snap_co(C, co, mval_fl, true, true, true);
+ }
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+static void view3d_ruler_header_update(ScrArea *sa)
+{
+ const char *text = "Ctrl+LMB: Add, "
+ "Del: Remove, "
+ "Ctrl+Drag: Snap, "
+ "Ctrl+C: Copy Value, "
+ "Enter: Store, "
+ "Esc: Cancel";
+
+ ED_area_headerprint(sa, text);
+}
+
+/* -------------------------------------------------------------------- */
+/* Operator callbacks */
+
+static int view3d_ruler_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ wmWindow *win = CTX_wm_window(C);
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ RulerInfo *ruler_info;
+
+ ruler_info = MEM_callocN(sizeof(RulerInfo), "RulerInfo");
+
+ if (view3d_ruler_from_gpencil(C, ruler_info)) {
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ }
+
+ op->customdata = ruler_info;
+
+ ruler_info->ar = ar;
+ ruler_info->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ruler_info_draw_pixel,
+ ruler_info, REGION_DRAW_POST_PIXEL);
+
+ view3d_ruler_header_update(sa);
+
+ WM_cursor_modal(win, BC_CROSSCURSOR);
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int view3d_ruler_cancel(bContext *C, wmOperator *op)
+{
+ RulerInfo *ruler_info = op->customdata;
+
+ view3d_ruler_end(C, ruler_info);
+ view3d_ruler_free(ruler_info);
+ op->customdata = NULL;
+
+ return OPERATOR_CANCELLED;
+}
+
+static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ bool do_draw = false;
+ int exit_code = OPERATOR_RUNNING_MODAL;
+ RulerInfo *ruler_info = op->customdata;
+ ARegion *ar = ruler_info->ar;
+ RegionView3D *rv3d = ar->regiondata;
+
+ (void)C;
+
+ switch (event->type) {
+ case LEFTMOUSE:
+ if (event->val == KM_RELEASE) {
+ if (ruler_info->state == RULER_STATE_DRAG) {
+ /* rubber-band angle removal */
+ RulerItem *ruler_item = ruler_item_active_get(ruler_info);
+ if (ruler_item && (ruler_item->co_index == 1) && (ruler_item->flag & RULERITEM_USE_ANGLE)) {
+ if (!BLI_rcti_isect_pt_v(&ar->winrct, &event->x)) {
+ ruler_item->flag &= ~RULERITEM_USE_ANGLE;
+ do_draw = true;
+ }
+ }
+ ruler_info->state = RULER_STATE_NORMAL;
+ }
+ }
+ else {
+ if (ruler_info->state == RULER_STATE_NORMAL) {
+
+ if (event->ctrl ||
+ /* weak - but user friendly */
+ (ruler_info->items.first == NULL))
+ {
+ /* Create new line */
+ RulerItem *ruler_item;
+ /* check if we want to drag an existing point or add a new one */
+ ruler_info->state = RULER_STATE_DRAG;
+
+ ruler_item = ruler_item_add(ruler_info);
+ ruler_item_active_set(ruler_info, ruler_item);
+
+ negate_v3_v3(ruler_item->co[0], rv3d->ofs);
+ view3d_ruler_item_project(ruler_info, ruler_item->co[0], event->mval);
+
+ /* snap the first point added, not essential but handy */
+ {
+ ruler_item->co_index = 0;
+ view3d_ruler_item_mousemove(C, ruler_info, event->mval, true);
+ }
+
+ copy_v3_v3(ruler_item->co[2], ruler_item->co[0]);
+ ruler_item->co_index = 2;
+
+ do_draw = true;
+ }
+ else {
+ float mval_fl[2] = {UNPACK2(event->mval)};
+ RulerItem *ruler_item_pick;
+ int co_index;
+
+ /* select and drag */
+ if (view3d_ruler_pick(ruler_info, mval_fl, &ruler_item_pick, &co_index)) {
+ if (co_index == -1) {
+ if ((ruler_item_pick->flag & RULERITEM_USE_ANGLE) == 0) {
+ /* Add Center Point */
+ 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;
+
+ /* find the factor */
+ {
+ float co_ss[2][2];
+ float fac;
+
+ ED_view3d_project_float_global(ar, ruler_item_pick->co[0], co_ss[0], V3D_PROJ_TEST_NOP);
+ ED_view3d_project_float_global(ar, ruler_item_pick->co[2], co_ss[1], V3D_PROJ_TEST_NOP);
+
+ fac = line_point_factor_v2(mval_fl, co_ss[0], co_ss[1]);
+ CLAMP(fac, 0.0f, 1.0f);
+
+ interp_v3_v3v3(ruler_item_pick->co[1],
+ ruler_item_pick->co[0],
+ ruler_item_pick->co[2], fac);
+ }
+
+ /* update the new location */
+ view3d_ruler_item_mousemove(C, ruler_info, event->mval, event->ctrl != 0);
+ do_draw = true;
+ }
+ }
+ else {
+ ruler_item_active_set(ruler_info, ruler_item_pick);
+ ruler_item_pick->co_index = co_index;
+ ruler_info->state = RULER_STATE_DRAG;
+ do_draw = true;
+ }
+ }
+ else {
+ exit_code = OPERATOR_PASS_THROUGH;
+ }
+
+ }
+ }
+ }
+ break;
+ case CKEY:
+ {
+ if (event->ctrl) {
+ RulerItem *ruler_item = ruler_item_active_get(ruler_info);
+ if (ruler_item) {
+ const int prec = 8;
+ char numstr[256];
+ Scene *scene = CTX_data_scene(C);
+ UnitSettings *unit = &scene->unit;
+
+ ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec);
+ WM_clipboard_text_set((void *) numstr, false);
+ }
+ }
+ }
+ case RIGHTCTRLKEY:
+ case LEFTCTRLKEY:
+ {
+ WM_event_add_mousemove(C);
+ break;
+ }
+ case MOUSEMOVE:
+ {
+ if (ruler_info->state == RULER_STATE_DRAG) {
+ if (view3d_ruler_item_mousemove(C, ruler_info, event->mval, event->ctrl != 0)) {
+ do_draw = true;
+ }
+ }
+ break;
+ }
+ case ESCKEY:
+ {
+ do_draw = true;
+ exit_code = OPERATOR_CANCELLED;
+ break;
+ }
+ case RETKEY:
+ {
+ view3d_ruler_to_gpencil(C, ruler_info);
+ do_draw = true;
+ exit_code = OPERATOR_FINISHED;
+ break;
+ }
+ case DELKEY:
+ {
+ if (event->val == KM_PRESS) {
+ if (ruler_info->state == RULER_STATE_NORMAL) {
+ RulerItem *ruler_item = ruler_item_active_get(ruler_info);
+ if (ruler_item) {
+ ruler_item_remove(ruler_info, ruler_item);
+ ruler_info->item_active = -1;
+ do_draw = true;
+ }
+ }
+ }
+ break;
+ }
+ default:
+ exit_code = OPERATOR_PASS_THROUGH;
+ break;
+
+ }
+
+ if (do_draw) {
+ ScrArea *sa = CTX_wm_area(C);
+
+ view3d_ruler_header_update(sa);
+
+ /* all 3d views draw rulers */
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ }
+
+ if (ELEM(exit_code, OPERATOR_FINISHED, OPERATOR_CANCELLED)) {
+ wmWindow *win = CTX_wm_window(C);
+ ScrArea *sa = CTX_wm_area(C);
+
+ WM_cursor_restore(win);
+
+ view3d_ruler_end(C, ruler_info);
+ view3d_ruler_free(ruler_info);
+ op->customdata = NULL;
+
+ ED_area_headerprint(sa, NULL);
+ }
+
+ return exit_code;
+}
+
+void VIEW3D_OT_ruler(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "3D Ruler & Protractor";
+ ot->description = "Interactive ruler";
+ ot->idname = "VIEW3D_OT_ruler";
+
+ /* api callbacks */
+ ot->invoke = view3d_ruler_invoke;
+ ot->cancel = view3d_ruler_cancel;
+ ot->modal = view3d_ruler_modal;
+ ot->poll = ED_operator_view3d_active;
+
+ /* flags */
+ ot->flag = 0;
+}
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 24260898066..b441e48f59d 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -108,23 +108,23 @@ void view3d_set_viewcontext(bContext *C, ViewContext *vc)
vc->obedit = CTX_data_edit_object(C);
}
-int view3d_get_view_aligned_coordinate(ViewContext *vc, float fp[3], const int mval[2], const short do_fallback)
+/**
+ * Re-project \a fp so it stays on the same view-plane but is under \a mval (normally the cursor location).
+ */
+bool view3d_get_view_aligned_coordinate(ARegion *ar, float fp[3], const int mval[2], const bool do_fallback)
{
+ RegionView3D *rv3d = ar->regiondata;
float dvec[3];
int mval_cpy[2];
eV3DProjStatus ret;
- mval_cpy[0] = mval[0];
- mval_cpy[1] = mval[1];
-
- ret = ED_view3d_project_int_global(vc->ar, fp, mval_cpy, V3D_PROJ_TEST_NOP);
-
- initgrabz(vc->rv3d, fp[0], fp[1], fp[2]);
+ ret = ED_view3d_project_int_global(ar, fp, mval_cpy, V3D_PROJ_TEST_NOP);
if (ret == V3D_PROJ_RET_OK) {
const float mval_f[2] = {(float)(mval_cpy[0] - mval[0]),
(float)(mval_cpy[1] - mval[1])};
- ED_view3d_win_to_delta(vc->ar, mval_f, dvec);
+ const float zfac = ED_view3d_calc_zfac(rv3d, fp, NULL);
+ ED_view3d_win_to_delta(ar, mval_f, dvec, zfac);
sub_v3_v3(fp, dvec);
return TRUE;
@@ -132,11 +132,11 @@ int view3d_get_view_aligned_coordinate(ViewContext *vc, float fp[3], const int m
else {
/* fallback to the view center */
if (do_fallback) {
- negate_v3_v3(fp, vc->rv3d->ofs);
- return view3d_get_view_aligned_coordinate(vc, fp, mval, FALSE);
+ negate_v3_v3(fp, rv3d->ofs);
+ return view3d_get_view_aligned_coordinate(ar, fp, mval, false);
}
else {
- return FALSE;
+ return false;
}
}
}
@@ -177,10 +177,9 @@ static void edbm_backbuf_check_and_select_verts(BMEditMesh *em, int select)
{
BMVert *eve;
BMIter iter;
- int index = bm_wireoffs;
+ unsigned int index = bm_wireoffs;
- eve = BM_iter_new(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
- for (; eve; eve = BM_iter_step(&iter), index++) {
+ for (eve = BM_iter_new(&iter, em->bm, BM_VERTS_OF_MESH, NULL); eve; eve = BM_iter_step(&iter), index++) {
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
if (EDBM_backbuf_check(index)) {
BM_vert_select_set(em->bm, eve, select);
@@ -209,7 +208,7 @@ static void edbm_backbuf_check_and_select_faces(BMEditMesh *em, int select)
{
BMFace *efa;
BMIter iter;
- int index = 1;
+ unsigned int index = 1;
efa = BM_iter_new(&iter, em->bm, BM_FACES_OF_MESH, NULL);
for (; efa; efa = BM_iter_step(&iter), index++) {
@@ -226,11 +225,11 @@ static void edbm_backbuf_check_and_select_faces(BMEditMesh *em, int select)
static void edbm_backbuf_check_and_select_verts_obmode(Mesh *me, int select)
{
MVert *mv = me->mvert;
- int a;
+ unsigned int index;
if (mv) {
- for (a = 1; a <= me->totvert; a++, mv++) {
- if (EDBM_backbuf_check(a)) {
+ for (index = 1; index <= me->totvert; index++, mv++) {
+ if (EDBM_backbuf_check(index)) {
if (!(mv->flag & ME_HIDE)) {
mv->flag = select ? (mv->flag | SELECT) : (mv->flag & ~SELECT);
}
@@ -243,11 +242,11 @@ static void edbm_backbuf_check_and_select_verts_obmode(Mesh *me, int select)
static void edbm_backbuf_check_and_select_tfaces(Mesh *me, int select)
{
MPoly *mpoly = me->mpoly;
- int a;
+ unsigned int index;
if (mpoly) {
- for (a = 1; a <= me->totpoly; a++, mpoly++) {
- if (EDBM_backbuf_check(a)) {
+ for (index = 1; index <= me->totpoly; index++, mpoly++) {
+ if (EDBM_backbuf_check(index)) {
mpoly->flag = select ? (mpoly->flag | ME_FACE_SEL) : (mpoly->flag & ~ME_FACE_SEL);
}
}
@@ -733,7 +732,7 @@ static void do_lasso_select_meta(ViewContext *vc, const int mcords[][2], short m
MetaBall *mb = (MetaBall *)vc->obedit->data;
if (extend == 0 && select)
- BKE_mball_deselect_all(mb);
+ BKE_mball_deselect_all(mb);
BLI_lasso_boundbox(&rect, mcords, moves);
@@ -780,9 +779,6 @@ static void do_lasso_select_paintvert(ViewContext *vc, const int mcords[][2], sh
}
else {
LassoSelectUserData data;
- rcti rect;
-
- BLI_lasso_boundbox(&rect, mcords, moves);
view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select);
@@ -1054,7 +1050,7 @@ static int object_select_menu_exec(bContext *C, wmOperator *op)
CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
{
/* this is a bit dodjy, there should only be ONE object with this name, but library objects can mess this up */
- if (strcmp(name, base->object->id.name + 2) == 0) {
+ if (STREQ(name, base->object->id.name + 2)) {
ED_base_object_activate(C, base);
ED_base_object_select(base, BA_SELECT);
changed = 1;
@@ -2230,7 +2226,7 @@ static int mouse_weight_paint_vertex_select(bContext *C, const int mval[2], shor
/* ****** Mouse Select ****** */
-static int view3d_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int view3d_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Object *obedit = CTX_data_edit_object(C);
Object *obact = CTX_data_active_object(C);
diff --git a/source/blender/editors/space_view3d/view3d_toolbar.c b/source/blender/editors/space_view3d/view3d_toolbar.c
index bb5b7aa6911..d3bf8a30792 100644
--- a/source/blender/editors/space_view3d/view3d_toolbar.c
+++ b/source/blender/editors/space_view3d/view3d_toolbar.c
@@ -156,7 +156,7 @@ static void operator_search_cb(const struct bContext *C, void *UNUSED(arg), cons
{
GHashIterator *iter = WM_operatortype_iter();
- for (; !BLI_ghashIterator_isDone(iter); BLI_ghashIterator_step(iter)) {
+ for (; BLI_ghashIterator_notDone(iter); BLI_ghashIterator_step(iter)) {
wmOperatorType *ot = BLI_ghashIterator_getValue(iter);
if (BLI_strcasestr(ot->name, str)) {
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index fba1ce328ba..b2e10fa8457 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -294,7 +294,7 @@ void view3d_smooth_view(bContext *C, View3D *v3d, ARegion *ar, Object *oldcamera
}
/* only meant for timer usage */
-static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
+static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
View3D *v3d = CTX_wm_view3d(C);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
@@ -667,22 +667,29 @@ void ED_view3d_depth_tag_update(RegionView3D *rv3d)
}
/* copies logic of get_view3d_viewplane(), keep in sync */
-int ED_view3d_clip_range_get(View3D *v3d, RegionView3D *rv3d, float *clipsta, float *clipend)
+bool ED_view3d_clip_range_get(View3D *v3d, RegionView3D *rv3d, float *r_clipsta, float *r_clipend,
+ const bool use_ortho_factor)
{
CameraParams params;
BKE_camera_params_init(&params);
BKE_camera_params_from_view3d(&params, v3d, rv3d);
- if (clipsta) *clipsta = params.clipsta;
- if (clipend) *clipend = params.clipend;
+ if (use_ortho_factor && params.is_ortho) {
+ const float fac = 2.0f / (params.clipend - params.clipsta);
+ params.clipsta *= fac;
+ params.clipend *= fac;
+ }
+
+ if (r_clipsta) *r_clipsta = params.clipsta;
+ if (r_clipend) *r_clipend = params.clipend;
return params.is_ortho;
}
/* also exposed in previewrender.c */
-int ED_view3d_viewplane_get(View3D *v3d, RegionView3D *rv3d, int winx, int winy,
- rctf *viewplane, float *clipsta, float *clipend)
+bool ED_view3d_viewplane_get(View3D *v3d, RegionView3D *rv3d, int winx, int winy,
+ rctf *r_viewplane, float *r_clipsta, float *r_clipend)
{
CameraParams params;
@@ -690,9 +697,9 @@ int ED_view3d_viewplane_get(View3D *v3d, RegionView3D *rv3d, int winx, int winy,
BKE_camera_params_from_view3d(&params, v3d, rv3d);
BKE_camera_params_compute_viewplane(&params, winx, winy, 1.0f, 1.0f);
- if (viewplane) *viewplane = params.viewplane;
- if (clipsta) *clipsta = params.clipsta;
- if (clipend) *clipend = params.clipend;
+ if (r_viewplane) *r_viewplane = params.viewplane;
+ if (r_clipsta) *r_clipsta = params.clipsta;
+ if (r_clipend) *r_clipend = params.clipend;
return params.is_ortho;
}
@@ -791,7 +798,7 @@ static void obmat_to_viewmat(View3D *v3d, RegionView3D *rv3d, Object *ob, short
#define QUATSET(a, b, c, d, e) { a[0] = b; a[1] = c; a[2] = d; a[3] = e; } (void)0
-int ED_view3d_lock(RegionView3D *rv3d)
+bool ED_view3d_lock(RegionView3D *rv3d)
{
switch (rv3d->view) {
case RV3D_VIEW_BOTTOM:
@@ -818,10 +825,10 @@ int ED_view3d_lock(RegionView3D *rv3d)
QUATSET(rv3d->viewquat, 0.5, -0.5, -0.5, -0.5);
break;
default:
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
/* don't set windows active in here, is used by renderwin too */
@@ -863,7 +870,9 @@ void setviewmatrixview3d(Scene *scene, View3D *v3d, RegionView3D *rv3d)
copy_v3_v3(vec, give_cursor(scene, v3d));
translate_m4(rv3d->viewmat, -vec[0], -vec[1], -vec[2]);
}
- else translate_m4(rv3d->viewmat, rv3d->ofs[0], rv3d->ofs[1], rv3d->ofs[2]);
+ else {
+ translate_m4(rv3d->viewmat, rv3d->ofs[0], rv3d->ofs[1], rv3d->ofs[2]);
+ }
}
}
@@ -1558,11 +1567,7 @@ static void UNUSED_FUNCTION(view3d_align_axis_to_vector)(View3D *v3d, RegionView
float ED_view3d_pixel_size(RegionView3D *rv3d, const float co[3])
{
- return (rv3d->persmat[3][3] + (
- rv3d->persmat[0][3] * co[0] +
- rv3d->persmat[1][3] * co[1] +
- rv3d->persmat[2][3] * co[2])
- ) * rv3d->pixsize * U.pixelsize;
+ return mul_project_m4_v3_zfac(rv3d->persmat, co) * rv3d->pixsize * U.pixelsize;
}
float ED_view3d_radius_to_persp_dist(const float angle, const float radius)
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index c8874d13cac..64e49abd761 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -98,6 +98,8 @@
#include "transform.h"
+#define MAX_INFO_LEN 256
+
static void drawTransformApply(const struct bContext *C, ARegion *ar, void *arg);
static int doEdgeSlide(TransInfo *t, float perc);
static int doVertSlide(TransInfo *t, float perc);
@@ -183,7 +185,7 @@ void convertViewVec(TransInfo *t, float r_vec[3], int dx, int dy)
{
if ((t->spacetype == SPACE_VIEW3D) && (t->ar->regiontype == RGN_TYPE_WINDOW)) {
const float mval_f[2] = {(float)dx, (float)dy};
- ED_view3d_win_to_delta(t->ar, mval_f, r_vec);
+ ED_view3d_win_to_delta(t->ar, mval_f, r_vec, t->zfac);
}
else if (t->spacetype == SPACE_IMAGE) {
float aspx, aspy;
@@ -864,7 +866,7 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm
}
}
-int transformEvent(TransInfo *t, wmEvent *event)
+int transformEvent(TransInfo *t, const wmEvent *event)
{
float mati[3][3] = MAT3_UNITY;
char cmode = constraintModeToChar(t);
@@ -1298,7 +1300,9 @@ int transformEvent(TransInfo *t, wmEvent *event)
if (t->flag & T_AUTOIK) {
transform_autoik_update(t, 1);
}
- else view_editmove(event->type);
+ else {
+ view_editmove(event->type);
+ }
t->redraw = 1;
break;
case PADMINUS:
@@ -1313,7 +1317,9 @@ int transformEvent(TransInfo *t, wmEvent *event)
if (t->flag & T_AUTOIK) {
transform_autoik_update(t, -1);
}
- else view_editmove(event->type);
+ else {
+ view_editmove(event->type);
+ }
t->redraw = 1;
break;
case LEFTALTKEY:
@@ -1854,7 +1860,7 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
}
/* note: caller needs to free 't' on a 0 return */
-int initTransform(bContext *C, TransInfo *t, wmOperator *op, wmEvent *event, int mode)
+int initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event, int mode)
{
int options = 0;
PropertyRNA *prop;
@@ -2654,11 +2660,12 @@ void initWarp(TransInfo *t)
mid_v3_v3v3(t->center, min, max);
- if (max[0] == min[0]) max[0] += 0.1f; /* not optimal, but flipping is better than invalid garbage (i.e. division by zero!) */
+ if (max[0] == min[0])
+ max[0] += 0.1f; /* not optimal, but flipping is better than invalid garbage (i.e. division by zero!) */
t->val = (max[0] - min[0]) / 2.0f; /* t->val is X dimension projected boundbox */
}
-int handleEventWarp(TransInfo *t, wmEvent *event)
+int handleEventWarp(TransInfo *t, const wmEvent *event)
{
int status = 0;
@@ -2681,7 +2688,7 @@ int Warp(TransInfo *t, const int UNUSED(mval[2]))
float vec[3], circumfac, dist, phi0, co, si, cursor[3], gcursor[3];
const float *curs;
int i;
- char str[50];
+ char str[MAX_INFO_LEN];
curs = give_cursor(t->scene, t->view);
/*
@@ -2716,13 +2723,13 @@ int Warp(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c);
- sprintf(str, IFACE_("Warp: %s"), c);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Warp: %s"), c);
circumfac = DEG2RADF(circumfac);
}
else {
/* default header print */
- sprintf(str, IFACE_("Warp: %.3f"), RAD2DEGF(circumfac));
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Warp: %.3f"), RAD2DEGF(circumfac));
}
t->values[0] = circumfac;
@@ -2799,7 +2806,7 @@ void initShear(TransInfo *t)
t->flag |= T_NO_CONSTRAINT;
}
-int handleEventShear(TransInfo *t, wmEvent *event)
+int handleEventShear(TransInfo *t, const wmEvent *event)
{
int status = 0;
@@ -2840,7 +2847,7 @@ int Shear(TransInfo *t, const int UNUSED(mval[2]))
float smat[3][3], tmat[3][3], totmat[3][3], persmat[3][3], persinv[3][3];
float value;
int i;
- char str[50];
+ char str[MAX_INFO_LEN];
copy_m3_m4(persmat, t->viewmat);
invert_m3_m3(persinv, persmat);
@@ -2857,11 +2864,11 @@ int Shear(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c);
- sprintf(str, IFACE_("Shear: %s %s"), c, t->proptext);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shear: %s %s"), c, t->proptext);
}
else {
/* default header print */
- sprintf(str, IFACE_("Shear: %.3f %s (Press X or Y to set shear axis)"), value, t->proptext);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shear: %.3f %s (Press X or Y to set shear axis)"), value, t->proptext);
}
t->values[0] = value;
@@ -2937,10 +2944,11 @@ void initResize(TransInfo *t)
t->num.increment = t->snap[1];
}
+/* We assume str is MAX_INFO_LEN long. */
static void headerResize(TransInfo *t, float vec[3], char *str)
{
char tvec[NUM_STR_REP_LEN * 3];
- char *spos = str;
+ size_t ofs = 0;
if (hasNumInput(&t->num)) {
outputNumInput(&(t->num), tvec);
}
@@ -2949,37 +2957,36 @@ static void headerResize(TransInfo *t, float vec[3], char *str)
BLI_snprintf(&tvec[NUM_STR_REP_LEN], NUM_STR_REP_LEN, "%.4f", vec[1]);
BLI_snprintf(&tvec[NUM_STR_REP_LEN * 2], NUM_STR_REP_LEN, "%.4f", vec[2]);
}
-
+
if (t->con.mode & CON_APPLY) {
switch (t->num.idx_max) {
case 0:
- spos += sprintf(spos, IFACE_("Scale: %s%s %s"), &tvec[0], t->con.text, t->proptext);
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Scale: %s%s %s"),
+ &tvec[0], t->con.text, t->proptext);
break;
case 1:
- spos += sprintf(spos, IFACE_("Scale: %s : %s%s %s"), &tvec[0], &tvec[NUM_STR_REP_LEN],
- t->con.text, t->proptext);
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Scale: %s : %s%s %s"),
+ &tvec[0], &tvec[NUM_STR_REP_LEN], t->con.text, t->proptext);
break;
case 2:
- spos += sprintf(spos, IFACE_("Scale: %s : %s : %s%s %s"), &tvec[0], &tvec[NUM_STR_REP_LEN],
- &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext);
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Scale: %s : %s : %s%s %s"), &tvec[0],
+ &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext);
}
}
else {
if (t->flag & T_2D_EDIT) {
- spos += sprintf(spos, IFACE_("Scale X: %s Y: %s%s %s"), &tvec[0], &tvec[NUM_STR_REP_LEN],
- t->con.text, t->proptext);
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Scale X: %s Y: %s%s %s"),
+ &tvec[0], &tvec[NUM_STR_REP_LEN], t->con.text, t->proptext);
}
else {
- spos += sprintf(spos, IFACE_("Scale X: %s Y: %s Z: %s%s %s"), &tvec[0], &tvec[NUM_STR_REP_LEN],
- &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext);
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Scale X: %s Y: %s Z: %s%s %s"),
+ &tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext);
}
}
-
+
if (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) {
- spos += sprintf(spos, IFACE_(" Proportional size: %.2f"), t->prop_size);
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
}
-
- (void)spos;
}
/* FLT_EPSILON is too small [#29633], 0.0000001f starts to flip */
@@ -3114,7 +3121,7 @@ int Resize(TransInfo *t, const int mval[2])
float size[3], mat[3][3];
float ratio;
int i;
- char str[200];
+ char str[MAX_INFO_LEN];
/* for manipulator, center handle, the scaling can't be done relative to center */
if ((t->flag & T_USES_MANIPULATOR) && t->con.mode == 0) {
@@ -3219,7 +3226,7 @@ int SkinResize(TransInfo *t, const int UNUSED(mval[2]))
float size[3], mat[3][3];
float ratio;
int i;
- char str[200];
+ char str[MAX_INFO_LEN];
ratio = t->values[0];
size[0] = size[1] = size[2] = ratio;
@@ -3313,7 +3320,7 @@ int ToSphere(TransInfo *t, const int UNUSED(mval[2]))
float vec[3];
float ratio, radius;
int i;
- char str[64];
+ char str[MAX_INFO_LEN];
TransData *td = t->data;
ratio = t->values[0];
@@ -3335,11 +3342,11 @@ int ToSphere(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c);
- sprintf(str, IFACE_("To Sphere: %s %s"), c, t->proptext);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("To Sphere: %s %s"), c, t->proptext);
}
else {
/* default header print */
- sprintf(str, IFACE_("To Sphere: %.4f %s"), ratio, t->proptext);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("To Sphere: %.4f %s"), ratio, t->proptext);
}
@@ -3528,7 +3535,8 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short
quat_to_axis_angle(td->ext->rotAxis, td->ext->rotAngle, tquat);
/* this function works on end result */
- protectedAxisAngleBits(td->protectflag, td->ext->rotAxis, td->ext->rotAngle, td->ext->irotAxis, td->ext->irotAngle);
+ protectedAxisAngleBits(td->protectflag, td->ext->rotAxis, td->ext->rotAngle, td->ext->irotAxis,
+ td->ext->irotAngle);
}
else {
float eulmat[3][3];
@@ -3575,12 +3583,15 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short
if ((t->flag & T_V3D_ALIGN) == 0) { // align mode doesn't rotate objects itself
/* euler or quaternion? */
if ((td->ext->rotOrder == ROT_MODE_QUAT) || (td->flag & TD_USEQUAT)) {
- mul_serie_m3(fmat, td->mtx, mat, td->smtx, NULL, NULL, NULL, NULL, NULL);
- mat3_to_quat(quat, fmat); // Actual transform
-
- mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat);
- /* this function works on end result */
- protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
+ /* can be called for texture space translate for example, then opt out */
+ if (td->ext->quat) {
+ mul_serie_m3(fmat, td->mtx, mat, td->smtx, NULL, NULL, NULL, NULL, NULL);
+ mat3_to_quat(quat, fmat); // Actual transform
+
+ mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat);
+ /* this function works on end result */
+ protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
+ }
}
else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
/* calculate effect based on quats */
@@ -3595,7 +3606,8 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short
quat_to_axis_angle(td->ext->rotAxis, td->ext->rotAngle, tquat);
/* this function works on end result */
- protectedAxisAngleBits(td->protectflag, td->ext->rotAxis, td->ext->rotAngle, td->ext->irotAxis, td->ext->irotAngle);
+ protectedAxisAngleBits(td->protectflag, td->ext->rotAxis, td->ext->rotAngle, td->ext->irotAxis,
+ td->ext->irotAngle);
}
else {
float obmat[3][3];
@@ -3654,14 +3666,15 @@ static void applyRotation(TransInfo *t, float angle, float axis[3])
int Rotation(TransInfo *t, const int UNUSED(mval[2]))
{
- char str[128], *spos = str;
-
+ char str[MAX_INFO_LEN];
+ size_t ofs = 0;
+
float final;
final = t->values[0];
-
+
snapGrid(t, &final);
-
+
if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
t->con.applyRot(t, NULL, t->axis, NULL);
}
@@ -3669,9 +3682,9 @@ int Rotation(TransInfo *t, const int UNUSED(mval[2]))
/* reset axis if constraint is not set */
copy_v3_v3(t->axis, t->axis_orig);
}
-
+
applySnapping(t, &final);
-
+
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
@@ -3679,19 +3692,19 @@ int Rotation(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c);
- spos += sprintf(spos, IFACE_("Rot: %s %s %s"), &c[0], t->con.text, t->proptext);
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Rot: %s %s %s"), &c[0], t->con.text, t->proptext);
/* Clamp between -180 and 180 */
final = angle_wrap_rad(DEG2RADF(final));
}
else {
- spos += sprintf(spos, IFACE_("Rot: %.2f%s %s"), RAD2DEGF(final), t->con.text, t->proptext);
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Rot: %.2f%s %s"),
+ RAD2DEGF(final), t->con.text, t->proptext);
}
if (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) {
- spos += sprintf(spos, IFACE_(" Proportional size: %.2f"), t->prop_size);
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
}
- (void)spos;
t->values[0] = final;
@@ -3756,7 +3769,8 @@ static void applyTrackball(TransInfo *t, float axis1[3], float axis2[3], float a
int Trackball(TransInfo *t, const int UNUSED(mval[2]))
{
- char str[128], *spos = str;
+ char str[MAX_INFO_LEN];
+ size_t ofs = 0;
float axis1[3], axis2[3];
float mat[3][3], totmat[3][3], smat[3][3];
float phi[2];
@@ -3778,19 +3792,20 @@ int Trackball(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c);
- spos += sprintf(spos, IFACE_("Trackball: %s %s %s"), &c[0], &c[NUM_STR_REP_LEN], t->proptext);
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Trackball: %s %s %s"),
+ &c[0], &c[NUM_STR_REP_LEN], t->proptext);
phi[0] = DEG2RADF(phi[0]);
phi[1] = DEG2RADF(phi[1]);
}
else {
- spos += sprintf(spos, IFACE_("Trackball: %.2f %.2f %s"), RAD2DEGF(phi[0]), RAD2DEGF(phi[1]), t->proptext);
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Trackball: %.2f %.2f %s"),
+ RAD2DEGF(phi[0]), RAD2DEGF(phi[1]), t->proptext);
}
if (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) {
- spos += sprintf(spos, IFACE_(" Proportional size: %.2f"), t->prop_size);
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
}
- (void)spos;
vec_rot_to_mat3(smat, axis1, phi[0]);
vec_rot_to_mat3(totmat, axis2, phi[1]);
@@ -3854,9 +3869,10 @@ void initTranslation(TransInfo *t)
t->num.increment = t->snap[1];
}
+/* We assume str is MAX_INFO_LEN long. */
static void headerTranslation(TransInfo *t, float vec[3], char *str)
{
- char *spos = str;
+ size_t ofs = 0;
char tvec[NUM_STR_REP_LEN * 3];
char distvec[NUM_STR_REP_LEN];
char autoik[NUM_STR_REP_LEN];
@@ -3877,29 +3893,30 @@ static void headerTranslation(TransInfo *t, float vec[3], char *str)
int i, do_split = t->scene->unit.flag & USER_UNIT_OPT_SPLIT ? 1 : 0;
for (i = 0; i < 3; i++) {
- bUnit_AsString(&tvec[i * NUM_STR_REP_LEN], NUM_STR_REP_LEN, dvec[i] * t->scene->unit.scale_length,
+ bUnit_AsString(&tvec[NUM_STR_REP_LEN * i], NUM_STR_REP_LEN, dvec[i] * t->scene->unit.scale_length,
4, t->scene->unit.system, B_UNIT_LENGTH, do_split, 1);
}
}
else {
- sprintf(&tvec[0], "%.4f", dvec[0]);
- sprintf(&tvec[NUM_STR_REP_LEN], "%.4f", dvec[1]);
- sprintf(&tvec[NUM_STR_REP_LEN * 2], "%.4f", dvec[2]);
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", dvec[0]);
+ BLI_snprintf(&tvec[NUM_STR_REP_LEN], NUM_STR_REP_LEN, "%.4f", dvec[1]);
+ BLI_snprintf(&tvec[NUM_STR_REP_LEN * 2], NUM_STR_REP_LEN, "%.4f", dvec[2]);
}
}
if (!(t->flag & T_2D_EDIT) && t->scene->unit.system)
- bUnit_AsString(distvec, sizeof(distvec), dist * t->scene->unit.scale_length, 4, t->scene->unit.system, B_UNIT_LENGTH, t->scene->unit.flag & USER_UNIT_OPT_SPLIT, 0);
+ bUnit_AsString(distvec, sizeof(distvec), dist * t->scene->unit.scale_length, 4, t->scene->unit.system,
+ B_UNIT_LENGTH, t->scene->unit.flag & USER_UNIT_OPT_SPLIT, 0);
else if (dist > 1e10f || dist < -1e10f) /* prevent string buffer overflow */
- sprintf(distvec, "%.4e", dist);
+ BLI_snprintf(distvec, NUM_STR_REP_LEN, "%.4e", dist);
else
- sprintf(distvec, "%.4f", dist);
+ BLI_snprintf(distvec, NUM_STR_REP_LEN, "%.4f", dist);
if (t->flag & T_AUTOIK) {
short chainlen = t->settings->autoik_chainlen;
if (chainlen)
- sprintf(autoik, IFACE_("AutoIK-Len: %d"), chainlen);
+ BLI_snprintf(autoik, NUM_STR_REP_LEN, IFACE_("AutoIK-Len: %d"), chainlen);
else
autoik[0] = '\0';
}
@@ -3909,32 +3926,34 @@ static void headerTranslation(TransInfo *t, float vec[3], char *str)
if (t->con.mode & CON_APPLY) {
switch (t->num.idx_max) {
case 0:
- spos += sprintf(spos, "D: %s (%s)%s %s %s", &tvec[0], distvec, t->con.text, t->proptext, &autoik[0]);
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "D: %s (%s)%s %s %s",
+ &tvec[0], distvec, t->con.text, t->proptext, autoik);
break;
case 1:
- spos += sprintf(spos, "D: %s D: %s (%s)%s %s %s", &tvec[0], &tvec[NUM_STR_REP_LEN],
- distvec, t->con.text, t->proptext, &autoik[0]);
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "D: %s D: %s (%s)%s %s %s",
+ &tvec[0], &tvec[NUM_STR_REP_LEN], distvec, t->con.text, t->proptext, autoik);
break;
case 2:
- spos += sprintf(spos, "D: %s D: %s D: %s (%s)%s %s %s", &tvec[0], &tvec[NUM_STR_REP_LEN],
- &tvec[NUM_STR_REP_LEN * 2], distvec, t->con.text, t->proptext, &autoik[0]);
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "D: %s D: %s D: %s (%s)%s %s %s",
+ &tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], distvec,
+ t->con.text, t->proptext, autoik);
}
}
else {
if (t->flag & T_2D_EDIT) {
- spos += sprintf(spos, "Dx: %s Dy: %s (%s)%s %s", &tvec[0], &tvec[NUM_STR_REP_LEN],
- distvec, t->con.text, t->proptext);
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "Dx: %s Dy: %s (%s)%s %s",
+ &tvec[0], &tvec[NUM_STR_REP_LEN], distvec, t->con.text, t->proptext);
}
else {
- spos += sprintf(spos, "Dx: %s Dy: %s Dz: %s (%s)%s %s %s", &tvec[0], &tvec[NUM_STR_REP_LEN],
- &tvec[NUM_STR_REP_LEN * 2], distvec, t->con.text, t->proptext, &autoik[0]);
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "Dx: %s Dy: %s Dz: %s (%s)%s %s %s",
+ &tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], distvec, t->con.text,
+ t->proptext, autoik);
}
}
-
+
if (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) {
- spos += sprintf(spos, IFACE_(" Proportional size: %.2f"), t->prop_size);
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
}
- (void)spos;
}
static void applyTranslation(TransInfo *t, float vec[3])
@@ -4006,7 +4025,7 @@ static void applyTranslation(TransInfo *t, float vec[3])
/* uses t->vec to store actual translation in */
int Translation(TransInfo *t, const int UNUSED(mval[2]))
{
- char str[250];
+ char str[MAX_INFO_LEN];
if (t->con.mode & CON_APPLY) {
float pvec[3] = {0.0f, 0.0f, 0.0f};
@@ -4082,8 +4101,8 @@ int ShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
{
float distance;
int i;
- char str[128];
- char *str_p;
+ char str[MAX_INFO_LEN];
+ size_t ofs = 0;
TransData *td = t->data;
distance = -t->values[0];
@@ -4093,31 +4112,30 @@ int ShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
applyNumInput(&t->num, &distance);
/* header print for NumInput */
- str_p = str;
- str_p += BLI_snprintf(str_p, sizeof(str), IFACE_("Shrink/Fatten:"));
+ ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Shrink/Fatten:"), MAX_INFO_LEN - ofs);
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
outputNumInput(&(t->num), c);
- str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), " %s", c);
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, " %s", c);
}
else {
/* default header print */
- str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), " %.4f", distance);
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, " %.4f", distance);
}
if (t->proptext[0]) {
- str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), " %s", t->proptext);
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, " %s", t->proptext);
}
- str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), ", (");
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, ", (");
{
wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_RESIZE);
if (kmi) {
- str_p += WM_keymap_item_to_string(kmi, str_p, sizeof(str) - (str_p - str));
+ ofs += WM_keymap_item_to_string(kmi, str + ofs, MAX_INFO_LEN - ofs);
}
}
- str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), IFACE_(" or Alt) Even Thickness %s"),
- (t->flag & T_ALT_TRANSFORM) ? IFACE_("ON") : IFACE_("OFF"));
+ BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" or Alt) Even Thickness %s"),
+ (t->flag & T_ALT_TRANSFORM) ? IFACE_("ON") : IFACE_("OFF"));
/* done with header string */
@@ -4173,7 +4191,7 @@ int Tilt(TransInfo *t, const int UNUSED(mval[2]))
{
TransData *td = t->data;
int i;
- char str[50];
+ char str[MAX_INFO_LEN];
float final;
@@ -4188,7 +4206,7 @@ int Tilt(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c);
- sprintf(str, IFACE_("Tilt: %s° %s"), &c[0], t->proptext);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Tilt: %s° %s"), &c[0], t->proptext);
final = DEG2RADF(final);
@@ -4196,7 +4214,7 @@ int Tilt(TransInfo *t, const int UNUSED(mval[2]))
t->values[0] = final;
}
else {
- sprintf(str, IFACE_("Tilt: %.2f° %s"), RAD2DEGF(final), t->proptext);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Tilt: %.2f° %s"), RAD2DEGF(final), t->proptext);
}
for (i = 0; i < t->total; i++, td++) {
@@ -4247,7 +4265,7 @@ int CurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
TransData *td = t->data;
float ratio;
int i;
- char str[50];
+ char str[MAX_INFO_LEN];
ratio = t->values[0];
@@ -4260,10 +4278,10 @@ int CurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
char c[NUM_STR_REP_LEN];
outputNumInput(&(t->num), c);
- sprintf(str, IFACE_("Shrink/Fatten: %s"), c);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shrink/Fatten: %s"), c);
}
else {
- sprintf(str, IFACE_("Shrink/Fatten: %3f"), ratio);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shrink/Fatten: %3f"), ratio);
}
for (i = 0; i < t->total; i++, td++) {
@@ -4315,7 +4333,7 @@ int MaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
TransData *td;
float ratio;
int i, initial_feather = FALSE;
- char str[50];
+ char str[MAX_INFO_LEN];
ratio = t->values[0];
@@ -4328,10 +4346,10 @@ int MaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
char c[NUM_STR_REP_LEN];
outputNumInput(&(t->num), c);
- sprintf(str, IFACE_("Feather Shrink/Fatten: %s"), c);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Feather Shrink/Fatten: %s"), c);
}
else {
- sprintf(str, IFACE_("Feather Shrink/Fatten: %3f"), ratio);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Feather Shrink/Fatten: %3f"), ratio);
}
/* detect if no points have feather yet */
@@ -4401,7 +4419,7 @@ int PushPull(TransInfo *t, const int UNUSED(mval[2]))
float vec[3], axis[3];
float distance;
int i;
- char str[128];
+ char str[MAX_INFO_LEN];
TransData *td = t->data;
distance = t->values[0];
@@ -4416,11 +4434,11 @@ int PushPull(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c);
- sprintf(str, IFACE_("Push/Pull: %s%s %s"), c, t->con.text, t->proptext);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Push/Pull: %s%s %s"), c, t->con.text, t->proptext);
}
else {
/* default header print */
- sprintf(str, IFACE_("Push/Pull: %.4f%s %s"), distance, t->con.text, t->proptext);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Push/Pull: %.4f%s %s"), distance, t->con.text, t->proptext);
}
t->values[0] = distance;
@@ -4496,7 +4514,7 @@ void initBevel(TransInfo *t)
}
}
-int handleEventBevel(TransInfo *t, wmEvent *event)
+int handleEventBevel(TransInfo *t, const wmEvent *event)
{
if (event->val == KM_PRESS) {
if (!G.editBMesh) return 0;
@@ -4533,7 +4551,7 @@ int Bevel(TransInfo *t, const int UNUSED(mval[2]))
{
float distance, d;
int i;
- char str[128];
+ char str[MAX_INFO_LEN];
const char *mode;
TransData *td = t->data;
@@ -4552,11 +4570,11 @@ int Bevel(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c);
- sprintf(str, IFACE_("Bevel - Dist: %s, Mode: %s (MMB to toggle))"), c, mode);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bevel - Dist: %s, Mode: %s (MMB to toggle))"), c, mode);
}
else {
/* default header print */
- sprintf(str, IFACE_("Bevel - Dist: %.4f, Mode: %s (MMB to toggle))"), distance, mode);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bevel - Dist: %.4f, Mode: %s (MMB to toggle))"), distance, mode);
}
if (distance < 0) distance = -distance;
@@ -4602,7 +4620,7 @@ int BevelWeight(TransInfo *t, const int UNUSED(mval[2]))
TransData *td = t->data;
float weight;
int i;
- char str[50];
+ char str[MAX_INFO_LEN];
weight = t->values[0];
@@ -4620,16 +4638,16 @@ int BevelWeight(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c);
if (weight >= 0.0f)
- sprintf(str, IFACE_("Bevel Weight: +%s %s"), c, t->proptext);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bevel Weight: +%s %s"), c, t->proptext);
else
- sprintf(str, IFACE_("Bevel Weight: %s %s"), c, t->proptext);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bevel Weight: %s %s"), c, t->proptext);
}
else {
/* default header print */
if (weight >= 0.0f)
- sprintf(str, IFACE_("Bevel Weight: +%.3f %s"), weight, t->proptext);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bevel Weight: +%.3f %s"), weight, t->proptext);
else
- sprintf(str, IFACE_("Bevel Weight: %.3f %s"), weight, t->proptext);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bevel Weight: %.3f %s"), weight, t->proptext);
}
for (i = 0; i < t->total; i++, td++) {
@@ -4675,7 +4693,7 @@ int Crease(TransInfo *t, const int UNUSED(mval[2]))
TransData *td = t->data;
float crease;
int i;
- char str[50];
+ char str[MAX_INFO_LEN];
crease = t->values[0];
@@ -4693,16 +4711,16 @@ int Crease(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c);
if (crease >= 0.0f)
- sprintf(str, IFACE_("Crease: +%s %s"), c, t->proptext);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Crease: +%s %s"), c, t->proptext);
else
- sprintf(str, IFACE_("Crease: %s %s"), c, t->proptext);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Crease: %s %s"), c, t->proptext);
}
else {
/* default header print */
if (crease >= 0.0f)
- sprintf(str, IFACE_("Crease: +%.3f %s"), crease, t->proptext);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Crease: +%.3f %s"), crease, t->proptext);
else
- sprintf(str, IFACE_("Crease: %.3f %s"), crease, t->proptext);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Crease: %.3f %s"), crease, t->proptext);
}
for (i = 0; i < t->total; i++, td++) {
@@ -4746,6 +4764,7 @@ void initBoneSize(TransInfo *t)
t->num.increment = t->snap[1];
}
+/* We assume str is MAX_INFO_LEN long. */
static void headerBoneSize(TransInfo *t, float vec[3], char *str)
{
char tvec[NUM_STR_REP_LEN * 3];
@@ -4753,22 +4772,22 @@ static void headerBoneSize(TransInfo *t, float vec[3], char *str)
outputNumInput(&(t->num), tvec);
}
else {
- sprintf(&tvec[0], "%.4f", vec[0]);
- sprintf(&tvec[NUM_STR_REP_LEN], "%.4f", vec[1]);
- sprintf(&tvec[NUM_STR_REP_LEN * 2], "%.4f", vec[2]);
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", vec[0]);
+ BLI_snprintf(&tvec[NUM_STR_REP_LEN], NUM_STR_REP_LEN, "%.4f", vec[1]);
+ BLI_snprintf(&tvec[NUM_STR_REP_LEN * 2], NUM_STR_REP_LEN, "%.4f", vec[2]);
}
/* hmm... perhaps the y-axis values don't need to be shown? */
if (t->con.mode & CON_APPLY) {
if (t->num.idx_max == 0)
- sprintf(str, IFACE_("ScaleB: %s%s %s"), &tvec[0], t->con.text, t->proptext);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("ScaleB: %s%s %s"), &tvec[0], t->con.text, t->proptext);
else
- sprintf(str, IFACE_("ScaleB: %s : %s : %s%s %s"), &tvec[0], &tvec[NUM_STR_REP_LEN],
- &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("ScaleB: %s : %s : %s%s %s"),
+ &tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext);
}
else {
- sprintf(str, IFACE_("ScaleB X: %s Y: %s Z: %s%s %s"), &tvec[0], &tvec[NUM_STR_REP_LEN],
- &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("ScaleB X: %s Y: %s Z: %s%s %s"),
+ &tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext);
}
}
@@ -4798,7 +4817,7 @@ int BoneSize(TransInfo *t, const int mval[2])
float size[3], mat[3][3];
float ratio;
int i;
- char str[60];
+ char str[MAX_INFO_LEN];
// TRANSFORM_FIX_ME MOVE TO MOUSE INPUT
/* for manipulator, center handle, the scaling can't be done relative to center */
@@ -4871,7 +4890,7 @@ int BoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
TransData *td = t->data;
float ratio;
int i;
- char str[50];
+ char str[MAX_INFO_LEN];
ratio = t->values[0];
@@ -4884,10 +4903,10 @@ int BoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
char c[NUM_STR_REP_LEN];
outputNumInput(&(t->num), c);
- sprintf(str, IFACE_("Envelope: %s"), c);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Envelope: %s"), c);
}
else {
- sprintf(str, IFACE_("Envelope: %3f"), ratio);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Envelope: %3f"), ratio);
}
for (i = 0; i < t->total; i++, td++) {
@@ -5604,7 +5623,8 @@ void projectEdgeSlideData(TransInfo *t, bool is_final)
f_copy_flip = BLI_smallhash_lookup(&sld->origfaces, (uintptr_t)e_sel->l->f);
}
else if (BM_vert_in_face(e_sel->l->radial_next->f, sv->down)) {
- f_copy_flip = BLI_smallhash_lookup(&sld->origfaces, (uintptr_t)e_sel->l->radial_next->f);
+ f_copy_flip = BLI_smallhash_lookup(&sld->origfaces,
+ (uintptr_t)e_sel->l->radial_next->f);
}
}
@@ -5613,7 +5633,8 @@ void projectEdgeSlideData(TransInfo *t, bool is_final)
f_copy_flip = BLI_smallhash_lookup(&sld->origfaces, (uintptr_t)e_sel->l->f);
}
else if (BM_vert_in_face(e_sel->l->radial_next->f, sv->up)) {
- f_copy_flip = BLI_smallhash_lookup(&sld->origfaces, (uintptr_t)e_sel->l->radial_next->f);
+ f_copy_flip = BLI_smallhash_lookup(&sld->origfaces,
+ (uintptr_t)e_sel->l->radial_next->f);
}
}
@@ -5746,7 +5767,7 @@ void initEdgeSlide(TransInfo *t)
t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
}
-int handleEventEdgeSlide(struct TransInfo *t, struct wmEvent *event)
+int handleEventEdgeSlide(struct TransInfo *t, const struct wmEvent *event)
{
if (t->mode == TFM_EDGE_SLIDE) {
EdgeSlideData *sld = t->customData;
@@ -5929,12 +5950,15 @@ static int doEdgeSlide(TransInfo *t, float perc)
int EdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
{
- char str[128];
+ char str[MAX_INFO_LEN];
float final;
EdgeSlideData *sld = t->customData;
bool flipped = sld->flipped_vtx;
bool is_proportional = sld->is_proportional;
+ const char *on_str = IFACE_("ON");
+ const char *off_str = IFACE_("OFF");
+
final = t->values[0];
snapGrid(t, &final);
@@ -5949,12 +5973,12 @@ int EdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c);
- BLI_snprintf(str, sizeof(str), IFACE_("Edge Slide: %s (E)ven: %s, (F)lipped: %s"),
- &c[0], !is_proportional ? IFACE_("ON") : IFACE_("OFF"), flipped ? IFACE_("ON") : IFACE_("OFF"));
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Edge Slide: %s (E)ven: %s, (F)lipped: %s"),
+ &c[0], !is_proportional ? on_str : off_str, flipped ? on_str : off_str);
}
else {
- BLI_snprintf(str, sizeof(str), IFACE_("Edge Slide: %.4f (E)ven: %s, (F)lipped: %s"),
- final, !is_proportional ? IFACE_("ON") : IFACE_("OFF"), flipped ? IFACE_("ON") : IFACE_("OFF"));
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Edge Slide: %.4f (E)ven: %s, (F)lipped: %s"),
+ final, !is_proportional ? on_str : off_str, flipped ? on_str : off_str);
}
CLAMP(final, -1.0f, 1.0f);
@@ -5962,10 +5986,11 @@ int EdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
t->values[0] = final;
/*do stuff here*/
- if (t->customData)
+ if (t->customData) {
doEdgeSlide(t, final);
+ }
else {
- strcpy(str, IFACE_("Invalid Edge Selection"));
+ BLI_strncpy(str, IFACE_("Invalid Edge Selection"), MAX_INFO_LEN);
t->state = TRANS_CANCEL;
}
@@ -6249,7 +6274,7 @@ void initVertSlide(TransInfo *t)
t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
}
-int handleEventVertSlide(struct TransInfo *t, struct wmEvent *event)
+int handleEventVertSlide(struct TransInfo *t, const struct wmEvent *event)
{
if (t->mode == TFM_VERT_SLIDE) {
VertSlideData *sld = t->customData;
@@ -6434,8 +6459,8 @@ static int doVertSlide(TransInfo *t, float perc)
int VertSlide(TransInfo *t, const int UNUSED(mval[2]))
{
- char str[128];
- char *str_p;
+ char str[MAX_INFO_LEN];
+ size_t ofs = 0;
float final;
VertSlideData *sld = t->customData;
const bool flipped = sld->flipped_vtx;
@@ -6443,6 +6468,9 @@ int VertSlide(TransInfo *t, const int UNUSED(mval[2]))
const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num));
+ const char *on_str = IFACE_("ON");
+ const char *off_str = IFACE_("OFF");
+
final = t->values[0];
snapGrid(t, &final);
@@ -6453,25 +6481,21 @@ int VertSlide(TransInfo *t, const int UNUSED(mval[2]))
}
/* header string */
- str_p = str;
- str_p += BLI_snprintf(str_p, sizeof(str), IFACE_("Vert Slide: "));
+ ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Vert Slide: "), MAX_INFO_LEN - ofs);
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
applyNumInput(&t->num, &final);
outputNumInput(&(t->num), c);
- str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), "%s", &c[0]);
+ ofs += BLI_strncpy_rlen(str + ofs, &c[0], MAX_INFO_LEN - ofs);
}
else {
- str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), "%.4f ", final);
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "%.4f ", final);
}
- str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), IFACE_("(E)ven: %s, "),
- !is_proportional ? IFACE_("ON") : IFACE_("OFF"));
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(E)ven: %s, "), !is_proportional ? on_str : off_str);
if (!is_proportional) {
- str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), IFACE_("(F)lipped: %s, "),
- flipped ? IFACE_("ON") : IFACE_("OFF"));
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(F)lipped: %s, "), flipped ? on_str : off_str);
}
- str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), IFACE_("Alt or (C)lamp: %s"),
- is_clamp ? IFACE_("ON") : IFACE_("OFF"));
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Alt or (C)lamp: %s"), is_clamp ? on_str : off_str);
/* done with header string */
/*do stuff here*/
@@ -6479,7 +6503,7 @@ int VertSlide(TransInfo *t, const int UNUSED(mval[2]))
doVertSlide(t, final);
}
else {
- strcpy(str, IFACE_("Invalid Vert Selection"));
+ BLI_strncpy(str, IFACE_("Invalid Vert Selection"), MAX_INFO_LEN);
t->state = TRANS_CANCEL;
}
@@ -6515,7 +6539,7 @@ int BoneRoll(TransInfo *t, const int UNUSED(mval[2]))
{
TransData *td = t->data;
int i;
- char str[50];
+ char str[MAX_INFO_LEN];
float final;
@@ -6530,12 +6554,12 @@ int BoneRoll(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c);
- sprintf(str, IFACE_("Roll: %s"), &c[0]);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Roll: %s"), &c[0]);
final = DEG2RADF(final);
}
else {
- sprintf(str, IFACE_("Roll: %.2f"), RAD2DEGF(final));
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Roll: %.2f"), RAD2DEGF(final));
}
/* set roll values */
@@ -6577,7 +6601,7 @@ int BakeTime(TransInfo *t, const int mval[2])
TransData *td = t->data;
float time;
int i;
- char str[50];
+ char str[MAX_INFO_LEN];
float fac = 0.1f;
@@ -6601,16 +6625,16 @@ int BakeTime(TransInfo *t, const int mval[2])
outputNumInput(&(t->num), c);
if (time >= 0.0f)
- sprintf(str, IFACE_("Time: +%s %s"), c, t->proptext);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Time: +%s %s"), c, t->proptext);
else
- sprintf(str, IFACE_("Time: %s %s"), c, t->proptext);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Time: %s %s"), c, t->proptext);
}
else {
/* default header print */
if (time >= 0.0f)
- sprintf(str, IFACE_("Time: +%.3f %s"), time, t->proptext);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Time: +%.3f %s"), time, t->proptext);
else
- sprintf(str, IFACE_("Time: %.3f %s"), time, t->proptext);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Time: %.3f %s"), time, t->proptext);
}
for (i = 0; i < t->total; i++, td++) {
@@ -6652,7 +6676,7 @@ int Mirror(TransInfo *t, const int UNUSED(mval[2]))
TransData *td;
float size[3], mat[3][3];
int i;
- char str[200];
+ char str[MAX_INFO_LEN];
/*
* OPTIMIZATION:
@@ -6670,7 +6694,7 @@ int Mirror(TransInfo *t, const int UNUSED(mval[2]))
t->con.applySize(t, NULL, mat);
}
- sprintf(str, IFACE_("Mirror%s"), t->con.text);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Mirror%s"), t->con.text);
for (i = 0, td = t->data; i < t->total; i++, td++) {
if (td->flag & TD_NOACTION)
@@ -6787,29 +6811,29 @@ void initSeqSlide(TransInfo *t)
t->num.increment = t->snap[1];
}
-static void headerSeqSlide(TransInfo *t, float val[2], char *str, size_t str_len)
+/* We assume str is MAX_INFO_LEN long. */
+static void headerSeqSlide(TransInfo *t, float val[2], char *str)
{
char tvec[NUM_STR_REP_LEN * 3];
- char *str_p;
+ size_t ofs = 0;
if (hasNumInput(&t->num)) {
outputNumInput(&(t->num), tvec);
}
else {
- sprintf(&tvec[0], "%.0f, %.0f", val[0], val[1]);
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.0f, %.0f", val[0], val[1]);
}
- str_p = str;
- str_p += BLI_snprintf(str, str_len, IFACE_("Sequence Slide: %s%s, ("), &tvec[0], t->con.text);
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Sequence Slide: %s%s, ("), &tvec[0], t->con.text);
{
wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_TRANSLATE);
if (kmi) {
- str_p += WM_keymap_item_to_string(kmi, str_p, str_len - (str_p - str));
+ ofs += WM_keymap_item_to_string(kmi, str + ofs, MAX_INFO_LEN - ofs);
}
}
- str_p += BLI_snprintf(str_p, str_len - (str_p - str), IFACE_(" or Alt) Expand to fit %s"),
- (t->flag & T_ALT_TRANSFORM) ? IFACE_("ON") : IFACE_("OFF"));
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" or Alt) Expand to fit %s"),
+ (t->flag & T_ALT_TRANSFORM) ? IFACE_("ON") : IFACE_("OFF"));
}
static void applySeqSlide(TransInfo *t, float val[2])
@@ -6837,7 +6861,7 @@ static void applySeqSlide(TransInfo *t, float val[2])
int SeqSlide(TransInfo *t, const int UNUSED(mval[2]))
{
- char str[200];
+ char str[MAX_INFO_LEN];
if (t->con.mode & CON_APPLY) {
float pvec[3] = {0.0f, 0.0f, 0.0f};
@@ -6853,7 +6877,7 @@ int SeqSlide(TransInfo *t, const int UNUSED(mval[2]))
t->values[0] = floor(t->values[0] + 0.5f);
t->values[1] = floor(t->values[1] + 0.5f);
- headerSeqSlide(t, t->values, str, sizeof(str));
+ headerSeqSlide(t, t->values, str);
applySeqSlide(t, t->values);
recalcData(t);
@@ -6953,7 +6977,11 @@ static void doAnimEdit_SnapFrame(TransInfo *t, TransData *td, TransData2D *td2d,
#if 0 /* 'do_time' disabled for now */
const Scene *scene = t->scene;
- const short do_time = 0; //getAnimEdit_DrawTime(t); // NOTE: this works, but may be confusing behavior given the option's label, hence disabled
+#if 0 /* NOTE: this works, but may be confusing behavior given the option's label, hence disabled */
+ const short do_time = getAnimEdit_DrawTime(t);
+#else
+ const short do_time = 0;
+#endif
const double secf = FPS;
#endif
double val;
@@ -7041,6 +7069,7 @@ void initTimeTranslate(TransInfo *t)
t->num.increment = t->snap[1];
}
+/* We assume str is MAX_INFO_LEN long. */
static void headerTimeTranslate(TransInfo *t, char *str)
{
char tvec[NUM_STR_REP_LEN * 3];
@@ -7069,12 +7098,12 @@ static void headerTimeTranslate(TransInfo *t, char *str)
}
if (autosnap == SACTSNAP_FRAME)
- sprintf(&tvec[0], "%d.00 (%.4f)", (int)val, val);
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%d.00 (%.4f)", (int)val, val);
else
- sprintf(&tvec[0], "%.4f", val);
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", val);
}
- sprintf(str, IFACE_("DeltaX: %s"), &tvec[0]);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("DeltaX: %s"), &tvec[0]);
}
static void applyTimeTranslate(TransInfo *t, float UNUSED(sval))
@@ -7138,7 +7167,7 @@ int TimeTranslate(TransInfo *t, const int mval[2])
{
View2D *v2d = (View2D *)t->view;
float cval[2], sval[2];
- char str[200];
+ char str[MAX_INFO_LEN];
/* calculate translation amount from mouse movement - in 'time-grid space' */
UI_view2d_region_to_view(v2d, mval[0], mval[0], &cval[0], &cval[1]);
@@ -7196,6 +7225,7 @@ void initTimeSlide(TransInfo *t)
t->num.increment = t->snap[1];
}
+/* We assume str is MAX_INFO_LEN long. */
static void headerTimeSlide(TransInfo *t, float sval, char *str)
{
char tvec[NUM_STR_REP_LEN * 3];
@@ -7212,10 +7242,10 @@ static void headerTimeSlide(TransInfo *t, float sval, char *str)
val = 2.0f * (cval - sval) / (maxx - minx);
CLAMP(val, -1.0f, 1.0f);
- sprintf(&tvec[0], "%.4f", val);
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", val);
}
- sprintf(str, IFACE_("TimeSlide: %s"), &tvec[0]);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("TimeSlide: %s"), &tvec[0]);
}
static void applyTimeSlide(TransInfo *t, float sval)
@@ -7271,7 +7301,7 @@ int TimeSlide(TransInfo *t, const int mval[2])
float cval[2], sval[2];
float minx = *((float *)(t->customData));
float maxx = *((float *)(t->customData) + 1);
- char str[200];
+ char str[MAX_INFO_LEN];
/* calculate mouse co-ordinates */
UI_view2d_region_to_view(v2d, mval[0], mval[1], &cval[0], &cval[1]);
@@ -7338,6 +7368,7 @@ void initTimeScale(TransInfo *t)
t->num.increment = t->snap[1];
}
+/* We assume str is MAX_INFO_LEN long. */
static void headerTimeScale(TransInfo *t, char *str)
{
char tvec[NUM_STR_REP_LEN * 3];
@@ -7345,9 +7376,9 @@ static void headerTimeScale(TransInfo *t, char *str)
if (hasNumInput(&t->num))
outputNumInput(&(t->num), tvec);
else
- sprintf(&tvec[0], "%.4f", t->values[0]);
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", t->values[0]);
- sprintf(str, IFACE_("ScaleX: %s"), &tvec[0]);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("ScaleX: %s"), &tvec[0]);
}
static void applyTimeScale(TransInfo *t)
@@ -7392,7 +7423,7 @@ static void applyTimeScale(TransInfo *t)
int TimeScale(TransInfo *t, const int UNUSED(mval[2]))
{
- char str[200];
+ char str[MAX_INFO_LEN];
/* handle numeric-input stuff */
t->vec[0] = t->values[0];
@@ -7423,3 +7454,5 @@ bool checkUseLocalCenter_GraphEdit(TransInfo *t)
{
return ((t->around == V3D_LOCAL) && !ELEM3(t->mode, TFM_TRANSLATION, TFM_TIME_TRANSLATE, TFM_TIME_SLIDE));
}
+
+#undef MAX_INFO_LEN
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index dbf56f658ac..a551ef5008e 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -288,7 +288,7 @@ typedef struct TransInfo {
float fac; /* factor for distance based transform */
int (*transform)(struct TransInfo *, const int *);
/* transform function pointer */
- int (*handleEvent)(struct TransInfo *, struct wmEvent *);
+ int (*handleEvent)(struct TransInfo *, const struct wmEvent *);
/* event handler function pointer RETURN 1 if redraw is needed */
int total; /* total number of transformed data */
TransData *data; /* transformed data (array) */
@@ -354,6 +354,7 @@ typedef struct TransInfo {
struct wmTimer *animtimer;
struct wmKeyMap *keymap; /* so we can do lookups for header text */
int mval[2]; /* current mouse position */
+ float zfac; /* use for 3d view */
struct Object *obedit;
void *draw_handle_apply;
void *draw_handle_view;
@@ -474,9 +475,9 @@ typedef struct TransInfo {
#define POINT_INIT 4
#define MULTI_POINTS 8
-int initTransform(struct bContext *C, struct TransInfo *t, struct wmOperator *op, struct wmEvent *event, int mode);
+int 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, struct wmEvent *event);
+int transformEvent(TransInfo *t, const struct wmEvent *event);
void transformApply(struct bContext *C, TransInfo *t);
int transformEnd(struct bContext *C, TransInfo *t);
@@ -491,11 +492,11 @@ void applyAspectRatio(TransInfo *t, float *vec);
void removeAspectRatio(TransInfo *t, float *vec);
void initWarp(TransInfo *t);
-int handleEventWarp(TransInfo *t, struct wmEvent *event);
+int handleEventWarp(TransInfo *t, const struct wmEvent *event);
int Warp(TransInfo *t, const int mval[2]);
void initShear(TransInfo *t);
-int handleEventShear(TransInfo *t, struct wmEvent *event);
+int handleEventShear(TransInfo *t, const struct wmEvent *event);
int Shear(TransInfo *t, const int mval[2]);
void initResize(TransInfo *t);
@@ -532,7 +533,7 @@ void initPushPull(TransInfo *t);
int PushPull(TransInfo *t, const int mval[2]);
void initBevel(TransInfo *t);
-int handleEventBevel(TransInfo *t, struct wmEvent *event);
+int handleEventBevel(TransInfo *t, const struct wmEvent *event);
int Bevel(TransInfo *t, const int mval[2]);
void initBevelWeight(TransInfo *t);
@@ -551,11 +552,11 @@ void initBoneRoll(TransInfo *t);
int BoneRoll(TransInfo *t, const int mval[2]);
void initEdgeSlide(TransInfo *t);
-int handleEventEdgeSlide(TransInfo *t, struct wmEvent *event);
+int handleEventEdgeSlide(TransInfo *t, const struct wmEvent *event);
int EdgeSlide(TransInfo *t, const int mval[2]);
void initVertSlide(TransInfo *t);
-int handleEventVertSlide(TransInfo *t, struct wmEvent *event);
+int handleEventVertSlide(TransInfo *t, const struct wmEvent *event);
int VertSlide(TransInfo *t, const int mval[2]);
void initTimeTranslate(TransInfo *t);
@@ -658,7 +659,7 @@ void initSnapping(struct TransInfo *t, struct wmOperator *op);
void applyProject(TransInfo *t);
void applySnapping(TransInfo *t, float *vec);
void resetSnapping(TransInfo *t);
-int handleSnapping(TransInfo *t, struct wmEvent *event);
+int handleSnapping(TransInfo *t, const struct wmEvent *event);
void drawSnapping(const struct bContext *C, TransInfo *t);
int usingSnappingNormal(TransInfo *t);
int validSnappingNormal(TransInfo *t);
@@ -687,7 +688,7 @@ typedef enum {
void initMouseInput(TransInfo *t, MouseInput *mi, const int center[2], const int mval[2]);
void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode);
-int handleMouseInput(struct TransInfo *t, struct MouseInput *mi, struct wmEvent *event);
+int handleMouseInput(struct TransInfo *t, struct MouseInput *mi, const struct wmEvent *event);
void applyMouseInput(struct TransInfo *t, struct MouseInput *mi, const int mval[2], float output[3]);
void setCustomPoints(TransInfo *t, MouseInput *mi, const int start[2], const int end[2]);
@@ -695,7 +696,7 @@ void setInputPostFct(MouseInput *mi, void (*post)(struct TransInfo *t, float val
/*********************** Generics ********************************/
-int initTransInfo(struct bContext *C, TransInfo *t, struct wmOperator *op, struct wmEvent *event);
+int initTransInfo(struct bContext *C, TransInfo *t, struct wmOperator *op, const struct wmEvent *event);
void postTrans (struct bContext *C, TransInfo *t);
void resetTransRestrictions(TransInfo *t);
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index c4d61472f18..f3026205ea2 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -29,19 +29,17 @@
* \ingroup edtransform
*/
-
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#ifndef WIN32
-#include <unistd.h>
+# include <unistd.h>
#else
-#include <io.h>
+# include <io.h>
#endif
-
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
@@ -53,13 +51,13 @@
#include "BKE_context.h"
-#include "ED_image.h"
-#include "ED_view3d.h"
-
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLI_string.h"
+#include "ED_image.h"
+#include "ED_view3d.h"
+
#include "BLF_translation.h"
#include "UI_resources.h"
@@ -867,11 +865,11 @@ static void setNearestAxis2d(TransInfo *t)
/* no correction needed... just use whichever one is lower */
if (abs(t->mval[0] - t->con.imval[0]) < abs(t->mval[1] - t->con.imval[1]) ) {
t->con.mode |= CON_AXIS1;
- BLI_snprintf(t->con.text, sizeof(t->con.text), IFACE_(" along Y axis"));
+ BLI_strncpy(t->con.text, IFACE_(" along Y axis"), sizeof(t->con.text));
}
else {
t->con.mode |= CON_AXIS0;
- BLI_snprintf(t->con.text, sizeof(t->con.text), IFACE_(" along X axis"));
+ BLI_strncpy(t->con.text, IFACE_(" along X axis"), sizeof(t->con.text));
}
}
@@ -892,9 +890,9 @@ static void setNearestAxis3d(TransInfo *t)
* and to overflow the short integers.
* The formula used is a bit stupid, just a simplification of the subtraction
* of two 2D points 30 pixels apart (that's the last factor in the formula) after
- * projecting them with window_to_3d_delta and then get the length of that vector.
+ * projecting them with ED_view3d_win_to_delta and then get the length of that vector.
*/
- zfac = t->persmat[0][3] * t->center[0] + t->persmat[1][3] * t->center[1] + t->persmat[2][3] * t->center[2] + t->persmat[3][3];
+ zfac = mul_project_m4_v3_zfac(t->persmat, t->center);
zfac = len_v3(t->persinv[0]) * 2.0f / t->ar->winx * zfac * 30.0f;
for (i = 0; i < 3; i++) {
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index 57816e7546c..b8a39cae381 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -223,7 +223,9 @@ static void set_prop_dist(TransInfo *t, short with_dist)
tob->rdist = dist;
}
}
- else break; // by definition transdata has selected items in beginning
+ else {
+ break; /* by definition transdata has selected items in beginning */
+ }
}
if (with_dist) {
tob->dist = tob->rdist;
@@ -1291,7 +1293,7 @@ static void calc_distanceCurveVerts(TransData *head, TransData *tail)
}
}
else {
- td->dist = MAXFLOAT;
+ td->dist = FLT_MAX;
td->flag |= TD_NOTCONNECTED;
}
}
@@ -2048,7 +2050,9 @@ static void createTransEditVerts(TransInfo *t)
if (propmode & T_PROP_CONNECTED)
dists = MEM_mallocN(em->bm->totvert * sizeof(float), "scratch nears");
}
- else t->total = countsel;
+ else {
+ t->total = countsel;
+ }
tob = t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Mesh EditMode)");
if (ELEM(t->mode, TFM_SKIN_RESIZE, TFM_SHRINKFATTEN)) {
@@ -2127,7 +2131,7 @@ static void createTransEditVerts(TransInfo *t)
}
else {
tob->flag |= TD_NOTCONNECTED;
- tob->dist = MAXFLOAT;
+ tob->dist = FLT_MAX;
}
}
@@ -2363,7 +2367,7 @@ static void UVsToTransData(SpaceImage *sima, TransData *td, TransData2D *td2d, f
td->dist = 0.0;
}
else {
- td->dist = MAXFLOAT;
+ td->dist = FLT_MAX;
}
unit_m3(td->mtx);
unit_m3(td->smtx);
@@ -3500,7 +3504,7 @@ static void bezt_to_transdata(TransData *td, TransData2D *td2d, AnimData *adt, B
td->dist = 0.0f;
}
else
- td->dist = MAXFLOAT;
+ td->dist = FLT_MAX;
if (ishandle)
td->flag |= TD_NOTIMESNAP;
@@ -3584,7 +3588,9 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
if (ELEM3(t->mode, TFM_TRANSLATION, TFM_TIME_TRANSLATE, TFM_TIME_SLIDE)) {
/* for 'normal' pivots - just include anything that is selected.
* this works a bit differently in translation modes */
- if (sel2) count++;
+ if (sel2) {
+ count++;
+ }
else {
if (sel1) count++;
if (sel3) count++;
@@ -6594,7 +6600,7 @@ void createTransData(bContext *C, TransInfo *t)
sort_trans_data_dist(t);
}
}
- else if (ob && (ob->mode & (OB_MODE_SCULPT | OB_MODE_TEXTURE_PAINT))) {
+ else if (ob && (ob->mode & (OB_MODE_ALL_PAINT))) {
/* sculpt mode and project paint have own undo stack
* transform ops redo clears sculpt/project undo stack.
*
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index c2a331f5249..2a3b0bc8726 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -1012,7 +1012,7 @@ void resetTransRestrictions(TransInfo *t)
}
/* the *op can be NULL */
-int initTransInfo(bContext *C, TransInfo *t, wmOperator *op, wmEvent *event)
+int initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event)
{
Scene *sce = CTX_data_scene(C);
ToolSettings *ts = CTX_data_tool_settings(C);
@@ -1669,7 +1669,7 @@ void calculateCenter(TransInfo *t)
projectIntView(t, axis, t->center2d);
- /* rotate only needs correct 2d center, grab needs initgrabz() value */
+ /* rotate only needs correct 2d center, grab needs ED_view3d_calc_zfac() value */
if (t->mode == TFM_TRANSLATION) {
copy_v3_v3(t->center, axis);
copy_v3_v3(t->con.center, t->center);
@@ -1679,18 +1679,16 @@ void calculateCenter(TransInfo *t)
}
if (t->spacetype == SPACE_VIEW3D) {
- /* initgrabz() defines a factor for perspective depth correction, used in window_to_3d_delta() */
+ /* ED_view3d_calc_zfac() defines a factor for perspective depth correction, used in ED_view3d_win_to_delta() */
+ float vec[3];
if (t->flag & (T_EDIT | T_POSE)) {
Object *ob = t->obedit ? t->obedit : t->poseobj;
- float vec[3];
-
- copy_v3_v3(vec, t->center);
- mul_m4_v3(ob->obmat, vec);
- initgrabz(t->ar->regiondata, vec[0], vec[1], vec[2]);
+ mul_v3_m4v3(vec, ob->obmat, t->center);
}
else {
- initgrabz(t->ar->regiondata, t->center[0], t->center[1], t->center[2]);
+ copy_v3_v3(vec, t->center);
}
+ t->zfac = ED_view3d_calc_zfac(t->ar->regiondata, vec, NULL);
}
}
diff --git a/source/blender/editors/transform/transform_input.c b/source/blender/editors/transform/transform_input.c
index 4e9a54692a5..4943a3a2fe7 100644
--- a/source/blender/editors/transform/transform_input.c
+++ b/source/blender/editors/transform/transform_input.c
@@ -393,7 +393,7 @@ void applyMouseInput(TransInfo *t, MouseInput *mi, const int mval[2], float outp
}
}
-int handleMouseInput(TransInfo *t, MouseInput *mi, wmEvent *event)
+int handleMouseInput(TransInfo *t, MouseInput *mi, const wmEvent *event)
{
int redraw = TREDRAW_NOTHING;
diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c
index 54fb567b8a2..bea1f9da057 100644
--- a/source/blender/editors/transform/transform_manipulator.c
+++ b/source/blender/editors/transform/transform_manipulator.c
@@ -856,7 +856,7 @@ static void axis_sort_v3(const float axis_values[3], int r_axis_order[3])
}
else {
if (v[1] < v[2]) { SWAP_AXIS(0, 1); }
- else { SWAP_AXIS(0, 2); }
+ else { SWAP_AXIS(0, 2); }
}
if (v[2] < v[1]) { SWAP_AXIS(1, 2); }
@@ -1293,7 +1293,9 @@ static void draw_manipulator_scale(View3D *v3d, RegionView3D *rv3d, int moving,
dz = 1.0;
}
- else dz = 1.0f - 4.0f * cusize;
+ else {
+ dz = 1.0f - 4.0f * cusize;
+ }
if (moving) {
float matt[4][4];
@@ -1739,8 +1741,12 @@ static int manipulator_selectbuf(ScrArea *sa, ARegion *ar, const int mval[2], fl
dep = buffer[4 * a + 1];
val = buffer[4 * a + 3];
- if (val == MAN_TRANS_C) return MAN_TRANS_C;
- else if (val == MAN_SCALE_C) return MAN_SCALE_C;
+ if (val == MAN_TRANS_C) {
+ return MAN_TRANS_C;
+ }
+ else if (val == MAN_SCALE_C) {
+ return MAN_SCALE_C;
+ }
else {
if (val & MAN_ROT_C) {
if (minvalrot == 0 || dep < mindeprot) {
@@ -1767,7 +1773,7 @@ static int manipulator_selectbuf(ScrArea *sa, ARegion *ar, const int mval[2], fl
/* return 0; nothing happened */
-int BIF_do_manipulator(bContext *C, struct wmEvent *event, wmOperator *op)
+int BIF_do_manipulator(bContext *C, const struct wmEvent *event, wmOperator *op)
{
ScrArea *sa = CTX_wm_area(C);
View3D *v3d = sa->spacedata.first;
@@ -1855,8 +1861,15 @@ int BIF_do_manipulator(bContext *C, struct wmEvent *event, wmOperator *op)
//wm_operator_invoke(C, WM_operatortype_find("TRANSFORM_OT_resize", 0), event, op->ptr, NULL, FALSE);
}
else if (drawflags == MAN_ROT_T) { /* trackball need special case, init is different */
- WM_operator_name_call(C, "TRANSFORM_OT_trackball", WM_OP_INVOKE_DEFAULT, op->ptr);
- //wm_operator_invoke(C, WM_operatortype_find("TRANSFORM_OT_trackball", 0), event, op->ptr, NULL, FALSE);
+ /* Do not pass op->ptr!!! trackball has no "constraint" properties!
+ * See [#34621], it's a miracle it did not cause more problems!!! */
+ /* However, we need to copy the "release_confirm" property... */
+ PointerRNA props_ptr;
+ WM_operator_properties_create(&props_ptr, "TRANSFORM_OT_trackball");
+ RNA_boolean_set(&props_ptr, "release_confirm", RNA_boolean_get(op->ptr, "release_confirm"));
+
+ WM_operator_name_call(C, "TRANSFORM_OT_trackball", WM_OP_INVOKE_DEFAULT, &props_ptr);
+ //wm_operator_invoke(C, WM_operatortype_find("TRANSFORM_OT_trackball", 0), event, NULL, NULL, FALSE);
}
else if (drawflags & MAN_ROT_C) {
switch (drawflags) {
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 0392c0f47a2..60b0c655691 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -24,16 +24,11 @@
* \ingroup edtransform
*/
-
#include "MEM_guardedalloc.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-#include "RNA_access.h"
-#include "RNA_define.h"
-#include "RNA_enum_types.h"
-
#include "BLI_math.h"
#include "BLI_utildefines.h"
@@ -44,6 +39,10 @@
#include "BKE_armature.h"
#include "BKE_report.h"
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -166,7 +165,7 @@ static int select_orientation_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int select_orientation_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
+static int select_orientation_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
{
uiPopupMenu *pup;
uiLayout *layout;
@@ -213,7 +212,7 @@ static int delete_orientation_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-static int delete_orientation_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int delete_orientation_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
return delete_orientation_exec(C, op);
}
@@ -269,7 +268,7 @@ static int create_orientation_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int create_orientation_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int create_orientation_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
return create_orientation_exec(C, op);
}
@@ -301,7 +300,7 @@ static void transformops_exit(bContext *C, wmOperator *op)
G.moving = 0;
}
-static int transformops_data(bContext *C, wmOperator *op, wmEvent *event)
+static int transformops_data(bContext *C, wmOperator *op, const wmEvent *event)
{
int retval = 1;
if (op->customdata == NULL) {
@@ -335,7 +334,7 @@ static int transformops_data(bContext *C, wmOperator *op, wmEvent *event)
return retval; /* return 0 on error */
}
-static int transform_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int transform_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
int exit_code;
@@ -402,7 +401,7 @@ static int transform_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int transform_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int transform_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (!transformops_data(C, op, event)) {
G.moving = 0;
@@ -431,7 +430,6 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
/* Make this not hidden when there's a nice axis selection widget */
RNA_def_property_flag(prop, PROP_HIDDEN);
RNA_def_property_ui_text(prop, "Axis", "The axis around which the transformation occurs");
-
}
if (flags & P_CONSTRAINT) {
@@ -439,8 +437,6 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
prop = RNA_def_property(ot->srna, "constraint_orientation", PROP_ENUM, PROP_NONE);
RNA_def_property_ui_text(prop, "Orientation", "Transformation orientation");
RNA_def_enum_funcs(prop, rna_TransformOrientation_itemf);
-
-
}
if (flags & P_MIRROR) {
@@ -558,6 +554,8 @@ static void TRANSFORM_OT_skin_resize(struct wmOperatorType *ot)
static void TRANSFORM_OT_trackball(struct wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Trackball";
ot->description = "Trackball style rotation of selected items";
@@ -571,7 +569,9 @@ static void TRANSFORM_OT_trackball(struct wmOperatorType *ot)
ot->cancel = transform_cancel;
ot->poll = ED_operator_screenactive;
- RNA_def_float_vector(ot->srna, "value", 2, VecOne, -FLT_MAX, FLT_MAX, "Angle", "", -FLT_MAX, FLT_MAX);
+ /* Maybe we could use float_vector_xyz here too? */
+ prop = RNA_def_float_vector(ot->srna, "value", 2, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -FLT_MAX, FLT_MAX);
+ RNA_def_property_subtype(prop, PROP_ANGLE);
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP);
}
@@ -841,7 +841,7 @@ static void TRANSFORM_OT_seq_slide(struct wmOperatorType *ot)
ot->cancel = transform_cancel;
ot->poll = ED_operator_sequencer_active;
- RNA_def_float_vector(ot->srna, "value", 2, VecOne, -FLT_MAX, FLT_MAX, "Angle", "", -FLT_MAX, FLT_MAX);
+ RNA_def_float_vector_xyz(ot->srna, "value", 2, NULL, -FLT_MAX, FLT_MAX, "Vector", "", -FLT_MAX, FLT_MAX);
Transform_Properties(ot, P_SNAP);
}
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index e507d062b0e..4fe36a15802 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -89,7 +89,7 @@ static TransformOrientation *findOrientationName(ListBase *lb, const char *name)
return NULL;
}
-static int uniqueOrientationNameCheck(void *arg, const char *name)
+static bool uniqueOrientationNameCheck(void *arg, const char *name)
{
return findOrientationName((ListBase *)arg, name) != NULL;
}
@@ -409,14 +409,16 @@ const char *BIF_menustringTransformOrientation(const bContext *C, const char *ti
int i = V3D_MANIP_CUSTOM;
char *str_menu, *p;
const int elem_size = MAX_NAME + 4;
+ size_t str_menu_size;
title = IFACE_(title);
- str_menu = MEM_callocN(strlen(menu) + strlen(title) + 1 + elem_size * BIF_countTransformOrientation(C), "UserTransSpace from matrix");
+ str_menu_size = strlen(menu) + strlen(title) + 1 + (elem_size * BIF_countTransformOrientation(C));
+ str_menu = MEM_callocN(str_menu_size, "UserTransSpace from matrix");
+
p = str_menu;
-
- p += sprintf(str_menu, "%s", title);
- p += sprintf(p, "%s", menu);
+ p += BLI_strncpy_rlen(p, title, str_menu_size);
+ p += BLI_strncpy_rlen(p, menu, str_menu_size - (p - str_menu));
for (ts = transform_spaces->first; ts; ts = ts->next) {
p += sprintf(p, "|%s %%x%d", ts->name, i++);
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 2efd35327c7..c92cd77449e 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -47,8 +47,6 @@
#include "DNA_view3d_types.h"
#include "DNA_windowmanager_types.h"
-#include "RNA_access.h"
-
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
@@ -62,6 +60,10 @@
#include "BKE_tessmesh.h"
#include "BKE_mesh.h"
+#include "RNA_access.h"
+
+#include "WM_types.h"
+
#include "ED_armature.h"
#include "ED_image.h"
#include "ED_mesh.h"
@@ -69,8 +71,6 @@
#include "ED_uvedit.h"
#include "ED_view3d.h"
-#include "WM_types.h"
-
#include "UI_resources.h"
#include "UI_view2d.h"
@@ -103,7 +103,7 @@ static float ResizeBetween(TransInfo *t, float p1[3], float p2[3]);
/****************** IMPLEMENTATIONS *********************/
-static int snapNodeTest(View2D *v2d, bNode *node, SnapMode mode);
+static bool snapNodeTest(View2D *v2d, bNode *node, SnapMode mode);
static NodeBorder snapNodeBorder(int snap_node_mode);
#if 0
@@ -260,7 +260,7 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
}
}
-int handleSnapping(TransInfo *t, wmEvent *event)
+int handleSnapping(TransInfo *t, const wmEvent *event)
{
int status = 0;
@@ -807,7 +807,7 @@ static float ResizeBetween(TransInfo *t, float p1[3], float p2[3])
/********************** CALC **************************/
-static void UNUSED_FUNCTION(CalcSnapGrid) (TransInfo * t, float *UNUSED(vec))
+static void UNUSED_FUNCTION(CalcSnapGrid) (TransInfo *t, float *UNUSED(vec))
{
snapGridAction(t, t->tsnap.snapPoint, BIG_GEARS);
}
@@ -818,7 +818,7 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
float loc[3];
float no[3];
float mval[2];
- int found = 0;
+ bool found = false;
int dist = SNAP_MIN_DISTANCE; // Use a user defined value here
mval[0] = t->mval[0];
@@ -901,7 +901,7 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
no[0] = 0.0;
no[1] = 0.0;
no[2] = 1.0;
- found = 1;
+ found = true;
}
BLI_freelistN(&depth_peels);
@@ -910,7 +910,7 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
found = snapObjectsTransform(t, mval, &dist, loc, no, t->tsnap.modeSelect);
}
- if (found == 1) {
+ if (found == true) {
float tangent[3];
sub_v3_v3v3(tangent, loc, t->tsnap.snapPoint);
@@ -1144,13 +1144,13 @@ static void TargetSnapClosest(TransInfo *t)
}
}
-static int snapEdge(ARegion *ar, float v1co[3], short v1no[3], float v2co[3], short v2no[3], float obmat[4][4], float timat[3][3],
- const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], const float mval[2],
- float r_loc[3], float r_no[3], int *r_dist, float *r_depth)
+static bool snapEdge(ARegion *ar, float v1co[3], short v1no[3], float v2co[3], short v2no[3], float obmat[4][4], float timat[3][3],
+ const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], const float mval[2],
+ float r_loc[3], float r_no[3], int *r_dist, float *r_depth)
{
float intersect[3] = {0, 0, 0}, ray_end[3], dvec[3];
int result;
- int retval = 0;
+ bool retval = false;
copy_v3_v3(ray_end, ray_normal_local);
mul_v3_fl(ray_end, 2000);
@@ -1206,7 +1206,7 @@ static int snapEdge(ARegion *ar, float v1co[3], short v1no[3], float v2co[3], sh
float n1[3], n2[3];
*r_depth = new_depth;
- retval = 1;
+ retval = true;
sub_v3_v3v3(edge_loc, v1co, v2co);
sub_v3_v3v3(vec, intersect, v2co);
@@ -1231,11 +1231,11 @@ static int snapEdge(ARegion *ar, float v1co[3], short v1no[3], float v2co[3], sh
return retval;
}
-static int snapVertex(ARegion *ar, float vco[3], short vno[3], float obmat[4][4], float timat[3][3],
- const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], const float mval[2],
- float r_loc[3], float r_no[3], int *r_dist, float *r_depth)
+static bool snapVertex(ARegion *ar, float vco[3], short vno[3], float obmat[4][4], float timat[3][3],
+ const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], const float mval[2],
+ float r_loc[3], float r_no[3], int *r_dist, float *r_depth)
{
- int retval = 0;
+ bool retval = false;
float dvec[3];
sub_v3_v3v3(dvec, vco, ray_start_local);
@@ -1262,7 +1262,7 @@ static int snapVertex(ARegion *ar, float vco[3], short vno[3], float obmat[4][4]
if (new_dist <= *r_dist && new_depth < *r_depth) {
*r_depth = new_depth;
- retval = 1;
+ retval = true;
copy_v3_v3(r_loc, location);
@@ -1279,13 +1279,13 @@ static int snapVertex(ARegion *ar, float vco[3], short vno[3], float obmat[4][4]
return retval;
}
-static int snapArmature(short snap_mode, ARegion *ar, Object *ob, bArmature *arm, float obmat[4][4],
- const float ray_start[3], const float ray_normal[3], const float mval[2],
- float r_loc[3], float *UNUSED(r_no), int *r_dist, float *r_depth)
+static bool snapArmature(short snap_mode, ARegion *ar, Object *ob, bArmature *arm, float obmat[4][4],
+ const float ray_start[3], const float ray_normal[3], const float mval[2],
+ float r_loc[3], float *UNUSED(r_no), int *r_dist, float *r_depth)
{
float imat[4][4];
float ray_start_local[3], ray_normal_local[3];
- int retval = 0;
+ bool retval = false;
invert_m4_m4(imat, obmat);
@@ -1342,11 +1342,11 @@ static int snapArmature(short snap_mode, ARegion *ar, Object *ob, bArmature *arm
return retval;
}
-static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, BMEditMesh *em, float obmat[4][4],
- const float ray_start[3], const float ray_normal[3], const float mval[2],
- float r_loc[3], float r_no[3], int *r_dist, float *r_depth)
+static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, BMEditMesh *em, float obmat[4][4],
+ const float ray_start[3], const float ray_normal[3], const float mval[2],
+ float r_loc[3], float r_no[3], int *r_dist, float *r_depth)
{
- int retval = 0;
+ bool retval = false;
int totvert = dm->getNumVerts(dm);
int totface = dm->getNumTessFaces(dm);
@@ -1514,12 +1514,12 @@ static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh
return retval;
}
-static int snapObject(Scene *scene, ARegion *ar, Object *ob, int editobject, float obmat[4][4],
- const float ray_start[3], const float ray_normal[3], const float mval[2],
- float r_loc[3], float r_no[3], int *r_dist, float *r_depth)
+static bool snapObject(Scene *scene, ARegion *ar, Object *ob, int editobject, float obmat[4][4],
+ const float ray_start[3], const float ray_normal[3], const float mval[2],
+ float r_loc[3], float r_no[3], int *r_dist, float *r_depth)
{
ToolSettings *ts = scene->toolsettings;
- int retval = 0;
+ bool retval = false;
if (ob->type == OB_MESH) {
BMEditMesh *em;
@@ -1546,12 +1546,12 @@ static int snapObject(Scene *scene, ARegion *ar, Object *ob, int editobject, flo
return retval;
}
-static int snapObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, const float mval[2],
- int *r_dist, float r_loc[3], float r_no[3], SnapMode mode)
+static bool snapObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, const float mval[2],
+ int *r_dist, float r_loc[3], float r_no[3], SnapMode mode)
{
Base *base;
- float depth = FLT_MAX;
- int retval = 0;
+ float depth = (FLT_MAX / 2.0f); /* use half of flt-max so we can scale up without an exception */
+ bool retval = false;
float ray_start[3], ray_normal[3];
ED_view3d_win_to_ray(ar, v3d, mval, ray_start, ray_normal);
@@ -1602,12 +1602,12 @@ static int snapObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, c
return retval;
}
-int snapObjectsTransform(TransInfo *t, const float mval[2], int *r_dist, float r_loc[3], float r_no[3], SnapMode mode)
+bool snapObjectsTransform(TransInfo *t, const float mval[2], int *r_dist, float r_loc[3], float r_no[3], SnapMode mode)
{
return snapObjects(t->scene, t->view, t->ar, t->obedit, mval, r_dist, r_loc, r_no, mode);
}
-int snapObjectsContext(bContext *C, const float mval[2], int *r_dist, float r_loc[3], float r_no[3], SnapMode mode)
+bool snapObjectsContext(bContext *C, const float mval[2], int *r_dist, float r_loc[3], float r_no[3], SnapMode mode)
{
ScrArea *sa = CTX_wm_area(C);
View3D *v3d = sa->spacedata.first;
@@ -1667,11 +1667,11 @@ static void addDepthPeel(ListBase *depth_peels, float depth, float p[3], float n
peel->flag = 0;
}
-static int peelDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[4][4],
- const float ray_start[3], const float ray_normal[3], const float UNUSED(mval[2]),
- ListBase *depth_peels)
+static bool peelDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[4][4],
+ const float ray_start[3], const float ray_normal[3], const float UNUSED(mval[2]),
+ ListBase *depth_peels)
{
- int retval = 0;
+ bool retval = false;
int totvert = dm->getNumVerts(dm);
int totface = dm->getNumTessFaces(dm);
@@ -1776,10 +1776,11 @@ static int peelDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[4][4],
return retval;
}
-static int peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, ListBase *depth_peels, const float mval[2], SnapMode mode)
+static bool peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit,
+ ListBase *depth_peels, const float mval[2], SnapMode mode)
{
Base *base;
- int retval = 0;
+ bool retval = false;
float ray_start[3], ray_normal[3];
ED_view3d_win_to_ray(ar, v3d, mval, ray_start, ray_normal);
@@ -1798,7 +1799,7 @@ static int peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, L
if (dob->type == OB_MESH) {
BMEditMesh *em;
DerivedMesh *dm = NULL;
- int val;
+ bool val;
if (dob != obedit) {
dm = mesh_get_derived_final(scene, dob, CD_MASK_BAREMESH);
@@ -1822,7 +1823,7 @@ static int peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, L
}
if (ob->type == OB_MESH) {
- int val = 0;
+ bool val = false;
if (ob != obedit && ((mode == SNAP_NOT_SELECTED && (base->flag & (SELECT | BA_WAS_SEL)) == 0) || ELEM(mode, SNAP_ALL, SNAP_NOT_OBEDIT))) {
DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
@@ -1850,12 +1851,12 @@ static int peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, L
return retval;
}
-int peelObjectsTransForm(TransInfo *t, ListBase *depth_peels, const float mval[2], SnapMode mode)
+bool peelObjectsTransForm(TransInfo *t, ListBase *depth_peels, const float mval[2], SnapMode mode)
{
return peelObjects(t->scene, t->view, t->ar, t->obedit, depth_peels, mval, mode);
}
-int peelObjectsContext(bContext *C, ListBase *depth_peels, const float mval[2], SnapMode mode)
+bool peelObjectsContext(bContext *C, ListBase *depth_peels, const float mval[2], SnapMode mode)
{
ScrArea *sa = CTX_wm_area(C);
View3D *v3d = sa->spacedata.first;
@@ -1865,7 +1866,7 @@ int peelObjectsContext(bContext *C, ListBase *depth_peels, const float mval[2],
/******************** NODES ***********************************/
-static int snapNodeTest(View2D *v2d, bNode *node, SnapMode mode)
+static bool snapNodeTest(View2D *v2d, bNode *node, SnapMode mode)
{
/* node is use for snapping only if a) snap mode matches and b) node is inside the view */
return ((mode == SNAP_NOT_SELECTED && !(node->flag & NODE_SELECT)) ||
@@ -1887,12 +1888,12 @@ static NodeBorder snapNodeBorder(int snap_node_mode)
return 0;
}
-static int snapNode(ToolSettings *ts, SpaceNode *UNUSED(snode), ARegion *ar, bNode *node, const int mval[2],
- float r_loc[2], int *r_dist, char *r_node_border)
+static bool snapNode(ToolSettings *ts, SpaceNode *UNUSED(snode), ARegion *ar, bNode *node, const int mval[2],
+ float r_loc[2], int *r_dist, char *r_node_border)
{
View2D *v2d = &ar->v2d;
NodeBorder border = snapNodeBorder(ts->snap_node_mode);
- int retval = 0;
+ bool retval = false;
rcti totr;
int new_dist;
@@ -1905,7 +1906,7 @@ static int snapNode(ToolSettings *ts, SpaceNode *UNUSED(snode), ARegion *ar, bNo
UI_view2d_region_to_view(v2d, totr.xmin, mval[1], &r_loc[0], &r_loc[1]);
*r_dist = new_dist;
*r_node_border = NODE_LEFT;
- retval = 1;
+ retval = true;
}
}
@@ -1915,7 +1916,7 @@ static int snapNode(ToolSettings *ts, SpaceNode *UNUSED(snode), ARegion *ar, bNo
UI_view2d_region_to_view(v2d, totr.xmax, mval[1], &r_loc[0], &r_loc[1]);
*r_dist = new_dist;
*r_node_border = NODE_RIGHT;
- retval = 1;
+ retval = true;
}
}
@@ -1925,7 +1926,7 @@ static int snapNode(ToolSettings *ts, SpaceNode *UNUSED(snode), ARegion *ar, bNo
UI_view2d_region_to_view(v2d, mval[0], totr.ymin, &r_loc[0], &r_loc[1]);
*r_dist = new_dist;
*r_node_border = NODE_BOTTOM;
- retval = 1;
+ retval = true;
}
}
@@ -1935,19 +1936,19 @@ static int snapNode(ToolSettings *ts, SpaceNode *UNUSED(snode), ARegion *ar, bNo
UI_view2d_region_to_view(v2d, mval[0], totr.ymax, &r_loc[0], &r_loc[1]);
*r_dist = new_dist;
*r_node_border = NODE_TOP;
- retval = 1;
+ retval = true;
}
}
return retval;
}
-static int snapNodes(ToolSettings *ts, SpaceNode *snode, ARegion *ar, const int mval[2],
+static bool snapNodes(ToolSettings *ts, SpaceNode *snode, ARegion *ar, const int mval[2],
int *r_dist, float r_loc[2], char *r_node_border, SnapMode mode)
{
bNodeTree *ntree = snode->edittree;
bNode *node;
- int retval = 0;
+ bool retval = false;
*r_node_border = 0;
@@ -1959,12 +1960,12 @@ static int snapNodes(ToolSettings *ts, SpaceNode *snode, ARegion *ar, const int
return retval;
}
-int snapNodesTransform(TransInfo *t, const int mval[2], int *r_dist, float r_loc[2], char *r_node_border, SnapMode mode)
+bool snapNodesTransform(TransInfo *t, const int mval[2], int *r_dist, float r_loc[2], char *r_node_border, SnapMode mode)
{
return snapNodes(t->settings, t->sa->spacedata.first, t->ar, mval, r_dist, r_loc, r_node_border, mode);
}
-int snapNodesContext(bContext *C, const int mval[2], int *r_dist, float r_loc[2], char *r_node_border, SnapMode mode)
+bool snapNodesContext(bContext *C, const int mval[2], int *r_dist, float r_loc[2], char *r_node_border, SnapMode mode)
{
Scene *scene = CTX_data_scene(C);
return snapNodes(scene->toolsettings, CTX_wm_space_node(C), CTX_wm_region(C), mval, r_dist, r_loc, r_node_border, mode);
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index f0f31b1e793..73062c57526 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -187,8 +187,7 @@ void unpack_menu(bContext *C, const char *opname, const char *id_name, const cha
if (G.relbase_valid) {
char local_name[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX];
- BLI_strncpy(local_name, abs_name, sizeof(local_name));
- BLI_splitdirstring(local_name, fi);
+ BLI_split_file_part(abs_name, fi, sizeof(fi));
BLI_snprintf(local_name, sizeof(local_name), "//%s/%s", folder, fi);
if (strcmp(abs_name, local_name) != 0) {
switch (checkPackedFile(local_name, pf)) {
diff --git a/source/blender/editors/util/editmode_undo.c b/source/blender/editors/util/editmode_undo.c
index c8c26ed771d..7f4e05ddefa 100644
--- a/source/blender/editors/util/editmode_undo.c
+++ b/source/blender/editors/util/editmode_undo.c
@@ -246,7 +246,9 @@ void undo_editmode_step(bContext *C, int step)
}
else if (step == 1) {
- if (curundo == NULL || curundo->prev == NULL) error("No more steps to undo");
+ if (curundo == NULL || curundo->prev == NULL) {
+ error("No more steps to undo");
+ }
else {
if (G.debug & G_DEBUG) printf("undo %s\n", curundo->name);
curundo = curundo->prev;
@@ -256,7 +258,9 @@ void undo_editmode_step(bContext *C, int step)
else {
/* curundo has to remain current situation! */
- if (curundo == NULL || curundo->next == NULL) error("No more steps to redo");
+ if (curundo == NULL || curundo->next == NULL) {
+ error("No more steps to redo");
+ }
else {
undo_restore(curundo->next, curundo->getdata(C), obedit->data);
curundo = curundo->next;
diff --git a/source/blender/editors/util/numinput.c b/source/blender/editors/util/numinput.c
index 0ec16ead35d..98a1b54c452 100644
--- a/source/blender/editors/util/numinput.c
+++ b/source/blender/editors/util/numinput.c
@@ -163,7 +163,7 @@ void applyNumInput(NumInput *n, float *vec)
}
}
-char handleNumInput(NumInput *n, wmEvent *event)
+char handleNumInput(NumInput *n, const wmEvent *event)
{
float Val = 0;
short idx = n->idx, idx_max = n->idx_max;
diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c
index ac2ee21d09d..fc603f7a593 100644
--- a/source/blender/editors/util/undo.c
+++ b/source/blender/editors/util/undo.c
@@ -475,7 +475,7 @@ static EnumPropertyItem *rna_undo_itemf(bContext *C, int undosys, int *totitem)
}
-static int undo_history_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
int undosys, totitem = 0;
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index ea7e17af086..ba4879b38ca 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -50,6 +50,7 @@
#include "BKE_tessmesh.h"
#include "BLI_array.h"
+#include "BLI_buffer.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
@@ -177,6 +178,9 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
const int cd_poly_tex_offset = CustomData_get_offset(&bm->pdata, CD_MTEXPOLY);
+ BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
+ BLI_buffer_declare_static(vec2f, tf_uvorig_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
+
ED_space_image_get_uv_aspect(sima, &aspx, &aspy);
switch (sima->dt_uvstretch) {
@@ -186,8 +190,8 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
const int efa_len = efa->len;
- float (*tf_uv)[2] = BLI_array_alloca(tf_uv, efa_len);
- float (*tf_uvorig)[2] = BLI_array_alloca(tf_uvorig, efa_len);
+ float (*tf_uv)[2] = (float (*)[2])BLI_buffer_resize_data(&tf_uv_buf, vec2f, efa_len);
+ float (*tf_uvorig)[2] = (float (*)[2])BLI_buffer_resize_data(&tf_uvorig_buf, vec2f, efa_len);
tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
@@ -229,8 +233,8 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
const int efa_len = efa->len;
- float (*tf_uv)[2] = BLI_array_alloca(tf_uv, efa_len);
- float (*tf_uvorig)[2] = BLI_array_alloca(tf_uvorig, efa_len);
+ float (*tf_uv)[2] = (float (*)[2])BLI_buffer_resize_data(&tf_uv_buf, vec2f, efa_len);
+ float (*tf_uvorig)[2] = (float (*)[2])BLI_buffer_resize_data(&tf_uvorig_buf, vec2f, efa_len);
area = BM_face_calc_area(efa) / totarea;
@@ -268,6 +272,11 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe
{
float a;
+ BLI_buffer_declare_static(float, uvang_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
+ BLI_buffer_declare_static(float, ang_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
+ BLI_buffer_declare_static(vec3f, av_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
+ BLI_buffer_declare_static(vec2f, auv_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
+
col[3] = 0.5f; /* hard coded alpha, not that nice */
glShadeModel(GL_SMOOTH);
@@ -277,12 +286,12 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe
if (uvedit_face_visible_test(scene, ima, efa, tf)) {
const int efa_len = efa->len;
- float (*tf_uv)[2] = BLI_array_alloca(tf_uv, efa_len);
- float (*tf_uvorig)[2] = BLI_array_alloca(tf_uvorig, efa_len);
- float *uvang = BLI_array_alloca(uvang, efa_len);
- float *ang = BLI_array_alloca(ang, efa_len);
- float (*av)[3] = BLI_array_alloca(av, efa_len); /* use for 2d and 3d angle vectors */
- float (*auv)[2] = BLI_array_alloca(auv, efa_len);
+ float (*tf_uv)[2] = (float (*)[2])BLI_buffer_resize_data(&tf_uv_buf, vec2f, efa_len);
+ float (*tf_uvorig)[2] = (float (*)[2])BLI_buffer_resize_data(&tf_uvorig_buf, vec2f, efa_len);
+ float *uvang = BLI_buffer_resize_data(&uvang_buf, float, efa_len);
+ float *ang = BLI_buffer_resize_data(&ang_buf, float, efa_len);
+ float (*av)[3] = (float (*)[3])BLI_buffer_resize_data(&av_buf, vec3f, efa_len);
+ float (*auv)[2] = (float (*)[2])BLI_buffer_resize_data(&auv_buf, vec2f, efa_len);
int j;
BM_elem_flag_enable(efa, BM_ELEM_TAG);
@@ -329,11 +338,19 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe
}
}
+ BLI_buffer_free(&uvang_buf);
+ BLI_buffer_free(&ang_buf);
+ BLI_buffer_free(&av_buf);
+ BLI_buffer_free(&auv_buf);
+
glShadeModel(GL_FLAT);
break;
}
}
+
+ BLI_buffer_free(&tf_uv_buf);
+ BLI_buffer_free(&tf_uvorig_buf);
}
static void draw_uvs_other(Scene *scene, Object *obedit, Image *curimage)
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index fbb6250c05b..85375bcaf83 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -2236,7 +2236,7 @@ static int select_exec(bContext *C, wmOperator *op)
return mouse_select(C, co, extend, loop);
}
-static int select_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
float co[2];
@@ -2281,7 +2281,7 @@ static int select_loop_exec(bContext *C, wmOperator *op)
return mouse_select(C, co, extend, loop);
}
-static int select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
float co[2];
@@ -2314,7 +2314,7 @@ static void UV_OT_select_loop(wmOperatorType *ot)
/* ******************** linked select operator **************** */
-static int select_linked_internal(bContext *C, wmOperator *op, wmEvent *event, int pick)
+static int select_linked_internal(bContext *C, wmOperator *op, const wmEvent *event, int pick)
{
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
@@ -2384,7 +2384,7 @@ static void UV_OT_select_linked(wmOperatorType *ot)
"Extend", "Extend selection rather than clearing the existing selection");
}
-static int select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
return select_linked_internal(C, op, event, 1);
}
@@ -3748,7 +3748,7 @@ static int set_2d_cursor_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int set_2d_cursor_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int set_2d_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
float location[2];
@@ -3799,7 +3799,7 @@ static int set_tile_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
-static int set_tile_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int set_tile_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = CTX_data_edit_image(C);
diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c
index 5bb8105cd14..4c56a016176 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -41,6 +41,7 @@
#include "DNA_meshdata_types.h"
#include "DNA_scene_types.h"
+#include "BLI_utildefines.h"
#include "BLI_ghash.h"
#include "BLI_math.h"
#include "BLI_math_vector.h"
@@ -1748,7 +1749,7 @@ static int stitch_init(bContext *C, wmOperator *op)
state->total_separate_edges = total_edges;
/* fill the edges with data */
- for (i = 0, BLI_ghashIterator_init(ghi, edge_hash); !BLI_ghashIterator_isDone(ghi); BLI_ghashIterator_step(ghi)) {
+ for (i = 0, BLI_ghashIterator_init(ghi, edge_hash); BLI_ghashIterator_notDone(ghi); BLI_ghashIterator_step(ghi)) {
edges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(ghi));
}
@@ -1910,7 +1911,7 @@ static int stitch_init(bContext *C, wmOperator *op)
return 1;
}
-static int stitch_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int stitch_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Object *obedit = CTX_data_edit_object(C);
if (!stitch_init(C, op))
@@ -2000,7 +2001,7 @@ static int stitch_exec(bContext *C, wmOperator *op)
}
}
-static void stitch_select(bContext *C, Scene *scene, wmEvent *event, StitchState *state)
+static void stitch_select(bContext *C, Scene *scene, const wmEvent *event, StitchState *state)
{
/* add uv under mouse to processed uv's */
float co[2];
@@ -2034,7 +2035,7 @@ static void stitch_select(bContext *C, Scene *scene, wmEvent *event, StitchState
}
}
-static int stitch_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int stitch_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
StitchState *state;
Scene *scene = CTX_data_scene(C);
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 4ddf4bd6a5c..9de43fc9d6b 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -654,7 +654,7 @@ static int minimize_stretch_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int minimize_stretch_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int minimize_stretch_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
MinStretch *ms;
@@ -670,7 +670,7 @@ static int minimize_stretch_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(
return OPERATOR_RUNNING_MODAL;
}
-static int minimize_stretch_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int minimize_stretch_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
MinStretch *ms = op->customdata;