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:
Diffstat (limited to 'source/blender/editors')
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c2
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c14
-rw-r--r--source/blender/editors/animation/anim_deps.c2
-rw-r--r--source/blender/editors/animation/anim_ipo_utils.c2
-rw-r--r--source/blender/editors/animation/anim_markers.c6
-rw-r--r--source/blender/editors/animation/anim_ops.c2
-rw-r--r--source/blender/editors/animation/keyframes_edit.c8
-rw-r--r--source/blender/editors/animation/keyframing.c4
-rw-r--r--source/blender/editors/armature/CMakeLists.txt1
-rw-r--r--source/blender/editors/armature/SConscript1
-rw-r--r--source/blender/editors/armature/armature_edit.c4
-rw-r--r--source/blender/editors/armature/armature_select.c6
-rw-r--r--source/blender/editors/armature/armature_skinning.c16
-rw-r--r--source/blender/editors/armature/editarmature_sketch.c8
-rw-r--r--source/blender/editors/armature/meshlaplacian.c9
-rw-r--r--source/blender/editors/armature/pose_edit.c4
-rw-r--r--source/blender/editors/armature/pose_lib.c4
-rw-r--r--source/blender/editors/armature/pose_select.c88
-rw-r--r--source/blender/editors/armature/pose_slide.c2
-rw-r--r--source/blender/editors/curve/editcurve.c2
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt2
-rw-r--r--source/blender/editors/datafiles/SConscript2
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c6
-rw-r--r--source/blender/editors/include/BIF_gl.h20
-rw-r--r--source/blender/editors/include/ED_armature.h2
-rw-r--r--source/blender/editors/include/ED_datafiles.h6
-rw-r--r--source/blender/editors/include/ED_image.h3
-rw-r--r--source/blender/editors/include/ED_paint.h6
-rw-r--r--source/blender/editors/include/ED_transform.h1
-rw-r--r--source/blender/editors/include/ED_uvedit.h2
-rw-r--r--source/blender/editors/include/ED_view3d.h6
-rw-r--r--source/blender/editors/include/UI_icons.h2
-rw-r--r--source/blender/editors/include/UI_interface.h17
-rw-r--r--source/blender/editors/include/UI_resources.h3
-rw-r--r--source/blender/editors/interface/interface.c32
-rw-r--r--source/blender/editors/interface/interface_draw.c10
-rw-r--r--source/blender/editors/interface/interface_handlers.c308
-rw-r--r--source/blender/editors/interface/interface_icons.c2
-rw-r--r--source/blender/editors/interface/interface_intern.h7
-rw-r--r--source/blender/editors/interface/interface_layout.c8
-rw-r--r--source/blender/editors/interface/interface_ops.c197
-rw-r--r--source/blender/editors/interface/interface_panel.c62
-rw-r--r--source/blender/editors/interface/interface_regions.c25
-rw-r--r--source/blender/editors/interface/interface_templates.c73
-rw-r--r--source/blender/editors/interface/interface_utils.c2
-rw-r--r--source/blender/editors/interface/interface_widgets.c14
-rw-r--r--source/blender/editors/interface/resources.c49
-rw-r--r--source/blender/editors/io/io_collada.c2
-rw-r--r--source/blender/editors/mesh/editmesh_knife_project.c2
-rw-r--r--source/blender/editors/mesh/editmesh_select.c46
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c18
-rw-r--r--source/blender/editors/metaball/mball_edit.c2
-rw-r--r--source/blender/editors/object/object_add.c4
-rw-r--r--source/blender/editors/object/object_bake.c2
-rw-r--r--source/blender/editors/object/object_bake_api.c52
-rw-r--r--source/blender/editors/object/object_constraint.c2
-rw-r--r--source/blender/editors/object/object_edit.c23
-rw-r--r--source/blender/editors/object/object_group.c64
-rw-r--r--source/blender/editors/object/object_hook.c3
-rw-r--r--source/blender/editors/object/object_intern.h2
-rw-r--r--source/blender/editors/object/object_modifier.c4
-rw-r--r--source/blender/editors/object/object_ops.c2
-rw-r--r--source/blender/editors/object/object_relations.c14
-rw-r--r--source/blender/editors/object/object_shapekey.c21
-rw-r--r--source/blender/editors/object/object_transform.c4
-rw-r--r--source/blender/editors/render/render_update.c10
-rw-r--r--source/blender/editors/screen/area.c4
-rw-r--r--source/blender/editors/screen/screen_edit.c2
-rw-r--r--source/blender/editors/screen/screen_ops.c15
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt1
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c164
-rw-r--r--source/blender/editors/sculpt_paint/paint_curve.c801
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c681
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c872
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c1005
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h63
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c6
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c176
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c486
-rw-r--r--source/blender/editors/sculpt_paint/paint_undo.c54
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c296
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c28
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c225
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h7
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c12
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_uv.c10
-rw-r--r--source/blender/editors/space_action/action_draw.c2
-rw-r--r--source/blender/editors/space_action/action_select.c15
-rw-r--r--source/blender/editors/space_api/spacetypes.c1
-rw-r--r--source/blender/editors/space_buttons/buttons_context.c8
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c2
-rw-r--r--source/blender/editors/space_clip/clip_draw.c2
-rw-r--r--source/blender/editors/space_clip/space_clip.c2
-rw-r--r--source/blender/editors/space_clip/tracking_ops.c4
-rw-r--r--source/blender/editors/space_file/space_file.c2
-rw-r--r--source/blender/editors/space_graph/graph_edit.c4
-rw-r--r--source/blender/editors/space_image/image_buttons.c16
-rw-r--r--source/blender/editors/space_image/image_edit.c39
-rw-r--r--source/blender/editors/space_image/image_ops.c18
-rw-r--r--source/blender/editors/space_image/space_image.c17
-rw-r--r--source/blender/editors/space_logic/logic_window.c2
-rw-r--r--source/blender/editors/space_node/drawnode.c9
-rw-r--r--source/blender/editors/space_node/node_edit.c4
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c2
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c10
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c2
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c2
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c10
-rw-r--r--source/blender/editors/space_outliner/space_outliner.c4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c22
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c8
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c4
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c157
-rw-r--r--source/blender/editors/space_text/text_draw.c2
-rw-r--r--source/blender/editors/space_view3d/drawarmature.c61
-rw-r--r--source/blender/editors/space_view3d/drawmesh.c108
-rw-r--r--source/blender/editors/space_view3d/drawobject.c25
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c34
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c10
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c23
-rw-r--r--source/blender/editors/space_view3d/view3d_header.c7
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c61
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c178
-rw-r--r--source/blender/editors/transform/CMakeLists.txt1
-rw-r--r--source/blender/editors/transform/SConscript1
-rw-r--r--source/blender/editors/transform/transform.c112
-rw-r--r--source/blender/editors/transform/transform.h11
-rw-r--r--source/blender/editors/transform/transform_constraints.c5
-rw-r--r--source/blender/editors/transform/transform_conversions.c220
-rw-r--r--source/blender/editors/transform/transform_generics.c54
-rw-r--r--source/blender/editors/transform/transform_manipulator.c96
-rw-r--r--source/blender/editors/transform/transform_orientations.c2
-rw-r--r--source/blender/editors/transform/transform_snap.c80
-rw-r--r--source/blender/editors/util/ed_transverts.c2
-rw-r--r--source/blender/editors/util/ed_util.c2
-rw-r--r--source/blender/editors/util/numinput.c10
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c53
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c10
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c4
140 files changed, 6070 insertions, 1709 deletions
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index 3530857266d..7d8e278f0cf 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -3846,7 +3846,7 @@ void ANIM_channel_draw_widgets(bContext *C, bAnimContext *ac, bAnimListElem *ale
short offset;
/* sanity checks - don't draw anything */
- if (ELEM3(NULL, acf, ale, block))
+ if (ELEM(NULL, acf, ale, block))
return;
/* get initial offset */
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index 9997cc07c19..b6ab0407711 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -605,7 +605,7 @@ static int animedit_poll_channels_active(bContext *C)
if (ELEM(NULL, sa, CTX_wm_region(C)))
return 0;
/* animation editor test */
- if (ELEM3(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0)
+ if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0)
return 0;
return 1;
@@ -622,7 +622,7 @@ static int animedit_poll_channels_nla_tweakmode_off(bContext *C)
if (ELEM(NULL, sa, CTX_wm_region(C)))
return 0;
/* animation editor test */
- if (ELEM3(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0)
+ if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0)
return 0;
/* NLA TweakMode test */
@@ -901,10 +901,10 @@ static void rearrange_animchannels_filter_visible(ListBase *anim_data_visible, b
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale, *ale_next;
- int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
+ int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
/* get all visible channels */
- ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* now, only keep the ones that are of the types we are interested in */
for (ale = anim_data.first; ale; ale = ale_next) {
@@ -2257,7 +2257,7 @@ static int animchannels_find_poll(bContext *C)
return 0;
/* animation editor with dopesheet */
- return ELEM3(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA);
+ return ELEM(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA);
}
/* find_invoke() - Get initial channels */
@@ -2802,7 +2802,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
/* deselect all other channels */
ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR);
- if (pchan) ED_pose_deselectall(ob, 0);
+ if (pchan) ED_pose_de_selectall(ob, SEL_DESELECT, false);
/* only select channels in group and group itself */
for (fcu = agrp->channels.first; fcu && fcu->grp == agrp; fcu = fcu->next)
@@ -2812,7 +2812,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
else {
/* select group by itself */
ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR);
- if (pchan) ED_pose_deselectall(ob, 0);
+ if (pchan) ED_pose_de_selectall(ob, SEL_DESELECT, false);
agrp->flag |= AGRP_SELECTED;
}
diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c
index 640349199be..f3b47b168e9 100644
--- a/source/blender/editors/animation/anim_deps.c
+++ b/source/blender/editors/animation/anim_deps.c
@@ -193,7 +193,7 @@ static void animchan_sync_fcurve(bAnimContext *ac, bAnimListElem *ale, FCurve **
/* major priority is selection status, so refer to the checks done in anim_filter.c
* skip_fcurve_selected_data() for reference about what's going on here...
*/
- if (ELEM3(NULL, fcu, fcu->rna_path, owner_id))
+ if (ELEM(NULL, fcu, fcu->rna_path, owner_id))
return;
if (GS(owner_id->name) == ID_OB) {
diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c
index d3e6d8f474f..57df6d32f03 100644
--- a/source/blender/editors/animation/anim_ipo_utils.c
+++ b/source/blender/editors/animation/anim_ipo_utils.c
@@ -63,7 +63,7 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu)
/* sanity checks */
if (name == NULL)
return icon;
- else if (ELEM3(NULL, id, fcu, fcu->rna_path)) {
+ else if (ELEM(NULL, id, fcu, fcu->rna_path)) {
if (fcu == NULL)
strcpy(name, IFACE_("<invalid>"));
else if (fcu->rna_path == NULL)
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index e519fc8bfef..a133bc49a69 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -204,7 +204,7 @@ void ED_markers_get_minmax(ListBase *markers, short sel, float *first, float *la
/* sanity check */
//printf("markers = %p - %p, %p\n", markers, markers->first, markers->last);
- if (ELEM3(NULL, markers, markers->first, markers->last)) {
+ if (ELEM(NULL, markers, markers->first, markers->last)) {
*first = 0.0f;
*last = 0.0f;
return;
@@ -1012,14 +1012,14 @@ static void select_timeline_marker_frame(ListBase *markers, int frame, bool exte
}
}
- LISTBASE_CIRCULAR_FORWARD_BEGIN (markers, marker, marker_first) {
+ BLI_LISTBASE_CIRCULAR_FORWARD_BEGIN (markers, marker, marker_first) {
/* this way a not-extend select will allways give 1 selected marker */
if (marker->frame == frame) {
marker->flag ^= SELECT;
break;
}
}
- LISTBASE_CIRCULAR_FORWARD_END (markers, marker, marker_first);
+ BLI_LISTBASE_CIRCULAR_FORWARD_END (markers, marker, marker_first);
}
static int ed_marker_select(bContext *C, const wmEvent *event, bool extend, bool camera)
diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c
index 88429aa3867..620bd52e527 100644
--- a/source/blender/editors/animation/anim_ops.c
+++ b/source/blender/editors/animation/anim_ops.c
@@ -72,7 +72,7 @@ static int change_frame_poll(bContext *C)
* this shouldn't show up in 3D editor (or others without 2D timeline view) via search
*/
if (sa) {
- if (ELEM5(sa->spacetype, SPACE_TIME, SPACE_ACTION, SPACE_NLA, SPACE_SEQ, SPACE_CLIP)) {
+ if (ELEM(sa->spacetype, SPACE_TIME, SPACE_ACTION, SPACE_NLA, SPACE_SEQ, SPACE_CLIP)) {
return true;
}
else if (sa->spacetype == SPACE_IPO) {
diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c
index ee5039488bd..83593faff22 100644
--- a/source/blender/editors/animation/keyframes_edit.c
+++ b/source/blender/editors/animation/keyframes_edit.c
@@ -670,8 +670,8 @@ static short snap_bezier_horizontal(KeyframeEditData *UNUSED(ked), BezTriple *be
if (bezt->f2 & SELECT) {
bezt->vec[0][1] = bezt->vec[2][1] = bezt->vec[1][1];
- if (ELEM3(bezt->h1, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) bezt->h1 = HD_ALIGN;
- if (ELEM3(bezt->h2, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) bezt->h2 = HD_ALIGN;
+ if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) bezt->h1 = HD_ALIGN;
+ if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) bezt->h2 = HD_ALIGN;
}
return 0;
}
@@ -810,9 +810,9 @@ KeyframeEditFunc ANIM_editkeyframes_mirror(short type)
*/
#define ENSURE_HANDLES_MATCH(bezt) \
if (bezt->h1 != bezt->h2) { \
- if (ELEM3(bezt->h1, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM)) \
+ if (ELEM(bezt->h1, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM)) \
bezt->h1 = HD_FREE; \
- if (ELEM3(bezt->h2, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM)) \
+ if (ELEM(bezt->h2, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM)) \
bezt->h2 = HD_FREE; \
} (void)0
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 878c9193b23..a68751e9294 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -652,7 +652,7 @@ static bool visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop)
const char *identifier = NULL;
/* validate data */
- if (ELEM3(NULL, ptr, ptr->data, prop))
+ if (ELEM(NULL, ptr, ptr->data, prop))
return 0;
/* get first constraint and determine type of keyframe constraints to check for
@@ -1042,7 +1042,7 @@ short insert_keyframe(ReportList *reports, ID *id, bAction *act, const char grou
/* for Loc/Rot/Scale and also Color F-Curves, the color of the F-Curve in the Graph Editor,
* is determined by the array index for the F-Curve
*/
- if (ELEM5(RNA_property_subtype(prop), PROP_TRANSLATION, PROP_XYZ, PROP_EULER, PROP_COLOR, PROP_COORDS)) {
+ if (ELEM(RNA_property_subtype(prop), PROP_TRANSLATION, PROP_XYZ, PROP_EULER, PROP_COLOR, PROP_COORDS)) {
fcu->color_mode = FCURVE_COLOR_AUTO_RGB;
}
}
diff --git a/source/blender/editors/armature/CMakeLists.txt b/source/blender/editors/armature/CMakeLists.txt
index ca2dc1b66e2..9aa17f1e503 100644
--- a/source/blender/editors/armature/CMakeLists.txt
+++ b/source/blender/editors/armature/CMakeLists.txt
@@ -26,6 +26,7 @@ set(INC
../../makesdna
../../makesrna
../../windowmanager
+ ../../gpu
../../../../intern/guardedalloc
)
diff --git a/source/blender/editors/armature/SConscript b/source/blender/editors/armature/SConscript
index b3c1ea2dbe9..c68045c9398 100644
--- a/source/blender/editors/armature/SConscript
+++ b/source/blender/editors/armature/SConscript
@@ -39,6 +39,7 @@ incs = [
'../../blenlib',
'../../makesdna',
'../../makesrna',
+ '../../gpu',
'../../windowmanager',
]
incs = ' '.join(incs)
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
index f71cfd52175..1e4d9bac246 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -1343,7 +1343,9 @@ static int armature_reveal_exec(bContext *C, wmOperator *UNUSED(op))
for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
if (arm->layer & ebone->layer) {
if (ebone->flag & BONE_HIDDEN_A) {
- ebone->flag |= (BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ if (!(ebone->flag & BONE_UNSELECTABLE)) {
+ ebone->flag |= (BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ }
ebone->flag &= ~BONE_HIDDEN_A;
}
}
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index 9c3c93e4850..12d13b05ee1 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -160,7 +160,7 @@ void *get_nearest_bone(bContext *C, short findunsel, int x, int y)
rect.ymin = rect.ymax = y;
glInitNames();
- hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
+ hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, true);
if (hits > 0)
return get_bone_from_selectbuffer(vc.scene, vc.scene->basact, buffer, hits, findunsel);
@@ -295,13 +295,13 @@ static EditBone *get_nearest_editbonepoint(ViewContext *vc, const int mval[2],
rect.ymin = mval[1] - 5;
rect.ymax = mval[1] + 5;
- hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect);
+ hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, true);
if (hits == 0) {
rect.xmin = mval[0] - 12;
rect.xmax = mval[0] + 12;
rect.ymin = mval[1] - 12;
rect.ymax = mval[1] + 12;
- hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect);
+ hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, true);
}
/* See if there are any selected bones in this group */
if (hits > 0) {
diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c
index e898e600e9b..57ae03ccebe 100644
--- a/source/blender/editors/armature/armature_skinning.c
+++ b/source/blender/editors/armature/armature_skinning.c
@@ -200,10 +200,22 @@ static void envelope_bone_weighting(Object *ob, Mesh *mesh, float (*verts)[3], i
float distance;
int i, iflip, j;
bool use_topology = (mesh->editflag & ME_EDIT_MIRROR_TOPO) != 0;
+ bool use_mask = false;
+
+ if ((ob->mode & OB_MODE_WEIGHT_PAINT) &&
+ (mesh->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)))
+ {
+ use_mask = true;
+ }
/* for each vertex in the mesh */
for (i = 0; i < mesh->totvert; i++) {
- iflip = (dgroupflip) ? mesh_get_x_mirror_vert(ob, i, use_topology) : 0;
+
+ if (use_mask && !(mesh->mvert[i].flag & SELECT)) {
+ continue;
+ }
+
+ iflip = (dgroupflip) ? mesh_get_x_mirror_vert(ob, i, use_topology) : -1;
/* for each skinnable bone */
for (j = 0; j < numbones; ++j) {
@@ -224,7 +236,7 @@ static void envelope_bone_weighting(Object *ob, Mesh *mesh, float (*verts)[3], i
ED_vgroup_vert_remove(ob, dgroup, i);
/* do same for mirror */
- if (dgroupflip && dgroupflip[j] && iflip >= 0) {
+ if (dgroupflip && dgroupflip[j] && iflip != -1) {
if (distance != 0.0f)
ED_vgroup_vert_add(ob, dgroupflip[j], iflip, distance,
WEIGHT_REPLACE);
diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c
index 475ffd23617..ba105325b97 100644
--- a/source/blender/editors/armature/editarmature_sketch.c
+++ b/source/blender/editors/armature/editarmature_sketch.c
@@ -53,6 +53,8 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "GPU_select.h"
+
typedef int (*GestureDetectFct)(bContext *, SK_Gesture *, SK_Sketch *);
typedef void (*GestureApplyFct)(bContext *, SK_Gesture *, SK_Sketch *);
@@ -493,7 +495,7 @@ static void sk_drawStroke(SK_Stroke *stk, int id, float color[3], int start, int
gluQuadricNormals(quad, GLU_SMOOTH);
if (id != -1) {
- glLoadName(id);
+ GPU_select_load_id(id);
for (i = 0; i < stk->nb_points; i++) {
glPushMatrix();
@@ -1969,7 +1971,7 @@ static int sk_selectStroke(bContext *C, SK_Sketch *sketch, const int mval[2], in
rect.ymin = mval[1] - 5;
rect.ymax = mval[1] + 5;
- hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
+ hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, true);
if (hits > 0) {
int besthitresult = -1;
@@ -2032,7 +2034,7 @@ static void sk_drawSketch(Scene *scene, View3D *UNUSED(v3d), SK_Sketch *sketch,
sk_drawStroke(stk, id, NULL, -1, -1);
}
- glLoadName(-1);
+ GPU_select_load_id(-1);
}
else {
float selected_rgb[3] = {1, 0, 0};
diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c
index 56e7bde0081..49650fcadbf 100644
--- a/source/blender/editors/armature/meshlaplacian.c
+++ b/source/blender/editors/armature/meshlaplacian.c
@@ -635,8 +635,8 @@ void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource,
bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
MVert *mvert = me->mvert;
- bool use_vert_sel = false;
- bool use_face_sel = false;
+ bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+ bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
*err_str = NULL;
@@ -652,9 +652,8 @@ void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource,
return;
/* count triangles and create mask */
- if (ob->mode == OB_MODE_WEIGHT_PAINT &&
- ((use_face_sel = ((me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0)) ||
- (use_vert_sel = ((me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0))))
+ if (ob->mode & OB_MODE_WEIGHT_PAINT &&
+ (use_face_sel || use_vert_sel))
{
mask = MEM_callocN(sizeof(int) * me->totvert, "heat_bone_weighting mask");
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index 890bf6649b9..da68108285f 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -1074,7 +1074,9 @@ static int show_pose_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr))
if (arm->layer & bone->layer) {
if (bone->flag & BONE_HIDDEN_P) {
bone->flag &= ~BONE_HIDDEN_P;
- bone->flag |= BONE_SELECTED;
+ if (!(bone->flag & BONE_UNSELECTABLE)) {
+ bone->flag |= BONE_SELECTED;
+ }
}
}
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index 6762ffc17b2..0609fcc29e8 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -307,7 +307,7 @@ static int poselib_sanitize_exec(bContext *C, wmOperator *op)
/* check if any pose matches this */
/* TODO: don't go looking through the list like this every time... */
for (marker = act->markers.first; marker; marker = marker->next) {
- if (IS_EQ(marker->frame, (double)ak->cfra)) {
+ if (IS_EQ((double)marker->frame, (double)ak->cfra)) {
marker->flag = -1;
break;
}
@@ -1417,7 +1417,7 @@ static void poselib_preview_init_data(bContext *C, wmOperator *op)
pld->marker = (pld->act) ? BLI_findlink(&pld->act->markers, pose_index) : NULL;
/* check if valid poselib */
- if (ELEM3(NULL, pld->ob, pld->pose, pld->arm)) {
+ if (ELEM(NULL, pld->ob, pld->pose, pld->arm)) {
BKE_report(op->reports, RPT_ERROR, "Pose lib is only for armatures in pose mode");
pld->state = PL_PREVIEW_ERROR;
return;
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index aa741ef9aaf..76284ba44de 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -69,6 +69,29 @@
/* ***************** Pose Select Utilities ********************* */
+/* Note: SEL_TOGGLE is assumed to have already been handled! */
+static void pose_do_bone_select(bPoseChannel *pchan, const int select_mode)
+{
+ /* select pchan only if selectable, but deselect works always */
+ switch (select_mode) {
+ case SEL_SELECT:
+ if (!(pchan->bone->flag & BONE_UNSELECTABLE))
+ pchan->bone->flag |= BONE_SELECTED;
+ break;
+ case SEL_DESELECT:
+ pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ break;
+ case SEL_INVERT:
+ if (pchan->bone->flag & BONE_SELECTED) {
+ pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else if (!(pchan->bone->flag & BONE_UNSELECTABLE)) {
+ pchan->bone->flag |= BONE_SELECTED;
+ }
+ break;
+ }
+}
+
/* Utility method for changing the selection status of a bone */
void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select)
{
@@ -76,7 +99,7 @@ void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select)
/* sanity checks */
// XXX: actually, we can probably still get away with no object - at most we have no updates
- if (ELEM4(NULL, ob, ob->pose, pchan, pchan->bone))
+ if (ELEM(NULL, ob, ob->pose, pchan, pchan->bone))
return;
arm = ob->data;
@@ -139,7 +162,7 @@ int ED_do_pose_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, shor
}
if (!extend && !deselect && !toggle) {
- ED_pose_deselectall(ob, 0);
+ ED_pose_de_selectall(ob, SEL_DESELECT, true);
nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
arm->act_bone = nearBone;
}
@@ -191,16 +214,12 @@ int ED_do_pose_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, shor
return nearBone != NULL;
}
-/* test==0: deselect all
- * test==1: swap select (apply to all the opposite of current situation)
- * test==2: only clear active tag
- * test==3: swap select (no test / inverse selection status of all independently)
- */
-void ED_pose_deselectall(Object *ob, int test)
+/* 'select_mode' is usual SEL_SELECT/SEL_DESELECT/SEL_TOGGLE/SEL_INVERT.
+ * When true, 'ignore_visibility' makes this func also affect invisible bones (hidden or on hidden layers). */
+void ED_pose_de_selectall(Object *ob, int select_mode, const bool ignore_visibility)
{
bArmature *arm = ob->data;
bPoseChannel *pchan;
- int selectmode = 0;
/* we call this from outliner too */
if (ob->pose == NULL) {
@@ -208,31 +227,23 @@ void ED_pose_deselectall(Object *ob, int test)
}
/* Determine if we're selecting or deselecting */
- if (test == 1) {
+ if (select_mode == SEL_TOGGLE) {
+ select_mode = SEL_SELECT;
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (PBONE_VISIBLE(arm, pchan->bone)) {
- if (pchan->bone->flag & BONE_SELECTED)
+ if (ignore_visibility || PBONE_VISIBLE(arm, pchan->bone)) {
+ if (pchan->bone->flag & BONE_SELECTED) {
+ select_mode = SEL_DESELECT;
break;
+ }
}
}
-
- if (pchan == NULL)
- selectmode = 1;
}
- else if (test == 2)
- selectmode = 2;
- /* Set the flags accordingly */
+ /* Set the flags accordingly */
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
/* ignore the pchan if it isn't visible or if its selection cannot be changed */
- if ((pchan->bone->layer & arm->layer) && !(pchan->bone->flag & (BONE_HIDDEN_P | BONE_UNSELECTABLE))) {
- if (test == 3) {
- pchan->bone->flag ^= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- else {
- if (selectmode == 0) pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- else if (selectmode == 1) pchan->bone->flag |= BONE_SELECTED;
- }
+ if (ignore_visibility || PBONE_VISIBLE(arm, pchan->bone)) {
+ pose_do_bone_select(pchan, select_mode);
}
}
}
@@ -353,24 +364,7 @@ static int pose_de_select_all_exec(bContext *C, wmOperator *op)
/* Set the flags */
CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones)
{
- /* select pchan only if selectable, but deselect works always */
- switch (action) {
- case SEL_SELECT:
- if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0)
- pchan->bone->flag |= BONE_SELECTED;
- break;
- case SEL_DESELECT:
- pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- break;
- case SEL_INVERT:
- if (pchan->bone->flag & BONE_SELECTED) {
- pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- else if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
- pchan->bone->flag |= BONE_SELECTED;
- }
- break;
- }
+ pose_do_bone_select(pchan, action);
}
CTX_DATA_END;
@@ -644,7 +638,7 @@ static bool pose_select_same_group(bContext *C, Object *ob, bool extend)
bool changed = false, tagged = false;
/* sanity checks */
- if (ELEM3(NULL, ob, pose, arm))
+ if (ELEM(NULL, ob, pose, arm))
return 0;
/* count the number of groups */
@@ -701,7 +695,7 @@ static bool pose_select_same_layer(bContext *C, Object *ob, bool extend)
bool changed = false;
int layers = 0;
- if (ELEM3(NULL, ob, pose, arm))
+ if (ELEM(NULL, ob, pose, arm))
return 0;
/* figure out what bones are selected */
@@ -761,7 +755,7 @@ static bool pose_select_same_keyingset(bContext *C, ReportList *reports, Object
return false;
}
- if (ELEM3(NULL, ob, pose, arm))
+ if (ELEM(NULL, ob, pose, arm))
return false;
/* if not extending selection, deselect all selected first */
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index 375cbb0fe2b..5f9f24d23a4 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -134,7 +134,7 @@ static int pose_slide_init(bContext *C, wmOperator *op, short mode)
pso->nextFrame = RNA_int_get(op->ptr, "next_frame");
/* check the settings from the context */
- if (ELEM4(NULL, pso->ob, pso->arm, pso->ob->adt, pso->ob->adt->action))
+ if (ELEM(NULL, pso->ob, pso->arm, pso->ob->adt, pso->ob->adt->action))
return 0;
else
act = pso->ob->adt->action;
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 11c8b11e31d..b0371b8dd6c 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -7019,7 +7019,7 @@ static int match_texture_space_poll(bContext *C)
{
Object *object = CTX_data_active_object(C);
- return object && ELEM3(object->type, OB_CURVE, OB_SURF, OB_FONT);
+ return object && ELEM(object->type, OB_CURVE, OB_SURF, OB_FONT);
}
static int match_texture_space_exec(bContext *C, wmOperator *UNUSED(op))
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index 3fc6e2e6f0d..2a84ca7f297 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -93,6 +93,8 @@ if(WITH_BLENDER)
data_to_c_simple(../../../../release/datafiles/brushicons/soften.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/subtract.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/texdraw.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/texfill.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/texmask.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/thumb.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/twist.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/vertexdraw.png SRC)
diff --git a/source/blender/editors/datafiles/SConscript b/source/blender/editors/datafiles/SConscript
index 47819d0e33c..6bc8f21e384 100644
--- a/source/blender/editors/datafiles/SConscript
+++ b/source/blender/editors/datafiles/SConscript
@@ -77,6 +77,8 @@ sources.extend((
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'], "texfill.png.c"),
+ os.path.join(env['DATA_SOURCES'], "texmask.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"),
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index b725f5c773a..6e17be04623 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -1412,7 +1412,7 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG
rctf subrect, *subrect_ptr = NULL;
/* error checking */
- if (ELEM3(NULL, gpd, gpl, gpf))
+ if (ELEM(NULL, gpd, gpl, gpf))
return;
/* only convert if there are any strokes on this layer's frame to convert */
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 4910396ac6f..afecdd91599 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -1861,7 +1861,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* we don't pass on key events, GP is used with key-modifiers - prevents Dkey to insert drivers */
if (ISKEYBOARD(event->type)) {
- if (ELEM4(event->type, LEFTARROWKEY, DOWNARROWKEY, RIGHTARROWKEY, UPARROWKEY)) {
+ if (ELEM(event->type, LEFTARROWKEY, DOWNARROWKEY, RIGHTARROWKEY, UPARROWKEY)) {
/* allow some keys - for frame changing: [#33412] */
}
else {
@@ -1874,7 +1874,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* exit painting mode (and/or end current stroke)
* NOTE: cannot do RIGHTMOUSE (as is standard for canceling) as that would break polyline [#32647]
*/
- if (ELEM4(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY)) {
+ if (ELEM(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY)) {
/* exit() ends the current stroke before cleaning up */
/* printf("\t\tGP - end of paint op + end of stroke\n"); */
p->status = GP_STATUS_DONE;
@@ -1949,7 +1949,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
/* eraser size */
else if ((p->paintmode == GP_PAINTMODE_ERASER) &&
- ELEM4(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE, PADPLUSKEY, PADMINUS))
+ ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE, PADPLUSKEY, PADMINUS))
{
/* just resize the brush (local version)
* TODO: fix the hardcoded size jumps (set to make a visible difference) and hardcoded keys
diff --git a/source/blender/editors/include/BIF_gl.h b/source/blender/editors/include/BIF_gl.h
index 477a7c0ce17..9fa603966b6 100644
--- a/source/blender/editors/include/BIF_gl.h
+++ b/source/blender/editors/include/BIF_gl.h
@@ -58,8 +58,24 @@
* */
void cpack(unsigned int x);
-#define glMultMatrixf(x) glMultMatrixf( (float *)(x))
-#define glLoadMatrixf(x) glLoadMatrixf( (float *)(x))
+
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
+# define glMultMatrixf(x) \
+ glMultMatrixf(_Generic((x), \
+ float *: (float *)(x), \
+ float (*)[4]: (float *)(x), \
+ const float *: (float *)(x), \
+ const float (*)[4]: (float *)(x)) \
+)
+# define glLoadMatrixf(x) \
+ glLoadMatrixf(_Generic((x), \
+ float *: (float *)(x), \
+ float (*)[4]: (float *)(x)) \
+)
+#else
+# define glMultMatrixf(x) glMultMatrixf((float *)(x))
+# define glLoadMatrixf(x) glLoadMatrixf((float *)(x))
+#endif
#define GLA_PIXEL_OFS 0.375f
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 7579f6cba65..f6a1b493fac 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -174,7 +174,7 @@ void ED_armature_ebone_selectflag_disable(EditBone *ebone, int flag);
/* poseobject.c */
void ED_armature_exit_posemode(struct bContext *C, struct Base *base);
void ED_armature_enter_posemode(struct bContext *C, struct Base *base);
-void ED_pose_deselectall(struct Object *ob, int test);
+void ED_pose_de_selectall(struct Object *ob, int select_mode, const bool ignore_visibility);
void ED_pose_bone_select(struct Object *ob, struct bPoseChannel *pchan, bool select);
void ED_pose_recalculate_paths(struct Scene *scene, struct Object *ob);
struct Object *ED_pose_object_from_context(struct bContext *C);
diff --git a/source/blender/editors/include/ED_datafiles.h b/source/blender/editors/include/ED_datafiles.h
index 9022a1481aa..661ab58b98c 100644
--- a/source/blender/editors/include/ED_datafiles.h
+++ b/source/blender/editors/include/ED_datafiles.h
@@ -150,6 +150,12 @@ extern char datatoc_subtract_png[];
extern int datatoc_texdraw_png_size;
extern char datatoc_texdraw_png[];
+extern int datatoc_texfill_png_size;
+extern char datatoc_texfill_png[];
+
+extern int datatoc_texmask_png_size;
+extern char datatoc_texmask_png[];
+
extern int datatoc_thumb_png_size;
extern char datatoc_thumb_png[];
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index b15a83809f5..db13c628ade 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -69,8 +69,11 @@ void ED_image_point_pos__reverse(struct SpaceImage *sima, struct ARegion *ar, co
bool ED_space_image_show_render(struct SpaceImage *sima);
bool ED_space_image_show_paint(struct SpaceImage *sima);
bool ED_space_image_show_uvedit(struct SpaceImage *sima, struct Object *obedit);
+bool ED_space_image_show_texpaint(struct SpaceImage *sima, struct Object *ob);
bool ED_space_image_show_uvshadow(struct SpaceImage *sima, struct Object *obedit);
+bool ED_space_image_paint_curve(const struct bContext *C);
+
bool ED_space_image_check_show_maskedit(struct Scene *scene, struct SpaceImage *sima);
int ED_space_image_maskedit_poll(struct bContext *C);
int ED_space_image_maskedit_mask_poll(struct bContext *C);
diff --git a/source/blender/editors/include/ED_paint.h b/source/blender/editors/include/ED_paint.h
index d7e84d8f50d..decd79fcc7b 100644
--- a/source/blender/editors/include/ED_paint.h
+++ b/source/blender/editors/include/ED_paint.h
@@ -28,9 +28,11 @@
struct bContext;
struct RegionView3D;
struct wmKeyConfig;
+struct wmOperator;
/* paint_ops.c */
void ED_operatortypes_paint(void);
+void ED_operatormacros_paint(void);
void ED_keymap_paint(struct wmKeyConfig *keyconf);
/* paint_undo.c */
@@ -41,6 +43,7 @@ enum {
typedef void (*UndoRestoreCb)(struct bContext *C, struct ListBase *lb);
typedef void (*UndoFreeCb)(struct ListBase *lb);
+typedef bool (*UndoCleanupCb)(struct bContext *C, struct ListBase *lb);
int ED_undo_paint_step(struct bContext *C, int type, int step, const char *name);
void ED_undo_paint_step_num(struct bContext *C, int type, int num);
@@ -48,7 +51,7 @@ const char *ED_undo_paint_get_name(struct bContext *C, int type, int nr, int *ac
void ED_undo_paint_free(void);
int ED_undo_paint_valid(int type, const char *name);
bool ED_undo_paint_empty(int type);
-void ED_undo_paint_push_begin(int type, const char *name, UndoRestoreCb restore, UndoFreeCb free);
+void ED_undo_paint_push_begin(int type, const char *name, UndoRestoreCb restore, UndoFreeCb free, UndoCleanupCb cleanup);
void ED_undo_paint_push_end(int type);
/* paint_image.c */
@@ -57,5 +60,6 @@ void ED_image_undo_restore(struct bContext *C, struct ListBase *lb);
void ED_image_undo_free(struct ListBase *lb);
void ED_imapaint_clear_partial_redraw(void);
void ED_imapaint_dirty_region(struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h);
+void ED_imapaint_bucket_fill(struct bContext *C, float color[3], struct wmOperator *op);
#endif /* __ED_PAINT_H__ */
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index 41ff9b88da9..daa6864b5aa 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -98,6 +98,7 @@ enum TfmMode {
#define CTX_NDOF (1 << 5)
#define CTX_MOVIECLIP (1 << 6)
#define CTX_MASK (1 << 7)
+#define CTX_PAINT_CURVE (1 << 8)
/* Standalone call to get the transformation center corresponding to the current situation
* returns 1 if successful, 0 otherwise (usually means there's no selection)
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index 04eb829979f..4b82fa40c6a 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -54,7 +54,7 @@ void ED_uvedit_assign_image(struct Main *bmain, struct Scene *scene, struct Obje
bool ED_uvedit_minmax(struct Scene *scene, struct Image *ima, struct Object *obedit, float min[2], float max[2]);
bool ED_object_get_active_image(struct Object *ob, int mat_nr,
- struct Image **r_ima, struct ImageUser **r_iuser, struct bNode **r_node);
+ struct Image **r_ima, struct ImageUser **r_iuser, struct bNode **r_node, struct bNodeTree **r_ntree);
void ED_object_assign_active_image(struct Main *bmain, struct Object *ob, int mat_nr, struct Image *ima);
bool ED_uvedit_test(struct Object *obedit);
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 76839747076..dceede7a540 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -56,6 +56,7 @@ struct bContext;
struct bPoseChannel;
struct bScreen;
struct bglMats;
+struct rctf;
struct rcti;
struct wmOperator;
struct wmOperatorType;
@@ -84,6 +85,7 @@ typedef struct ViewDepths {
float *ED_view3d_cursor3d_get(struct Scene *scene, struct View3D *v3d);
void ED_view3d_cursor3d_position(struct bContext *C, float fp[3], const int mval[2]);
+void ED_view3d_cursor3d_update(struct bContext *C, const int mval[2]);
struct Camera *ED_view3d_camera_data_get(struct View3D *v3d, struct RegionView3D *rv3d);
@@ -269,7 +271,7 @@ bool ED_view3d_autodist_depth_seg(struct ARegion *ar, const int mval_sta[2], con
/* select */
#define MAXPICKBUF 10000
-short view3d_opengl_select(struct ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const rcti *input);
+short view3d_opengl_select(struct ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const struct rcti *input, bool do_nearest);
/* view3d_select.c */
float ED_view3d_select_dist_px(void);
@@ -364,6 +366,6 @@ void ED_view3d_operator_properties_viewmat_get(struct wmOperator *op, int *winx,
#endif
/* render */
-void ED_view3d_shade_update(struct Main *bmain, struct View3D *v3d, struct ScrArea *sa);
+void ED_view3d_shade_update(struct Main *bmain, struct Scene *scene, struct View3D *v3d, struct ScrArea *sa);
#endif /* __ED_VIEW3D_H__ */
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index 904c14f0573..f1b544f269b 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -978,6 +978,8 @@ DEF_ICON(BRUSH_SNAKE_HOOK)
DEF_ICON(BRUSH_SOFTEN)
DEF_ICON(BRUSH_SUBTRACT)
DEF_ICON(BRUSH_TEXDRAW)
+DEF_ICON(BRUSH_TEXFILL)
+DEF_ICON(BRUSH_TEXMASK)
DEF_ICON(BRUSH_THUMB)
DEF_ICON(BRUSH_ROTATE)
DEF_ICON(BRUSH_VERTEXDRAW)
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 1565583b574..d7b4f753810 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -75,6 +75,9 @@ struct ImBuf;
struct bNodeTree;
struct bNode;
struct bNodeSocket;
+struct wmDropBox;
+struct wmDrag;
+struct wmEvent;
typedef struct uiBut uiBut;
typedef struct uiBlock uiBlock;
@@ -175,6 +178,7 @@ enum {
UI_BUT_DRAG_MULTI = (1 << 25), /* edit this button as well as the active button (not just dragging) */
UI_BUT_SCA_LINK_GREY = (1 << 26), /* used to flag if sca links shoud be grey out */
UI_BUT_HAS_SEP_CHAR = (1 << 27), /* but->str contains UI_SEP_CHAR, used for key shortcuts */
+ UI_OPTION_TOOLTIPS = (1 << 28), /* force show tooltips when holding option/alt if U's USER_TOOLTIPS is off */
};
#define UI_PANEL_WIDTH 340
@@ -288,6 +292,9 @@ typedef enum {
#define UI_GRAD_V_ALT 9
#define UI_GRAD_L_ALT 10
+#define UI_PALETTE_COLOR 20
+#define UI_PALETTE_COLOR_ACTIVE 1
+
/* Drawing
*
* Functions to draw various shapes, taking theme settings into account.
@@ -437,6 +444,7 @@ void uiButSetDragValue(uiBut *but);
void uiButSetDragImage(uiBut *but, const char *path, int icon, struct ImBuf *ima, float scale);
bool UI_but_active_drop_name(struct bContext *C);
+bool UI_but_active_drop_color(struct bContext *C);
void uiButSetFlag(uiBut *but, int flag);
void uiButClearFlag(uiBut *but, int flag);
@@ -708,7 +716,6 @@ void UI_remove_popup_handlers_all(struct bContext *C, struct ListBase *handlers)
void UI_init(void);
void UI_init_userdef(void);
-void UI_init_userdef_factory(void);
void UI_reinit_font(void);
void UI_exit(void);
@@ -847,6 +854,7 @@ void uiTemplateVectorscope(uiLayout *layout, struct PointerRNA *ptr, const char
void uiTemplateCurveMapping(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int type,
int levels, int brush, int neg_slope);
void uiTemplateColorPicker(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int value_slider, int lock, int lock_luminosity, int cubic);
+void uiTemplatePalette(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int color);
void uiTemplateLayers(uiLayout *layout, struct PointerRNA *ptr, const char *propname,
PointerRNA *used_ptr, const char *used_propname, int active_layer);
void uiTemplateGameStates(uiLayout *layout, struct PointerRNA *ptr, const char *propname,
@@ -916,7 +924,14 @@ void uiItemMenuEnumO(uiLayout *layout, struct bContext *C, const char *opname, c
void uiItemMenuEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name, int icon);
/* UI Operators */
+typedef struct uiDragColorHandle {
+ float color[3];
+ bool gamma_corrected;
+} uiDragColorHandle;
+
void UI_buttons_operatortypes(void);
+void UI_drop_color_copy(struct wmDrag *drag, struct wmDropBox *drop);
+int UI_drop_color_poll(struct bContext *C, struct wmDrag *drag, const struct wmEvent *event);
/* Helpers for Operators */
uiBut *uiContextActiveButton(const struct bContext *C);
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index 2e78940a813..da365355e95 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -237,6 +237,9 @@ enum {
TH_STITCH_PREVIEW_UNSTITCHABLE,
TH_STITCH_PREVIEW_ACTIVE,
+ TH_PAINT_CURVE_HANDLE,
+ TH_PAINT_CURVE_PIVOT,
+
TH_UV_SHADOW,
TH_UV_OTHERS,
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index c857150782e..0a45ffc4c13 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -830,7 +830,7 @@ static void ui_menu_block_set_keyaccels(uiBlock *block)
* fun first pass on all buttons so first word chars always get first priority */
for (but = block->buttons.first; but; but = but->next) {
- if (!ELEM5(but->type, BUT, BUTM, MENU, BLOCK, PULLDOWN) || (but->flag & UI_HIDDEN)) {
+ if (!ELEM(but->type, BUT, BUTM, MENU, BLOCK, PULLDOWN) || (but->flag & UI_HIDDEN)) {
/* pass */
}
else if (but->menu_key == '\0') {
@@ -1320,7 +1320,7 @@ int ui_is_but_push_ex(uiBut *but, double *value)
int is_push = 0;
if (but->bit) {
- const bool state = ELEM3(but->type, TOGN, ICONTOGN, OPTIONN) ? false : true;
+ const bool state = ELEM(but->type, TOGN, ICONTOGN, OPTIONN) ? false : true;
int lvalue;
UI_GET_BUT_VALUE_INIT(but, *value);
lvalue = (int)*value;
@@ -1630,7 +1630,7 @@ bool ui_is_but_float(const uiBut *but)
bool ui_is_but_bool(const uiBut *but)
{
- if (ELEM4(but->type, TOG, TOGN, ICONTOG, ICONTOGN))
+ if (ELEM(but->type, TOG, TOGN, ICONTOG, ICONTOGN))
return true;
if (but->rnaprop && RNA_property_type(but->rnaprop) == PROP_BOOLEAN)
@@ -1843,7 +1843,7 @@ void ui_set_but_val(uiBut *but, double value)
int ui_get_but_string_max_length(uiBut *but)
{
- if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK))
+ if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK))
return but->hardmax;
else
return UI_MAX_DRAW_STR;
@@ -1958,7 +1958,7 @@ static float ui_get_but_step_unit(uiBut *but, float step_default)
*/
void ui_get_but_string_ex(uiBut *but, char *str, const size_t maxlen, const int float_precision)
{
- if (but->rnaprop && ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (but->rnaprop && ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
PropertyType type;
const char *buf = NULL;
int buf_len;
@@ -2095,7 +2095,7 @@ bool ui_set_but_string_eval_num(bContext *C, uiBut *but, const char *str, double
bool ui_set_but_string(bContext *C, uiBut *but, const char *str)
{
- if (but->rnaprop && ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (but->rnaprop && ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
if (RNA_property_editable(&but->rnapoin, but->rnaprop)) {
PropertyType type;
@@ -2747,7 +2747,7 @@ void uiBlockEndAlign(uiBlock *block)
bool ui_but_can_align(uiBut *but)
{
- return !ELEM5(but->type, LABEL, OPTION, OPTIONN, SEPR, SEPRLINE);
+ return !ELEM(but->type, LABEL, OPTION, OPTIONN, SEPR, SEPRLINE);
}
static void ui_block_do_align_but(uiBut *first, short nr)
@@ -3029,7 +3029,7 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str,
}
if ((block->flag & UI_BLOCK_LOOP) ||
- ELEM8(but->type, MENU, TEX, LABEL, BLOCK, BUTM, SEARCH_MENU, PROGRESSBAR, SEARCH_MENU_UNLINK))
+ ELEM(but->type, MENU, TEX, LABEL, BLOCK, BUTM, SEARCH_MENU, PROGRESSBAR, SEARCH_MENU_UNLINK))
{
but->drawflag |= (UI_BUT_TEXT_LEFT | UI_BUT_ICON_LEFT);
}
@@ -3048,7 +3048,7 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str,
}
/* keep track of UI_interface.h */
- if (ELEM11(but->type, BLOCK, BUT, LABEL, PULLDOWN, ROUNDBOX, LISTBOX, BUTM, SCROLL, SEPR, SEPRLINE, GRIP)) {}
+ if (ELEM(but->type, BLOCK, BUT, LABEL, PULLDOWN, ROUNDBOX, LISTBOX, BUTM, SCROLL, SEPR, SEPRLINE, GRIP)) {}
else if (but->type >= SEARCH_MENU) {}
else but->flag |= UI_BUT_UNDO;
@@ -3213,12 +3213,12 @@ static uiBut *ui_def_but_rna(uiBlock *block, int type, int retval, const char *s
int icon = 0;
uiMenuCreateFunc func = NULL;
- if (ELEM3(type, COLOR, HSVCIRCLE, HSVCUBE)) {
+ if (ELEM(type, COLOR, HSVCIRCLE, HSVCUBE)) {
BLI_assert(index == -1);
}
/* use rna values if parameters are not specified */
- if ((proptype == PROP_ENUM) && ELEM3(type, MENU, ROW, LISTROW)) {
+ if ((proptype == PROP_ENUM) && ELEM(type, MENU, ROW, LISTROW)) {
/* MENU is handled a little differently here */
EnumPropertyItem *item;
int value;
@@ -3811,9 +3811,6 @@ void uiBlockFlipOrder(uiBlock *block)
but->rect.ymax = centy - (but->rect.ymax - centy);
SWAP(float, but->rect.ymin, but->rect.ymax);
}
-
- /* also flip order in block itself, for example for arrowkey */
- BLI_listbase_reverse(&block->buttons);
}
@@ -4339,7 +4336,7 @@ void uiButGetStrInfo(bContext *C, uiBut *but, ...)
}
tmp = BLI_strdup(_tmp);
}
- else if (ELEM3(type, BUT_GET_RNAENUM_IDENTIFIER, BUT_GET_RNAENUM_LABEL, BUT_GET_RNAENUM_TIP)) {
+ else if (ELEM(type, BUT_GET_RNAENUM_IDENTIFIER, BUT_GET_RNAENUM_LABEL, BUT_GET_RNAENUM_TIP)) {
PointerRNA *ptr = NULL;
PropertyRNA *prop = NULL;
int value = 0;
@@ -4429,11 +4426,6 @@ void UI_init_userdef(void)
uiStyleInit();
}
-void UI_init_userdef_factory(void)
-{
- init_userdef_factory();
-}
-
void UI_reinit_font(void)
{
uiStyleInit();
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index f821aab8c4d..15b8494cb34 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -695,11 +695,11 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol),
}
/* RGB / YCC (3 channels) */
- else if (ELEM4(scopes->wavefrm_mode,
- SCOPES_WAVEFRM_RGB,
- SCOPES_WAVEFRM_YCC_601,
- SCOPES_WAVEFRM_YCC_709,
- SCOPES_WAVEFRM_YCC_JPEG))
+ else if (ELEM(scopes->wavefrm_mode,
+ SCOPES_WAVEFRM_RGB,
+ SCOPES_WAVEFRM_YCC_601,
+ SCOPES_WAVEFRM_YCC_709,
+ SCOPES_WAVEFRM_YCC_JPEG))
{
int rgb = (scopes->wavefrm_mode == SCOPES_WAVEFRM_RGB);
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index d37660a0611..68148d30136 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -38,6 +38,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_brush_types.h"
#include "DNA_sensor_types.h"
#include "DNA_controller_types.h"
#include "DNA_actuator_types.h"
@@ -60,6 +61,7 @@
#include "PIL_time.h"
#include "BKE_blender.h"
+#include "BKE_brush.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_idprop.h"
@@ -383,16 +385,16 @@ void ui_pan_to_scroll(const wmEvent *event, int *type, int *val)
}
}
-static bool ui_but_editable(uiBut *but)
+bool ui_but_is_editable(const uiBut *but)
{
- return ELEM6(but->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX, PROGRESSBAR);
+ return !ELEM(but->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX, PROGRESSBAR);
}
static uiBut *ui_but_prev(uiBut *but)
{
while (but->prev) {
but = but->prev;
- if (!ui_but_editable(but)) return but;
+ if (ui_but_is_editable(but)) return but;
}
return NULL;
}
@@ -401,7 +403,7 @@ static uiBut *ui_but_next(uiBut *but)
{
while (but->next) {
but = but->next;
- if (!ui_but_editable(but)) return but;
+ if (ui_but_is_editable(but)) return but;
}
return NULL;
}
@@ -412,7 +414,7 @@ static uiBut *ui_but_first(uiBlock *block)
but = block->buttons.first;
while (but) {
- if (!ui_but_editable(but)) return but;
+ if (ui_but_is_editable(but)) return but;
but = but->next;
}
return NULL;
@@ -424,7 +426,7 @@ static uiBut *ui_but_last(uiBlock *block)
but = block->buttons.last;
while (but) {
- if (!ui_but_editable(but)) return but;
+ if (ui_but_is_editable(but)) return but;
but = but->prev;
}
return NULL;
@@ -433,7 +435,7 @@ static uiBut *ui_but_last(uiBlock *block)
static bool ui_is_a_warp_but(uiBut *but)
{
if (U.uiflag & USER_CONTINUOUS_MOUSE) {
- if (ELEM6(but->type, NUM, NUMSLI, HSVCIRCLE, TRACKPREVIEW, HSVCUBE, BUT_CURVE)) {
+ if (ELEM(but->type, NUM, NUMSLI, HSVCIRCLE, TRACKPREVIEW, HSVCUBE, BUT_CURVE)) {
return true;
}
}
@@ -463,7 +465,7 @@ bool ui_is_but_utf8(const uiBut *but)
{
if (but->rnaprop) {
const int subtype = RNA_property_subtype(but->rnaprop);
- return !(ELEM4(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME, PROP_BYTESTRING));
+ return !(ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME, PROP_BYTESTRING));
}
else {
return !(but->flag & UI_BUT_NO_UTF8);
@@ -717,7 +719,7 @@ static void ui_apply_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data)
if (value == 0.0) push = 1;
else push = 0;
- if (ELEM3(but->type, TOGN, ICONTOGN, OPTIONN)) push = !push;
+ if (ELEM(but->type, TOGN, ICONTOGN, OPTIONN)) push = !push;
ui_set_but_val(but, (double)push);
if (but->type == ICONTOG || but->type == ICONTOGN) ui_check_but(but);
}
@@ -1189,7 +1191,7 @@ static bool ui_but_mouse_inside_icon(uiBut *but, ARegion *ar, const wmEvent *eve
BLI_rcti_rctf_copy(&rect, &but->rect);
- if (but->imb) {
+ if (but->imb || but->type == COLOR) {
/* use button size itself */
}
else if (but->drawflag & UI_BUT_ICON_LEFT) {
@@ -1242,10 +1244,42 @@ static bool ui_but_start_drag(bContext *C, uiBut *but, uiHandleButtonData *data,
}
else
#endif
- {
+ if (but->type == COLOR) {
+ bool valid = false;
+ uiDragColorHandle *drag_info = MEM_callocN(sizeof(*drag_info), __func__);
+
+ /* TODO support more button pointer types */
+ if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
+ RNA_property_float_get_array(&but->rnapoin, but->rnaprop, drag_info->color);
+ drag_info->gamma_corrected = true;
+ valid = true;
+ }
+ else if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
+ RNA_property_float_get_array(&but->rnapoin, but->rnaprop, drag_info->color);
+ drag_info->gamma_corrected = false;
+ valid = true;
+ }
+ else if (but->pointype == UI_BUT_POIN_FLOAT) {
+ copy_v3_v3(drag_info->color, (float *)but->poin);
+ valid = true;
+ }
+ else if (but->pointype == UI_BUT_POIN_CHAR) {
+ rgb_uchar_to_float(drag_info->color, (unsigned char *)but->poin);
+ valid = true;
+ }
+
+ if (valid) {
+ WM_event_start_drag(C, ICON_COLOR, WM_DRAG_COLOR, drag_info, 0.0, WM_DRAG_FREE_DATA);
+ }
+ else {
+ MEM_freeN(drag_info);
+ return false;
+ }
+ }
+ else {
wmDrag *drag;
- drag = WM_event_start_drag(C, but->icon, but->dragtype, but->dragpoin, ui_get_but_val(but));
+ drag = WM_event_start_drag(C, but->icon, but->dragtype, but->dragpoin, ui_get_but_val(but), WM_DRAG_NOP);
if (but->imb)
WM_event_drag_image(drag, but->imb, but->imb_scale, BLI_rctf_size_x(&but->rect), BLI_rctf_size_y(&but->rect));
}
@@ -1655,7 +1689,7 @@ static void ui_but_drop(bContext *C, const wmEvent *event, uiBut *but, uiHandleB
for (wmd = drags->first; wmd; wmd = wmd->next) {
if (wmd->type == WM_DRAG_ID) {
/* align these types with UI_but_active_drop_name */
- if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
ID *id = (ID *)wmd->poin;
button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
@@ -1802,7 +1836,7 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
}
/* text/string and ID data */
- else if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ else if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
uiHandleButtonData *active_data = but->active;
if (but->poin == NULL && but->rnapoin.data == NULL) {
@@ -2009,7 +2043,7 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con
BLI_strncpy(origstr, but->editstr, data->maxlen);
- if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
if (but->flag & UI_HAS_ICON) {
startx += UI_DPI_ICON_SIZE / aspect;
}
@@ -2461,11 +2495,11 @@ static void ui_textedit_next_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa
uiBut *but;
/* label and roundbox can overlap real buttons (backdrops...) */
- if (ELEM5(actbut->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX))
+ if (ELEM(actbut->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX))
return;
for (but = actbut->next; but; but = but->next) {
- if (ELEM5(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
if (!(but->flag & UI_BUT_DISABLED)) {
data->postbut = but;
data->posttype = BUTTON_ACTIVATE_TEXT_EDITING;
@@ -2474,7 +2508,7 @@ static void ui_textedit_next_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa
}
}
for (but = block->buttons.first; but != actbut; but = but->next) {
- if (ELEM5(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
if (!(but->flag & UI_BUT_DISABLED)) {
data->postbut = but;
data->posttype = BUTTON_ACTIVATE_TEXT_EDITING;
@@ -2489,11 +2523,11 @@ static void ui_textedit_prev_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa
uiBut *but;
/* label and roundbox can overlap real buttons (backdrops...) */
- if (ELEM5(actbut->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX))
+ if (ELEM(actbut->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX))
return;
for (but = actbut->prev; but; but = but->prev) {
- if (ELEM5(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
if (!(but->flag & UI_BUT_DISABLED)) {
data->postbut = but;
data->posttype = BUTTON_ACTIVATE_TEXT_EDITING;
@@ -2502,7 +2536,7 @@ static void ui_textedit_prev_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa
}
}
for (but = block->buttons.last; but != actbut; but = but->prev) {
- if (ELEM5(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
if (!(but->flag & UI_BUT_DISABLED)) {
data->postbut = but;
data->posttype = BUTTON_ACTIVATE_TEXT_EDITING;
@@ -2803,7 +2837,7 @@ static void ui_numedit_begin(uiBut *but, uiHandleButtonData *data)
data->coba = (ColorBand *)but->poin;
but->editcoba = data->coba;
}
- else if (ELEM4(but->type, BUT_NORMAL, HSVCUBE, HSVCIRCLE, COLOR)) {
+ else if (ELEM(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;
@@ -2990,7 +3024,7 @@ static int ui_do_but_BUT(bContext *C, uiBut *but, uiHandleButtonData *data, cons
static int ui_do_but_HOTKEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
- if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
+ if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
but->drawstr[0] = 0;
but->modifier_key = 0;
button_activate_state(C, but, BUTTON_STATE_WAIT_KEY_EVENT);
@@ -3053,7 +3087,7 @@ static int ui_do_but_HOTKEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data
static int ui_do_but_KEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
- if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
+ if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
button_activate_state(C, but, BUTTON_STATE_WAIT_KEY_EVENT);
return WM_UI_HANDLER_BREAK;
}
@@ -3078,7 +3112,7 @@ static int ui_do_but_KEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, c
static int ui_do_but_TEX(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
- if (ELEM4(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) && event->val == KM_PRESS) {
+ if (ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) && event->val == KM_PRESS) {
if (ELEM(event->type, PADENTER, RETKEY) && (!ui_is_but_utf8(but))) {
/* pass - allow filesel, enter to execute */
}
@@ -3106,7 +3140,7 @@ static int ui_do_but_TEX(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
static int ui_do_but_SEARCH_UNLINK(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
/* unlink icon is on right */
- if (ELEM4(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) && event->val == KM_PRESS &&
+ if (ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) && event->val == KM_PRESS &&
ui_is_but_search_unlink_visible(but))
{
ARegion *ar = data->region;
@@ -3156,7 +3190,7 @@ static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, cons
}
#endif
if (data->state == BUTTON_STATE_HIGHLIGHT) {
- if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
+ if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
#if 0 /* UNUSED */
data->togdual = event->ctrl;
data->togonly = !event->shift;
@@ -3194,7 +3228,7 @@ static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, con
}
#endif
- if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
+ if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
int ret = WM_UI_HANDLER_BREAK;
/* XXX (a bit ugly) Special case handling for filebrowser drag button */
if (but->dragpoin && but->imb && ui_but_mouse_inside_icon(but, data->region, event)) {
@@ -3243,7 +3277,7 @@ static float ui_numedit_apply_snapf(uiBut *but, float tempf, float softmin, floa
if (bUnit_IsValid(unit->system, unit_type)) {
fac = (float)bUnit_BaseScalar(unit->system, unit_type);
- if (ELEM3(unit_type, B_UNIT_LENGTH, B_UNIT_AREA, B_UNIT_VOLUME)) {
+ if (ELEM(unit_type, B_UNIT_LENGTH, B_UNIT_AREA, B_UNIT_VOLUME)) {
fac /= unit->scale_length;
}
}
@@ -3478,7 +3512,7 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
click = 1;
}
else if (event->val == KM_PRESS) {
- if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->ctrl) {
+ if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->ctrl) {
button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
retval = WM_UI_HANDLER_BREAK;
}
@@ -3767,7 +3801,7 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
click = 2;
}
else if (event->val == KM_PRESS) {
- if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->ctrl) {
+ if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->ctrl) {
button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
retval = WM_UI_HANDLER_BREAK;
}
@@ -4024,7 +4058,7 @@ static int ui_do_but_LISTROW(bContext *C, uiBut *but, uiHandleButtonData *data,
/* hack to pass on ctrl+click and double click to overlapping text
* editing field for editing list item names
*/
- if ((ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS && event->ctrl) ||
+ if ((ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS && event->ctrl) ||
(event->type == LEFTMOUSE && event->val == KM_DBL_CLICK))
{
uiBut *labelbut = ui_but_list_row_text_activate(C, but, data, event, BUTTON_ACTIVATE_TEXT_EDITING);
@@ -4053,7 +4087,7 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co
}
}
#ifdef USE_DRAG_TOGGLE
- if (event->type == LEFTMOUSE && ui_is_but_drag_toggle(but)) {
+ if (event->type == LEFTMOUSE && event->val == KM_PRESS && (ui_is_but_drag_toggle(but))) {
button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
data->dragstartx = event->x;
data->dragstarty = event->y;
@@ -4061,7 +4095,7 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co
}
#endif
/* regular open menu */
- if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
+ if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
button_activate_state(C, but, BUTTON_STATE_MENU_OPEN);
return WM_UI_HANDLER_BREAK;
}
@@ -4206,11 +4240,29 @@ static bool ui_numedit_but_NORMAL(uiBut *but, uiHandleButtonData *data,
static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
- if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
+ /* first handle click on icondrag type button */
+ if (event->type == LEFTMOUSE && but->dragpoin && event->val == KM_PRESS) {
+ if (ui_but_mouse_inside_icon(but, data->region, event)) {
+ button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
+ data->dragstartx = event->x;
+ data->dragstarty = event->y;
+ return WM_UI_HANDLER_BREAK;
+ }
+ }
+#ifdef USE_DRAG_TOGGLE
+ if (event->type == LEFTMOUSE && event->val == KM_PRESS) {
+ button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
+ data->dragstartx = event->x;
+ data->dragstarty = event->y;
+ return WM_UI_HANDLER_BREAK;
+ }
+#endif
+ /* regular open menu */
+ if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
button_activate_state(C, but, BUTTON_STATE_MENU_OPEN);
return WM_UI_HANDLER_BREAK;
}
- else if (ELEM3(event->type, MOUSEPAN, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->alt) {
+ else if (ELEM(event->type, MOUSEPAN, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->alt) {
float *hsv = ui_block_hsv_get(but->block);
float col[3];
@@ -4233,6 +4285,81 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co
ui_apply_button(C, but->block, but, data, true);
return WM_UI_HANDLER_BREAK;
}
+ else if ((int)(but->a1) == UI_PALETTE_COLOR &&
+ event->type == DELKEY && event->val == KM_PRESS)
+ {
+ Scene *scene = CTX_data_scene(C);
+ Paint *paint = BKE_paint_get_active(scene);
+ Palette *palette = BKE_paint_palette(paint);
+ PaletteColor *color = but->rnapoin.data;
+
+ BKE_palette_color_remove(palette, color);
+
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+ return WM_UI_HANDLER_BREAK;
+ }
+ }
+ else if (data->state == BUTTON_STATE_WAIT_DRAG) {
+
+ /* this function also ends state */
+ if (ui_but_start_drag(C, but, data, event)) {
+ return WM_UI_HANDLER_BREAK;
+ }
+
+ /* outside icon quit, not needed if drag activated */
+ if (0 == ui_but_mouse_inside_icon(but, data->region, event)) {
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+ data->cancel = true;
+ return WM_UI_HANDLER_BREAK;
+ }
+
+ if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
+ if ((int)(but->a1) == UI_PALETTE_COLOR) {
+ Palette *palette = but->rnapoin.id.data;
+ PaletteColor *color = but->rnapoin.data;
+ palette->active_color = BLI_findindex(&palette->colors, color);
+
+ if (!event->ctrl) {
+ float color[3];
+ Scene *scene = CTX_data_scene(C);
+ Paint *paint = BKE_paint_get_active(scene);
+ Brush *brush = BKE_paint_brush(paint);
+
+ if (brush->flag & BRUSH_USE_GRADIENT) {
+ float *target = &brush->gradient->data[brush->gradient->cur].r;
+
+ if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
+ RNA_property_float_get_array(&but->rnapoin, but->rnaprop, target);
+ ui_block_to_scene_linear_v3(but->block, target);
+ }
+ else if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
+ RNA_property_float_get_array(&but->rnapoin, but->rnaprop, target);
+ }
+ }
+ else {
+ if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
+ RNA_property_float_get_array(&but->rnapoin, but->rnaprop, color);
+ BKE_brush_color_set(scene, brush, color);
+ }
+ else if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
+ RNA_property_float_get_array(&but->rnapoin, but->rnaprop, color);
+ ui_block_to_display_space_v3(but->block, color);
+ BKE_brush_color_set(scene, brush, color);
+ }
+ }
+
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+ }
+ else {
+ button_activate_state(C, but, BUTTON_STATE_MENU_OPEN);
+ }
+ }
+ else {
+ button_activate_state(C, but, BUTTON_STATE_MENU_OPEN);
+ }
+ return WM_UI_HANDLER_BREAK;
+ }
+
}
return WM_UI_HANDLER_CONTINUE;
@@ -4412,7 +4539,7 @@ static bool ui_numedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data,
}
if (snap != SNAP_OFF) {
- if (ELEM3((int)but->a1, UI_GRAD_HV, UI_GRAD_HS, UI_GRAD_H)) {
+ if (ELEM((int)but->a1, UI_GRAD_HV, UI_GRAD_HS, UI_GRAD_H)) {
ui_color_snap_hue(snap, &hsv[0]);
}
}
@@ -4489,7 +4616,7 @@ static void ui_ndofedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data,
}
if (snap != SNAP_OFF) {
- if (ELEM3((int)but->a1, UI_GRAD_HV, UI_GRAD_HS, UI_GRAD_H)) {
+ if (ELEM((int)but->a1, UI_GRAD_HV, UI_GRAD_HS, UI_GRAD_H)) {
ui_color_snap_hue(snap, &hsv[0]);
}
}
@@ -6012,7 +6139,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
}
/* handle drivers */
else if ((event->type == DKEY) &&
- !ELEM3(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift) &&
+ !ELEM(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift) &&
(event->val == KM_PRESS))
{
if (event->alt)
@@ -6026,7 +6153,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
}
/* handle keyingsets */
else if ((event->type == KKEY) &&
- !ELEM3(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift) &&
+ !ELEM(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift) &&
(event->val == KM_PRESS))
{
if (event->alt)
@@ -6250,7 +6377,7 @@ static bool ui_but_contains_pt(uiBut *but, float mx, float my)
return BLI_rctf_isect_pt(&but->rect, mx, my);
}
-static uiBut *ui_but_find_activated(ARegion *ar)
+uiBut *ui_but_find_activated(ARegion *ar)
{
uiBlock *block;
uiBut *but;
@@ -6298,13 +6425,27 @@ bool UI_but_active_drop_name(bContext *C)
uiBut *but = ui_but_find_activated(ar);
if (but) {
- if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK))
+ if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK))
return 1;
}
return 0;
}
+bool UI_but_active_drop_color(bContext *C)
+{
+ ARegion *ar = CTX_wm_region(C);
+
+ if (ar) {
+ uiBut *but = ui_but_find_activated(ar);
+
+ if (but && but->type == COLOR)
+ return true;
+ }
+
+ return false;
+}
+
static void ui_blocks_set_tooltips(ARegion *ar, const bool enable)
{
uiBlock *block;
@@ -6378,7 +6519,7 @@ static bool ui_is_but_interactive(const uiBut *but, const bool labeledit)
/* note, LABEL is included for highlights, this allows drags */
if ((but->type == LABEL) && but->dragpoin == NULL)
return false;
- if (ELEM4(but->type, ROUNDBOX, SEPR, SEPRLINE, LISTBOX))
+ if (ELEM(but->type, ROUNDBOX, SEPR, SEPRLINE, LISTBOX))
return false;
if (but->flag & UI_HIDDEN)
return false;
@@ -6471,9 +6612,13 @@ static uiBut *ui_list_find_mouse_over(ARegion *ar, int x, int y)
static bool button_modal_state(uiHandleButtonState state)
{
- return ELEM6(state, BUTTON_STATE_WAIT_RELEASE, BUTTON_STATE_WAIT_KEY_EVENT,
- BUTTON_STATE_NUM_EDITING, BUTTON_STATE_TEXT_EDITING,
- BUTTON_STATE_TEXT_SELECTING, BUTTON_STATE_MENU_OPEN);
+ return ELEM(state,
+ BUTTON_STATE_WAIT_RELEASE,
+ BUTTON_STATE_WAIT_KEY_EVENT,
+ BUTTON_STATE_NUM_EDITING,
+ BUTTON_STATE_TEXT_EDITING,
+ BUTTON_STATE_TEXT_SELECTING,
+ BUTTON_STATE_MENU_OPEN);
}
static void button_timers_tooltip_remove(bContext *C, uiBut *but)
@@ -6511,7 +6656,7 @@ static void button_tooltip_timer_reset(bContext *C, uiBut *but)
data->tooltiptimer = NULL;
}
- if (U.flag & USER_TOOLTIPS)
+ if ((U.flag & USER_TOOLTIPS) || (but->flag & UI_OPTION_TOOLTIPS))
if (!but->block->tooltipdisabled)
if (!wm->drags.first)
data->tooltiptimer = WM_event_add_timer(data->wm, data->window, TIMER, BUTTON_TOOLTIP_DELAY);
@@ -6664,7 +6809,7 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA
copy_v2_fl(data->ungrab_mval, FLT_MAX);
#endif
- if (ELEM3(but->type, BUT_CURVE, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, BUT_CURVE, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
/* XXX curve is temp */
}
else {
@@ -7023,6 +7168,11 @@ static int ui_handle_button_over(bContext *C, const wmEvent *event, ARegion *ar)
if (event->type == MOUSEMOVE) {
but = ui_but_find_mouse_over(ar, event);
if (but) {
+ if (event->alt)
+ /* display tooltips if holding alt on mouseover when tooltips are off in prefs */
+ but->flag |= UI_OPTION_TOOLTIPS;
+ else
+ but->flag &= ~UI_OPTION_TOOLTIPS;
button_activate_init(C, ar, but, BUTTON_ACTIVATE_OVER);
}
}
@@ -7054,6 +7204,17 @@ void ui_button_activate_do(bContext *C, ARegion *ar, uiBut *but)
ui_do_button(C, but->block, but, &event);
}
+/**
+ * Simulate moving the mouse over a button (or navigating to it with arrow keys).
+ *
+ * exported so menus can start with a highlighted button,
+ * even if the mouse isnt over it
+ */
+void ui_button_activate_over(bContext *C, ARegion *ar, uiBut *but)
+{
+ button_activate_init(C, ar, but, BUTTON_ACTIVATE_OVER);
+}
+
void ui_button_execute_begin(struct bContext *UNUSED(C), struct ARegion *ar, uiBut *but, void **active_back)
{
/* note: ideally we would not have to change 'but->active' however
@@ -7116,12 +7277,20 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
retval = WM_UI_HANDLER_CONTINUE;
break;
case MOUSEMOVE:
- /* verify if we are still over the button, if not exit */
- if (!ui_mouse_inside_button(ar, but, event->x, event->y)) {
- data->cancel = true;
- button_activate_state(C, but, BUTTON_STATE_EXIT);
+ {
+ uiBut *but_other = ui_but_find_mouse_over(ar, event);
+ bool exit = false;
+
+ if (!ui_block_is_menu(block) &&
+ !ui_mouse_inside_button(ar, but, event->x, event->y))
+ {
+ exit = true;
+ }
+ else if (but_other && ui_but_is_editable(but_other) && (but_other != but)) {
+ exit = true;
}
- else if (ui_but_find_mouse_over(ar, event) != but) {
+
+ if (exit) {
data->cancel = true;
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
@@ -7132,6 +7301,7 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
}
break;
+ }
case TIMER:
{
/* handle tooltip timer */
@@ -7715,6 +7885,22 @@ static int ui_handle_menu_button(bContext *C, const wmEvent *event, uiPopupBlock
int retval;
if (but) {
+ /* Its possible there is an active menu item NOT under the mouse,
+ * in this case ignore mouse clicks outside the button (but Enter etc is accepted) */
+ if (event->val == KM_RELEASE) {
+ /* pass, needed so we can exit active menu-items when click-dragging out of them */
+ }
+ else if (!ui_mouse_inside_region(but->active->region, event->x, event->y)) {
+ /* pass, needed to click-exit outside of non-flaoting menus */
+ }
+ else if ((event->type != MOUSEMOVE) && ISMOUSE(event->type)) {
+ if (!ui_mouse_inside_button(but->active->region, but, event->x, event->y)) {
+ but = NULL;
+ }
+ }
+ }
+
+ if (but) {
ScrArea *ctx_area = CTX_wm_area(C);
ARegion *ctx_region = CTX_wm_region(C);
@@ -7764,6 +7950,7 @@ static int ui_handle_menu_event(
if (menu->is_grab) {
if (event->type == LEFTMOUSE) {
menu->is_grab = false;
+ retval = WM_UI_HANDLER_BREAK;
}
else {
if (event->type == MOUSEMOVE) {
@@ -7968,7 +8155,7 @@ static int ui_handle_menu_event(
for (but = block->buttons.first; but; but = but->next) {
bool doit = false;
- if (!ELEM3(but->type, LABEL, SEPR, SEPRLINE))
+ if (!ELEM(but->type, LABEL, SEPR, SEPRLINE))
count++;
/* exception for rna layer buts */
@@ -8079,7 +8266,7 @@ static int ui_handle_menu_event(
if (inside == 0) {
uiSafetyRct *saferct = block->saferct.first;
- if (ELEM3(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE) &&
+ if (ELEM(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE) &&
ELEM(event->val, KM_PRESS, KM_DBL_CLICK))
{
if ((is_parent_menu == false) && (U.uiflag & USER_MENUOPENAUTO) == 0) {
@@ -8121,9 +8308,14 @@ static int ui_handle_menu_event(
else if ((event->type == LEFTMOUSE) && (event->val == KM_PRESS) &&
(inside && is_floating && inside_title))
{
- if (!ui_but_find_activated(ar)) {
+ if (!but || !ui_mouse_inside_button(ar, but, event->x, event->y)) {
+ if (but) {
+ button_timers_tooltip_remove(C, but);
+ }
+
menu->is_grab = true;
copy_v2_v2_int(menu->grab_xy_prev, &event->x);
+ retval = WM_UI_HANDLER_BREAK;
}
}
#endif
@@ -8458,15 +8650,15 @@ static int ui_handler_popup(bContext *C, const wmEvent *event, void *userdata)
/* free if done, does not free handle itself */
if (menu->menuretval) {
+ wmWindow *win = CTX_wm_window(C);
/* copy values, we have to free first (closes region) */
uiPopupBlockHandle temp = *menu;
ui_popup_block_free(C, menu);
- UI_remove_popup_handlers(&CTX_wm_window(C)->modalhandlers, menu);
+ UI_remove_popup_handlers(&win->modalhandlers, menu);
#ifdef USE_DRAG_TOGGLE
{
- wmWindow *win = CTX_wm_window(C);
WM_event_free_ui_handler_all(C, &win->modalhandlers,
ui_handler_region_drag_toggle, ui_handler_region_drag_toggle_remove);
}
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 546b2b85af5..51dd9166e46 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -508,6 +508,8 @@ static void init_brush_icons(void)
INIT_BRUSH_ICON(ICON_BRUSH_SOFTEN, soften);
INIT_BRUSH_ICON(ICON_BRUSH_SUBTRACT, subtract);
INIT_BRUSH_ICON(ICON_BRUSH_TEXDRAW, texdraw);
+ INIT_BRUSH_ICON(ICON_BRUSH_TEXFILL, texfill);
+ INIT_BRUSH_ICON(ICON_BRUSH_TEXMASK, texmask);
INIT_BRUSH_ICON(ICON_BRUSH_THUMB, thumb);
INIT_BRUSH_ICON(ICON_BRUSH_ROTATE, twist);
INIT_BRUSH_ICON(ICON_BRUSH_VERTEXDRAW, vertexdraw);
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index cd3b6390184..7d03aaea6b3 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -186,6 +186,7 @@ struct uiBut {
* (type == LABEL), Use (a1 == 1.0f) to use a2 as a blending factor (wow, this is imaginative!).
* (type == SCROLL) Use as scroll size.
* (type == SEARCH_MENU) Use as number or rows.
+ * (type == COLOR) Use as indication of color palette
*/
float a1;
@@ -193,6 +194,7 @@ struct uiBut {
* (type == NUM), Use to store RNA 'precision' value, for dragging and click-step.
* (type == LABEL), If (a1 == 1.0f) use a2 as a blending factor.
* (type == SEARCH_MENU) Use as number or columns.
+ * (type == COLOR) Use as indication of active palette color
*/
float a2;
@@ -550,12 +552,16 @@ void ui_draw_but_NODESOCKET(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol
PointerRNA *ui_handle_afterfunc_add_operator(struct wmOperatorType *ot, int opcontext, bool create_props);
extern void ui_pan_to_scroll(const struct wmEvent *event, int *type, int *val);
extern void ui_button_activate_do(struct bContext *C, struct ARegion *ar, uiBut *but);
+extern void ui_button_activate_over(struct bContext *C, struct ARegion *ar, uiBut *but);
extern void ui_button_execute_begin(struct bContext *C, struct ARegion *ar, uiBut *but, void **active_back);
extern void ui_button_execute_end(struct bContext *C, struct ARegion *ar, uiBut *but, void *active_back);
extern void ui_button_active_free(const struct bContext *C, uiBut *but);
extern bool ui_button_is_active(struct ARegion *ar) ATTR_WARN_UNUSED_RESULT;
extern int ui_button_open_menu_direction(uiBut *but);
extern void ui_button_text_password_hide(char password_str[UI_MAX_DRAW_STR], uiBut *but, const bool restore);
+extern uiBut *ui_but_find_activated(struct ARegion *ar);
+bool ui_but_is_editable(const uiBut *but);
+
void ui_button_clipboard_free(void);
void ui_panel_menu(struct bContext *C, ARegion *ar, Panel *pa);
uiBut *ui_but_find_old(uiBlock *block_old, const uiBut *but_new);
@@ -589,7 +595,6 @@ int ui_id_icon_get(struct bContext *C, struct ID *id, const bool big);
/* resources.c */
void init_userdef_do_versions(void);
-void init_userdef_factory(void);
void ui_theme_init_default(void);
void ui_style_init_default(void);
void ui_resources_init(void);
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index 789c10d6693..645eb607031 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -1181,7 +1181,7 @@ void uiItemFullR(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index
if (flag & UI_ITEM_R_ICON_ONLY) {
/* pass */
}
- else if (ELEM4(type, PROP_INT, PROP_FLOAT, PROP_STRING, PROP_POINTER)) {
+ else if (ELEM(type, PROP_INT, PROP_FLOAT, PROP_STRING, PROP_POINTER)) {
name = ui_item_name_add_colon(name, namestr);
}
else if (type == PROP_BOOLEAN && is_array && index == RNA_NO_INDEX) {
@@ -1323,9 +1323,9 @@ void uiItemEnumR_string(uiLayout *layout, struct PointerRNA *ptr, const char *pr
for (a = 0; item[a].identifier; a++) {
if (item[a].value == ivalue) {
- const char *item_name = CTX_IFACE_(RNA_property_translation_context(prop), item[a].name);
+ const char *item_name = name ? name : CTX_IFACE_(RNA_property_translation_context(prop), item[a].name);
- uiItemFullR(layout, ptr, prop, RNA_ENUM_VALUE, ivalue, 0, item_name ? item_name : name, icon ? icon : item[a].icon);
+ uiItemFullR(layout, ptr, prop, RNA_ENUM_VALUE, ivalue, 0, item_name, icon ? icon : item[a].icon);
break;
}
}
@@ -1559,7 +1559,7 @@ void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propna
}
type = RNA_property_type(prop);
- if (!ELEM3(type, PROP_POINTER, PROP_STRING, PROP_ENUM)) {
+ if (!ELEM(type, PROP_POINTER, PROP_STRING, PROP_ENUM)) {
RNA_warning("Property %s must be a pointer, string or enum", propname);
return;
}
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 877a993e0ac..458aca444cb 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -35,6 +35,7 @@
#include "DNA_text_types.h" /* for UI_OT_reports_to_text */
#include "BLI_blenlib.h"
+#include "BLI_math_color.h"
#include "BLF_api.h"
#include "BLF_translation.h"
@@ -44,6 +45,7 @@
#include "BKE_global.h"
#include "BKE_text.h" /* for UI_OT_reports_to_text */
#include "BKE_report.h"
+#include "BKE_paint.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -55,6 +57,8 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "ED_paint.h"
+
/* only for UI_OT_editsource */
#include "ED_screen.h"
#include "BKE_main.h"
@@ -258,28 +262,43 @@ static void UI_OT_unset_property_button(wmOperatorType *ot)
/* Copy To Selected Operator ------------------------ */
-static bool copy_to_selected_list(bContext *C, PointerRNA *ptr, ListBase *lb, bool *use_path)
+static bool copy_to_selected_list(
+ bContext *C, PointerRNA *ptr, PropertyRNA *prop,
+ ListBase *r_lb, bool *r_use_path_from_id, char **r_path)
{
- *use_path = false;
+ *r_use_path_from_id = false;
+ *r_path = NULL;
- if (RNA_struct_is_a(ptr->type, &RNA_EditBone))
- *lb = CTX_data_collection_get(C, "selected_editable_bones");
- else if (RNA_struct_is_a(ptr->type, &RNA_PoseBone))
- *lb = CTX_data_collection_get(C, "selected_pose_bones");
- else if (RNA_struct_is_a(ptr->type, &RNA_Sequence))
- *lb = CTX_data_collection_get(C, "selected_editable_sequences");
- else {
+ if (RNA_struct_is_a(ptr->type, &RNA_EditBone)) {
+ *r_lb = CTX_data_collection_get(C, "selected_editable_bones");
+ }
+ else if (RNA_struct_is_a(ptr->type, &RNA_PoseBone)) {
+ *r_lb = CTX_data_collection_get(C, "selected_pose_bones");
+ }
+ else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) {
+ *r_lb = CTX_data_collection_get(C, "selected_editable_sequences");
+ }
+ else if (ptr->id.data) {
ID *id = ptr->id.data;
- if (id && GS(id->name) == ID_OB) {
- *lb = CTX_data_collection_get(C, "selected_editable_objects");
- *use_path = true;
+ if (GS(id->name) == ID_OB) {
+ *r_lb = CTX_data_collection_get(C, "selected_editable_objects");
+ *r_use_path_from_id = true;
+ *r_path = RNA_path_from_ID_to_property(ptr, prop);
}
- else {
- return false;
+ else if (GS(id->name) == ID_SCE) {
+ /* Sequencer's ID is scene :/ */
+ /* Try to recursively find an RNA_Sequence ancestor, to handle situations like T41062... */
+ if ((*r_path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Sequence)) != NULL) {
+ *r_lb = CTX_data_collection_get(C, "selected_editable_sequences");
+ }
}
+ return (*r_path != NULL);
}
-
+ else {
+ return false;
+ }
+
return true;
}
@@ -303,47 +322,54 @@ static bool copy_to_selected_button(bContext *C, bool all, bool poll)
/* if there is a valid property that is editable... */
if (ptr.data && prop) {
char *path = NULL;
- bool use_path;
+ bool use_path_from_id;
CollectionPointerLink *link;
ListBase lb;
- if (!copy_to_selected_list(C, &ptr, &lb, &use_path))
+ if (!copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path))
return success;
- if (!use_path || (path = RNA_path_from_ID_to_property(&ptr, prop))) {
- for (link = lb.first; link; link = link->next) {
- if (link->ptr.data != ptr.data) {
- if (use_path) {
- lprop = NULL;
- RNA_id_pointer_create(link->ptr.id.data, &idptr);
- RNA_path_resolve_property(&idptr, path, &lptr, &lprop);
- }
- else {
- lptr = link->ptr;
- lprop = prop;
- }
+ for (link = lb.first; link; link = link->next) {
+ if (link->ptr.data != ptr.data) {
+ if (use_path_from_id) {
+ /* Path relative to ID. */
+ lprop = NULL;
+ RNA_id_pointer_create(link->ptr.id.data, &idptr);
+ RNA_path_resolve_property(&idptr, path, &lptr, &lprop);
+ }
+ else if (path) {
+ /* Path relative to elements from list. */
+ lprop = NULL;
+ RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop);
+ }
+ else {
+ lptr = link->ptr;
+ lprop = prop;
+ }
+
+ if (lptr.data == ptr.data) {
+ /* lptr might not be the same as link->ptr! */
+ continue;
+ }
- if (lprop == prop) {
- if (RNA_property_editable(&lptr, lprop)) {
- if (poll) {
+ if (lprop == prop) {
+ if (RNA_property_editable(&lptr, lprop)) {
+ if (poll) {
+ success = true;
+ break;
+ }
+ else {
+ if (RNA_property_copy(&lptr, &ptr, prop, (all) ? -1 : index)) {
+ RNA_property_update(C, &lptr, prop);
success = true;
- break;
- }
- else {
- if (RNA_property_copy(&lptr, &ptr, prop, (all) ? -1 : index)) {
- RNA_property_update(C, &lptr, prop);
- success = true;
- }
}
}
}
}
}
-
- if (path)
- MEM_freeN(path);
}
+ MEM_SAFE_FREE(path);
BLI_freelistN(&lb);
}
@@ -810,6 +836,91 @@ static void UI_OT_reloadtranslation(wmOperatorType *ot)
ot->exec = reloadtranslation_exec;
}
+int UI_drop_color_poll(struct bContext *C, wmDrag *drag, const wmEvent *UNUSED(event))
+{
+ /* should only return true for regions that include buttons, for now
+ * return true always */
+ if (drag->type == WM_DRAG_COLOR) {
+ SpaceImage *sima = CTX_wm_space_image(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ if (UI_but_active_drop_color(C))
+ return 1;
+
+ if (sima && (sima->mode == SI_MODE_PAINT) &&
+ sima->image && (ar && ar->regiontype == RGN_TYPE_WINDOW))
+ {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+void UI_drop_color_copy(wmDrag *drag, wmDropBox *drop)
+{
+ uiDragColorHandle *drag_info = (uiDragColorHandle *)drag->poin;
+
+ RNA_float_set_array(drop->ptr, "color", drag_info->color);
+ RNA_boolean_set(drop->ptr, "gamma", drag_info->gamma_corrected);
+}
+
+static int drop_color_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ ARegion *ar = CTX_wm_region(C);
+ uiBut *but = NULL;
+ float color[3];
+ bool gamma;
+
+ RNA_float_get_array(op->ptr, "color", color);
+ gamma = RNA_boolean_get(op->ptr, "gamma");
+
+ /* find button under mouse, check if it has RNA color property and
+ * if it does copy the data */
+ but = ui_but_find_activated(ar);
+
+ if (but && but->type == COLOR && but->rnaprop) {
+ if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
+ if (!gamma)
+ ui_block_to_display_space_v3(but->block, color);
+ RNA_property_float_set_array(&but->rnapoin, but->rnaprop, color);
+ RNA_property_update(C, &but->rnapoin, but->rnaprop);
+ }
+ else if (RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
+ if (gamma)
+ ui_block_to_scene_linear_v3(but->block, color);
+ RNA_property_float_set_array(&but->rnapoin, but->rnaprop, color);
+ RNA_property_update(C, &but->rnapoin, but->rnaprop);
+ }
+ }
+ else {
+ if (gamma) {
+ srgb_to_linearrgb_v3_v3(color, color);
+ }
+
+ ED_imapaint_bucket_fill(C, color, op);
+ }
+
+ ED_region_tag_redraw(ar);
+
+ return OPERATOR_FINISHED;
+}
+
+
+static void UI_OT_drop_color(wmOperatorType *ot)
+{
+ ot->name = "Drop Color";
+ ot->idname = "UI_OT_drop_color";
+ ot->description = "Drop colors to buttons";
+
+ ot->invoke = drop_color_invoke;
+
+ RNA_def_float_color(ot->srna, "color", 3, NULL, 0.0, FLT_MAX, "Color", "Source color", 0.0, 1.0);
+ RNA_def_boolean(ot->srna, "gamma", 0, "Gamma Corrected", "The source color is gamma corrected ");
+}
+
+
+
/* ********************************************************* */
/* Registration */
@@ -821,7 +932,7 @@ void UI_buttons_operatortypes(void)
WM_operatortype_append(UI_OT_unset_property_button);
WM_operatortype_append(UI_OT_copy_to_selected_button);
WM_operatortype_append(UI_OT_reports_to_textblock); /* XXX: temp? */
-
+ WM_operatortype_append(UI_OT_drop_color);
#ifdef WITH_PYTHON
WM_operatortype_append(UI_OT_editsource);
WM_operatortype_append(UI_OT_edittranslation_init);
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index 2ccb3740777..d0909e9413c 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -120,7 +120,7 @@ static int panel_aligned(ScrArea *sa, ARegion *ar)
return BUT_VERTICAL;
else if (sa->spacetype == SPACE_IMAGE && ar->regiontype == RGN_TYPE_PREVIEW)
return BUT_VERTICAL;
- else if (ELEM3(ar->regiontype, RGN_TYPE_UI, RGN_TYPE_TOOLS, RGN_TYPE_TOOL_PROPS))
+ else if (ELEM(ar->regiontype, RGN_TYPE_UI, RGN_TYPE_TOOLS, RGN_TYPE_TOOL_PROPS))
return BUT_VERTICAL;
return 0;
@@ -462,31 +462,41 @@ static void ui_draw_panel_scalewidget(const rcti *rect)
fdrawline(xmin + dx, ymin + 1, xmax, ymax - dy + 1);
glDisable(GL_BLEND);
}
-
static void ui_draw_panel_dragwidget(const rctf *rect)
{
- float xmin, xmax, dx;
- float ymin, ymax, dy;
-
- xmin = rect->xmin;
- xmax = rect->xmax;
- ymin = rect->ymin;
- ymax = rect->ymax;
-
- dx = (xmax - xmin) / 3.0f;
- dy = (ymax - ymin) / 3.0f;
-
- glEnable(GL_BLEND);
- glColor4ub(255, 255, 255, 50);
- fdrawline(xmin, ymax, xmax, ymin);
- fdrawline(xmin + dx, ymax, xmax, ymin + dy);
- fdrawline(xmin + 2 * dx, ymax, xmax, ymin + 2 * dy);
-
- glColor4ub(0, 0, 0, 50);
- fdrawline(xmin, ymax + 1, xmax, ymin + 1);
- fdrawline(xmin + dx, ymax + 1, xmax, ymin + dy + 1);
- fdrawline(xmin + 2 * dx, ymax + 1, xmax, ymin + 2 * dy + 1);
- glDisable(GL_BLEND);
+ unsigned char col_back[3], col_high[3], col_dark[3];
+ const int col_tint = 84;
+
+ const int px = (int)U.pixelsize;
+ const int px_zoom = max_ii(iroundf(BLI_rctf_size_y(rect) / 22.0f), 1);
+
+ const int box_margin = max_ii(iroundf((float)(px_zoom * 2.0f)), px);
+ const int box_size = max_ii(iroundf((BLI_rctf_size_y(rect) / 8.0f) - px), px);
+
+ const int x_min = rect->xmin;
+ const int y_min = rect->ymin;
+ const int y_ofs = max_ii(iroundf(BLI_rctf_size_y(rect) / 3.0f), px);
+ const int x_ofs = y_ofs;
+ int i_x, i_y;
+
+
+ UI_GetThemeColor3ubv(UI_GetThemeValue(TH_PANEL_SHOW_HEADER) ? TH_PANEL_HEADER : TH_PANEL_BACK, col_back);
+ UI_GetColorPtrShade3ubv(col_back, col_high, col_tint);
+ UI_GetColorPtrShade3ubv(col_back, col_dark, -col_tint);
+
+
+ /* draw multiple boxes */
+ for (i_x = 0; i_x < 4; i_x++) {
+ for (i_y = 0; i_y < 2; i_y++) {
+ const int x_co = (x_min + x_ofs) + (i_x * (box_size + box_margin));
+ const int y_co = (y_min + y_ofs) + (i_y * (box_size + box_margin));
+
+ glColor3ubv(col_dark);
+ glRectf(x_co - box_size, y_co - px_zoom, x_co, (y_co + box_size) - px_zoom);
+ glColor3ubv(col_high);
+ glRectf(x_co - box_size, y_co, x_co, y_co + box_size);
+ }
+ }
}
@@ -1131,7 +1141,7 @@ static void ui_handle_panel_header(const bContext *C, uiBlock *block, int mx, in
button = 1;
else if (event == AKEY)
button = 1;
- else if (ELEM3(event, 0, RETKEY, LEFTMOUSE) && shift) {
+ else if (ELEM(event, 0, RETKEY, LEFTMOUSE) && shift) {
block->panel->flag ^= PNL_PIN;
button = 2;
}
@@ -1716,7 +1726,7 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar)
/* XXX hardcoded key warning */
if ((inside || inside_header) && event->val == KM_PRESS) {
- if (event->type == AKEY && !ELEM4(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift, event->alt)) {
+ if (event->type == AKEY && !ELEM(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift, event->alt)) {
if (pa->flag & PNL_CLOSEDY) {
if ((block->rect.ymax <= my) && (block->rect.ymax + PNL_HEADER >= my))
diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c
index c32f0de937e..3629c72ce49 100644
--- a/source/blender/editors/interface/interface_regions.c
+++ b/source/blender/editors/interface/interface_regions.c
@@ -392,7 +392,7 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
data->totline++;
}
- if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
/* better not show the value of a password */
if ((but->rnaprop && (RNA_property_subtype(but->rnaprop) == PROP_PASSWORD)) == 0) {
/* full string */
@@ -1872,7 +1872,7 @@ static void ui_update_block_buts_rgb(uiBlock *block, const float rgb[3], bool is
if (rgb_gamma[2] > 1.0f) rgb_gamma[2] = modf(rgb_gamma[2], &intpart);
rgb_float_to_uchar(rgb_gamma_uchar, rgb_gamma);
- BLI_snprintf(col, sizeof(col), "%02X%02X%02X", UNPACK3OP((unsigned int), rgb_gamma_uchar));
+ BLI_snprintf(col, sizeof(col), "%02X%02X%02X", UNPACK3_EX((unsigned int), rgb_gamma_uchar, ));
strcpy(bt->poin, col);
}
@@ -2160,7 +2160,7 @@ static void uiBlockPicker(uiBlock *block, float rgba[4], PointerRNA *ptr, Proper
}
rgb_float_to_uchar(rgb_gamma_uchar, rgb_gamma);
- BLI_snprintf(hexcol, sizeof(hexcol), "%02X%02X%02X", UNPACK3OP((unsigned int), rgb_gamma_uchar));
+ BLI_snprintf(hexcol, sizeof(hexcol), "%02X%02X%02X", UNPACK3_EX((unsigned int), rgb_gamma_uchar, ));
yco = -3.0f * UI_UNIT_Y;
bt = uiDefBut(block, TEX, 0, IFACE_("Hex: "), 0, yco, butwidth, UI_UNIT_Y, hexcol, 0, 8, 0, 0, TIP_("Hex triplet for color (#RRGGBB)"));
@@ -2408,6 +2408,7 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
uiBlockSetFlag(block, UI_BLOCK_MOVEMOUSE_QUIT);
if (pup->popup) {
+ uiBut *but_activate = NULL;
uiBlockSetFlag(block, UI_BLOCK_LOOP | UI_BLOCK_REDRAW | UI_BLOCK_NUMSELECT);
uiBlockSetDirection(block, direction);
@@ -2421,6 +2422,10 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
* block to be under the mouse */
offset[0] = -(bt->rect.xmin + 0.8f * BLI_rctf_size_x(&bt->rect));
offset[1] = -(bt->rect.ymin + 0.5f * UI_UNIT_Y);
+
+ if (ui_but_is_editable(bt)) {
+ but_activate = bt;
+ }
}
else {
/* position mouse at 0.8*width of the button and below the tile
@@ -2430,6 +2435,20 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
offset[0] = min_ii(offset[0], -(bt->rect.xmin + 0.8f * BLI_rctf_size_x(&bt->rect)));
offset[1] = 2.1 * UI_UNIT_Y;
+
+ for (bt = block->buttons.first; bt; bt = bt->next) {
+ if (ui_but_is_editable(bt)) {
+ but_activate = bt;
+ break;
+ }
+ }
+ }
+
+ /* in rare cases this is needed since moving the popup
+ * to be within the window bounds may move it away from the mouse,
+ * This ensures we set an item to be active. */
+ if (but_activate) {
+ ui_button_activate_over(C, handle->region, but_activate);
}
block->minbounds = minwidth;
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 1c5d3ecfd2e..cb5f5331c2e 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -36,6 +36,7 @@
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "DNA_object_force.h"
+#include "DNA_brush_types.h"
#include "BLI_utildefines.h"
#include "BLI_string.h"
@@ -60,6 +61,7 @@
#include "BKE_object.h"
#include "BKE_packedFile.h"
#include "BKE_particle.h"
+#include "BKE_paint.h"
#include "BKE_report.h"
#include "BKE_sca.h"
#include "BKE_screen.h"
@@ -349,6 +351,8 @@ static const char *template_id_browse_tip(StructRNA *type)
case ID_BR: return N_("Browse Brush to be linked");
case ID_PA: return N_("Browse Particle Settings to be linked");
case ID_GD: return N_("Browse Grease Pencil Data to be linked");
+ case ID_PAL: return N_("Browse Palette Data to be linked");
+ case ID_PC: return N_("Browse Paint Curve Data to be linked");
}
}
return N_("Browse ID data to be linked");
@@ -489,7 +493,7 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str
if (user_alert) uiButSetFlag(but, UI_BUT_REDALERT);
- if (id->lib == NULL && !(ELEM5(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB))) {
+ if (id->lib == NULL && !(ELEM(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB))) {
uiDefButR(block, TOG, 0, "F", 0, 0, UI_UNIT_X, UI_UNIT_Y, &idptr, "use_fake_user", -1, 0, 0, -1, -1, NULL);
}
}
@@ -808,7 +812,7 @@ static int modifier_can_delete(ModifierData *md)
static int modifier_is_simulation(ModifierData *md)
{
/* Physic Tab */
- if (ELEM7(md->type, eModifierType_Cloth, eModifierType_Collision, eModifierType_Fluidsim, eModifierType_Smoke,
+ if (ELEM(md->type, eModifierType_Cloth, eModifierType_Collision, eModifierType_Fluidsim, eModifierType_Smoke,
eModifierType_Softbody, eModifierType_Surface, eModifierType_DynamicPaint))
{
return 1;
@@ -906,9 +910,9 @@ static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob,
uiBlockSetEmboss(block, UI_EMBOSS);
}
} /* tessellation point for curve-typed objects */
- else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
+ else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
/* some modifiers could work with pre-tessellated curves only */
- if (ELEM3(md->type, eModifierType_Hook, eModifierType_Softbody, eModifierType_MeshDeform)) {
+ if (ELEM(md->type, eModifierType_Hook, eModifierType_Softbody, eModifierType_MeshDeform)) {
/* add disabled pre-tessellated button, so users could have
* message for this modifiers */
but = uiDefIconButBitI(block, TOG, eModifierMode_ApplyOnSpline, 0, ICON_SURFACE_DATA, 0, 0,
@@ -979,7 +983,7 @@ static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob,
uiBlockClearButLock(block);
uiBlockSetButLock(block, ob && ob->id.lib, ERROR_LIBDATA_MESSAGE);
- if (!ELEM5(md->type, eModifierType_Fluidsim, eModifierType_Softbody, eModifierType_ParticleSystem,
+ if (!ELEM(md->type, eModifierType_Fluidsim, eModifierType_Softbody, eModifierType_ParticleSystem,
eModifierType_Cloth, eModifierType_Smoke))
{
uiItemO(row, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Copy"), ICON_NONE,
@@ -1298,7 +1302,7 @@ void uiTemplatePreview(uiLayout *layout, bContext *C, ID *id, int show_buttons,
char _preview_id[UI_MAX_NAME_STR];
- if (id && !ELEM5(GS(id->name), ID_MA, ID_TE, ID_WO, ID_LA, ID_LS)) {
+ if (id && !ELEM(GS(id->name), ID_MA, ID_TE, ID_WO, ID_LA, ID_LS)) {
RNA_warning("Expected ID of type material, texture, lamp, world or line style");
return;
}
@@ -2363,6 +2367,61 @@ void uiTemplateColorPicker(uiLayout *layout, PointerRNA *ptr, const char *propna
}
}
+void uiTemplatePalette(uiLayout *layout, PointerRNA *ptr, const char *propname, int UNUSED(colors))
+{
+ PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
+ PointerRNA cptr;
+ Palette *palette;
+ PaletteColor *color;
+ uiBlock *block;
+ uiLayout *col;
+ int row_cols = 0, col_id = 0;
+ int cols_per_row = MAX2(uiLayoutGetWidth(layout) / UI_UNIT_X, 1);
+
+ if (!prop) {
+ RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
+ return;
+ }
+
+ cptr = RNA_property_pointer_get(ptr, prop);
+ if (!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Palette))
+ return;
+
+ block = uiLayoutGetBlock(layout);
+
+ palette = cptr.data;
+
+ /* first delete any pending colors */
+ BKE_palette_cleanup(palette);
+
+ color = palette->colors.first;
+
+ col = uiLayoutColumn(layout, true);
+ uiLayoutRow(col, true);
+ uiDefIconButO(block, BUT, "PALETTE_OT_color_add", WM_OP_INVOKE_DEFAULT, ICON_ZOOMIN, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
+ uiDefIconButO(block, BUT, "PALETTE_OT_color_delete", WM_OP_INVOKE_DEFAULT, ICON_ZOOMOUT, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
+
+ col = uiLayoutColumn(layout, true);
+ uiLayoutRow(col, true);
+
+ for (; color; color = color->next) {
+ PointerRNA ptr;
+
+ if (row_cols >= cols_per_row) {
+ uiLayoutRow(col, true);
+ row_cols = 0;
+ }
+
+ RNA_pointer_create(&palette->id, &RNA_PaletteColor, color, &ptr);
+ uiDefButR(block, COLOR, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, &ptr, "color", -1, 0.0, 1.0,
+ UI_PALETTE_COLOR, (col_id == palette->active_color) ? UI_PALETTE_COLOR_ACTIVE : 0.0, "");
+
+ row_cols++;
+ col_id++;
+ }
+}
+
+
/********************* Layer Buttons Template ************************/
static void handle_layer_buttons(bContext *C, void *arg1, void *arg2)
@@ -3543,7 +3602,7 @@ void uiTemplateColormanagedViewSettings(uiLayout *layout, bContext *UNUSED(C), P
col = uiLayoutColumn(layout, false);
row = uiLayoutRow(col, false);
- uiItemR(row, &view_transform_ptr, "view_transform", UI_ITEM_R_EXPAND, IFACE_("View"), ICON_NONE);
+ uiItemR(row, &view_transform_ptr, "view_transform", 0, IFACE_("View"), ICON_NONE);
col = uiLayoutColumn(layout, false);
uiItemR(col, &view_transform_ptr, "exposure", 0, NULL, ICON_NONE);
diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c
index 744ed7e5b72..008ea84b607 100644
--- a/source/blender/editors/interface/interface_utils.c
+++ b/source/blender/editors/interface/interface_utils.c
@@ -151,7 +151,7 @@ int uiDefAutoButsRNA(uiLayout *layout, PointerRNA *ptr,
const char *name;
int tot = 0;
- assert(ELEM3(label_align, '\0', 'H', 'V'));
+ assert(ELEM(label_align, '\0', 'H', 'V'));
RNA_STRUCT_BEGIN (ptr, prop)
{
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 6ea0a55729d..23f185befb9 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -33,6 +33,7 @@
#include <string.h>
#include <assert.h>
+#include "DNA_brush_types.h"
#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
@@ -848,7 +849,7 @@ static void widget_draw_icon(const uiBut *but, BIFIconID icon, float alpha, cons
height = ICON_DEFAULT_HEIGHT / aspect;
/* calculate blend color */
- if (ELEM4(but->type, TOG, ROW, TOGN, LISTROW)) {
+ if (ELEM(but->type, TOG, ROW, TOGN, LISTROW)) {
if (but->flag & UI_SELECT) {}
else if (but->flag & UI_ACTIVE) {}
else alpha = 0.5f;
@@ -2825,6 +2826,17 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat
widgetbase_draw(&wtb, wcol);
+ if (but->a1 == UI_PALETTE_COLOR && but->a2 == UI_PALETTE_COLOR_ACTIVE) {
+ float width = rect->xmax - rect->xmin;
+ float height = rect->ymax - rect->ymin;
+
+ glColor4ubv((unsigned char *)wcol->outline);
+ glBegin(GL_TRIANGLES);
+ glVertex2f(rect->xmin + 0.1f * width, rect->ymin + 0.9f * height);
+ glVertex2f(rect->xmin + 0.1f * width, rect->ymin + 0.5f * height);
+ glVertex2f(rect->xmin + 0.5f * width, rect->ymin + 0.9f * height);
+ glEnd();
+ }
}
static void widget_normal(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index 372ced0a6fd..dbb0235f40f 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -36,11 +36,10 @@
#include "MEM_guardedalloc.h"
#include "DNA_curve_types.h"
-#include "DNA_userdef_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
#include "DNA_windowmanager_types.h"
-#include "DNA_mesh_types.h" /* init_userdef_factory */
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
@@ -51,7 +50,6 @@
#include "BKE_main.h"
#include "BKE_texture.h"
-
#include "BIF_gl.h"
#include "UI_interface.h"
@@ -537,6 +535,13 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
cp = ts->preview_stitch_active;
break;
+ case TH_PAINT_CURVE_HANDLE:
+ cp = ts->paint_curve_handle;
+ break;
+ case TH_PAINT_CURVE_PIVOT:
+ cp = ts->paint_curve_pivot;
+ break;
+
case TH_UV_OTHERS:
cp = ts->uv_others;
break;
@@ -774,6 +779,8 @@ static void ui_theme_space_init_handles_color(ThemeSpace *theme_space)
rgba_char_args_set(theme_space->handle_sel_auto, 0xf0, 0xff, 0x40, 255);
rgba_char_args_set(theme_space->handle_sel_vect, 0x40, 0xc0, 0x30, 255);
rgba_char_args_set(theme_space->handle_sel_align, 0xf0, 0x90, 0xa0, 255);
+ rgba_char_args_set(theme_space->handle_vertex, 0x00, 0x00, 0x00, 0xff);
+ rgba_char_args_set(theme_space->handle_vertex_select, 0xff, 0xff, 0, 0xff);
rgba_char_args_set(theme_space->act_spline, 0xdb, 0x25, 0x12, 255);
}
@@ -871,6 +878,8 @@ void ui_theme_init_default(void)
rgba_char_args_set(btheme->tv3d.title, 0, 0, 0, 255);
rgba_char_args_set(btheme->tv3d.freestyle_edge_mark, 0x7f, 0xff, 0x7f, 255);
rgba_char_args_set(btheme->tv3d.freestyle_face_mark, 0x7f, 0xff, 0x7f, 51);
+ rgba_char_args_set_fl(btheme->tv3d.paint_curve_handle, 0.5f, 1.0f, 0.5f, 0.5f);
+ rgba_char_args_set_fl(btheme->tv3d.paint_curve_pivot, 1.0f, 0.5f, 0.5f, 0.5f);
btheme->tv3d.facedot_size = 4;
@@ -1129,8 +1138,6 @@ void ui_theme_init_default(void)
rgba_char_args_set(btheme->tclip.path_after, 0x00, 0x00, 0xff, 255);
rgba_char_args_set(btheme->tclip.grid, 0x5e, 0x5e, 0x5e, 255);
rgba_char_args_set(btheme->tclip.cframe, 0x60, 0xc0, 0x40, 255);
- rgba_char_args_set(btheme->tclip.handle_vertex, 0x00, 0x00, 0x00, 0xff);
- rgba_char_args_set(btheme->tclip.handle_vertex_select, 0xff, 0xff, 0, 0xff);
rgba_char_args_set(btheme->tclip.list, 0x66, 0x66, 0x66, 0xff);
rgba_char_args_set(btheme->tclip.strip, 0x0c, 0x0a, 0x0a, 0x80);
rgba_char_args_set(btheme->tclip.strip_select, 0xff, 0x8c, 0x00, 0xff);
@@ -2427,6 +2434,16 @@ void init_userdef_do_versions(void)
}
}
+ if (U.versionfile < 272 || (U.versionfile == 272 && U.subversionfile < 2)) {
+ bTheme *btheme;
+ for (btheme = U.themes.first; btheme; btheme = btheme->next) {
+ rgba_char_args_set_fl(btheme->tv3d.paint_curve_handle, 0.5f, 1.0f, 0.5f, 0.5f);
+ rgba_char_args_set_fl(btheme->tv3d.paint_curve_pivot, 1.0f, 0.5f, 0.5f, 0.5f);
+ rgba_char_args_set_fl(btheme->tima.paint_curve_handle, 0.5f, 1.0f, 0.5f, 0.5f);
+ rgba_char_args_set_fl(btheme->tima.paint_curve_pivot, 1.0f, 0.5f, 0.5f, 0.5f);
+ }
+ }
+
{
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
@@ -2449,25 +2466,3 @@ void init_userdef_do_versions(void)
// XXX reset_autosave();
}
-
-/**
- * Override values in in-memory startup.blend, avoids resaving for small changes.
- */
-void init_userdef_factory(void)
-{
- /* defaults from T37518 */
-
- U.uiflag |= USER_ZBUF_CURSOR;
- U.uiflag |= USER_QUIT_PROMPT;
- U.uiflag |= USER_CONTINUOUS_MOUSE;
-
- U.versions = 1;
- U.savetime = 2;
-
- {
- Mesh *me;
- for (me = G.main->mesh.first; me; me = me->id.next) {
- me->flag &= ~ME_TWOSIDED;
- }
- }
-}
diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c
index 4d2ea0e64f4..a4130540b1b 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -250,7 +250,7 @@ static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr)
row = uiLayoutRow(box, false);
split = uiLayoutSplit(row, 0.6f, UI_LAYOUT_ALIGN_RIGHT);
- uiItemL(split, IFACE_("Transformation Type"), ICON_NONE);
+ uiItemL(split, IFACE_("Transformation Type"), ICON_NONE);
uiItemR(split, imfptr, "export_transformation_type_selection", 0, "", ICON_NONE);
row = uiLayoutRow(box, false);
diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c
index cc26d6079a9..553c1faa36a 100644
--- a/source/blender/editors/mesh/editmesh_knife_project.c
+++ b/source/blender/editors/mesh/editmesh_knife_project.c
@@ -65,7 +65,7 @@ static LinkNode *knifeproject_poly_from_object(ARegion *ar, Scene *scene, Object
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)) {
+ else if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {
dm = CDDM_from_curve(ob);
dm_needsFree = true;
}
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index 23828098940..9cdfb43ae15 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -2807,6 +2807,13 @@ static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op)
BMEdge *e;
BMIter iter;
+ const bool use_wire = RNA_boolean_get(op->ptr, "use_wire");
+ const bool use_boundary = RNA_boolean_get(op->ptr, "use_boundary");
+ const bool use_multi_face = RNA_boolean_get(op->ptr, "use_multi_face");
+ const bool use_non_contiguous = RNA_boolean_get(op->ptr, "use_non_contiguous");
+ const bool use_verts = RNA_boolean_get(op->ptr, "use_verts");
+
+
if (!RNA_boolean_get(op->ptr, "extend"))
EDBM_flag_disable_all(em, BM_ELEM_SELECT);
@@ -2819,15 +2826,30 @@ static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
- if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN) && !BM_vert_is_manifold(v)) {
- BM_vert_select_set(em->bm, v, true);
+ if (use_verts) {
+ BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
+ if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
+ if (!BM_vert_is_manifold(v)) {
+ BM_vert_select_set(em->bm, v, true);
+ }
+ }
}
}
- BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN) && !BM_edge_is_manifold(e)) {
- BM_edge_select_set(em->bm, e, true);
+ if (use_wire || use_boundary || use_multi_face || use_non_contiguous) {
+ BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
+ if ((use_wire && BM_edge_is_wire(e)) ||
+ (use_boundary && BM_edge_is_boundary(e)) ||
+ (use_non_contiguous && (BM_edge_is_manifold(e) && !BM_edge_is_contiguous(e))) ||
+ (use_multi_face && (BM_edge_face_count(e) > 2)))
+ {
+ /* check we never select perfect edge (in test above) */
+ BLI_assert(!(BM_edge_is_manifold(e) && BM_edge_is_contiguous(e)));
+
+ BM_edge_select_set(em->bm, e, true);
+ }
+ }
}
}
@@ -2854,6 +2876,18 @@ void MESH_OT_select_non_manifold(wmOperatorType *ot)
/* props */
RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend the selection");
+ /* edges */
+ RNA_def_boolean(ot->srna, "use_wire", true, "Wire",
+ "Wire edges");
+ RNA_def_boolean(ot->srna, "use_boundary", true, "Boundaries",
+ "Boundary edges");
+ RNA_def_boolean(ot->srna, "use_multi_face", true,
+ "Multiple Faces", "Edges shared by 3+ faces");
+ RNA_def_boolean(ot->srna, "use_non_contiguous", true, "Non Contiguous",
+ "Edges between faces pointing in alternate directions");
+ /* verts */
+ RNA_def_boolean(ot->srna, "use_verts", true, "Vertices",
+ "Vertices connecting multiple face regions");
}
static int edbm_select_random_exec(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 27145cc7649..ddf7650deaf 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -3052,7 +3052,7 @@ static int edbm_knife_cut_exec(bContext *C, wmOperator *op)
float (*screen_vert_coords)[2], (*sco)[2], (*mouse_path)[2];
/* edit-object needed for matrix, and ar->regiondata for projections to work */
- if (ELEM3(NULL, obedit, ar, ar->regiondata))
+ if (ELEM(NULL, obedit, ar, ar->regiondata))
return OPERATOR_CANCELLED;
if (bm->totvertsel < 2) {
@@ -3675,7 +3675,7 @@ static void edbm_fill_grid_prepare(BMesh *bm, int offset, int *r_span, bool span
}
/* set this vertex first */
- BLI_rotatelist_first(verts, v_act_link);
+ BLI_listbase_rotate_first(verts, v_act_link);
BM_edgeloop_edges_get(el_store, edges);
@@ -4107,6 +4107,11 @@ static void edbm_dissolve_prop__use_face_split(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "use_face_split", 0, "Face Split",
"Split off face corners to maintain surrounding geometry");
}
+static void edbm_dissolve_prop__use_boundary_tear(wmOperatorType *ot)
+{
+ RNA_def_boolean(ot->srna, "use_boundary_tear", 0, "Tear Boundary",
+ "Split off face corners instead of merging faces");
+}
static int edbm_dissolve_verts_exec(bContext *C, wmOperator *op)
{
@@ -4114,9 +4119,14 @@ static int edbm_dissolve_verts_exec(bContext *C, wmOperator *op)
BMEditMesh *em = BKE_editmesh_from_object(obedit);
const bool use_face_split = RNA_boolean_get(op->ptr, "use_face_split");
+ const bool use_boundary_tear = RNA_boolean_get(op->ptr, "use_boundary_tear");
- if (!EDBM_op_callf(em, op, "dissolve_verts verts=%hv use_face_split=%b", BM_ELEM_SELECT, use_face_split))
+ if (!EDBM_op_callf(em, op,
+ "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b",
+ BM_ELEM_SELECT, use_face_split, use_boundary_tear))
+ {
return OPERATOR_CANCELLED;
+ }
EDBM_update_generic(em, true, true);
@@ -4138,6 +4148,7 @@ void MESH_OT_dissolve_verts(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
edbm_dissolve_prop__use_face_split(ot);
+ edbm_dissolve_prop__use_boundary_tear(ot);
}
static int edbm_dissolve_edges_exec(bContext *C, wmOperator *op)
@@ -4249,6 +4260,7 @@ void MESH_OT_dissolve_mode(wmOperatorType *ot)
edbm_dissolve_prop__use_verts(ot);
edbm_dissolve_prop__use_face_split(ot);
+ edbm_dissolve_prop__use_boundary_tear(ot);
}
static int edbm_dissolve_limited_exec(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c
index 36c7bb404da..feac7f6ece3 100644
--- a/source/blender/editors/metaball/mball_edit.c
+++ b/source/blender/editors/metaball/mball_edit.c
@@ -594,7 +594,7 @@ bool mouse_mball(bContext *C, const int mval[2], bool extend, bool deselect, boo
rect.ymin = mval[1] - 12;
rect.ymax = mval[1] + 12;
- hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
+ hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, true);
/* does startelem exist? */
ml = mb->editelems->first;
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 99dd8b75609..34b4ca2c0f1 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -1470,7 +1470,7 @@ static void convert_ensure_curve_cache(Main *bmain, Scene *scene, Object *ob)
/* Force creation. This is normally not needed but on operator
* redo we might end up with an object which isn't evaluated yet.
*/
- if (ELEM3(ob->type, OB_SURF, OB_CURVE, OB_FONT)) {
+ if (ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) {
BKE_displist_make_curveTypes(scene, ob, false);
}
else if (ob->type == OB_MBALL) {
@@ -2274,7 +2274,7 @@ static int join_poll(bContext *C)
if (!ob || ob->id.lib) return 0;
- if (ELEM4(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_ARMATURE))
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_ARMATURE))
return ED_operator_screenactive(C);
else
return 0;
diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c
index 94574e81b81..2402ecb498d 100644
--- a/source/blender/editors/object/object_bake.c
+++ b/source/blender/editors/object/object_bake.c
@@ -770,7 +770,7 @@ static int objects_bake_render_modal(bContext *C, wmOperator *UNUSED(op), const
static bool is_multires_bake(Scene *scene)
{
- if (ELEM4(scene->r.bake_mode, RE_BAKE_NORMALS, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_AO))
+ if (ELEM(scene->r.bake_mode, RE_BAKE_NORMALS, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_AO))
return scene->r.bake_flag & R_BAKE_MULTIRES;
return 0;
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index f57ab220471..e21f56538aa 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -51,6 +51,7 @@
#include "BKE_image.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_node.h"
#include "BKE_report.h"
#include "BKE_modifier.h"
#include "BKE_mesh.h"
@@ -177,7 +178,7 @@ static bool write_internal_bake_pixels(
void *lock;
bool is_float;
char *mask_buffer = NULL;
- const int num_pixels = width * height;
+ const size_t num_pixels = (size_t)width * (size_t)height;
ibuf = BKE_image_acquire_ibuf(image, NULL, &lock);
@@ -310,7 +311,7 @@ static bool write_external_bake_pixels(
/* margins */
if (margin > 0) {
char *mask_buffer = NULL;
- const int num_pixels = width * height;
+ const size_t num_pixels = (size_t)width * (size_t)height;
mask_buffer = MEM_callocN(sizeof(char) * num_pixels, "Bake Mask");
RE_bake_mask_fill(pixel_array, num_pixels, mask_buffer);
@@ -335,14 +336,14 @@ static bool write_external_bake_pixels(
static bool is_noncolor_pass(ScenePassType pass_type)
{
- return ELEM7(pass_type,
- SCE_PASS_Z,
- SCE_PASS_NORMAL,
- SCE_PASS_VECTOR,
- SCE_PASS_INDEXOB,
- SCE_PASS_UV,
- SCE_PASS_RAYHITS,
- SCE_PASS_INDEXMA);
+ return ELEM(pass_type,
+ SCE_PASS_Z,
+ SCE_PASS_NORMAL,
+ SCE_PASS_VECTOR,
+ SCE_PASS_INDEXOB,
+ SCE_PASS_UV,
+ SCE_PASS_RAYHITS,
+ SCE_PASS_INDEXMA);
}
/* if all is good tag image and return true */
@@ -367,10 +368,22 @@ static bool bake_object_check(Object *ob, ReportList *reports)
}
for (i = 0; i < ob->totcol; i++) {
- ED_object_get_active_image(ob, i + 1, &image, NULL, NULL);
+ bNodeTree *ntree = NULL;
+ bNode *node = NULL;
+ ED_object_get_active_image(ob, i + 1, &image, NULL, &node, &ntree);
if (image) {
- ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, &lock);
+ ImBuf *ibuf;
+
+ if (node) {
+ if (BKE_node_is_connected_to_output(ntree, node)) {
+ BKE_reportf(reports, RPT_ERROR,
+ "Circular dependency for image \"%s\" from object \"%s\"",
+ image->id.name + 2, ob->id.name + 2);
+ }
+ }
+
+ ibuf = BKE_image_acquire_ibuf(image, NULL, &lock);
if (ibuf) {
BKE_image_release_ibuf(image, ibuf, lock);
@@ -429,7 +442,7 @@ static bool bake_objects_check(Main *bmain, Object *ob, ListBase *selected_objec
if (ob_iter == ob)
continue;
- if (ELEM5(ob_iter->type, OB_MESH, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL) == false) {
+ if (ELEM(ob_iter->type, OB_MESH, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL) == false) {
BKE_reportf(reports, RPT_ERROR, "Object \"%s\" is not a mesh or can't be converted to a mesh (Curve, Text, Surface or Metaball)", ob_iter->id.name + 2);
return false;
}
@@ -477,7 +490,7 @@ static void build_image_lookup(Main *bmain, Object *ob, BakeImages *bake_images)
for (i = 0; i < tot_mat; i++) {
Image *image;
- ED_object_get_active_image(ob, i + 1, &image, NULL, NULL);
+ ED_object_get_active_image(ob, i + 1, &image, NULL, NULL, NULL);
if ((image->id.flag & LIB_DOIT)) {
for (j = 0; j < i; j++) {
@@ -501,10 +514,10 @@ static void build_image_lookup(Main *bmain, Object *ob, BakeImages *bake_images)
/*
* returns the total number of pixels
*/
-static int initialize_internal_images(BakeImages *bake_images, ReportList *reports)
+static size_t initialize_internal_images(BakeImages *bake_images, ReportList *reports)
{
int i;
- int tot_size = 0;
+ size_t tot_size = 0;
for (i = 0; i < bake_images->size; i++) {
ImBuf *ibuf;
@@ -518,7 +531,7 @@ static int initialize_internal_images(BakeImages *bake_images, ReportList *repor
bk_image->height = ibuf->y;
bk_image->offset = tot_size;
- tot_size += ibuf->x * ibuf->y;
+ tot_size += (size_t)ibuf->x * (size_t)ibuf->y;
}
else {
BKE_image_release_ibuf(bk_image->image, ibuf, lock);
@@ -563,7 +576,7 @@ static int bake(
BakeImages bake_images = {NULL};
- int num_pixels;
+ size_t num_pixels;
int tot_materials;
int i;
@@ -620,7 +633,7 @@ static int bake(
else {
/* when saving extenally always use the size specified in the UI */
- num_pixels = width * height * bake_images.size;
+ num_pixels = (size_t)width * (size_t)height * bake_images.size;
for (i = 0; i < bake_images.size; i++) {
bake_images.data[i].width = width;
@@ -1067,7 +1080,6 @@ static int bake_exec(bContext *C, wmOperator *op)
/* setup new render */
RE_test_break_cb(re, NULL, bake_break);
- RE_progress_cb(re, NULL, bake_progress_update);
if (!bake_objects_check(bkr.main, bkr.ob, &bkr.selected_objects, bkr.reports, bkr.is_selected_to_active))
return OPERATOR_CANCELLED;
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index 85e4bbce8dc..92ed84b7f5e 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -485,7 +485,7 @@ static void test_constraints(Object *owner, bPoseChannel *pchan)
}
/* target checks for specific constraints */
- if (ELEM3(curcon->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO, CONSTRAINT_TYPE_SPLINEIK)) {
+ if (ELEM(curcon->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO, CONSTRAINT_TYPE_SPLINEIK)) {
if (ct->tar) {
if (ct->tar->type != OB_CURVE) {
ct->tar = NULL;
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index a6ab4bafcaf..2f499cbc4eb 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -139,7 +139,9 @@ static int object_hide_view_clear_exec(bContext *C, wmOperator *UNUSED(op))
/* XXX need a context loop to handle such cases */
for (base = FIRSTBASE; base; base = base->next) {
if ((base->lay & v3d->lay) && base->object->restrictflag & OB_RESTRICT_VIEW) {
- base->flag |= SELECT;
+ if (!(base->object->restrictflag & OB_RESTRICT_SELECT)) {
+ base->flag |= SELECT;
+ }
base->object->flag = base->flag;
base->object->restrictflag &= ~OB_RESTRICT_VIEW;
changed = true;
@@ -344,6 +346,11 @@ static bool ED_object_editmode_load_ex(Object *obedit, const bool freedata)
if (freedata) free_editMball(obedit);
}
+ /* Tag update so no access to freed data referenced from
+ * derived cache will happen.
+ */
+ DAG_id_tag_update((ID *)obedit->data, 0);
+
return true;
}
@@ -430,7 +437,7 @@ void ED_object_editmode_enter(bContext *C, int flag)
base = scene->basact;
}
- if (ELEM3(NULL, base, base->object, base->object->data)) return;
+ if (ELEM(NULL, base, base->object, base->object->data)) return;
ob = base->object;
@@ -559,7 +566,7 @@ static int editmode_toggle_poll(bContext *C)
if ((ob->restrictflag & OB_RESTRICT_VIEW) && !(ob->mode & OB_MODE_EDIT))
return 0;
- return (ELEM7(ob->type, OB_MESH, OB_ARMATURE, OB_FONT, OB_MBALL, OB_LATTICE, OB_SURF, OB_CURVE));
+ return OB_TYPE_SUPPORT_EDITMODE(ob->type);
}
void OBJECT_OT_editmode_toggle(wmOperatorType *ot)
@@ -730,7 +737,7 @@ static void copy_texture_space(Object *to, Object *ob)
texflag = ((Mesh *)ob->data)->texflag;
poin2 = ((Mesh *)ob->data)->loc;
}
- else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
+ else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
texflag = ((Curve *)ob->data)->texflag;
poin2 = ((Curve *)ob->data)->loc;
}
@@ -745,7 +752,7 @@ static void copy_texture_space(Object *to, Object *ob)
((Mesh *)to->data)->texflag = texflag;
poin1 = ((Mesh *)to->data)->loc;
}
- else if (ELEM3(to->type, OB_CURVE, OB_SURF, OB_FONT)) {
+ else if (ELEM(to->type, OB_CURVE, OB_SURF, OB_FONT)) {
((Curve *)to->data)->texflag = texflag;
poin1 = ((Curve *)to->data)->loc;
}
@@ -1082,7 +1089,7 @@ void ED_object_check_force_modifiers(Main *bmain, Scene *scene, Object *object)
/* add/remove modifier as needed */
if (!md) {
if (pd && (pd->shape == PFIELD_SHAPE_SURFACE) && ELEM(pd->forcefield, PFIELD_GUIDE, PFIELD_TEXTURE) == 0)
- if (ELEM4(object->type, OB_MESH, OB_SURF, OB_FONT, OB_CURVE))
+ if (ELEM(object->type, OB_MESH, OB_SURF, OB_FONT, OB_CURVE))
ED_object_modifier_add(NULL, bmain, scene, object, NULL, eModifierType_Surface);
}
else {
@@ -1423,7 +1430,7 @@ static void UNUSED_FUNCTION(image_aspect) (Scene *scene, View3D *v3d)
BKE_mesh_texspace_get(ob->data, NULL, NULL, size);
space = size[0] / size[1];
}
- else if (ELEM3(ob->type, OB_CURVE, OB_FONT, OB_SURF)) {
+ else if (ELEM(ob->type, OB_CURVE, OB_FONT, OB_SURF)) {
float size[3];
BKE_curve_texspace_get(ob->data, NULL, NULL, size);
space = size[0] / size[1];
@@ -1470,7 +1477,7 @@ static EnumPropertyItem *object_mode_set_itemsf(bContext *C, PointerRNA *UNUSED(
if ((input->value == OB_MODE_EDIT && OB_TYPE_SUPPORT_EDITMODE(ob->type)) ||
(input->value == OB_MODE_POSE && (ob->type == OB_ARMATURE)) ||
(input->value == OB_MODE_PARTICLE_EDIT && use_mode_particle_edit) ||
- (ELEM4(input->value, OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT,
+ (ELEM(input->value, OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT,
OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT) && (ob->type == OB_MESH)) ||
(input->value == OB_MODE_OBJECT))
{
diff --git a/source/blender/editors/object/object_group.c b/source/blender/editors/object/object_group.c
index 47b5f1605e7..20e2e22cdf8 100644
--- a/source/blender/editors/object/object_group.c
+++ b/source/blender/editors/object/object_group.c
@@ -563,3 +563,67 @@ void OBJECT_OT_group_remove(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+static int group_unlink_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Group *group = CTX_data_pointer_get_type(C, "group", &RNA_Group).data;
+
+ if (!group)
+ return OPERATOR_CANCELLED;
+
+ BKE_group_unlink(group);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_group_unlink(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Unlink Group";
+ ot->idname = "OBJECT_OT_group_unlink";
+ ot->description = "Unlink the group from all objects";
+
+ /* api callbacks */
+ ot->exec = group_unlink_exec;
+ ot->poll = ED_operator_objectmode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int select_grouped_exec(bContext *C, wmOperator *UNUSED(op)) /* Select objects in the same group as the active */
+{
+ Group *group = CTX_data_pointer_get_type(C, "group", &RNA_Group).data;
+
+ if (!group)
+ return OPERATOR_CANCELLED;
+
+ CTX_DATA_BEGIN (C, Base *, base, visible_bases)
+ {
+ if (!(base->flag & SELECT) && BKE_group_object_exists(group, base->object)) {
+ ED_base_object_select(base, BA_SELECT);
+ }
+ }
+ CTX_DATA_END;
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_grouped_select(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Grouped";
+ ot->idname = "OBJECT_OT_grouped_select";
+ ot->description = "Select all objects in group";
+
+ /* api callbacks */
+ ot->exec = select_grouped_exec;
+ ot->poll = ED_operator_objectmode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c
index afff367b939..9f9a647c9f1 100644
--- a/source/blender/editors/object/object_hook.c
+++ b/source/blender/editors/object/object_hook.c
@@ -528,8 +528,7 @@ static int add_hook_object(Main *bmain, Scene *scene, Object *obedit, Object *ob
invert_m4_m4(ob->imat, ob->obmat);
/* apparently this call goes from right to left... */
- mul_serie_m4(hmd->parentinv, pose_mat, ob->imat, obedit->obmat,
- NULL, NULL, NULL, NULL, NULL);
+ mul_m4_series(hmd->parentinv, pose_mat, ob->imat, obedit->obmat);
DAG_relations_tag_update(bmain);
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index fd6b9a1bad0..b8824420018 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -251,6 +251,8 @@ void OBJECT_OT_shape_key_move(struct wmOperatorType *ot);
void OBJECT_OT_group_add(struct wmOperatorType *ot);
void OBJECT_OT_group_link(struct wmOperatorType *ot);
void OBJECT_OT_group_remove(struct wmOperatorType *ot);
+void OBJECT_OT_group_unlink(struct wmOperatorType *ot);
+void OBJECT_OT_grouped_select(struct wmOperatorType *ot);
/* object_bake.c */
void OBJECT_OT_bake_image(wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index 1249beb4517..b05840b5823 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -98,7 +98,7 @@ ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *sc
ModifierTypeInfo *mti = modifierType_getInfo(type);
/* only geometry objects should be able to get modifiers [#25291] */
- if (!ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
+ if (!ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
BKE_reportf(reports, RPT_WARNING, "Modifiers cannot be added to object '%s'", ob->id.name + 2);
return NULL;
}
@@ -1876,7 +1876,7 @@ static int meshdeform_bind_exec(bContext *C, wmOperator *op)
else if (ob->type == OB_MBALL) {
BKE_displist_make_mball(CTX_data_main(C)->eval_ctx, scene, ob);
}
- else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
+ else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
BKE_displist_make_curveTypes(scene, ob, 0);
}
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index a8f07747d3a..45f981016dc 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -229,6 +229,8 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_group_add);
WM_operatortype_append(OBJECT_OT_group_link);
WM_operatortype_append(OBJECT_OT_group_remove);
+ WM_operatortype_append(OBJECT_OT_group_unlink);
+ WM_operatortype_append(OBJECT_OT_grouped_select);
WM_operatortype_append(OBJECT_OT_hook_add_selob);
WM_operatortype_append(OBJECT_OT_hook_add_newob);
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 3059d84a085..f6d1df4e8d4 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -444,7 +444,7 @@ EnumPropertyItem prop_clear_parent_types[] = {
/* Helper for ED_object_parent_clear() - Remove deform-modifiers associated with parent */
static void object_remove_parent_deform_modifiers(Object *ob, const Object *par)
{
- if (ELEM3(par->type, OB_ARMATURE, OB_LATTICE, OB_CURVE)) {
+ if (ELEM(par->type, OB_ARMATURE, OB_LATTICE, OB_CURVE)) {
ModifierData *md, *mdn;
/* assume that we only need to remove the first instance of matching deform modifier here */
@@ -593,7 +593,7 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
int partype, bool xmirror, bool keep_transform, const int vert_par[3])
{
bPoseChannel *pchan = NULL;
- int pararm = ELEM4(partype, PAR_ARMATURE, PAR_ARMATURE_NAME, PAR_ARMATURE_ENVELOPE, PAR_ARMATURE_AUTO);
+ int pararm = ELEM(partype, PAR_ARMATURE, PAR_ARMATURE_NAME, PAR_ARMATURE_ENVELOPE, PAR_ARMATURE_AUTO);
DAG_id_tag_update(&par->id, OB_RECALC_OB);
@@ -678,7 +678,7 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
* assuming that the parent is selected too...
*/
// XXX currently this should only happen for meshes, curves, surfaces, and lattices - this stuff isn't available for metas yet
- if (ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
ModifierData *md;
switch (partype) {
@@ -1128,7 +1128,7 @@ static int object_track_clear_exec(bContext *C, wmOperator *op)
/* also remove all tracking constraints */
for (con = ob->constraints.last; con; con = pcon) {
pcon = con->prev;
- if (ELEM3(con->type, CONSTRAINT_TYPE_TRACKTO, CONSTRAINT_TYPE_LOCKTRACK, CONSTRAINT_TYPE_DAMPTRACK))
+ if (ELEM(con->type, CONSTRAINT_TYPE_TRACKTO, CONSTRAINT_TYPE_LOCKTRACK, CONSTRAINT_TYPE_DAMPTRACK))
BKE_constraint_remove(&ob->constraints, con);
}
@@ -1192,7 +1192,7 @@ static int track_set_exec(bContext *C, wmOperator *op)
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
/* Lamp, Camera and Speaker track differently by default */
- if (ELEM3(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) {
+ if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) {
data->trackflag = TRACK_nZ;
}
}
@@ -1213,7 +1213,7 @@ static int track_set_exec(bContext *C, wmOperator *op)
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
/* Lamp, Camera and Speaker track differently by default */
- if (ELEM3(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) {
+ if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) {
data->reserved1 = TRACK_nZ;
data->reserved2 = UP_Y;
}
@@ -1235,7 +1235,7 @@ static int track_set_exec(bContext *C, wmOperator *op)
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
/* Lamp, Camera and Speaker track differently by default */
- if (ELEM3(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) {
+ if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) {
data->trackflag = TRACK_nZ;
data->lockflag = LOCK_Y;
}
diff --git a/source/blender/editors/object/object_shapekey.c b/source/blender/editors/object/object_shapekey.c
index be050917f5a..d741991ce7f 100644
--- a/source/blender/editors/object/object_shapekey.c
+++ b/source/blender/editors/object/object_shapekey.c
@@ -494,9 +494,9 @@ static int shape_key_move_poll(bContext *C)
Object *ob = ED_object_context(C);
ID *data = (ob) ? ob->data : NULL;
Key *key = BKE_key_from_object(ob);
- return (ob && !ob->id.lib && data && !data->lib && ob->mode != OB_MODE_EDIT && key && key->totkey);
-}
+ return (ob && !ob->id.lib && data && !data->lib && ob->mode != OB_MODE_EDIT && key && key->totkey > 1);
+}
static EnumPropertyItem slot_move[] = {
{ -2, "TOP", 0, "Top of the list", "" },
@@ -510,17 +510,15 @@ static int shape_key_move_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_context(C);
- int type = RNA_enum_get(op->ptr, "type");
- int act_index = ob->shapenr - 1;
- int new_index = act_index;
Key *key = BKE_key_from_object(ob);
KeyBlock *kb = BKE_keyblock_from_object(ob);
+ const int type = RNA_enum_get(op->ptr, "type");
+ const int totkey = key->totkey;
+ const int act_index = ob->shapenr - 1;
+ int new_index;
- if (type >= -1 && type <= 1) {
- new_index = act_index + type;
- }
- else if (type == 2) {
- new_index = key->totkey - 1;
+ if (type == 2) {
+ new_index = totkey - 1;
}
else if (type == -2) {
if (act_index == 1 || act_index == 0)
@@ -528,6 +526,9 @@ static int shape_key_move_exec(bContext *C, wmOperator *op)
else
new_index = 1;
}
+ else {
+ new_index = (totkey + act_index + type) % totkey;
+ }
BKE_keyblock_move(ob, kb, new_index);
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index 6e59f9f4aea..e2ebe583ecf 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -385,7 +385,7 @@ static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_l
/* first check if we can execute */
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
{
- if (ELEM6(ob->type, OB_MESH, OB_ARMATURE, OB_LATTICE, OB_MBALL, OB_CURVE, OB_SURF)) {
+ if (ELEM(ob->type, OB_MESH, OB_ARMATURE, OB_LATTICE, OB_MBALL, OB_CURVE, OB_SURF)) {
ID *obdata = ob->data;
if (ID_REAL_USERS(obdata) > 1) {
BKE_reportf(reports, RPT_ERROR,
@@ -784,7 +784,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
}
if (ctx_ob_act) {
- BLI_rotatelist_first(&ctx_data_list, (LinkData *)ctx_ob_act);
+ BLI_listbase_rotate_first(&ctx_data_list, (LinkData *)ctx_ob_act);
}
for (tob = bmain->object.first; tob; tob = tob->id.next) {
diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c
index 94d8d78de1a..8a034fdd8b5 100644
--- a/source/blender/editors/render/render_update.c
+++ b/source/blender/editors/render/render_update.c
@@ -45,6 +45,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
#include "BKE_icons.h"
#include "BKE_main.h"
@@ -165,6 +166,7 @@ void ED_render_engine_changed(Main *bmain)
bScreen *sc;
ScrArea *sa;
Scene *scene;
+ Material *ma;
for (sc = bmain->screen.first; sc; sc = sc->id.next)
for (sa = sc->areabase.first; sa; sa = sa->next)
@@ -174,6 +176,14 @@ void ED_render_engine_changed(Main *bmain)
for (scene = bmain->scene.first; scene; scene = scene->id.next)
ED_render_id_flush_update(bmain, &scene->id);
+
+ /* reset texture painting */
+ for (ma = bmain->mat.first; ma; ma = ma->id.next) {
+ if (ma->texpaintslot) {
+ BKE_texpaint_slots_clear(ma);
+ DAG_id_tag_update(&ma->id, 0);
+ }
+ }
}
/***************************** Updates ***********************************
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index d1375b1b8ab..11e7174ea98 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -931,11 +931,11 @@ static bool region_is_overlap(wmWindow *win, ScrArea *sa, ARegion *ar)
if (U.uiflag2 & USER_REGION_OVERLAP) {
if (WM_is_draw_triple(win)) {
if (ELEM(sa->spacetype, SPACE_VIEW3D, SPACE_SEQ)) {
- if (ELEM3(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS))
+ if (ELEM(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS))
return 1;
}
else if (sa->spacetype == SPACE_IMAGE) {
- if (ELEM4(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS, RGN_TYPE_PREVIEW))
+ if (ELEM(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS, RGN_TYPE_PREVIEW))
return 1;
}
}
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index f76f76aacaa..5beab9fcc14 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -378,7 +378,7 @@ ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge)
if (split == 0) return NULL;
/* note regarding (fac > 0.5f) checks below.
- * notmally it shouldn't matter which is used since the copy should match the original
+ * normally it shouldn't matter which is used since the copy should match the original
* however with viewport rendering and python console this isn't the case. - campbell */
if (dir == 'h') {
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 2ddda19fb28..7c7574b3af3 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -201,7 +201,7 @@ int ED_operator_animview_active(bContext *C)
{
if (ED_operator_areaactive(C)) {
SpaceLink *sl = (SpaceLink *)CTX_wm_space_data(C);
- if (sl && (ELEM5(sl->spacetype, SPACE_SEQ, SPACE_ACTION, SPACE_NLA, SPACE_IPO, SPACE_TIME)))
+ if (sl && (ELEM(sl->spacetype, SPACE_SEQ, SPACE_ACTION, SPACE_NLA, SPACE_IPO, SPACE_TIME)))
return true;
}
@@ -3220,6 +3220,16 @@ static int match_region_with_redraws(int spacetype, int regiontype, int redraws)
}
}
+ else if (regiontype == RGN_TYPE_CHANNELS) {
+ switch (spacetype) {
+ case SPACE_IPO:
+ case SPACE_ACTION:
+ case SPACE_NLA:
+ if (redraws & TIME_ALL_ANIM_WIN)
+ return 1;
+ break;
+ }
+ }
else if (regiontype == RGN_TYPE_UI) {
if (spacetype == SPACE_CLIP) {
/* Track Preview button is on Properties Editor in SpaceClip,
@@ -4154,7 +4164,8 @@ void ED_keymap_screen(wmKeyConfig *keyconf)
/* dropbox for entire window */
lb = WM_dropboxmap_find("Window", 0, 0);
WM_dropbox_add(lb, "WM_OT_open_mainfile", open_file_drop_poll, open_file_drop_copy);
-
+ WM_dropbox_add(lb, "UI_OT_drop_color", UI_drop_color_poll, UI_drop_color_copy);
+
keymap_modal_set(keyconf);
}
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index 79ce4f879b7..18db57c9f21 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -40,6 +40,7 @@ set(INC_SYS
set(SRC
paint_cursor.c
+ paint_curve.c
paint_hide.c
paint_image.c
paint_image_2d.c
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index b1e4696cd02..7b9ede38b39 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -44,6 +44,7 @@
#include "BKE_brush.h"
#include "BKE_context.h"
+#include "BKE_curve.h"
#include "BKE_image.h"
#include "BKE_node.h"
#include "BKE_paint.h"
@@ -58,6 +59,8 @@
#include "ED_view3d.h"
+#include "UI_resources.h"
+
#include "paint_intern.h"
/* still needed for sculpt_stroke_get_location, should be
* removed eventually (TODO) */
@@ -756,7 +759,7 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush,
ViewContext *vc, int x, int y, float zoom, PaintMode mode)
{
/* color means that primary brush texture is colured and secondary is used for alpha/mask control */
- bool col = ELEM3(mode, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D, PAINT_VERTEX) ? true : false;
+ bool col = ELEM(mode, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D, PAINT_VERTEX) ? true : false;
OverlayControlFlags flags = BKE_paint_get_overlay_flags();
/* save lots of GL state
* TODO: check on whether all of these are needed? */
@@ -791,6 +794,138 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush,
glPopAttrib();
}
+
+BLI_INLINE void draw_tri_point(float *co, float width, bool selected)
+{
+ float w = width / 2.0f;
+ if (selected)
+ UI_ThemeColor4(TH_VERTEX_SELECT);
+ else
+ UI_ThemeColor4(TH_PAINT_CURVE_PIVOT);
+
+ glLineWidth(3.0);
+
+ glBegin(GL_LINE_LOOP);
+ glVertex2f(co[0], co[1] + w);
+ glVertex2f(co[0] - w, co[1] - w);
+ glVertex2f(co[0] + w, co[1] - w);
+ glEnd();
+
+ glColor4f(1.0, 1.0, 1.0, 0.5);
+ glLineWidth(1.0);
+
+ glBegin(GL_LINE_LOOP);
+ glVertex2f(co[0], co[1] + w);
+ glVertex2f(co[0] - w, co[1] - w);
+ glVertex2f(co[0] + w, co[1] - w);
+ glEnd();
+}
+
+BLI_INLINE void draw_rect_point(float *co, float width, bool selected)
+{
+ float w = width / 2.0f;
+ if (selected)
+ UI_ThemeColor4(TH_VERTEX_SELECT);
+ else
+ UI_ThemeColor4(TH_PAINT_CURVE_HANDLE);
+ glLineWidth(3.0);
+
+ glBegin(GL_LINE_LOOP);
+ glVertex2f(co[0] + w, co[1] + w);
+ glVertex2f(co[0] - w, co[1] + w);
+ glVertex2f(co[0] - w, co[1] - w);
+ glVertex2f(co[0] + w, co[1] - w);
+ glEnd();
+
+ glColor4f(1.0, 1.0, 1.0, 0.5);
+ glLineWidth(1.0);
+
+ glBegin(GL_LINE_LOOP);
+ glVertex2f(co[0] + w, co[1] + w);
+ glVertex2f(co[0] - w, co[1] + w);
+ glVertex2f(co[0] - w, co[1] - w);
+ glVertex2f(co[0] + w, co[1] - w);
+ glEnd();
+}
+
+
+BLI_INLINE void draw_bezier_handle_lines(BezTriple *bez)
+{
+ short line1[] = {0, 1};
+ short line2[] = {1, 2};
+
+ glVertexPointer(2, GL_FLOAT, 3 * sizeof(float), bez->vec);
+ glColor4f(0.0, 0.0, 0.0, 0.5);
+ glLineWidth(3.0);
+ glDrawArrays(GL_LINE_STRIP, 0, 3);
+
+ glLineWidth(1.0);
+ if (bez->f1 || bez->f2)
+ UI_ThemeColor4(TH_VERTEX_SELECT);
+ else
+ glColor4f(1.0, 1.0, 1.0, 0.5);
+ glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, line1);
+ if (bez->f3 || bez->f2)
+ UI_ThemeColor4(TH_VERTEX_SELECT);
+ else
+ glColor4f(1.0, 1.0, 1.0, 0.5);
+ glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, line2);
+}
+
+static void paint_draw_curve_cursor(Brush *brush)
+{
+ if (brush->paint_curve && brush->paint_curve->points) {
+ int i;
+ PaintCurve *pc = brush->paint_curve;
+ PaintCurvePoint *cp = pc->points;
+
+ glEnable(GL_LINE_SMOOTH);
+ glEnable(GL_BLEND);
+ glEnableClientState(GL_VERTEX_ARRAY);
+
+ /* draw the bezier handles and the curve segment between the current and next point */
+ for (i = 0; i < pc->tot_points - 1; i++, cp++) {
+ int j;
+ PaintCurvePoint *cp_next = cp + 1;
+ float data[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2];
+ /* use color coding to distinguish handles vs curve segments */
+ draw_bezier_handle_lines(&cp->bez);
+ draw_tri_point(&cp->bez.vec[1][0], 10.0, cp->bez.f2);
+ draw_rect_point(&cp->bez.vec[0][0], 8.0, cp->bez.f1 || cp->bez.f2);
+ draw_rect_point(&cp->bez.vec[2][0], 8.0, cp->bez.f3 || cp->bez.f2);
+
+ for (j = 0; j < 2; j++)
+ BKE_curve_forward_diff_bezier(
+ cp->bez.vec[1][j],
+ cp->bez.vec[2][j],
+ cp_next->bez.vec[0][j],
+ cp_next->bez.vec[1][j],
+ data + j, PAINT_CURVE_NUM_SEGMENTS, sizeof(float[2]));
+
+ glVertexPointer(2, GL_FLOAT, 0, data);
+ glLineWidth(3.0);
+ glColor4f(0.0, 0.0, 0.0, 0.5);
+ glDrawArrays(GL_LINE_STRIP, 0, PAINT_CURVE_NUM_SEGMENTS + 1);
+
+ glLineWidth(1.0);
+ glColor4f(0.9, 0.9, 1.0, 0.5);
+ glDrawArrays(GL_LINE_STRIP, 0, PAINT_CURVE_NUM_SEGMENTS + 1);
+ }
+
+ /* draw last line segment */
+ draw_bezier_handle_lines(&cp->bez);
+ draw_tri_point(&cp->bez.vec[1][0], 10.0, cp->bez.f2);
+ draw_rect_point(&cp->bez.vec[0][0], 8.0, cp->bez.f1 || cp->bez.f2);
+ draw_rect_point(&cp->bez.vec[2][0], 8.0, cp->bez.f3 || cp->bez.f2);
+
+ glLineWidth(1.0);
+
+ glDisable(GL_BLEND);
+ glDisable(GL_LINE_SMOOTH);
+ glDisableClientState(GL_VERTEX_ARRAY);
+ }
+}
+
/* Special actions taken when paint cursor goes over mesh */
/* TODO: sculpt only for now */
static void paint_cursor_on_hit(UnifiedPaintSettings *ups, Brush *brush, ViewContext *vc,
@@ -848,6 +983,12 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
zoomx = max_ff(zoomx, zoomy);
mode = BKE_paintmode_get_active_from_context(C);
+ /* skip everything and draw brush here */
+ if (brush->flag & BRUSH_CURVE) {
+ paint_draw_curve_cursor(brush);
+ return;
+ }
+
/* set various defaults */
translation[0] = x;
translation[1] = y;
@@ -857,8 +998,11 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
/* don't calculate rake angles while a stroke is active because the rake variables are global and
* we may get interference with the stroke itself. For line strokes, such interference is visible */
- if (!ups->stroke_active && (brush->flag & BRUSH_RAKE))
- paint_calculate_rake_rotation(ups, translation);
+ if (!ups->stroke_active) {
+ 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, zoomx, mode);
@@ -878,9 +1022,9 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
/* check if brush is subtracting, use different color then */
/* TODO: no way currently to know state of pen flip or
* invert key modifier without starting a stroke */
- if ((!(brush->flag & BRUSH_INVERTED) ^
+ if ((!(ups->draw_inverted) ^
!(brush->flag & BRUSH_DIR_IN)) &&
- ELEM5(brush->sculpt_tool, SCULPT_TOOL_DRAW,
+ ELEM(brush->sculpt_tool, SCULPT_TOOL_DRAW,
SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY,
SCULPT_TOOL_PINCH, SCULPT_TOOL_CREASE))
{
@@ -890,12 +1034,12 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
/* only do if brush is over the mesh */
if (hit)
paint_cursor_on_hit(ups, brush, &vc, location);
+ }
- if (ups->draw_anchored) {
- final_radius = ups->anchored_size;
- translation[0] = ups->anchored_initial_mouse[0];
- translation[1] = ups->anchored_initial_mouse[1];
- }
+ if (ups->draw_anchored) {
+ final_radius = ups->anchored_size;
+ translation[0] = ups->anchored_initial_mouse[0];
+ translation[1] = ups->anchored_initial_mouse[1];
}
/* make lines pretty */
diff --git a/source/blender/editors/sculpt_paint/paint_curve.c b/source/blender/editors/sculpt_paint/paint_curve.c
new file mode 100644
index 00000000000..217c88c87ea
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/paint_curve.c
@@ -0,0 +1,801 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/sculpt_paint/paint_curve.c
+ * \ingroup edsculpt
+ */
+
+#include <string.h>
+#include <limits.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_context.h"
+#include "BKE_main.h"
+#include "BKE_paint.h"
+
+#include "BLI_math_vector.h"
+#include "BLI_string.h"
+
+#include "ED_paint.h"
+#include "ED_view3d.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_view2d.h"
+
+#include "paint_intern.h"
+
+#define PAINT_CURVE_SELECT_THRESHOLD 40.0f
+#define PAINT_CURVE_POINT_SELECT(pcp, i) (*(&pcp->bez.f1 + i) = SELECT)
+
+
+int paint_curve_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+ Paint *p;
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ SpaceImage *sima;
+
+ if (rv3d && !(ob && ((ob->mode & OB_MODE_ALL_PAINT) != 0)))
+ return false;
+
+ sima = CTX_wm_space_image(C);
+
+ if (sima && sima->mode != SI_MODE_PAINT)
+ return false;
+
+ p = BKE_paint_get_active_from_context(C);
+
+ if (p && p->brush && (p->brush->flag & BRUSH_CURVE)) {
+ return true;
+ }
+
+ return false;
+}
+
+/* Paint Curve Undo*/
+
+typedef struct UndoCurve {
+ struct UndoImageTile *next, *prev;
+
+ PaintCurvePoint *points; /* points of curve */
+ int tot_points;
+ int active_point;
+
+ char idname[MAX_ID_NAME]; /* name instead of pointer*/
+} UndoCurve;
+
+static void paintcurve_undo_restore(bContext *C, ListBase *lb)
+{
+ Paint *p = BKE_paint_get_active_from_context(C);
+ UndoCurve *uc;
+ PaintCurve *pc = NULL;
+
+ if (p->brush) {
+ pc = p->brush->paint_curve;
+ }
+
+ if (!pc)
+ return;
+
+ uc = (UndoCurve *)lb->first;
+
+ if (strncmp(uc->idname, pc->id.name, BLI_strnlen(uc->idname, sizeof(uc->idname))) == 0) {
+ SWAP(PaintCurvePoint *, pc->points, uc->points);
+ SWAP(int, pc->tot_points, uc->tot_points);
+ SWAP(int, pc->add_index, uc->active_point);
+ }
+}
+
+static void paintcurve_undo_delete(ListBase *lb)
+{
+ UndoCurve *uc;
+ uc = (UndoCurve *)lb->first;
+
+ if (uc->points)
+ MEM_freeN(uc->points);
+ uc->points = NULL;
+}
+
+
+static void paintcurve_undo_begin(bContext *C, wmOperator *op, PaintCurve *pc)
+{
+ PaintMode mode = BKE_paintmode_get_active_from_context(C);
+ ListBase *lb = NULL;
+ int undo_stack_id;
+ UndoCurve *uc;
+
+ switch (mode) {
+ case PAINT_TEXTURE_2D:
+ case PAINT_TEXTURE_PROJECTIVE:
+ undo_stack_id = UNDO_PAINT_IMAGE;
+ break;
+
+ case PAINT_SCULPT:
+ undo_stack_id = UNDO_PAINT_MESH;
+ break;
+
+ default:
+ /* do nothing, undo is handled by global */
+ return;
+ }
+
+
+ ED_undo_paint_push_begin(undo_stack_id, op->type->name,
+ paintcurve_undo_restore, paintcurve_undo_delete, NULL);
+ lb = undo_paint_push_get_list(undo_stack_id);
+
+ uc = MEM_callocN(sizeof(*uc), "Undo_curve");
+
+ lb->first = uc;
+
+ BLI_strncpy(uc->idname, pc->id.name, sizeof(uc->idname));
+ uc->tot_points = pc->tot_points;
+ uc->active_point = pc->add_index;
+ uc->points = MEM_dupallocN(pc->points);
+
+ undo_paint_push_count_alloc(undo_stack_id, sizeof(*uc) + sizeof(*pc->points) * pc->tot_points);
+
+ ED_undo_paint_push_end(undo_stack_id);
+}
+#define SEL_F1 (1 << 0)
+#define SEL_F2 (1 << 1)
+#define SEL_F3 (1 << 2)
+
+/* returns 0, 1, or 2 in point according to handle 1, pivot or handle 2 */
+static PaintCurvePoint *paintcurve_point_get_closest(PaintCurve *pc, const float pos[2], bool ignore_pivot, const float threshold, char *point)
+{
+ PaintCurvePoint *pcp, *closest = NULL;
+ int i;
+ float dist, closest_dist = FLT_MAX;
+
+ for (i = 0, pcp = pc->points; i < pc->tot_points; i++, pcp++) {
+ dist = len_manhattan_v2v2(pos, pcp->bez.vec[0]);
+ if (dist < threshold) {
+ if (dist < closest_dist) {
+ closest = pcp;
+ closest_dist = dist;
+ if (point)
+ *point = SEL_F1;
+ }
+ }
+ if (!ignore_pivot) {
+ dist = len_manhattan_v2v2(pos, pcp->bez.vec[1]);
+ if (dist < threshold) {
+ if (dist < closest_dist) {
+ closest = pcp;
+ closest_dist = dist;
+ if (point)
+ *point = SEL_F2;
+ }
+ }
+ }
+ dist = len_manhattan_v2v2(pos, pcp->bez.vec[2]);
+ if (dist < threshold) {
+ if (dist < closest_dist) {
+ closest = pcp;
+ closest_dist = dist;
+ if (point)
+ *point = SEL_F3;
+ }
+ }
+ }
+
+ return closest;
+}
+
+static int paintcurve_point_co_index(char sel)
+{
+ char i = 0;
+ while (sel != 1) {
+ sel >>= 1;
+ i++;
+ }
+ return i;
+}
+
+/******************* Operators *********************************/
+
+static int paintcurve_new_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Paint *p = BKE_paint_get_active_from_context(C);
+ Main *bmain = CTX_data_main(C);
+
+ if (p && p->brush) {
+ p->brush->paint_curve = BKE_paint_curve_add(bmain, "PaintCurve");
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void PAINTCURVE_OT_new(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add New Paint Curve";
+ ot->description = "Add new paint curve";
+ ot->idname = "PAINTCURVE_OT_new";
+
+ /* api callbacks */
+ ot->exec = paintcurve_new_exec;
+ ot->poll = paint_curve_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static void paintcurve_point_add(bContext *C, wmOperator *op, const int loc[2])
+{
+ Paint *p = BKE_paint_get_active_from_context(C);
+ Brush *br = p->brush;
+ Main *bmain = CTX_data_main(C);
+ PaintCurve *pc;
+ PaintCurvePoint *pcp;
+ wmWindow *window = CTX_wm_window(C);
+ ARegion *ar = CTX_wm_region(C);
+ float vec[3] = {loc[0], loc[1], 0.0};
+ int add_index;
+ int i;
+
+ pc = br->paint_curve;
+ if (!pc) {
+ br->paint_curve = pc = BKE_paint_curve_add(bmain, "PaintCurve");
+ }
+
+ paintcurve_undo_begin(C, op, pc);
+
+ pcp = MEM_mallocN((pc->tot_points + 1) * sizeof(PaintCurvePoint), "PaintCurvePoint");
+ add_index = pc->add_index;
+
+ if (pc->points) {
+ if (add_index > 0)
+ memcpy(pcp, pc->points, add_index * sizeof(PaintCurvePoint));
+ if (add_index < pc->tot_points)
+ memcpy(pcp + add_index + 1, pc->points + add_index, (pc->tot_points - add_index) * sizeof(PaintCurvePoint));
+
+ MEM_freeN(pc->points);
+ }
+ pc->points = pcp;
+ pc->tot_points++;
+
+ /* initialize new point */
+ memset(&pcp[add_index], 0, sizeof(PaintCurvePoint));
+ copy_v3_v3(pcp[add_index].bez.vec[0], vec);
+ copy_v3_v3(pcp[add_index].bez.vec[1], vec);
+ copy_v3_v3(pcp[add_index].bez.vec[2], vec);
+
+ /* last step, clear selection from all bezier handles expect the next */
+ for (i = 0; i < pc->tot_points; i++) {
+ pcp[i].bez.f1 = pcp[i].bez.f2 = pcp[i].bez.f3 = 0;
+ }
+ pcp[add_index].bez.f3 = SELECT;
+ pcp[add_index].bez.h2 = HD_ALIGN;
+
+ pc->add_index = add_index + 1;
+
+ WM_paint_cursor_tag_redraw(window, ar);
+}
+
+
+static int paintcurve_add_point_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ int loc[2] = {event->mval[0], event->mval[1]};
+ paintcurve_point_add(C, op, loc);
+ RNA_int_set_array(op->ptr, "location", loc);
+ return OPERATOR_FINISHED;
+}
+
+static int paintcurve_add_point_exec(bContext *C, wmOperator *op)
+{
+ int loc[2];
+
+ if (RNA_struct_property_is_set(op->ptr, "location")) {
+ RNA_int_get_array(op->ptr, "location", loc);
+ paintcurve_point_add(C, op, loc);
+ return OPERATOR_FINISHED;
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+void PAINTCURVE_OT_add_point(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add New Paint Curve Point";
+ ot->description = "Add new paint curve point";
+ ot->idname = "PAINTCURVE_OT_add_point";
+
+ /* api callbacks */
+ ot->invoke = paintcurve_add_point_invoke;
+ ot->exec = paintcurve_add_point_exec;
+ ot->poll = paint_curve_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
+
+ /* properties */
+ RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, SHRT_MAX,
+ "Location", "Location of vertex in area space", 0, SHRT_MAX);
+}
+
+static int paintcurve_delete_point_exec(bContext *C, wmOperator *op)
+{
+ Paint *p = BKE_paint_get_active_from_context(C);
+ Brush *br = p->brush;
+ PaintCurve *pc;
+ PaintCurvePoint *pcp;
+ wmWindow *window = CTX_wm_window(C);
+ ARegion *ar = CTX_wm_region(C);
+ int i;
+ int tot_del = 0;
+ pc = br->paint_curve;
+
+ if (!pc || pc->tot_points == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ paintcurve_undo_begin(C, op, pc);
+
+#define DELETE_TAG 2
+
+ for (i = 0, pcp = pc->points; i < pc->tot_points; i++, pcp++) {
+ if ((pcp->bez.f1 & SELECT) || (pcp->bez.f2 & SELECT) || (pcp->bez.f3 & SELECT)) {
+ pcp->bez.f2 |= DELETE_TAG;
+ tot_del++;
+ }
+ }
+
+ if (tot_del > 0) {
+ int j = 0;
+ int new_tot = pc->tot_points - tot_del;
+ PaintCurvePoint *points_new = NULL;
+ if (new_tot > 0)
+ points_new = MEM_mallocN(new_tot * sizeof(PaintCurvePoint), "PaintCurvePoint");
+
+ for (i = 0, pcp = pc->points; i < pc->tot_points; i++, pcp++) {
+ if (!(pcp->bez.f2 & DELETE_TAG)) {
+ points_new[j] = pc->points[i];
+
+ if ((i + 1) == pc->add_index) {
+ pc->add_index = j + 1;
+ }
+ j++;
+ }
+ else if ((i + 1) == pc->add_index) {
+ /* prefer previous point */
+ pc->add_index = j;
+ }
+ }
+ MEM_freeN(pc->points);
+
+ pc->points = points_new;
+ pc->tot_points = new_tot;
+ }
+
+#undef DELETE_TAG
+
+ WM_paint_cursor_tag_redraw(window, ar);
+
+ return OPERATOR_FINISHED;
+}
+
+
+void PAINTCURVE_OT_delete_point(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add New Paint Curve Point";
+ ot->description = "Add new paint curve point";
+ ot->idname = "PAINTCURVE_OT_delete_point";
+
+ /* api callbacks */
+ ot->exec = paintcurve_delete_point_exec;
+ ot->poll = paint_curve_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+}
+
+
+static bool paintcurve_point_select(bContext *C, wmOperator *op, const int loc[2], bool toggle, bool extend)
+{
+ wmWindow *window = CTX_wm_window(C);
+ ARegion *ar = CTX_wm_region(C);
+ Paint *p = BKE_paint_get_active_from_context(C);
+ Brush *br = p->brush;
+ PaintCurve *pc;
+ PaintCurvePoint *pcp;
+ int i;
+ const float loc_fl[2] = {UNPACK2(loc)};
+
+ pc = br->paint_curve;
+
+ if (!pc)
+ return false;
+
+ paintcurve_undo_begin(C, op, pc);
+
+ pcp = pc->points;
+
+ if (toggle) {
+ char select = 0;
+ bool selected = false;
+
+ for (i = 0; i < pc->tot_points; i++) {
+ if (pcp[i].bez.f1 || pcp[i].bez.f2 || pcp[i].bez.f3) {
+ selected = true;
+ break;
+ }
+ }
+
+ if (!selected) {
+ select = SELECT;
+ }
+
+ for (i = 0; i < pc->tot_points; i++) {
+ pc->points[i].bez.f1 = pc->points[i].bez.f2 = pc->points[i].bez.f3 = select;
+ }
+ }
+ else {
+ PaintCurvePoint *pcp;
+ char selflag;
+
+ pcp = paintcurve_point_get_closest(pc, loc_fl, false, PAINT_CURVE_SELECT_THRESHOLD, &selflag);
+
+ if (pcp) {
+ pc->add_index = (pcp - pc->points) + 1;
+
+ if (selflag == SEL_F2) {
+ if (extend)
+ pcp->bez.f2 ^= SELECT;
+ else
+ pcp->bez.f2 |= SELECT;
+ }
+ else if (selflag == SEL_F1) {
+ if (extend)
+ pcp->bez.f1 ^= SELECT;
+ else
+ pcp->bez.f1 |= SELECT;
+ }
+ else if (selflag == SEL_F3) {
+ if (extend)
+ pcp->bez.f3 ^= SELECT;
+ else
+ pcp->bez.f3 |= SELECT;
+ }
+ }
+
+ /* clear selection for unselected points if not extending and if a point has been selected */
+ if (!extend && pcp) {
+ for (i = 0; i < pc->tot_points; i++) {
+ pc->points[i].bez.f1 = pc->points[i].bez.f2 = pc->points[i].bez.f3 = 0;
+
+ if ((pc->points + i) == pcp) {
+ char index = paintcurve_point_co_index(selflag);
+ PAINT_CURVE_POINT_SELECT(pcp, index);
+ }
+ }
+ }
+
+ if (!pcp)
+ return false;
+ }
+
+ WM_paint_cursor_tag_redraw(window, ar);
+
+ return true;
+}
+
+
+static int paintcurve_select_point_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ int loc[2] = {UNPACK2(event->mval)};
+ bool toggle = RNA_boolean_get(op->ptr, "toggle");
+ bool extend = RNA_boolean_get(op->ptr, "extend");
+ if (paintcurve_point_select(C, op, loc, toggle, extend)) {
+ RNA_int_set_array(op->ptr, "location", loc);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static int paintcurve_select_point_exec(bContext *C, wmOperator *op)
+{
+ int loc[2];
+
+ if (RNA_struct_property_is_set(op->ptr, "location")) {
+ bool toggle = RNA_boolean_get(op->ptr, "toggle");
+ bool extend = RNA_boolean_get(op->ptr, "extend");
+ RNA_int_get_array(op->ptr, "location", loc);
+ if (paintcurve_point_select(C, op, loc, toggle, extend))
+ return OPERATOR_FINISHED;
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+void PAINTCURVE_OT_select(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Select Paint Curve Point";
+ ot->description = "Select a paint curve point";
+ ot->idname = "PAINTCURVE_OT_select";
+
+ /* api callbacks */
+ ot->invoke = paintcurve_select_point_invoke;
+ ot->exec = paintcurve_select_point_exec;
+ ot->poll = paint_curve_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
+
+ /* properties */
+ RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, SHRT_MAX,
+ "Location", "Location of vertex in area space", 0, SHRT_MAX);
+ prop = RNA_def_boolean(ot->srna, "toggle", false, "Toggle", "(De)select all");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
+typedef struct PointSlideData {
+ PaintCurvePoint *pcp;
+ char select;
+ int initial_loc[2];
+ float point_initial_loc[3][2];
+ int event;
+ bool align;
+} PointSlideData;
+
+static int paintcurve_slide_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Paint *p = BKE_paint_get_active_from_context(C);
+ const float loc_fl[2] = {UNPACK2(event->mval)};
+ char select;
+ int i;
+ bool do_select = RNA_boolean_get(op->ptr, "select");
+ bool align = RNA_boolean_get(op->ptr, "align");
+ Brush *br = p->brush;
+ PaintCurve *pc = br->paint_curve;
+ PaintCurvePoint *pcp;
+
+ if (!pc)
+ return OPERATOR_PASS_THROUGH;
+
+ if (do_select) {
+ pcp = paintcurve_point_get_closest(pc, loc_fl, align, PAINT_CURVE_SELECT_THRESHOLD, &select);
+ }
+ else {
+ pcp = NULL;
+ /* just find first selected point */
+ for (i = 0; i < pc->tot_points; i++) {
+ if (pc->points[i].bez.f1 || pc->points[i].bez.f2 || pc->points[i].bez.f3) {
+ pcp = &pc->points[i];
+ select = SEL_F3;
+ break;
+ }
+ }
+ }
+
+
+ if (pcp) {
+ ARegion *ar = CTX_wm_region(C);
+ wmWindow *window = CTX_wm_window(C);
+ PointSlideData *psd = MEM_mallocN(sizeof(PointSlideData), "PointSlideData");
+ copy_v2_v2_int(psd->initial_loc, event->mval);
+ psd->event = event->type;
+ psd->pcp = pcp;
+ psd->select = paintcurve_point_co_index(select);
+ for (i = 0; i < 3; i++) {
+ copy_v2_v2(psd->point_initial_loc[i], pcp->bez.vec[i]);
+ }
+ psd->align = align;
+ op->customdata = psd;
+
+ if (do_select)
+ paintcurve_undo_begin(C, op, pc);
+
+ /* first, clear all selection from points */
+ for (i = 0; i < pc->tot_points; i++)
+ pc->points[i].bez.f1 = pc->points[i].bez.f3 = pc->points[i].bez.f2 = 0;
+
+ /* only select the active point */
+ PAINT_CURVE_POINT_SELECT(pcp, psd->select);
+ pc->add_index = (pcp - pc->points) + 1;
+
+ WM_event_add_modal_handler(C, op);
+ WM_paint_cursor_tag_redraw(window, ar);
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ return OPERATOR_PASS_THROUGH;
+}
+
+static int paintcurve_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ PointSlideData *psd = op->customdata;
+
+ if (event->type == psd->event && event->val == KM_RELEASE) {
+ MEM_freeN(psd);
+ return OPERATOR_FINISHED;
+ }
+
+ switch (event->type) {
+ case MOUSEMOVE:
+ {
+ ARegion *ar = CTX_wm_region(C);
+ wmWindow *window = CTX_wm_window(C);
+ float diff[2] = {event->mval[0] - psd->initial_loc[0],
+ event->mval[1] - psd->initial_loc[1]};
+ if (psd->select == 1) {
+ int i;
+ for (i = 0; i < 3; i++)
+ add_v2_v2v2(psd->pcp->bez.vec[i], diff, psd->point_initial_loc[i]);
+ }
+ else {
+ add_v2_v2(diff, psd->point_initial_loc[psd->select]);
+ copy_v2_v2(psd->pcp->bez.vec[psd->select], diff);
+
+ if (psd->align) {
+ char opposite = (psd->select == 0) ? 2 : 0;
+ sub_v2_v2v2(diff, psd->pcp->bez.vec[1], psd->pcp->bez.vec[psd->select]);
+ add_v2_v2v2(psd->pcp->bez.vec[opposite], psd->pcp->bez.vec[1], diff);
+ }
+ }
+ WM_paint_cursor_tag_redraw(window, ar);
+ break;
+ }
+ default:
+ break;
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+
+void PAINTCURVE_OT_slide(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Slide Paint Curve Point";
+ ot->description = "Select and slide paint curve point";
+ ot->idname = "PAINTCURVE_OT_slide";
+
+ /* api callbacks */
+ ot->invoke = paintcurve_slide_invoke;
+ ot->modal = paintcurve_slide_modal;
+ ot->poll = paint_curve_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "align", false, "Align Handles", "Aligns opposite point handle during transform");
+ RNA_def_boolean(ot->srna, "select", true, "Select", "Attempt to select a point handle before transform");
+}
+
+static int paintcurve_draw_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ PaintMode mode = BKE_paintmode_get_active_from_context(C);
+ const char *name;
+
+ switch (mode) {
+ case PAINT_TEXTURE_2D:
+ case PAINT_TEXTURE_PROJECTIVE:
+ name = "PAINT_OT_image_paint";
+ break;
+ case PAINT_WEIGHT:
+ name = "PAINT_OT_weight_paint";
+ break;
+ case PAINT_VERTEX:
+ name = "PAINT_OT_vertex_paint";
+ break;
+ case PAINT_SCULPT:
+ name = "SCULPT_OT_brush_stroke";
+ break;
+ default:
+ return OPERATOR_PASS_THROUGH;
+ }
+
+ return WM_operator_name_call(C, name, WM_OP_INVOKE_DEFAULT, NULL);
+}
+
+void PAINTCURVE_OT_draw(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Draw Curve";
+ ot->description = "Draw curve";
+ ot->idname = "PAINTCURVE_OT_draw";
+
+ /* api callbacks */
+ ot->exec = paintcurve_draw_exec;
+ ot->poll = paint_curve_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+}
+
+static int paintcurve_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ op->customdata = SET_INT_IN_POINTER(event->type);
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int paintcurve_cursor_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ if (event->type == GET_INT_FROM_POINTER(op->customdata) && event->val == KM_RELEASE)
+ return OPERATOR_FINISHED;
+
+ if (event->type == MOUSEMOVE) {
+ PaintMode mode = BKE_paintmode_get_active_from_context(C);
+
+ switch (mode) {
+ case PAINT_TEXTURE_2D:
+ {
+ ARegion *ar = CTX_wm_region(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ float location[2];
+
+ if (!sima)
+ return OPERATOR_CANCELLED;
+
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
+ copy_v2_v2(sima->cursor, location);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL);
+ break;
+ }
+ default:
+ ED_view3d_cursor3d_update(C, event->mval);
+ break;
+ }
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void PAINTCURVE_OT_cursor(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Place Cursor";
+ ot->description = "Place cursor";
+ ot->idname = "PAINTCURVE_OT_cursor";
+
+ /* api callbacks */
+ ot->invoke = paintcurve_cursor_invoke;
+ ot->modal = paintcurve_cursor_modal;
+ ot->poll = paint_curve_poll;
+
+ /* flags */
+ ot->flag = 0;
+}
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index 34232c51ff7..f1a2a8156d8 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -43,6 +43,7 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_threads.h"
#include "PIL_time.h"
@@ -59,15 +60,21 @@
#include "BKE_brush.h"
#include "BKE_image.h"
#include "BKE_main.h"
+#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_node.h"
#include "BKE_paint.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_texture.h"
+#include "BKE_colortools.h"
#include "BKE_editmesh.h"
#include "UI_view2d.h"
#include "ED_image.h"
+#include "ED_mesh.h"
#include "ED_object.h"
#include "ED_paint.h"
#include "ED_screen.h"
@@ -82,6 +89,9 @@
#include "GPU_draw.h"
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
#include "IMB_colormanagement.h"
#include "paint_intern.h"
@@ -102,14 +112,27 @@ typedef struct UndoImageTile {
int x, y;
+ Image *ima;
short source, use_float;
char gen_type;
+ bool valid;
} UndoImageTile;
/* this is a static resource for non-globality,
* Maybe it should be exposed as part of the
* paint operation, but for now just give a public interface */
static ImagePaintPartialRedraw imapaintpartial = {0, 0, 0, 0, 0};
+static SpinLock undolock;
+
+void image_undo_init_locks(void)
+{
+ BLI_spin_init(&undolock);
+}
+
+void image_undo_end_locks(void)
+{
+ BLI_spin_end(&undolock);
+}
ImagePaintPartialRedraw *get_imapaintpartial(void)
{
@@ -122,26 +145,53 @@ void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr)
}
/* UNDO */
+typedef enum {
+ COPY = 0,
+ RESTORE = 1,
+ RESTORE_COPY = 2
+} CopyMode;
-static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, int restore)
+static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, CopyMode mode)
{
- /* copy or swap contents of tile->rect and region in ibuf->rect */
- IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x * IMAPAINT_TILE_SIZE,
- tile->y * IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
+ if (mode == COPY) {
+ /* copy or swap contents of tile->rect and region in ibuf->rect */
+ IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x * IMAPAINT_TILE_SIZE,
+ tile->y * IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
- if (ibuf->rect_float) {
- SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
+ if (ibuf->rect_float) {
+ SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
+ }
+ else {
+ SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
+ }
}
else {
- SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
- }
-
- if (restore)
+ if (mode == RESTORE_COPY)
+ IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x * IMAPAINT_TILE_SIZE,
+ tile->y * IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
+ /* swap to the tmpbuf for easy copying */
+ if (ibuf->rect_float) {
+ SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
+ }
+ else {
+ SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
+ }
+
IMB_rectcpy(ibuf, tmpibuf, tile->x * IMAPAINT_TILE_SIZE,
tile->y * IMAPAINT_TILE_SIZE, 0, 0, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
+
+ if (mode == RESTORE) {
+ if (ibuf->rect_float) {
+ SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
+ }
+ else {
+ SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
+ }
+ }
+ }
}
-void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask)
+void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask, bool validate)
{
ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
UndoImageTile *tile;
@@ -160,6 +210,8 @@ void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsi
*mask = tile->mask;
}
+ if (validate)
+ tile->valid = true;
return tile->rect.pt;
}
@@ -170,7 +222,7 @@ void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsi
return NULL;
}
-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, unsigned short **mask, bool **valid, bool proj)
{
ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
UndoImageTile *tile;
@@ -179,10 +231,14 @@ void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile,
void *data;
/* check if tile is already pushed */
- data = image_undo_find_tile(ima, ibuf, x_tile, y_tile, NULL);
- if (data)
- return data;
-
+
+ /* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */
+ if (!proj) {
+ data = image_undo_find_tile(ima, ibuf, x_tile, y_tile, mask, true);
+ if (data)
+ return data;
+ }
+
if (*tmpibuf == NULL)
*tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect);
@@ -191,6 +247,11 @@ void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile,
tile->x = x_tile;
tile->y = y_tile;
+ /* add mask explicitly here */
+ if (mask)
+ *mask = tile->mask = MEM_callocN(sizeof(unsigned short) * IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE,
+ "UndoImageTile.mask");
+
allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4;
allocsize *= (ibuf->rect_float) ? sizeof(float) : sizeof(char);
tile->rect.pt = MEM_mapallocN(allocsize, "UndeImageTile.rect");
@@ -200,12 +261,23 @@ void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile,
tile->gen_type = ima->gen_type;
tile->source = ima->source;
tile->use_float = use_float;
+ tile->valid = true;
+ tile->ima = ima;
- undo_copy_tile(tile, *tmpibuf, ibuf, 0);
- undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, allocsize);
+ if (valid)
+ *valid = &tile->valid;
+
+ undo_copy_tile(tile, *tmpibuf, ibuf, COPY);
+
+ if (proj)
+ BLI_spin_lock(&undolock);
+ undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, allocsize);
BLI_addtail(lb, tile);
-
+
+ if (proj)
+ BLI_spin_unlock(&undolock);
+
return tile->rect.pt;
}
@@ -222,6 +294,33 @@ void image_undo_remove_masks(void)
}
}
+static void image_undo_restore_runtime(ListBase *lb)
+{
+ ImBuf *ibuf, *tmpibuf;
+ UndoImageTile *tile;
+
+ tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32,
+ IB_rectfloat | IB_rect);
+
+ for (tile = lb->first; tile; tile = tile->next) {
+ Image *ima = tile->ima;
+ ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+
+ undo_copy_tile(tile, tmpibuf, ibuf, RESTORE);
+
+ GPU_free_image(ima); /* force OpenGL reload (maybe partial update will operate better?) */
+ if (ibuf->rect_float)
+ ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
+ if (ibuf->mipmap[0])
+ ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */
+ ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
+
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ }
+
+ IMB_freeImBuf(tmpibuf);
+}
+
void ED_image_undo_restore(bContext *C, ListBase *lb)
{
Main *bmain = CTX_data_main(C);
@@ -273,7 +372,7 @@ void ED_image_undo_restore(bContext *C, ListBase *lb)
continue;
}
- undo_copy_tile(tile, tmpibuf, ibuf, 1);
+ undo_copy_tile(tile, tmpibuf, ibuf, RESTORE_COPY);
GPU_free_image(ima); /* force OpenGL reload */
if (ibuf->rect_float)
@@ -282,6 +381,8 @@ void ED_image_undo_restore(bContext *C, ListBase *lb)
ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
+ DAG_id_tag_update(&ima->id, 0);
+
BKE_image_release_ibuf(ima, ibuf, NULL);
}
@@ -296,6 +397,42 @@ void ED_image_undo_free(ListBase *lb)
MEM_freeN(tile->rect.pt);
}
+static void image_undo_end(void)
+{
+ ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
+ UndoImageTile *tile;
+ int deallocsize = 0;
+ int allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4;
+
+ /* first dispose of invalid tiles (may happen due to drag dot for instance) */
+ for (tile = lb->first; tile;) {
+ if (!tile->valid) {
+ UndoImageTile *tmp_tile = tile->next;
+ deallocsize += allocsize * ((tile->use_float) ? sizeof(float) : sizeof(char));
+ MEM_freeN(tile->rect.pt);
+ BLI_freelinkN (lb, tile);
+ tile = tmp_tile;
+ }
+ else {
+ tile = tile->next;
+ }
+ }
+
+ /* don't forget to remove the size of deallocated tiles */
+ undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, -deallocsize);
+
+ ED_undo_paint_push_end(UNDO_PAINT_IMAGE);
+}
+
+static void image_undo_invalidate(void)
+{
+ UndoImageTile *tile;
+ ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
+
+ for (tile = lb->first; tile; tile = tile->next)
+ tile->valid = false;
+}
+
/* Imagepaint Partial Redraw & Dirty Region */
void ED_imapaint_clear_partial_redraw(void)
@@ -344,7 +481,7 @@ void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int
for (ty = tiley; ty <= tileh; ty++)
for (tx = tilex; tx <= tilew; tx++)
- image_undo_push_tile(ima, ibuf, &tmpibuf, tx, ty);
+ image_undo_push_tile(ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false);
ibuf->userflags |= IB_BITMAPDIRTY;
@@ -373,6 +510,70 @@ void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short te
}
}
+/* paint blur kernels */
+BlurKernel *paint_new_blur_kernel(Brush *br)
+{
+ int i, j;
+ BlurKernel *kernel = MEM_mallocN(sizeof(BlurKernel), "blur kernel");
+ int pixel_len = br->blur_kernel_radius;
+ BlurKernelType type = br->blur_mode;
+
+ kernel->side = pixel_len * 2 + 1;
+ kernel->side_squared = kernel->side * kernel->side;
+ kernel->wdata = MEM_mallocN(sizeof(float) * kernel->side_squared, "blur kernel data");
+ kernel->pixel_len = pixel_len;
+
+ switch (type) {
+ case KERNEL_BOX:
+ for (i = 0; i < kernel->side_squared; i++)
+ kernel->wdata[i] = 1.0;
+ break;
+
+ case KERNEL_GAUSSIAN:
+ {
+ float standard_dev = pixel_len / 3.0; /* at standard deviation of 3.0 kernel is at about zero */
+ int i_term = pixel_len + 1;
+
+ /* make the necessary adjustment to the value for use in the normal distribution formula */
+ standard_dev = standard_dev * standard_dev * 2;
+
+ kernel->wdata[pixel_len + pixel_len * kernel->side] = 1.0;
+ /* fill in all four quadrants at once */
+ for (i = 0; i < i_term; i++) {
+ for (j = 0; j < pixel_len; j++) {
+ float idist = pixel_len - i;
+ float jdist = pixel_len - j;
+
+ float value = exp((idist * idist + jdist * jdist) / standard_dev);
+
+ kernel->wdata[i + j * kernel->side] =
+ kernel->wdata[(kernel->side - j - 1) + i * kernel->side] =
+ kernel->wdata[(kernel->side - i - 1) + (kernel->side - j - 1) * kernel->side] =
+ kernel->wdata[j + (kernel->side - i - 1) * kernel->side] =
+ value;
+ }
+ }
+
+ break;
+ }
+
+ default:
+ printf("unidentified kernel type, aborting\n");
+ MEM_freeN(kernel->wdata);
+ MEM_freeN(kernel);
+ return NULL;
+ break;
+ }
+
+ return kernel;
+}
+
+void paint_delete_blur_kernel(BlurKernel *kernel)
+{
+ if (kernel->wdata)
+ MEM_freeN(kernel->wdata);
+}
+
/************************ image paint poll ************************/
static Brush *image_paint_brush(bContext *C)
@@ -432,11 +633,57 @@ typedef struct PaintOperation {
void *custom_paint;
float prevmouse[2];
+ float startmouse[2];
double starttime;
+ void *cursor;
ViewContext vc;
} PaintOperation;
+bool paint_use_opacity_masking(Brush *brush)
+{
+ return (brush->flag & BRUSH_AIRBRUSH) ||
+ (brush->flag & BRUSH_DRAG_DOT) ||
+ (brush->flag & BRUSH_ANCHORED) ||
+ (brush->imagepaint_tool == PAINT_TOOL_SMEAR) ||
+ (brush->imagepaint_tool == PAINT_TOOL_SOFTEN) ||
+ (brush->imagepaint_tool == PAINT_TOOL_FILL) ||
+ (brush->flag & BRUSH_USE_GRADIENT) ||
+ (brush->mtex.tex && !ELEM(brush->mtex.brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL, MTEX_MAP_MODE_3D)) ?
+ false : true;
+}
+
+void paint_brush_color_get(struct Scene *scene, struct Brush *br, bool color_correction, bool invert, float distance,
+ float pressure, float color[3], struct ColorManagedDisplay *display)
+{
+ if (invert)
+ copy_v3_v3(color, BKE_brush_secondary_color_get(scene, br));
+ else {
+ if (br->flag & BRUSH_USE_GRADIENT) {
+ switch (br->gradient_stroke_mode) {
+ case BRUSH_GRADIENT_PRESSURE:
+ do_colorband(br->gradient, pressure, color);
+ break;
+ case BRUSH_GRADIENT_SPACING_REPEAT:
+ {
+ float coord = fmod(distance / br->gradient_spacing, 1.0);
+ do_colorband(br->gradient, coord, color);
+ break;
+ }
+ case BRUSH_GRADIENT_SPACING_CLAMP:
+ {
+ do_colorband(br->gradient, distance / br->gradient_spacing, color);
+ break;
+ }
+ }
+ }
+ else
+ copy_v3_v3(color, BKE_brush_color_get(scene, br));
+ }
+ if (color_correction)
+ IMB_colormanagement_display_to_scene_linear_v3(color, display);
+}
+
void paint_brush_init_tex(Brush *brush)
{
/* init mtex nodes */
@@ -462,26 +709,54 @@ void paint_brush_exit_tex(Brush *brush)
}
}
+static void gradient_draw_line(bContext *UNUSED(C), int x, int y, void *customdata)
+{
+ PaintOperation *pop = (PaintOperation *)customdata;
+
+ if (pop) {
+ glEnable(GL_LINE_SMOOTH);
+ glEnable(GL_BLEND);
+
+ glLineWidth(4.0);
+ glColor4ub(0, 0, 0, 255);
+ sdrawline(x, y, pop->startmouse[0], pop->startmouse[1]);
+ glLineWidth(2.0);
+ glColor4ub(255, 255, 255, 255);
+ sdrawline(x, y, pop->startmouse[0], pop->startmouse[1]);
+ glLineWidth(1.0);
+
+ glDisable(GL_BLEND);
+ glDisable(GL_LINE_SMOOTH);
+ }
+}
+
-static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, float mouse[2])
+static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const float mouse[2])
{
Scene *scene = CTX_data_scene(C);
ToolSettings *settings = scene->toolsettings;
PaintOperation *pop = MEM_callocN(sizeof(PaintOperation), "PaintOperation"); /* caller frees */
+ Brush *brush = BKE_paint_brush(&settings->imapaint.paint);
int mode = RNA_enum_get(op->ptr, "mode");
view3d_set_viewcontext(C, &pop->vc);
- pop->prevmouse[0] = mouse[0];
- pop->prevmouse[1] = mouse[1];
+ copy_v2_v2(pop->prevmouse, mouse);
+ copy_v2_v2(pop->startmouse, mouse);
+
+ if ((brush->imagepaint_tool == PAINT_TOOL_FILL) && (brush->flag & BRUSH_USE_GRADIENT)) {
+ pop->cursor = WM_paint_cursor_activate(CTX_wm_manager(C), image_paint_poll, gradient_draw_line, pop);
+ }
/* initialize from context */
if (CTX_wm_region_view3d(C)) {
+ Object *ob = OBACT;
+ paint_proj_mesh_data_ensure(C, ob, op);
pop->mode = PAINT_MODE_3D_PROJECT;
- pop->custom_paint = paint_proj_new_stroke(C, OBACT, pop->prevmouse, mode);
+ pop->custom_paint = paint_proj_new_stroke(C, ob, mouse, mode);
}
else {
pop->mode = PAINT_MODE_2D;
- pop->custom_paint = paint_2d_new_stroke(C, op);
+ pop->custom_paint = paint_2d_new_stroke(C, op, mode);
}
if (!pop->custom_paint) {
@@ -491,52 +766,69 @@ static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, float mou
settings->imapaint.flag |= IMAGEPAINT_DRAWING;
ED_undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name,
- ED_image_undo_restore, ED_image_undo_free);
-
- {
- UnifiedPaintSettings *ups = &settings->unified_paint_settings;
- ups->stroke_active = true;
- }
+ ED_image_undo_restore, ED_image_undo_free, NULL);
return pop;
}
+/* restore painting image to previous state. Used for anchored and drag-dot style brushes*/
+static void paint_stroke_restore(void)
+{
+ ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
+ image_undo_restore_runtime(lb);
+ image_undo_invalidate();
+}
+
static void paint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
{
PaintOperation *pop = paint_stroke_mode_data(stroke);
Scene *scene = CTX_data_scene(C);
- Brush *brush = BKE_paint_brush(&scene->toolsettings->imapaint.paint);
+ ToolSettings *toolsettings = CTX_data_tool_settings(C);
+ UnifiedPaintSettings *ups = &toolsettings->unified_paint_settings;
+ Brush *brush = BKE_paint_brush(&toolsettings->imapaint.paint);
+
+ float alphafac = (brush->flag & BRUSH_ACCUMULATE) ? ups->overlap_factor : 1.0f;
/* initial brush values. Maybe it should be considered moving these to stroke system */
- float startsize = (float)BKE_brush_size_get(scene, brush);
float startalpha = BKE_brush_alpha_get(scene, brush);
float mouse[2];
float pressure;
+ float size;
+ float distance = paint_stroke_distance_get(stroke);
int eraser;
RNA_float_get_array(itemptr, "mouse", mouse);
pressure = RNA_float_get(itemptr, "pressure");
eraser = RNA_boolean_get(itemptr, "pen_flip");
+ size = max_ff(1.0f, RNA_float_get(itemptr, "size"));
+
+ /* stroking with fill tool only acts on stroke end */
+ if (brush->imagepaint_tool == PAINT_TOOL_FILL) {
+ copy_v2_v2(pop->prevmouse, mouse);
+ return;
+ }
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, (int)max_ff(1.0f, startsize * pressure));
+ BKE_brush_alpha_set(scene, brush, max_ff(0.0f, startalpha * pressure * alphafac));
+ else
+ BKE_brush_alpha_set(scene, brush, max_ff(0.0f, startalpha * alphafac));
+
+ if ((brush->flag & BRUSH_DRAG_DOT) || (brush->flag & BRUSH_ANCHORED)) {
+ paint_stroke_restore();
+ }
if (pop->mode == PAINT_MODE_3D_PROJECT) {
- paint_proj_stroke(C, pop->custom_paint, pop->prevmouse, mouse);
+ paint_proj_stroke(C, pop->custom_paint, pop->prevmouse, mouse, pressure, distance, size);
}
else {
- paint_2d_stroke(pop->custom_paint, pop->prevmouse, mouse, eraser);
+ paint_2d_stroke(pop->custom_paint, pop->prevmouse, mouse, eraser, pressure, distance, size);
}
- pop->prevmouse[0] = mouse[0];
- pop->prevmouse[1] = mouse[1];
+ copy_v2_v2(pop->prevmouse, mouse);
/* restore brush values */
BKE_brush_alpha_set(scene, brush, startalpha);
- BKE_brush_size_set(scene, brush, startsize);
}
static void paint_stroke_redraw(const bContext *C, struct PaintStroke *stroke, bool final)
@@ -554,11 +846,39 @@ static void paint_stroke_redraw(const bContext *C, struct PaintStroke *stroke, b
static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke)
{
Scene *scene = CTX_data_scene(C);
- ToolSettings *settings = scene->toolsettings;
+ ToolSettings *toolsettings = scene->toolsettings;
PaintOperation *pop = paint_stroke_mode_data(stroke);
+ Brush *brush = BKE_paint_brush(&toolsettings->imapaint.paint);
- settings->imapaint.flag &= ~IMAGEPAINT_DRAWING;
+ toolsettings->imapaint.flag &= ~IMAGEPAINT_DRAWING;
+ if (brush->imagepaint_tool == PAINT_TOOL_FILL) {
+ if (brush->flag & BRUSH_USE_GRADIENT) {
+ if (pop->mode == PAINT_MODE_2D) {
+ paint_2d_gradient_fill(C, brush, pop->startmouse, pop->prevmouse, pop->custom_paint);
+ }
+ else {
+ paint_proj_stroke(C, pop->custom_paint, pop->startmouse, pop->prevmouse, 1.0, 0.0, BKE_brush_size_get(scene, brush));
+ /* two redraws, one for GPU update, one for notification */
+ paint_proj_redraw(C, pop->custom_paint, false);
+ paint_proj_redraw(C, pop->custom_paint, true);
+ }
+ }
+ else {
+ if (pop->mode == PAINT_MODE_2D) {
+ float color[3];
+
+ srgb_to_linearrgb_v3_v3(color, BKE_brush_color_get(scene, brush));
+ paint_2d_bucket_fill(C, color, brush, pop->prevmouse, pop->custom_paint);
+ }
+ else {
+ paint_proj_stroke(C, pop->custom_paint, pop->startmouse, pop->prevmouse, 1.0, 0.0, BKE_brush_size_get(scene, brush));
+ /* two redraws, one for GPU update, one for notification */
+ paint_proj_redraw(C, pop->custom_paint, false);
+ paint_proj_redraw(C, pop->custom_paint, true);
+ }
+ }
+ }
if (pop->mode == PAINT_MODE_3D_PROJECT) {
paint_proj_stroke_done(pop->custom_paint);
}
@@ -566,7 +886,11 @@ static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke)
paint_2d_stroke_done(pop->custom_paint);
}
- ED_undo_paint_push_end(UNDO_PAINT_IMAGE);
+ if (pop->cursor) {
+ WM_paint_cursor_end(CTX_wm_manager(C), pop->cursor);
+ }
+
+ image_undo_end();
/* duplicate warning, see texpaint_init */
#if 0
@@ -576,43 +900,41 @@ static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke)
BKE_reportf(op->reports, RPT_WARNING, "Packed MultiLayer files cannot be painted: %s", pop->s.warnpackedfile);
#endif
MEM_freeN(pop);
-
- {
- UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
- ups->stroke_active = false;
- }
-}
-
-static bool paint_stroke_test_start(bContext *UNUSED(C), wmOperator *UNUSED(op), const float UNUSED(mouse[2]))
-{
- return true;
}
-
-static int paint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static bool paint_stroke_test_start(bContext *C, wmOperator *op, const float mouse[2])
{
PaintOperation *pop;
- float mouse[2];
- int retval;
/* TODO Should avoid putting this here. Instead, last position should be requested
* from stroke system. */
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
if (!(pop = texture_paint_init(C, op, mouse))) {
- return OPERATOR_CANCELLED;
+ return false;
}
- op->customdata = paint_stroke_new(C, NULL, paint_stroke_test_start,
+ paint_stroke_set_mode_data(op->customdata, pop);
+
+ return true;
+}
+
+
+static int paint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ int retval;
+
+ op->customdata = paint_stroke_new(C, op, NULL, paint_stroke_test_start,
paint_stroke_update_step,
paint_stroke_redraw,
paint_stroke_done, event->type);
- paint_stroke_set_mode_data(op->customdata, pop);
+
+ if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
+ paint_stroke_data_free(op);
+ return OPERATOR_FINISHED;
+ }
/* add modal handler */
WM_event_add_modal_handler(C, op);
- retval = op->type->modal(C, op, event);
OPERATOR_RETVAL_CHECK(retval);
BLI_assert(retval == OPERATOR_RUNNING_MODAL);
@@ -637,12 +959,10 @@ static int paint_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- op->customdata = paint_stroke_new(C, NULL, paint_stroke_test_start,
+ op->customdata = paint_stroke_new(C, op, NULL, paint_stroke_test_start,
paint_stroke_update_step,
paint_stroke_redraw,
paint_stroke_done, 0);
- paint_stroke_set_mode_data(op->customdata, pop);
-
/* frees op->customdata */
paint_stroke_exec(C, op);
@@ -686,9 +1006,9 @@ int get_imapaint_zoom(bContext *C, float *zoomx, float *zoomy)
if (!rv3d) {
SpaceImage *sima = CTX_wm_space_image(C);
- ARegion *ar = CTX_wm_region(C);
if (sima->mode == SI_MODE_PAINT) {
+ ARegion *ar = CTX_wm_region(C);
ED_space_image_get_zoom(sima, ar, zoomx, zoomy);
return 1;
@@ -847,17 +1167,39 @@ void PAINT_OT_grab_clone(wmOperatorType *ot)
typedef struct {
bool show_cursor;
short event_type;
-} SampleColorData;
+ float initcolor[3];
+ bool sample_palette;
+} SampleColorData;
+
+
+static void sample_color_update_header(SampleColorData *data, bContext *C)
+{
+#define HEADER_LENGTH 150
+ char msg[HEADER_LENGTH];
+ ScrArea *sa = CTX_wm_area(C);
+
+ if (sa) {
+ BLI_snprintf(msg, HEADER_LENGTH,
+ "Sample color for %s",
+ !data->sample_palette ?
+ "Brush. Use Left Click to sample for palette instead" :
+ "Palette. Use Left Click to sample more colors");
+ ED_area_headerprint(sa, msg);
+ }
+
+#undef HEADER_LENGTH
+}
static int sample_color_exec(bContext *C, wmOperator *op)
{
Paint *paint = BKE_paint_get_active_from_context(C);
Brush *brush = BKE_paint_brush(paint);
+ PaintMode mode = BKE_paintmode_get_active_from_context(C);
ARegion *ar = CTX_wm_region(C);
wmWindow *win = CTX_wm_window(C);
bool show_cursor = ((paint->flags & PAINT_SHOW_BRUSH) != 0);
int location[2];
-
+ bool use_palette;
paint->flags &= ~PAINT_SHOW_BRUSH;
/* force redraw without cursor */
@@ -865,7 +1207,9 @@ static int sample_color_exec(bContext *C, wmOperator *op)
WM_redraw_windows(C);
RNA_int_get_array(op->ptr, "location", location);
- paint_sample_color(C, ar, location[0], location[1]);
+ use_palette = RNA_boolean_get(op->ptr, "palette");
+
+ paint_sample_color(C, ar, location[0], location[1], mode == PAINT_TEXTURE_PROJECTIVE, use_palette);
if (show_cursor) {
paint->flags |= PAINT_SHOW_BRUSH;
@@ -878,7 +1222,9 @@ static int sample_color_exec(bContext *C, wmOperator *op)
static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ Scene *scene = CTX_data_scene(C);
Paint *paint = BKE_paint_get_active_from_context(C);
+ PaintMode mode = BKE_paintmode_get_active_from_context(C);
Brush *brush = BKE_paint_brush(paint);
SampleColorData *data = MEM_mallocN(sizeof(SampleColorData), "sample color custom data");
ARegion *ar = CTX_wm_region(C);
@@ -886,18 +1232,24 @@ static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event
data->event_type = event->type;
data->show_cursor = ((paint->flags & PAINT_SHOW_BRUSH) != 0);
+ copy_v3_v3(data->initcolor, BKE_brush_color_get(scene, brush));
+ data->sample_palette = false;
op->customdata = data;
paint->flags &= ~PAINT_SHOW_BRUSH;
+ sample_color_update_header(data, C);
+
+ WM_event_add_modal_handler(C, op);
+
/* force redraw without cursor */
WM_paint_cursor_tag_redraw(win, ar);
WM_redraw_windows(C);
RNA_int_set_array(op->ptr, "location", event->mval);
- paint_sample_color(C, ar, event->mval[0], event->mval[1]);
+
+ paint_sample_color(C, ar, event->mval[0], event->mval[1], mode == PAINT_TEXTURE_PROJECTIVE, false);
WM_cursor_modal_set(win, BC_EYEDROPPER_CURSOR);
- WM_event_add_modal_handler(C, op);
WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
return OPERATOR_RUNNING_MODAL;
@@ -905,17 +1257,27 @@ static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event
static int sample_color_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
+ Scene *scene = CTX_data_scene(C);
SampleColorData *data = op->customdata;
Paint *paint = BKE_paint_get_active_from_context(C);
Brush *brush = BKE_paint_brush(paint);
+ PaintMode mode = BKE_paintmode_get_active_from_context(C);
if ((event->type == data->event_type) && (event->val == KM_RELEASE)) {
+ ScrArea *sa = CTX_wm_area(C);
+
if (data->show_cursor) {
paint->flags |= PAINT_SHOW_BRUSH;
}
+ if (data->sample_palette) {
+ BKE_brush_color_set(scene, brush, data->initcolor);
+ RNA_boolean_set(op->ptr, "palette", true);
+ }
WM_cursor_modal_restore(CTX_wm_window(C));
MEM_freeN(data);
+ ED_area_headerprint(sa, NULL);
+
return OPERATOR_FINISHED;
}
@@ -924,10 +1286,22 @@ static int sample_color_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
RNA_int_set_array(op->ptr, "location", event->mval);
- paint_sample_color(C, ar, event->mval[0], event->mval[1]);
+ paint_sample_color(C, ar, event->mval[0], event->mval[1], mode == PAINT_TEXTURE_PROJECTIVE, false);
WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
break;
}
+
+ case LEFTMOUSE:
+ if (event->val == KM_PRESS) {
+ ARegion *ar = CTX_wm_region(C);
+ RNA_int_set_array(op->ptr, "location", event->mval);
+ paint_sample_color(C, ar, event->mval[0], event->mval[1], mode == PAINT_TEXTURE_PROJECTIVE, true);
+ if (!data->sample_palette) {
+ data->sample_palette = true;
+ sample_color_update_header(data, C);
+ }
+ }
+ break;
}
return OPERATOR_RUNNING_MODAL;
@@ -956,6 +1330,7 @@ void PAINT_OT_sample_color(wmOperatorType *ot)
/* properties */
RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location", "Cursor location in region coordinates", 0, 16384);
+ RNA_def_boolean(ot->srna, "palette", 0, "Palette", "Add color to palette");
}
/******************** texture paint toggle operator ********************/
@@ -973,13 +1348,78 @@ static int texture_paint_toggle_poll(bContext *C)
return 1;
}
+
+/* Make sure that active object has a material, and assign UVs and image layers if they do not exist */
+void paint_proj_mesh_data_ensure(bContext *C, Object *ob, wmOperator *op)
+{
+ Mesh *me;
+ int layernum;
+ bool add_material = false;
+ ImagePaintSettings *imapaint = &(CTX_data_tool_settings(C)->imapaint);
+ Brush *br = BKE_paint_brush(&imapaint->paint);
+
+ /* no material, add one */
+ if (ob->totcol == 0) {
+ add_material = true;
+ }
+ else {
+ /* there may be material slots but they may be empty, check */
+ bool has_material = false;
+ int i;
+
+ for (i = 1; i < ob->totcol + 1; i++) {
+ Material *ma = give_current_material(ob, i);
+ if (ma) {
+ has_material = true;
+ if (!ma->texpaintslot) {
+ proj_paint_add_slot(C, ma, NULL);
+ }
+ }
+ }
+
+ if (!has_material)
+ add_material = true;
+ }
+
+ if (add_material) {
+ Material *ma = BKE_material_add(CTX_data_main(C), "Material");
+ /* no material found, just assign to first slot */
+ assign_material(ob, ma, 1, BKE_MAT_ASSIGN_USERPREF);
+ proj_paint_add_slot(C, ma, NULL);
+ }
+
+ me = BKE_mesh_from_object(ob);
+ layernum = CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY);
+
+ if (layernum == 0) {
+ BKE_reportf(op->reports, RPT_WARNING, "Object did not have UV map, manual unwrap recommended");
+
+ ED_mesh_uv_texture_add(me, "UVMap", true);
+ }
+
+ /* Make sure we have a stencil to paint on! */
+ if (br->imagepaint_tool == PAINT_TOOL_MASK) {
+ imapaint->flag |= IMAGEPAINT_PROJECT_LAYER_STENCIL;
+
+ if (imapaint->stencil == NULL) {
+ int width;
+ int height;
+ Main *bmain = CTX_data_main(C);
+ float color[4] = {0.0, 0.0, 0.0, 1.0};
+
+ width = 1024;
+ height = 1024;
+ imapaint->stencil = BKE_image_add_generated(bmain, width, height, "Stencil", 32, false, IMA_GENTYPE_BLANK, color);
+ }
+ }
+}
+
static int texture_paint_toggle_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
const int mode_flag = OB_MODE_TEXTURE_PAINT;
const bool is_mode_set = (ob->mode & mode_flag) != 0;
- Mesh *me;
if (!is_mode_set) {
if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
@@ -987,8 +1427,6 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op)
}
}
- me = BKE_mesh_from_object(ob);
-
if (ob->mode & mode_flag) {
ob->mode &= ~mode_flag;
@@ -999,11 +1437,36 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op)
toggle_paint_cursor(C, 0);
}
else {
- ob->mode |= mode_flag;
+ bScreen *sc;
+ Main *bmain = CTX_data_main(C);
+ Material *ma;
+
+ bool use_nodes = BKE_scene_use_new_shading_nodes(scene);
+ /* This has to stay here to regenerate the texture paint
+ * cache in case we are loading a file */
+ BKE_texpaint_slots_refresh_object(ob, use_nodes);
+
+ paint_proj_mesh_data_ensure(C, ob, op);
+
+ /* set the current material active paint slot on image editor */
+ ma = give_current_material(ob, ob->actcol);
+
+ if (ma->tot_slots > 0) {
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
+ ScrArea *sa;
+ for (sa = sc->areabase.first; sa; sa = sa->next) {
+ SpaceLink *sl;
+ for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = (SpaceImage *)sl;
+ ED_space_image_set(sima, scene, scene->obedit, ma->texpaintslot[ma->paint_active_slot].ima);
+ }
+ }
+ }
+ }
+ }
- if (me->mtface == NULL)
- me->mtface = CustomData_add_layer(&me->fdata, CD_MTFACE, CD_DEFAULT,
- NULL, me->totface);
+ ob->mode |= mode_flag;
BKE_paint_init(&scene->toolsettings->imapaint.paint, PAINT_CURSOR_TEXTURE_PAINT);
@@ -1035,6 +1498,60 @@ void PAINT_OT_texture_paint_toggle(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+static int brush_colors_flip_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
+ Brush *br = image_paint_brush(C);
+ if (ups->flag & UNIFIED_PAINT_COLOR) {
+ swap_v3_v3(ups->rgb, ups->secondary_rgb);
+ }
+ else if (br) {
+ swap_v3_v3(br->rgb, br->secondary_rgb);
+ }
+ WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, br);
+
+ return OPERATOR_FINISHED;
+}
+
+static int brush_colors_flip_poll(bContext *C)
+{
+ if (image_paint_poll(C)) {
+ Brush *br = image_paint_brush(C);
+ if (br->imagepaint_tool == PAINT_TOOL_DRAW)
+ return 1;
+ }
+
+ return 0;
+}
+
+void PAINT_OT_brush_colors_flip(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Brush Colors Flip";
+ ot->idname = "PAINT_OT_brush_colors_flip";
+ ot->description = "Toggle foreground and background brush colors";
+
+ /* api callbacks */
+ ot->exec = brush_colors_flip_exec;
+ ot->poll = brush_colors_flip_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
+void ED_imapaint_bucket_fill(struct bContext *C, float color[3], wmOperator *op)
+{
+ ED_undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name,
+ ED_image_undo_restore, ED_image_undo_free, NULL);
+
+ paint_2d_bucket_fill(C, color, NULL, NULL, NULL);
+
+ ED_undo_paint_push_end(UNDO_PAINT_IMAGE);
+}
+
+
static int texture_paint_poll(bContext *C)
{
if (texture_paint_toggle_poll(C))
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index 4f67fc9cc87..1f66910eaa2 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -40,11 +40,18 @@
#include "BLI_math.h"
+#include "BLI_rect.h"
+#include "BLI_math_color_blend.h"
+#include "BLI_stack.h"
+#include "BLI_bitmap.h"
+
#include "BKE_context.h"
+#include "BKE_depsgraph.h"
#include "BKE_brush.h"
#include "BKE_image.h"
#include "BKE_paint.h"
#include "BKE_report.h"
+#include "BKE_texture.h"
#include "ED_paint.h"
#include "ED_screen.h"
@@ -69,24 +76,25 @@
/* Defines and Structs */
typedef struct BrushPainterCache {
- int size; /* size override, if 0 uses 2*BKE_brush_size_get(brush) */
-
bool use_float; /* need float imbuf? */
bool use_color_correction; /* use color correction for float */
- bool use_masking; /* use masking? */
+ bool invert;
bool is_texbrush;
bool is_maskbrush;
- int lastsize;
- float lastalpha;
- float lastjitter;
+ int lastdiameter;
float last_tex_rotation;
float last_mask_rotation;
+ float last_pressure;
ImBuf *ibuf;
ImBuf *texibuf;
- unsigned short *mask;
+ unsigned short *curve_mask;
+ unsigned short *tex_mask;
+ unsigned short *tex_mask_old;
+ unsigned int tex_mask_old_w;
+ unsigned int tex_mask_old_h;
} BrushPainterCache;
typedef struct BrushPainter {
@@ -136,43 +144,42 @@ typedef struct ImagePaintState {
int do_facesel;
bool need_redraw;
+
+ BlurKernel *blurkernel;
} ImagePaintState;
-static BrushPainter *brush_painter_2d_new(Scene *scene, Brush *brush)
+static BrushPainter *brush_painter_2d_new(Scene *scene, Brush *brush, bool invert)
{
BrushPainter *painter = MEM_callocN(sizeof(BrushPainter), "BrushPainter");
painter->brush = brush;
painter->scene = scene;
painter->firsttouch = 1;
- painter->cache.lastsize = -1; /* force ibuf create in refresh */
+ painter->cache.lastdiameter = -1; /* force ibuf create in refresh */
+ painter->cache.invert = invert;
return painter;
}
-static void brush_painter_2d_require_imbuf(BrushPainter *painter, bool use_float, bool use_color_correction, bool use_masking)
+static void brush_painter_2d_require_imbuf(BrushPainter *painter, bool use_float, bool use_color_correction)
{
Brush *brush = painter->brush;
if ((painter->cache.use_float != use_float)) {
if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf);
- if (painter->cache.mask) MEM_freeN(painter->cache.mask);
+ if (painter->cache.curve_mask) MEM_freeN(painter->cache.curve_mask);
+ if (painter->cache.tex_mask) MEM_freeN(painter->cache.tex_mask);
+ if (painter->cache.tex_mask_old) MEM_freeN(painter->cache.tex_mask_old);
painter->cache.ibuf = NULL;
- painter->cache.mask = NULL;
- painter->cache.lastsize = -1; /* force ibuf create in refresh */
- }
-
- if (painter->cache.use_float != use_float) {
- if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf);
- painter->cache.texibuf = NULL;
- painter->cache.lastsize = -1; /* force ibuf create in refresh */
+ painter->cache.curve_mask = NULL;
+ painter->cache.tex_mask = NULL;
+ painter->cache.lastdiameter = -1; /* force ibuf create in refresh */
}
painter->cache.use_float = use_float;
painter->cache.use_color_correction = use_float && use_color_correction;
- painter->cache.use_masking = use_masking;
painter->cache.is_texbrush = (brush->mtex.tex && brush->imagepaint_tool == PAINT_TOOL_DRAW) ? true : false;
painter->cache.is_maskbrush = (brush->mask_mtex.tex) ? true : false;
}
@@ -181,7 +188,9 @@ static void brush_painter_2d_free(BrushPainter *painter)
{
if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf);
if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf);
- if (painter->cache.mask) MEM_freeN(painter->cache.mask);
+ if (painter->cache.curve_mask) MEM_freeN(painter->cache.curve_mask);
+ if (painter->cache.tex_mask) MEM_freeN(painter->cache.tex_mask);
+ if (painter->cache.tex_mask_old) MEM_freeN(painter->cache.tex_mask_old);
MEM_freeN(painter);
}
@@ -192,41 +201,177 @@ static void brush_imbuf_tex_co(rctf *mapping, int x, int y, float texco[3])
texco[2] = 0.0f;
}
-/* create a mask with the falloff strength and optionally brush alpha */
-static unsigned short *brush_painter_mask_new(BrushPainter *painter, int size)
+/* create a mask with the mask texture */
+static unsigned short *brush_painter_mask_ibuf_new(BrushPainter *painter, int size)
{
Scene *scene = painter->scene;
Brush *brush = painter->brush;
- bool use_masking = painter->cache.use_masking;
-
- float alpha = (use_masking) ? 1.0f : BKE_brush_alpha_get(scene, brush);
- int radius = BKE_brush_size_get(scene, brush);
- int xoff = -size * 0.5f + 0.5f;
- int yoff = -size * 0.5f + 0.5f;
+ rctf mask_mapping = painter->mask_mapping;
+ struct ImagePool *pool = painter->pool;
+ float texco[3];
unsigned short *mask, *m;
- int x, y;
+ int x, y, thread = 0;
- mask = MEM_callocN(sizeof(unsigned short) * size * size, "brush_painter_mask");
+ mask = MEM_mallocN(sizeof(unsigned short) * size * size, "brush_painter_mask");
m = mask;
for (y = 0; y < size; y++) {
for (x = 0; x < size; x++, m++) {
+ float res;
+ brush_imbuf_tex_co(&mask_mapping, x, y, texco);
+ res = BKE_brush_sample_masktex(scene, brush, texco, thread, pool);
+ *m = (unsigned short)(65535.0f * res);
+ }
+ }
+
+ return mask;
+}
+
+/* update rectangular section of the brush image */
+static void brush_painter_mask_imbuf_update(
+ BrushPainter *painter, unsigned short *tex_mask_old,
+ int origx, int origy, int w, int h, int xt, int yt, int diameter)
+{
+ Scene *scene = painter->scene;
+ Brush *brush = painter->brush;
+ rctf tex_mapping = painter->mask_mapping;
+ struct ImagePool *pool = painter->pool;
+ unsigned short res;
+
+ bool use_texture_old = (tex_mask_old != NULL);
+
+ int x, y, thread = 0;
+
+ unsigned short *tex_mask = painter->cache.tex_mask;
+ unsigned short *tex_mask_cur = painter->cache.tex_mask_old;
+
+ /* fill pixels */
+ for (y = origy; y < h; y++) {
+ for (x = origx; x < w; x++) {
+ /* sample texture */
+ float texco[3];
+
+ /* handle byte pixel */
+ unsigned short *b = tex_mask + (y * diameter + x);
+ unsigned short *t = tex_mask_cur + (y * diameter + x);
+
+ if (!use_texture_old) {
+ brush_imbuf_tex_co(&tex_mapping, x, y, texco);
+ res = (unsigned short)(65535.0f * BKE_brush_sample_masktex(scene, brush, texco, thread, pool));
+ }
+
+ /* read from old texture buffer */
+ if (use_texture_old) {
+ res = *(tex_mask_old + ((y - origy + yt) * painter->cache.tex_mask_old_w + (x - origx + xt)));
+ }
+
+ /* write to new texture mask */
+ *t = res;
+ /* write to mask image buffer */
+ *b = res;
+ }
+ }
+}
+
+
+/**
+ * Update the brush mask image by trying to reuse the cached texture result.
+ * This can be considerably faster for brushes that change size due to pressure or
+ * textures that stick to the surface where only part of the pixels are new
+ */
+static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter, const float pos[2], int diameter)
+{
+ BrushPainterCache *cache = &painter->cache;
+ unsigned short *tex_mask_old;
+ int destx, desty, srcx, srcy, w, h, x1, y1, x2, y2;
+
+ /* create brush image buffer if it didn't exist yet */
+ if (!cache->tex_mask)
+ cache->tex_mask = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask");
+
+ /* create new texture image buffer with coordinates relative to old */
+ tex_mask_old = cache->tex_mask_old;
+ cache->tex_mask_old = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask");
+
+ if (tex_mask_old) {
+ ImBuf maskibuf;
+ ImBuf maskibuf_old;
+ maskibuf.x = maskibuf.y = diameter;
+ maskibuf_old.x = cache->tex_mask_old_w;
+ maskibuf_old.y = cache->tex_mask_old_h;
+
+ srcx = srcy = 0;
+ w = cache->tex_mask_old_w;
+ h = cache->tex_mask_old_h;
+ destx = (int)painter->lastpaintpos[0] - (int)pos[0] + (diameter / 2 - w / 2);
+ desty = (int)painter->lastpaintpos[1] - (int)pos[1] + (diameter / 2 - h / 2);
+
+ /* hack, use temporary rects so that clipping works */
+ IMB_rectclip(&maskibuf, &maskibuf_old, &destx, &desty, &srcx, &srcy, &w, &h);
+ }
+ else {
+ srcx = srcy = 0;
+ destx = desty = 0;
+ w = h = 0;
+ }
+
+ x1 = min_ii(destx, diameter);
+ y1 = min_ii(desty, diameter);
+ x2 = min_ii(destx + w, diameter);
+ y2 = min_ii(desty + h, diameter);
+
+ /* blend existing texture in new position */
+ if ((x1 < x2) && (y1 < y2))
+ brush_painter_mask_imbuf_update(painter, tex_mask_old, x1, y1, x2, y2, srcx, srcy, diameter);
+
+ if (tex_mask_old)
+ MEM_freeN(tex_mask_old);
+
+ /* sample texture in new areas */
+ if ((0 < x1) && (0 < diameter))
+ brush_painter_mask_imbuf_update(painter, NULL, 0, 0, x1, diameter, 0, 0, diameter);
+ if ((x2 < diameter) && (0 < diameter))
+ brush_painter_mask_imbuf_update(painter, NULL, x2, 0, diameter, diameter, 0, 0, diameter);
+ if ((x1 < x2) && (0 < y1))
+ brush_painter_mask_imbuf_update(painter, NULL, x1, 0, x2, y1, 0, 0, diameter);
+ if ((x1 < x2) && (y2 < diameter))
+ brush_painter_mask_imbuf_update(painter, NULL, x1, y2, x2, diameter, 0, 0, diameter);
+
+ /* through with sampling, now update sizes */
+ cache->tex_mask_old_w = diameter;
+ cache->tex_mask_old_h = diameter;
+}
+
+/* create a mask with the falloff strength */
+static unsigned short *brush_painter_curve_mask_new(BrushPainter *painter, int diameter, float radius)
+{
+ Brush *brush = painter->brush;
+
+ int xoff = -diameter * 0.5f + 0.5f;
+ int yoff = -diameter * 0.5f + 0.5f;
+
+ unsigned short *mask, *m;
+ int x, y;
+
+ mask = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask");
+ m = mask;
+
+ for (y = 0; y < diameter; y++) {
+ for (x = 0; x < diameter; x++, m++) {
float xy[2] = {x + xoff, y + yoff};
float len = len_v2(xy);
- float strength = alpha;
-
- strength *= BKE_brush_curve_strength_clamp(brush, len, radius);
- *m = (unsigned short)(65535.0f * strength);
+ *m = (unsigned short)(65535.0f * BKE_brush_curve_strength_clamp(brush, len, radius));
}
}
return mask;
}
+
/* create imbuf with brush color */
-static ImBuf *brush_painter_imbuf_new(BrushPainter *painter, int size)
+static ImBuf *brush_painter_imbuf_new(BrushPainter *painter, int size, float pressure, float distance)
{
Scene *scene = painter->scene;
Brush *brush = painter->brush;
@@ -235,19 +380,11 @@ static ImBuf *brush_painter_imbuf_new(BrushPainter *painter, int size)
struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
rctf tex_mapping = painter->tex_mapping;
- rctf mask_mapping = painter->mask_mapping;
struct ImagePool *pool = painter->pool;
- bool use_masking = painter->cache.use_masking;
bool use_color_correction = painter->cache.use_color_correction;
bool use_float = painter->cache.use_float;
bool is_texbrush = painter->cache.is_texbrush;
- bool is_maskbrush = painter->cache.is_maskbrush;
-
- float alpha = (use_masking) ? 1.0f : BKE_brush_alpha_get(scene, brush);
- int radius = BKE_brush_size_get(scene, brush);
- int xoff = -size * 0.5f + 0.5f;
- int yoff = -size * 0.5f + 0.5f;
int x, y, thread = 0;
float brush_rgb[3];
@@ -257,11 +394,7 @@ static ImBuf *brush_painter_imbuf_new(BrushPainter *painter, int size)
/* get brush color */
if (brush->imagepaint_tool == PAINT_TOOL_DRAW) {
- copy_v3_v3(brush_rgb, brush->rgb);
-
- if (use_color_correction) {
- IMB_colormanagement_display_to_scene_linear_v3(brush_rgb, display);
- }
+ paint_brush_color_get(scene, brush, use_color_correction, painter->cache.invert, distance, pressure, brush_rgb, display);
}
else {
brush_rgb[0] = 1.0f;
@@ -289,19 +422,6 @@ static ImBuf *brush_painter_imbuf_new(BrushPainter *painter, int size)
rgba[3] = 1.0f;
}
- if (is_maskbrush) {
- brush_imbuf_tex_co(&mask_mapping, x, y, texco);
- rgba[3] *= BKE_brush_sample_masktex(scene, brush, texco, thread, pool);
- }
-
- /* when not using masking, multiply in falloff and strength */
- if (!use_masking) {
- float xy[2] = {x + xoff, y + yoff};
- float len = len_v2(xy);
-
- rgba[3] *= alpha * BKE_brush_curve_strength_clamp(brush, len, radius);
- }
-
if (use_float) {
/* write to float pixel */
float *dstf = ibuf->rect_float + (y * size + x) * 4;
@@ -332,14 +452,11 @@ static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf,
struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
rctf tex_mapping = painter->tex_mapping;
- rctf mask_mapping = painter->mask_mapping;
struct ImagePool *pool = painter->pool;
- bool use_masking = painter->cache.use_masking;
bool use_color_correction = painter->cache.use_color_correction;
bool use_float = painter->cache.use_float;
bool is_texbrush = painter->cache.is_texbrush;
- bool is_maskbrush = painter->cache.is_maskbrush;
bool use_texture_old = (oldtexibuf != NULL);
int x, y, thread = 0;
@@ -347,15 +464,10 @@ static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf,
ImBuf *ibuf = painter->cache.ibuf;
ImBuf *texibuf = painter->cache.texibuf;
- unsigned short *mask = painter->cache.mask;
/* get brush color */
if (brush->imagepaint_tool == PAINT_TOOL_DRAW) {
- copy_v3_v3(brush_rgb, brush->rgb);
-
- if (use_color_correction) {
- IMB_colormanagement_display_to_scene_linear_v3(brush_rgb, display);
- }
+ paint_brush_color_get(scene, brush, use_color_correction, painter->cache.invert, 0.0, 1.0, brush_rgb, display);
}
else {
brush_rgb[0] = 1.0f;
@@ -363,7 +475,7 @@ static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf,
brush_rgb[2] = 1.0f;
}
- /* fill pixes */
+ /* fill pixels */
for (y = origy; y < h; y++) {
for (x = origx; x < w; x++) {
/* sample texture and multiply with brush color */
@@ -383,11 +495,6 @@ static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf,
copy_v3_v3(rgba, brush_rgb);
rgba[3] = 1.0f;
}
-
- if (is_maskbrush) {
- brush_imbuf_tex_co(&mask_mapping, x, y, texco);
- rgba[3] *= BKE_brush_sample_masktex(scene, brush, texco, thread, pool);
- }
}
if (use_float) {
@@ -404,12 +511,6 @@ static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf,
/* write to new texture buffer */
copy_v4_v4(tf, rgba);
- /* if not using masking, multiply in the mask now */
- if (!use_masking) {
- unsigned short *m = mask + (y * ibuf->x + x);
- rgba[3] *= *m * (1.0f / 65535.0f);
- }
-
/* output premultiplied float image, mf was already premultiplied */
mul_v3_v3fl(bf, rgba, rgba[3]);
bf[3] = rgba[3];
@@ -438,12 +539,6 @@ static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf,
t[2] = crgba[2];
t[3] = crgba[3];
- /* if not using masking, multiply in the mask now */
- if (!use_masking) {
- unsigned short *m = mask + (y * ibuf->x + x);
- crgba[3] = (crgba[3] * (*m)) / 65535;
- }
-
/* write to brush image buffer */
b[0] = crgba[0];
b[1] = crgba[1];
@@ -457,14 +552,11 @@ static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf,
/* update the brush image by trying to reuse the cached texture result. this
* can be considerably faster for brushes that change size due to pressure or
* textures that stick to the surface where only part of the pixels are new */
-static void brush_painter_imbuf_partial_update(BrushPainter *painter, const float pos[2])
+static void brush_painter_imbuf_partial_update(BrushPainter *painter, const float pos[2], int diameter)
{
- const Scene *scene = painter->scene;
- Brush *brush = painter->brush;
BrushPainterCache *cache = &painter->cache;
ImBuf *oldtexibuf, *ibuf;
int imbflag, destx, desty, srcx, srcy, w, h, x1, y1, x2, y2;
- int diameter = 2 * BKE_brush_size_get(scene, brush);
/* create brush image buffer if it didn't exist yet */
imbflag = (cache->use_float) ? IB_rectfloat : IB_rect;
@@ -478,10 +570,10 @@ static void brush_painter_imbuf_partial_update(BrushPainter *painter, const floa
if (oldtexibuf) {
srcx = srcy = 0;
- destx = (int)painter->lastpaintpos[0] - (int)pos[0];
- desty = (int)painter->lastpaintpos[1] - (int)pos[1];
w = oldtexibuf->x;
h = oldtexibuf->y;
+ destx = (int)painter->lastpaintpos[0] - (int)pos[0] + (diameter / 2 - w / 2);
+ desty = (int)painter->lastpaintpos[1] - (int)pos[1] + (diameter / 2 - h / 2);
IMB_rectclip(cache->texibuf, oldtexibuf, &destx, &desty, &srcx, &srcy, &w, &h);
}
@@ -514,7 +606,7 @@ static void brush_painter_imbuf_partial_update(BrushPainter *painter, const floa
brush_painter_imbuf_update(painter, NULL, x1, y2, x2, ibuf->y, 0, 0);
}
-static void brush_painter_2d_tex_mapping(ImagePaintState *s, int size, const float startpos[2], const float pos[2], const float mouse[2], int mapmode, rctf *mapping)
+static void brush_painter_2d_tex_mapping(ImagePaintState *s, int diameter, const float startpos[2], const float pos[2], const float mouse[2], int mapmode, rctf *mapping)
{
float invw = 1.0f / (float)s->canvas->x;
float invh = 1.0f / (float)s->canvas->y;
@@ -522,19 +614,19 @@ static void brush_painter_2d_tex_mapping(ImagePaintState *s, int size, const flo
int ipos[2];
/* find start coordinate of brush in canvas */
- ipos[0] = (int)floorf((pos[0] - size / 2) + 1.0f);
- ipos[1] = (int)floorf((pos[1] - size / 2) + 1.0f);
+ ipos[0] = (int)floorf((pos[0] - diameter / 2) + 1.0f);
+ ipos[1] = (int)floorf((pos[1] - diameter / 2) + 1.0f);
if (mapmode == MTEX_MAP_MODE_STENCIL) {
/* map from view coordinates of brush to region coordinates */
UI_view2d_view_to_region(s->v2d, ipos[0] * invw, ipos[1] * invh, &xmin, &ymin);
- UI_view2d_view_to_region(s->v2d, (ipos[0] + size) * invw, (ipos[1] + size) * invh, &xmax, &ymax);
+ UI_view2d_view_to_region(s->v2d, (ipos[0] + diameter) * invw, (ipos[1] + diameter) * invh, &xmax, &ymax);
/* output mapping from brush ibuf x/y to region coordinates */
mapping->xmin = xmin;
mapping->ymin = ymin;
- mapping->xmax = (xmax - xmin) / (float)size;
- mapping->ymax = (ymax - ymin) / (float)size;
+ mapping->xmax = (xmax - xmin) / (float)diameter;
+ mapping->ymax = (ymax - ymin) / (float)diameter;
}
else if (mapmode == MTEX_MAP_MODE_3D) {
/* 3D mapping, just mapping to canvas 0..1 */
@@ -545,104 +637,126 @@ static void brush_painter_2d_tex_mapping(ImagePaintState *s, int size, const flo
}
else if (ELEM(mapmode, MTEX_MAP_MODE_VIEW, MTEX_MAP_MODE_RANDOM)) {
/* view mapping */
- mapping->xmin = mouse[0] - size * 0.5f + 0.5f;
- mapping->ymin = mouse[1] - size * 0.5f + 0.5f;
+ mapping->xmin = mouse[0] - diameter * 0.5f + 0.5f;
+ mapping->ymin = mouse[1] - diameter * 0.5f + 0.5f;
mapping->xmax = 1.0f;
mapping->ymax = 1.0f;
}
else /* if (mapmode == MTEX_MAP_MODE_TILED) */ {
- mapping->xmin = -size * 0.5f + 0.5f + (int)pos[0] - (int)startpos[0];
- mapping->ymin = -size * 0.5f + 0.5f + (int)pos[1] - (int)startpos[1];
+ mapping->xmin = (int)(-diameter * 0.5) + (int)pos[0] - (int)startpos[0];
+ mapping->ymin = (int)(-diameter * 0.5) + (int)pos[1] - (int)startpos[1];
mapping->xmax = 1.0f;
mapping->ymax = 1.0f;
}
}
-static void brush_painter_2d_refresh_cache(ImagePaintState *s, BrushPainter *painter, const float pos[2], const float mouse[2])
+static void brush_painter_2d_refresh_cache(ImagePaintState *s, BrushPainter *painter, const float pos[2], const float mouse[2], float pressure, float distance, float size)
{
const Scene *scene = painter->scene;
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
Brush *brush = painter->brush;
BrushPainterCache *cache = &painter->cache;
- const int diameter = 2 * BKE_brush_size_get(scene, brush);
- const int size = (cache->size) ? cache->size : diameter;
- const float alpha = BKE_brush_alpha_get(scene, brush);
- const bool use_masking = painter->cache.use_masking;
+ const int diameter = 2 * size;
bool do_random = false;
bool do_partial_update = false;
- bool do_view = false;
+ bool update_color = (brush->flag & BRUSH_USE_GRADIENT) &&
+ ((ELEM(brush->gradient_stroke_mode,
+ BRUSH_GRADIENT_SPACING_REPEAT,
+ BRUSH_GRADIENT_SPACING_CLAMP)) ||
+ (cache->last_pressure != pressure));
float tex_rotation = -brush->mtex.rot;
float mask_rotation = -brush->mask_mtex.rot;
+ painter->pool = BKE_image_pool_new();
+
/* determine how can update based on textures used */
if (painter->cache.is_texbrush) {
if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) {
- do_view = true;
tex_rotation += ups->brush_rotation;
}
else if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)
do_random = true;
- else
+ else if (!((brush->flag & BRUSH_ANCHORED) || update_color))
do_partial_update = true;
- brush_painter_2d_tex_mapping(s, size, painter->startpaintpos, pos, mouse,
+ brush_painter_2d_tex_mapping(s, diameter, painter->startpaintpos, pos, mouse,
brush->mtex.brush_map_mode, &painter->tex_mapping);
}
if (painter->cache.is_maskbrush) {
+ bool renew_maxmask = false;
+ bool do_partial_update_mask = false;
+ /* invalidate case for all mapping modes */
if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) {
- do_view = true;
mask_rotation += ups->brush_rotation;
}
- else if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)
- do_random = true;
- else
- do_partial_update = true;
+ else if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM) {
+ renew_maxmask = true;
+ }
+ else if (!(brush->flag & BRUSH_ANCHORED)) {
+ do_partial_update_mask = true;
+ renew_maxmask = true;
+ }
+ /* explicilty disable partial update even if it has been enabled above */
+ if (brush->mask_pressure) {
+ do_partial_update_mask = false;
+ renew_maxmask = true;
+ }
- brush_painter_2d_tex_mapping(s, size, painter->startpaintpos, pos, mouse,
- brush->mask_mtex.brush_map_mode, &painter->mask_mapping);
+ if ((diameter != cache->lastdiameter) ||
+ (mask_rotation != cache->last_mask_rotation) ||
+ renew_maxmask)
+ {
+ if (cache->tex_mask) {
+ MEM_freeN(cache->tex_mask);
+ cache->tex_mask = NULL;
+ }
+
+ brush_painter_2d_tex_mapping(s, diameter, painter->startpaintpos, pos, mouse,
+ brush->mask_mtex.brush_map_mode, &painter->mask_mapping);
+
+ if (do_partial_update_mask)
+ brush_painter_mask_imbuf_partial_update(painter, pos, diameter);
+ else
+ cache->tex_mask = brush_painter_mask_ibuf_new(painter, diameter);
+ cache->last_mask_rotation = mask_rotation;
+ }
}
- if (do_view || do_random)
- do_partial_update = false;
+ /* curve mask can only change if the size changes */
+ if (diameter != cache->lastdiameter) {
+ if (cache->curve_mask) {
+ MEM_freeN(cache->curve_mask);
+ cache->curve_mask = NULL;
+ }
- painter->pool = BKE_image_pool_new();
+ cache->curve_mask = brush_painter_curve_mask_new(painter, diameter, size);
+ }
/* detect if we need to recreate image brush buffer */
- if (diameter != cache->lastsize ||
- alpha != cache->lastalpha ||
- brush->jitter != cache->lastjitter ||
- tex_rotation != cache->last_tex_rotation ||
- mask_rotation != cache->last_mask_rotation ||
- do_random)
+ if ((diameter != cache->lastdiameter) ||
+ (tex_rotation != cache->last_tex_rotation) ||
+ do_random ||
+ update_color)
{
if (cache->ibuf) {
IMB_freeImBuf(cache->ibuf);
cache->ibuf = NULL;
}
- if (cache->mask) {
- MEM_freeN(cache->mask);
- cache->mask = NULL;
- }
if (do_partial_update) {
- /* do partial update of texture + recreate mask */
- cache->mask = brush_painter_mask_new(painter, size);
- brush_painter_imbuf_partial_update(painter, pos);
+ /* do partial update of texture */
+ brush_painter_imbuf_partial_update(painter, pos, diameter);
}
else {
- /* create brush and mask from scratch */
- if (use_masking)
- cache->mask = brush_painter_mask_new(painter, size);
- cache->ibuf = brush_painter_imbuf_new(painter, size);
+ /* create brush from scratch */
+ cache->ibuf = brush_painter_imbuf_new(painter, diameter, pressure, distance);
}
- cache->lastsize = diameter;
- cache->lastalpha = alpha;
- cache->lastjitter = brush->jitter;
+ cache->lastdiameter = diameter;
cache->last_tex_rotation = tex_rotation;
- cache->last_mask_rotation = mask_rotation;
+ cache->last_pressure = pressure;
}
else if (do_partial_update) {
/* do only partial update of texture */
@@ -650,7 +764,7 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s, BrushPainter *pai
int dy = (int)painter->lastpaintpos[1] - (int)pos[1];
if ((dx != 0) || (dy != 0)) {
- brush_painter_imbuf_partial_update(painter, pos);
+ brush_painter_imbuf_partial_update(painter, pos, diameter);
}
}
@@ -703,7 +817,7 @@ static void paint_2d_ibuf_rgb_set(ImBuf *ibuf, int x, int y, const bool is_torus
}
}
-static int paint_2d_ibuf_add_if(ImBuf *ibuf, unsigned int x, unsigned int y, float *outrgb, short torus)
+static float paint_2d_ibuf_add_if(ImBuf *ibuf, unsigned int x, unsigned int y, float *outrgb, short torus, float w)
{
float inrgb[4];
@@ -716,16 +830,23 @@ static int paint_2d_ibuf_add_if(ImBuf *ibuf, unsigned int x, unsigned int y, flo
paint_2d_ibuf_rgb_get(ibuf, x, y, 0, inrgb);
}
+ mul_v4_fl(inrgb, w);
add_v4_v4(outrgb, inrgb);
- return 1;
+ return w;
}
-static void paint_2d_lift_soften(ImBuf *ibuf, ImBuf *ibufb, int *pos, const bool is_torus)
+static void paint_2d_lift_soften(ImagePaintState *s, ImBuf *ibuf, ImBuf *ibufb, int *pos, const short is_torus)
{
- int x, y, count, xi, yi, xo, yo;
+ bool sharpen = (s->painter->cache.invert ^ ((s->brush->flag & BRUSH_DIR_IN) != 0));
+ float threshold = s->brush->sharp_threshold;
+ int x, y, xi, yi, xo, yo, xk, yk;
+ float count;
int out_off[2], in_off[2], dim[2];
+ int diff_pos[2];
float outrgb[4];
+ float rgba[4];
+ BlurKernel *kernel = s->blurkernel;
dim[0] = ibufb->x;
dim[1] = ibufb->y;
@@ -741,28 +862,52 @@ static void paint_2d_lift_soften(ImBuf *ibuf, ImBuf *ibufb, int *pos, const bool
return;
}
+ /* find offset inside mask buffers to sample them */
+ sub_v2_v2v2_int(diff_pos, out_off, in_off);
+
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;
- paint_2d_ibuf_rgb_get(ibuf, xi, yi, is_torus, outrgb);
+ count = 0.0;
+ paint_2d_ibuf_rgb_get(ibuf, xi, yi, is_torus, rgba);
+ zero_v4(outrgb);
- 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);
+ for (yk = 0; yk < kernel->side; yk++) {
+ for (xk = 0; xk < kernel->side; xk++) {
+ count += paint_2d_ibuf_add_if(ibuf, xi + xk - kernel->pixel_len,
+ yi + yk - kernel->pixel_len, outrgb, is_torus,
+ kernel->wdata[xk + yk * kernel->side]);
+ }
+ }
- 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 (count > 0.0f) {
+ mul_v4_fl(outrgb, 1.0f / (float)count);
- 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);
+ if (sharpen) {
+ /* subtract blurred image from normal image gives high pass filter */
+ sub_v3_v3v3(outrgb, rgba, outrgb);
- mul_v4_fl(outrgb, 1.0f / (float)count);
+ /* now rgba_ub contains the edge result, but this should be converted to luminance to avoid
+ * colored speckles appearing in final image, and also to check for threshold */
+ outrgb[0] = outrgb[1] = outrgb[2] = rgb_to_grayscale(outrgb);
+ if (fabsf(outrgb[0]) > threshold) {
+ float mask = BKE_brush_alpha_get(s->scene, s->brush);
+ float alpha = rgba[3];
+ rgba[3] = outrgb[3] = mask;
+ /* add to enhance edges */
+ blend_color_add_float(outrgb, rgba, outrgb);
+ outrgb[3] = alpha;
+ }
+ else
+ copy_v4_v4(outrgb, rgba);
+ }
+ }
+ else
+ copy_v4_v4(outrgb, rgba);
/* write into brush buffer */
xo = out_off[0] + x;
yo = out_off[1] + y;
@@ -830,10 +975,10 @@ static void paint_2d_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos)
tot = paint_2d_torus_split_region(region, ibufb, ibuf);
for (a = 0; a < tot; a++)
- IMB_rectblend(ibufb, ibufb, ibuf, NULL, NULL, 0, region[a].destx, region[a].desty,
+ IMB_rectblend(ibufb, ibufb, ibuf, NULL, NULL, NULL, 0, region[a].destx, region[a].desty,
region[a].destx, region[a].desty,
region[a].srcx, region[a].srcy,
- region[a].width, region[a].height, IMB_BLEND_COPY_RGB);
+ region[a].width, region[a].height, IMB_BLEND_COPY_RGB, false);
}
static ImBuf *paint_2d_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos)
@@ -844,10 +989,10 @@ static ImBuf *paint_2d_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos)
ImBuf *clonebuf = IMB_allocImBuf(w, h, ibufb->planes, ibufb->flags);
IMB_rectclip(clonebuf, ibuf, &destx, &desty, &srcx, &srcy, &w, &h);
- IMB_rectblend(clonebuf, clonebuf, ibufb, NULL, NULL, 0, destx, desty, destx, desty, destx, desty, w, h,
- IMB_BLEND_COPY_ALPHA);
- IMB_rectblend(clonebuf, clonebuf, ibuf, NULL, NULL, 0, destx, desty, destx, desty, srcx, srcy, w, h,
- IMB_BLEND_COPY_RGB);
+ IMB_rectblend(clonebuf, clonebuf, ibufb, NULL, NULL, NULL, 0, destx, desty, destx, desty, destx, desty, w, h,
+ IMB_BLEND_COPY_ALPHA, false);
+ IMB_rectblend(clonebuf, clonebuf, ibuf, NULL, NULL, NULL, 0, destx, desty, destx, desty, srcx, srcy, w, h,
+ IMB_BLEND_COPY_RGB, false);
return clonebuf;
}
@@ -858,17 +1003,16 @@ static void paint_2d_convert_brushco(ImBuf *ibufb, const float pos[2], int ipos[
ipos[1] = (int)floorf((pos[1] - ibufb->y / 2) + 1.0f);
}
-static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *maskb, const float lastpos[2], const float pos[2])
+static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsigned short *texmaskb, const float lastpos[2], const float pos[2])
{
ImagePaintState *s = ((ImagePaintState *)state);
- ImBuf *clonebuf = NULL, *frombuf, *tmpbuf = NULL;
+ ImBuf *clonebuf = NULL, *frombuf;
ImagePaintRegion region[4];
short torus = s->brush->flag & BRUSH_TORUS;
short blend = s->blend;
const float *offset = s->brush->clone.offset;
float liftpos[2];
- float brush_alpha = BKE_brush_alpha_get(s->scene, s->brush);
- unsigned short mask_max = (unsigned short)(brush_alpha * 65535.0f);
+ float mask_max = BKE_brush_alpha_get(s->scene, s->brush);
int bpos[2], blastpos[2], bliftpos[2];
int a, tot;
@@ -876,7 +1020,7 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *maskb, const f
/* lift from canvas */
if (s->tool == PAINT_TOOL_SOFTEN) {
- paint_2d_lift_soften(s->canvas, ibufb, bpos, torus);
+ paint_2d_lift_soften(s, s->canvas, ibufb, bpos, torus);
}
else if (s->tool == PAINT_TOOL_SMEAR) {
if (lastpos[0] == pos[0] && lastpos[1] == pos[1])
@@ -903,9 +1047,6 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *maskb, const f
paint_2d_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y);
tot = 1;
}
-
- if (s->do_masking)
- tmpbuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, 0);
/* blend into canvas */
for (a = 0; a < tot; a++) {
@@ -916,11 +1057,14 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *maskb, const f
if (s->do_masking) {
/* masking, find original pixels tiles from undo buffer to composite over */
int tilex, tiley, tilew, tileh, tx, ty;
+ ImBuf *tmpbuf;
imapaint_region_tiles(s->canvas, region[a].destx, region[a].desty,
region[a].width, region[a].height,
&tilex, &tiley, &tilew, &tileh);
-
+
+ tmpbuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, 0);
+
for (ty = tiley; ty <= tileh; ty++) {
for (tx = tilex; tx <= tilew; tx++) {
/* retrieve original pixels + mask from undo buffer */
@@ -929,31 +1073,32 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *maskb, const f
int origy = region[a].desty - ty * IMAPAINT_TILE_SIZE;
if (s->canvas->rect_float)
- tmpbuf->rect_float = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask);
+ tmpbuf->rect_float = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask, false);
else
- tmpbuf->rect = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask);
+ tmpbuf->rect = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask, false);
IMB_rectblend(s->canvas, tmpbuf, frombuf, mask,
- maskb, mask_max,
+ curveb, texmaskb, mask_max,
region[a].destx, region[a].desty,
origx, origy,
region[a].srcx, region[a].srcy,
- region[a].width, region[a].height, blend);
+ region[a].width, region[a].height, blend, ((s->brush->flag & BRUSH_ACCUMULATE) != 0));
}
}
+
+ IMB_freeImBuf(tmpbuf);
}
else {
/* no masking, composite brush directly onto canvas */
- IMB_rectblend(s->canvas, s->canvas, frombuf, NULL, NULL, 0,
+ IMB_rectblend(s->canvas, s->canvas, frombuf, NULL, curveb, texmaskb, mask_max,
region[a].destx, region[a].desty,
region[a].destx, region[a].desty,
region[a].srcx, region[a].srcy,
- region[a].width, region[a].height, blend);
+ region[a].width, region[a].height, blend, false);
}
}
if (clonebuf) IMB_freeImBuf(clonebuf);
- if (tmpbuf) IMB_freeImBuf(tmpbuf);
return 1;
}
@@ -1003,10 +1148,7 @@ static int paint_2d_canvas_set(ImagePaintState *s, Image *ima)
}
/* set masking */
- s->do_masking = (s->brush->flag & BRUSH_AIRBRUSH ||
- (s->brush->imagepaint_tool == PAINT_TOOL_SMEAR) ||
- (s->brush->mtex.tex && !ELEM3(s->brush->mtex.brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL, MTEX_MAP_MODE_3D)))
- ? false : true;
+ s->do_masking = paint_use_opacity_masking(s->brush);
return 1;
}
@@ -1016,11 +1158,15 @@ 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);
- if (s->do_masking)
- image_undo_remove_masks();
+ if (s->blurkernel) {
+ paint_delete_blur_kernel(s->blurkernel);
+ MEM_freeN(s->blurkernel);
+ }
+
+ image_undo_remove_masks();
}
-void paint_2d_stroke(void *ps, const float prev_mval[2], const float mval[2], int eraser)
+void paint_2d_stroke(void *ps, const float prev_mval[2], const float mval[2], int eraser, float pressure, float distance, float size)
{
float newuv[2], olduv[2];
ImagePaintState *s = ps;
@@ -1063,17 +1209,17 @@ void paint_2d_stroke(void *ps, const float prev_mval[2], const float mval[2], in
/* 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 != NULL), !is_data, s->do_masking);
+ brush_painter_2d_require_imbuf(painter, (ibuf->rect_float != NULL), !is_data);
- brush_painter_2d_refresh_cache(s, painter, newuv, mval);
+ brush_painter_2d_refresh_cache(s, painter, newuv, mval, pressure, distance, size);
- if (paint_2d_op(s, painter->cache.ibuf, painter->cache.mask, olduv, newuv))
+ if (paint_2d_op(s, painter->cache.ibuf, painter->cache.curve_mask, painter->cache.tex_mask, olduv, newuv))
s->need_redraw = true;
BKE_image_release_ibuf(s->image, ibuf, NULL);
}
-void *paint_2d_new_stroke(bContext *C, wmOperator *op)
+void *paint_2d_new_stroke(bContext *C, wmOperator *op, int mode)
{
Scene *scene = CTX_data_scene(C);
ToolSettings *settings = scene->toolsettings;
@@ -1102,10 +1248,14 @@ void *paint_2d_new_stroke(bContext *C, wmOperator *op)
return NULL;
}
+ if (brush->imagepaint_tool == PAINT_TOOL_SOFTEN) {
+ s->blurkernel = paint_new_blur_kernel(brush);
+ }
+
paint_brush_init_tex(s->brush);
/* create painter */
- s->painter = brush_painter_2d_new(scene, s->brush);
+ s->painter = brush_painter_2d_new(scene, s->brush, mode == BRUSH_STROKE_INVERT);
return s;
}
@@ -1134,6 +1284,7 @@ void paint_2d_redraw(const bContext *C, void *ps, bool final)
/* compositor listener deals with updating */
WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, s->image);
+ DAG_id_tag_update(&s->image->id, 0);
}
else {
if (!s->sima || !s->sima->lock)
@@ -1153,3 +1304,334 @@ void paint_2d_stroke_done(void *ps)
MEM_freeN(s);
}
+
+static void paint_2d_fill_add_pixel_byte(
+ const int x_px, const int y_px, ImBuf *ibuf, BLI_Stack *stack, BLI_bitmap *touched,
+ const float color[4], float threshold_sq)
+{
+ int coordinate;
+
+ if (x_px >= ibuf->x || x_px < 0 || y_px >= ibuf->y || y_px < 0)
+ return;
+
+ coordinate = y_px * ibuf->x + x_px;
+
+ if (!BLI_BITMAP_TEST(touched, coordinate)) {
+ float color_f[4];
+ unsigned char *color_b = (unsigned char *)(ibuf->rect + coordinate);
+ rgba_uchar_to_float(color_f, color_b);
+
+ if (compare_len_squared_v3v3(color_f, color, threshold_sq)) {
+ BLI_stack_push(stack, &coordinate);
+ }
+ BLI_BITMAP_SET(touched, coordinate, true);
+ }
+}
+
+static void paint_2d_fill_add_pixel_float(
+ const int x_px, const int y_px, ImBuf *ibuf, BLI_Stack *stack, BLI_bitmap *touched,
+ const float color[4], float threshold_sq)
+{
+ int coordinate;
+
+ if (x_px >= ibuf->x || x_px < 0 || y_px >= ibuf->y || y_px < 0)
+ return;
+
+ coordinate = y_px * ibuf->x + x_px;
+
+ if (!BLI_BITMAP_TEST(touched, coordinate)) {
+ if (compare_len_squared_v3v3(ibuf->rect_float + 4 * coordinate, color, threshold_sq)) {
+ BLI_stack_push(stack, &coordinate);
+ }
+ BLI_BITMAP_SET(touched, coordinate, true);
+ }
+}
+
+/* this function expects linear space color values */
+void paint_2d_bucket_fill(
+ const bContext *C, const float color[3], Brush *br,
+ const float mouse_init[2],
+ void *ps)
+{
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Image *ima = sima->image;
+
+ ImagePaintState *s = ps;
+
+ ImBuf *ibuf;
+ int x_px, y_px;
+ unsigned int color_b;
+ float color_f[4];
+ float strength = br ? br->alpha : 1.0f;
+
+ bool do_float;
+
+ if (!ima)
+ return;
+
+ ibuf = BKE_image_acquire_ibuf(ima, &sima->iuser, NULL);
+
+ if (!ibuf)
+ return;
+
+ do_float = (ibuf->rect_float != NULL);
+ /* first check if our image is float. If it is not we should correct the color to
+ * be in gamma space. strictly speaking this is not correct, but blender does not paint
+ * byte images in linear space */
+ if (!do_float) {
+ linearrgb_to_srgb_uchar3((unsigned char *)&color_b, color);
+ *(((char *)&color_b) + 3) = strength * 255;
+ }
+ else {
+ copy_v3_v3(color_f, color);
+ color_f[3] = strength;
+ }
+
+ if (!mouse_init || !br) {
+ /* first case, no image UV, fill the whole image */
+ ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y);
+
+ if (do_float) {
+ for (x_px = 0; x_px < ibuf->x; x_px++) {
+ for (y_px = 0; y_px < ibuf->y; y_px++) {
+ blend_color_mix_float(ibuf->rect_float + 4 * (y_px * ibuf->x + x_px),
+ ibuf->rect_float + 4 * (y_px * ibuf->x + x_px), color_f);
+ }
+ }
+ }
+ else {
+ for (x_px = 0; x_px < ibuf->x; x_px++) {
+ for (y_px = 0; y_px < ibuf->y; y_px++) {
+ blend_color_mix_byte((unsigned char *)(ibuf->rect + y_px * ibuf->x + x_px),
+ (unsigned char *)(ibuf->rect + y_px * ibuf->x + x_px), (unsigned char *)&color_b);
+ }
+ }
+ }
+ }
+ else {
+ /* second case, start sweeping the neighboring pixels, looking for pixels whose
+ * value is within the brush fill threshold from the fill color */
+ BLI_Stack *stack;
+ BLI_bitmap *touched;
+ int coordinate;
+ int width = ibuf->x;
+ float image_init[2];
+ int minx = ibuf->x, miny = ibuf->y, maxx = 0, maxy = 0;
+ float pixel_color[4];
+ float threshold_sq = br->fill_threshold * br->fill_threshold;
+
+ UI_view2d_region_to_view(s->v2d, mouse_init[0], mouse_init[1], &image_init[0], &image_init[1]);
+
+ x_px = image_init[0] * ibuf->x;
+ y_px = image_init[1] * ibuf->y;
+
+ if (x_px >= ibuf->x || x_px < 0 || y_px > ibuf->y || y_px < 0) {
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ return;
+ }
+
+ /* change image invalidation method later */
+ ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y);
+
+ stack = BLI_stack_new(sizeof(int), __func__);
+ touched = BLI_BITMAP_NEW(ibuf->x * ibuf->y, "bucket_fill_bitmap");
+
+ coordinate = (y_px * ibuf->x + x_px);
+
+ if (do_float) {
+ copy_v4_v4(pixel_color, ibuf->rect_float + 4 * coordinate);
+ }
+ else {
+ int pixel_color_b = *(ibuf->rect + coordinate);
+ rgba_uchar_to_float(pixel_color, (unsigned char *)&pixel_color_b);
+ }
+
+ BLI_stack_push(stack, &coordinate);
+ BLI_BITMAP_SET(touched, coordinate, true);
+
+ if (do_float) {
+ while (!BLI_stack_is_empty(stack)) {
+ BLI_stack_pop(stack, &coordinate);
+
+ IMB_blend_color_float(ibuf->rect_float + 4 * (coordinate),
+ ibuf->rect_float + 4 * (coordinate),
+ color_f, br->blend);
+
+ /* reconstruct the coordinates here */
+ x_px = coordinate % width;
+ y_px = coordinate / width;
+
+ paint_2d_fill_add_pixel_float(x_px - 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_float(x_px - 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_float(x_px - 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_float(x_px, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_float(x_px, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_float(x_px + 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_float(x_px + 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_float(x_px + 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
+
+ if (x_px > maxx)
+ maxx = x_px;
+ if (x_px < minx)
+ minx = x_px;
+ if (y_px > maxy)
+ maxy = y_px;
+ if (x_px > miny)
+ miny = y_px;
+ }
+ }
+ else {
+ while (!BLI_stack_is_empty(stack)) {
+ BLI_stack_pop(stack, &coordinate);
+
+ IMB_blend_color_byte((unsigned char *)(ibuf->rect + coordinate),
+ (unsigned char *)(ibuf->rect + coordinate),
+ (unsigned char *)&color_b, br->blend);
+
+ /* reconstruct the coordinates here */
+ x_px = coordinate % width;
+ y_px = coordinate / width;
+
+ paint_2d_fill_add_pixel_byte(x_px - 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_byte(x_px - 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_byte(x_px - 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_byte(x_px, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_byte(x_px, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_byte(x_px + 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_byte(x_px + 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_byte(x_px + 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
+
+ if (x_px > maxx)
+ maxx = x_px;
+ if (x_px < minx)
+ minx = x_px;
+ if (y_px > maxy)
+ maxy = y_px;
+ if (x_px > miny)
+ miny = y_px;
+ }
+ }
+
+ MEM_freeN(touched);
+ BLI_stack_free(stack);
+ }
+
+ imapaint_image_update(sima, ima, ibuf, false);
+ ED_imapaint_clear_partial_redraw();
+
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+
+ WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
+}
+
+void paint_2d_gradient_fill(
+ const bContext *C, Brush *br,
+ const float mouse_init[2], const float mouse_final[2],
+ void *ps)
+{
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Image *ima = sima->image;
+ ImagePaintState *s = ps;
+
+ ImBuf *ibuf;
+ int x_px, y_px;
+ unsigned int color_b;
+ float color_f[4];
+ float image_init[2], image_final[2];
+ float tangent[2];
+ float line_len_sq_inv, line_len;
+
+ bool do_float;
+
+ if (!ima)
+ return;
+
+ ibuf = BKE_image_acquire_ibuf(ima, &sima->iuser, NULL);
+
+ if (!ibuf)
+ return;
+
+ UI_view2d_region_to_view(s->v2d, mouse_final[0], mouse_final[1], &image_final[0], &image_final[1]);
+ UI_view2d_region_to_view(s->v2d, mouse_init[0], mouse_init[1], &image_init[0], &image_init[1]);
+
+ image_final[0] *= ibuf->x;
+ image_final[1] *= ibuf->y;
+
+ image_init[0] *= ibuf->x;
+ image_init[1] *= ibuf->y;
+
+ /* some math to get needed gradient variables */
+ sub_v2_v2v2(tangent, image_final, image_init);
+ line_len = len_squared_v2(tangent);
+ line_len_sq_inv = 1.0f / line_len;
+ line_len = sqrt(line_len);
+
+ do_float = (ibuf->rect_float != NULL);
+
+ /* this will be substituted by something else when selection is available */
+ ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y);
+
+ if (do_float) {
+ for (x_px = 0; x_px < ibuf->x; x_px++) {
+ for (y_px = 0; y_px < ibuf->y; y_px++) {
+ float f;
+ float p[2] = {x_px - image_init[0], y_px - image_init[1]};
+
+ switch (br->gradient_fill_mode) {
+ case BRUSH_GRADIENT_LINEAR:
+ {
+ f = dot_v2v2(p, tangent) * line_len_sq_inv;
+ break;
+ }
+ case BRUSH_GRADIENT_RADIAL:
+ {
+ f = len_v2(p) / line_len;
+ break;
+ }
+ }
+ do_colorband(br->gradient, f, color_f);
+ /* convert to premultiplied */
+ mul_v3_fl(color_f, color_f[3]);
+ color_f[3] *= br->alpha;
+ IMB_blend_color_float(ibuf->rect_float + 4 * (y_px * ibuf->x + x_px),
+ ibuf->rect_float + 4 * (y_px * ibuf->x + x_px),
+ color_f, br->blend);
+ }
+ }
+ }
+ else {
+ for (x_px = 0; x_px < ibuf->x; x_px++) {
+ for (y_px = 0; y_px < ibuf->y; y_px++) {
+ float f;
+ float p[2] = {x_px - image_init[0], y_px - image_init[1]};
+
+ switch (br->gradient_fill_mode) {
+ case BRUSH_GRADIENT_LINEAR:
+ {
+ f = dot_v2v2(p, tangent) * line_len_sq_inv;
+ break;
+ }
+ case BRUSH_GRADIENT_RADIAL:
+ {
+ f = len_v2(p) / line_len;
+ break;
+ }
+ }
+
+ do_colorband(br->gradient, f, color_f);
+ rgba_float_to_uchar((unsigned char *)&color_b, color_f);
+ ((unsigned char *)&color_b)[3] *= br->alpha;
+ IMB_blend_color_byte((unsigned char *)(ibuf->rect + y_px * ibuf->x + x_px),
+ (unsigned char *)(ibuf->rect + y_px * ibuf->x + x_px),
+ (unsigned char *)&color_b, br->blend);
+ }
+ }
+ }
+
+ imapaint_image_update(sima, ima, ibuf, false);
+ ED_imapaint_clear_partial_redraw();
+
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+
+ WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
+}
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 399b5044a05..e10c97ea9f0 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -48,30 +48,39 @@
#include "BLI_threads.h"
#include "BLI_utildefines.h"
+#include "BLF_translation.h"
+
#include "PIL_time.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "DNA_brush_types.h"
+#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
#include "BKE_camera.h"
+#include "BKE_colortools.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_material.h"
+#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_paint.h"
#include "BKE_report.h"
#include "BKE_scene.h"
+#include "BKE_texture.h"
#include "UI_view2d.h"
+#include "UI_interface.h"
#include "ED_paint.h"
#include "ED_screen.h"
@@ -141,6 +150,7 @@ BLI_INLINE unsigned char f_to_char(const float val)
#define PROJ_SRC_VIEW 1
#define PROJ_SRC_IMAGE_CAM 2
#define PROJ_SRC_IMAGE_VIEW 3
+#define PROJ_SRC_VIEW_FILL 4
#define PROJ_VIEW_DATA_ID "view_data"
#define PROJ_VIEW_DATA_SIZE (4 * 4 + 4 * 4 + 3) /* viewmat + winmat + clipsta + clipend + is_ortho */
@@ -162,6 +172,9 @@ BLI_INLINE unsigned char f_to_char(const float val)
/* vert flags */
#define PROJ_VERT_CULL 1
+/* to avoid locking in tile initialization */
+#define TILE_PENDING SET_INT_IN_POINTER(-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 */
@@ -169,7 +182,10 @@ typedef struct ProjPaintImage {
Image *ima;
ImBuf *ibuf;
ImagePaintPartialRedraw *partRedrawRect;
- void **undoRect; /* only used to build undo tiles after painting */
+ volatile void **undoRect; /* only used to build undo tiles during painting */
+ unsigned short **maskRect; /* the mask accumulation must happen on canvas, not on space screen bucket.
+ * Here we store the mask rectangle */
+ bool **valid; /* store flag to enforce validation of undo rectangle */
int touch;
} ProjPaintImage;
@@ -181,9 +197,14 @@ typedef struct ProjPaintState {
Scene *scene;
int source; /* PROJ_SRC_**** */
+ /* the paint color. It can change depending of inverted mode or not */
+ float paint_color[3];
+ float paint_color_linear[3];
+
Brush *brush;
short tool, blend, mode;
int orig_brush_size;
+ float brush_size;
Object *ob;
/* end similarities with ImagePaintState */
@@ -194,10 +215,13 @@ typedef struct ProjPaintState {
MVert *dm_mvert;
MFace *dm_mface;
- MTFace *dm_mtface;
- MTFace *dm_mtface_clone; /* other UV map, use for cloning between layers */
+ MTFace **dm_mtface;
+ MTFace **dm_mtface_clone; /* other UV map, use for cloning between layers */
MTFace *dm_mtface_stencil;
+ Image *stencil_ima;
+ float stencil_value;
+
/* 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 */
@@ -231,6 +255,7 @@ typedef struct ProjPaintState {
bool do_layer_clone;
bool do_layer_stencil;
bool do_layer_stencil_inv;
+ bool do_stencil_brush;
bool do_occlude; /* Use raytraced occlusion? - ortherwise will paint right through to the back*/
bool do_backfacecull; /* ignore faces with normals pointing away, skips a lot of raycasts if your normals are correctly flipped */
@@ -245,7 +270,6 @@ typedef struct ProjPaintState {
bool do_masking; /* use masking during painting. Some operations such as airbrush may disable */
bool is_texbrush; /* only to avoid running */
bool is_maskbrush; /* mask brush is applied before masking */
- bool is_maskbrush_tiled; /* mask brush is applied after masking */
#ifndef PROJ_DEBUG_NOSEAMBLEED
float seam_bleed_px;
#endif
@@ -269,6 +293,10 @@ typedef struct ProjPaintState {
/* redraw */
bool need_redraw;
+
+ BlurKernel *blurkernel;
+
+ SpinLock *tile_lock;
} ProjPaintState;
typedef union pixelPointer {
@@ -290,14 +318,16 @@ typedef struct ProjPixel {
* 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_accum */
- unsigned short mask_accum;
+ unsigned short *mask_accum;
/* for various reasons we may want to mask out painting onto this pixel */
unsigned short mask;
short x_px, y_px;
+ /* horrible hack, store tile valid flag pointer here to re-validate tiles used for anchored and drag-dot strokes */
+ bool *valid;
- PixelStore origColor;
+ PixelPointer origColor;
PixelStore newColor;
PixelPointer pixel;
@@ -310,33 +340,44 @@ typedef struct ProjPixelClone {
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
+/* undo tile pushing */
+typedef struct {
+ SpinLock *lock;
+ bool masked;
+ unsigned short tile_width;
+ ImBuf **tmpibuf;
+ ProjPaintImage *pjima;
+} TileInfo;
-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)
+static TexPaintSlot *project_paint_face_paint_slot(const ProjPaintState *ps, int face_index)
{
- Image *ima;
+ MFace *mf = ps->dm_mface + face_index;
+ Material *ma = ps->dm->mat[mf->mat_nr];
+ return ma->texpaintslot + ma->paint_active_slot;
+}
- 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);
+static Image *project_paint_face_paint_image(const ProjPaintState *ps, int face_index)
+{
+ if (ps->do_stencil_brush) {
+ return ps->stencil_ima;
}
else {
- ima = dm_mtface[face_index].tpage;
+ MFace *mf = ps->dm_mface + face_index;
+ Material *ma = ps->dm->mat[mf->mat_nr];
+ TexPaintSlot *slot = ma->texpaintslot + ma->paint_active_slot;
+ return slot ? slot->ima : NULL;
}
+}
+
- return ima;
+static TexPaintSlot *project_paint_face_clone_slot(const ProjPaintState *ps, int face_index)
+{
+ MFace *mf = ps->dm_mface + face_index;
+ Material *ma = ps->dm->mat[mf->mat_nr];
+ return &ma->texpaintslot[ma->paint_clone_slot];
}
/* fast projection bucket array lookup, use the safe version for bound checking */
@@ -477,8 +518,8 @@ static int project_paint_PickFace(const ProjPaintState *ps, const float pt[2], f
static void uvco_to_wrapped_pxco(const 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);
+ *x = fmodf(uv[0], 1.0f);
+ *y = fmodf(uv[1], 1.0f);
if (*x < 0.0f) *x += 1.0f;
if (*y < 0.0f) *y += 1.0f;
@@ -505,7 +546,7 @@ static bool project_paint_PickColor(const ProjPaintState *ps, const float pt[2],
if (face_index == -1)
return 0;
- tf = ps->dm_mtface + face_index;
+ tf = *(ps->dm_mtface + face_index);
if (side == 0) {
interp_v2_v2v2v2(uv, tf->uv[0], tf->uv[1], tf->uv[2], w);
@@ -514,8 +555,9 @@ static bool project_paint_PickColor(const ProjPaintState *ps, const float pt[2],
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);
+ ima = project_paint_face_paint_image(ps, face_index);
ibuf = BKE_image_get_first_ibuf(ima); /* we must have got the imbuf before getting here */
+ if (!ibuf) return 0;
if (interp) {
float x, y;
@@ -762,11 +804,11 @@ static int line_isect_x(const float p1[2], const float p2[2], const float x_leve
static bool 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 xa = fmodf(vec2a[0], 1.0f);
+ float ya = fmodf(vec2a[1], 1.0f);
- float xb = (float)fmodf(vec2b[0], 1.0f);
- float yb = (float)fmodf(vec2b[1], 1.0f);
+ float xb = fmodf(vec2b[0], 1.0f);
+ float yb = fmodf(vec2b[1], 1.0f);
if (xa < 0.0f) xa += 1.0f;
if (ya < 0.0f) ya += 1.0f;
@@ -843,7 +885,7 @@ static bool pixel_bounds_array(float (*uv)[2], rcti *bounds_px, const int ibuf_x
static void project_face_winding_init(const ProjPaintState *ps, const int face_index)
{
/* detect the winding of faces in uv space */
- MTFace *tf = ps->dm_mtface + face_index;
+ MTFace *tf = ps->dm_mtface[face_index];
float winding = cross_tri_v2(tf->uv[0], tf->uv[1], tf->uv[2]);
if (ps->dm_mface[face_index].v4)
@@ -868,7 +910,7 @@ static bool check_seam(const ProjPaintState *ps,
MFace *mf;
MTFace *tf;
const MFace *orig_mf = ps->dm_mface + orig_face;
- const MTFace *orig_tf = ps->dm_mtface + 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));
@@ -890,13 +932,13 @@ static bool check_seam(const ProjPaintState *ps,
/* 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);
+ Image *tpage = project_paint_face_paint_image(ps, face_index);
+ Image *orig_tpage = project_paint_face_paint_image(ps, orig_face);
BLI_assert(i1_fidx != -1);
/* This IS an adjacent face!, now lets check if the UVs are ok */
- tf = ps->dm_mtface + face_index;
+ tf = ps->dm_mtface[face_index];
/* set up the other face */
*other_face = face_index;
@@ -909,7 +951,7 @@ static bool check_seam(const ProjPaintState *ps,
/* 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]) )
+ cmp_uv(orig_tf->uv[orig_i2_fidx], tf->uv[i2_fidx]))
{
/* if faces don't have the same winding in uv space,
* they are on the same side so edge is boundary */
@@ -1168,7 +1210,7 @@ static float project_paint_uvpixel_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);
+ Image *other_tpage = ps->stencil_ima;
const MTFace *tf_other = ps->dm_mtface_stencil + face_index;
if (other_tpage && (ibuf_other = BKE_image_acquire_ibuf(other_tpage, NULL, NULL))) {
@@ -1296,24 +1338,70 @@ static int project_paint_pixel_sizeof(const short tool)
}
}
+static int project_paint_undo_subtiles(const TileInfo *tinf, int tx, int ty)
+{
+ ProjPaintImage *pjIma = tinf->pjima;
+ int tile_index = tx + ty * tinf->tile_width;
+ bool generate_tile = false;
+
+ /* double check lock to avoid locking */
+ if (UNLIKELY(!pjIma->undoRect[tile_index])) {
+ if (tinf->lock)
+ BLI_spin_lock(tinf->lock);
+ if (LIKELY(!pjIma->undoRect[tile_index])) {
+ pjIma->undoRect[tile_index] = TILE_PENDING;
+ generate_tile = true;
+ }
+ if (tinf->lock)
+ BLI_spin_unlock(tinf->lock);
+ }
+
+
+ if (generate_tile) {
+ volatile void *undorect;
+ if (tinf->masked) {
+ undorect = image_undo_push_tile(pjIma->ima, pjIma->ibuf, tinf->tmpibuf, tx, ty, &pjIma->maskRect[tile_index], &pjIma->valid[tile_index], true);
+ }
+ else {
+ undorect = image_undo_push_tile(pjIma->ima, pjIma->ibuf, tinf->tmpibuf, tx, ty, NULL, &pjIma->valid[tile_index], true);
+ }
+
+ pjIma->ibuf->userflags |= IB_BITMAPDIRTY;
+ /* tile ready, publish */
+ if (tinf->lock)
+ BLI_spin_lock(tinf->lock);
+ pjIma->undoRect[tile_index] = undorect;
+ if (tinf->lock)
+ BLI_spin_unlock(tinf->lock);
+
+ }
+
+ return tile_index;
+}
/* 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,
+ const TileInfo *tinf,
int x_px, int 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;
-
+ int x_tile, y_tile;
+ int x_round, y_round;
+ int tile_offset;
+ /* volatile is important here to ensure pending check is not optimized away by compiler*/
+ volatile int tile_index;
+
+ ProjPaintImage *projima = tinf->pjima;
+ ImBuf *ibuf = projima->ibuf;
/* wrap pixel location */
x_px = mod_i(x_px, ibuf->x);
@@ -1321,19 +1409,36 @@ static ProjPixel *project_paint_uvpixel_init(
BLI_assert(ps->pixel_sizeof == project_paint_pixel_sizeof(ps->tool));
projPixel = (ProjPixel *)BLI_memarena_alloc(arena, ps->pixel_sizeof);
+
+ /* calculate the undo tile offset of the pixel, used to store the original
+ * pixel color and accumulated mask if any */
+ x_tile = x_px >> IMAPAINT_TILE_BITS;
+ y_tile = y_px >> IMAPAINT_TILE_BITS;
+
+ x_round = x_tile * IMAPAINT_TILE_SIZE;
+ y_round = y_tile * IMAPAINT_TILE_SIZE;
//memset(projPixel, 0, size);
+ tile_offset = (x_px - x_round) + (y_px - y_round) * IMAPAINT_TILE_SIZE;
+ tile_index = project_paint_undo_subtiles(tinf, x_tile, y_tile);
+
+ /* other thread may be initializing the tile so wait here */
+ while (projima->undoRect[tile_index] == TILE_PENDING)
+ ;
+
+ BLI_assert(tile_index < (IMAPAINT_TILE_NUMBER(ibuf->x) * IMAPAINT_TILE_NUMBER(ibuf->y)));
+ BLI_assert(tile_offset < (IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE));
+
+ projPixel->valid = projima->valid[tile_index];
+
if (ibuf->rect_float) {
projPixel->pixel.f_pt = ibuf->rect_float + ((x_px + y_px * ibuf->x) * 4);
- 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];
+ projPixel->origColor.f_pt = (float *)projima->undoRect[tile_index] + 4 * tile_offset;
zero_v4(projPixel->newColor.f);
}
else {
- projPixel->pixel.ch_pt = ((unsigned char *)ibuf->rect + ((x_px + y_px * ibuf->x) * 4));
- projPixel->origColor.uint = *projPixel->pixel.uint_pt;
+ projPixel->pixel.ch_pt = (unsigned char *)(ibuf->rect + (x_px + y_px * ibuf->x));
+ projPixel->origColor.uint_pt = (unsigned int *)projima->undoRect[tile_index] + tile_offset;
projPixel->newColor.uint = 0;
}
@@ -1348,7 +1453,10 @@ static ProjPixel *project_paint_uvpixel_init(
projPixel->y_px = y_px;
projPixel->mask = (unsigned short)(mask * 65535);
- projPixel->mask_accum = 0;
+ if (ps->do_masking)
+ projPixel->mask_accum = projima->maskRect[tile_index] + tile_offset;
+ else
+ projPixel->mask_accum = NULL;
/* which bounding box cell are we in?, needed for undo */
projPixel->bb_cell_index = ((int)(((float)x_px / (float)ibuf->x) * PROJ_BOUNDBOX_DIV)) +
@@ -1358,8 +1466,8 @@ static ProjPixel *project_paint_uvpixel_init(
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;
+ Image *other_tpage = project_paint_face_clone_slot(ps, face_index)->ima;
+ 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 */
@@ -1423,7 +1531,8 @@ static ProjPixel *project_paint_uvpixel_init(
if (ibuf->rect_float) projPixel->pixel.f_pt[0] = 0;
else projPixel->pixel.ch_pt[0] = 0;
#endif
- projPixel->image_index = image_index;
+ /* pointer arithmetics */
+ projPixel->image_index = projima - ps->projImages;
return projPixel;
}
@@ -2131,15 +2240,24 @@ static bool IsectPoly2Df_twoside(const float pt[2], float uv[][2], const int tot
/* 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)
+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, ImBuf *ibuf, ImBuf **tmpibuf, 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];
+ bool threaded = (ps->thread_tot > 1);
+
+ TileInfo tinf = {
+ ps->tile_lock,
+ ps->do_masking,
+ IMAPAINT_TILE_NUMBER(ibuf->x),
+ tmpibuf,
+ ps->projImages + image_index
+ };
const MFace *mf = ps->dm_mface + face_index;
- const MTFace *tf = ps->dm_mtface + face_index;
+ const MTFace *tf = ps->dm_mtface[face_index];
/* UV/pixel seeking data */
int x; /* Image X-Pixel */
@@ -2183,8 +2301,8 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
/* 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 * (1.0f / 3.0f))) / ibuf_xf;
- yhalfpx = (0.5f + (PROJ_GEOM_TOLERANCE * (1.0f / 4.0f))) / ibuf_yf;
+ xhalfpx = (0.5f + (PROJ_PIXEL_TOLERANCE * (1.0f / 3.0f))) / ibuf_xf;
+ yhalfpx = (0.5f + (PROJ_PIXEL_TOLERANCE * (1.0f / 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.
@@ -2258,6 +2376,10 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
CLAMP(bounds_px.ymax, 0, ibuf->y);
}
+ /*
+ project_paint_undo_tiles_init(&bounds_px, ps->projImages + image_index, tmpibuf,
+ tile_width, threaded, ps->do_masking);
+ */
/* clip face and */
has_isect = 0;
@@ -2300,8 +2422,8 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
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),
+ project_paint_uvpixel_init(ps, arena, &tinf, x, y, mask, face_index,
+ pixelScreenCo, wco, side, w),
arena
);
}
@@ -2333,7 +2455,7 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
if (ps->seam_bleed_px > 0.0f) {
int face_seam_flag;
- if (ps->thread_tot > 1)
+ if (threaded)
BLI_lock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */
face_seam_flag = ps->faceSeamFlags[face_index];
@@ -2351,7 +2473,7 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
if ((face_seam_flag & (PROJ_FACE_SEAM1 | PROJ_FACE_SEAM2 | PROJ_FACE_SEAM3 | PROJ_FACE_SEAM4)) == 0) {
- if (ps->thread_tot > 1)
+ if (threaded)
BLI_unlock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */
}
@@ -2376,7 +2498,7 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
uv_image_outset(tf_uv_pxoffset, outset_uv, ps->seam_bleed_px, ibuf->x, ibuf->y, mf->v4 != 0);
/* ps->faceSeamUVs cant be modified when threading, now this is done we can unlock */
- if (ps->thread_tot > 1)
+ if (threaded)
BLI_unlock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */
vCoSS[0] = ps->screenCoords[mf->v1];
@@ -2520,7 +2642,8 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
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),
+ project_paint_uvpixel_init(ps, arena, &tinf, x, y, mask, face_index,
+ pixelScreenCo, wco, side, w),
arena
);
}
@@ -2589,6 +2712,7 @@ static void project_bucket_init(const ProjPaintState *ps, const int thread_index
ImBuf *ibuf = NULL;
Image *tpage_last = NULL, *tpage;
Image *ima = NULL;
+ ImBuf *tmpibuf = NULL;
if (ps->image_tot == 1) {
/* Simple loop, no context switching */
@@ -2596,7 +2720,7 @@ static void project_bucket_init(const ProjPaintState *ps, const int thread_index
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);
+ project_paint_face_init(ps, thread_index, bucket_index, GET_INT_FROM_POINTER(node->link), 0, bucket_bounds, ibuf, &tmpibuf, ima->tpageflag & IMA_CLAMP_U, ima->tpageflag & IMA_CLAMP_V);
}
}
else {
@@ -2606,7 +2730,7 @@ static void project_bucket_init(const ProjPaintState *ps, const int thread_index
face_index = GET_INT_FROM_POINTER(node->link);
/* Image context switching */
- tpage = project_paint_face_image(ps, ps->dm_mtface, face_index);
+ tpage = project_paint_face_paint_image(ps, face_index);
if (tpage_last != tpage) {
tpage_last = tpage;
@@ -2620,10 +2744,13 @@ static void project_bucket_init(const ProjPaintState *ps, const int thread_index
}
/* 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);
+ project_paint_face_init(ps, thread_index, bucket_index, face_index, image_index, bucket_bounds, ibuf, &tmpibuf, ima->tpageflag & IMA_CLAMP_U, ima->tpageflag & IMA_CLAMP_V);
}
}
+ if (tmpibuf)
+ IMB_freeImBuf(tmpibuf);
+
ps->bucketFlags[bucket_index] |= PROJ_BUCKET_INIT;
}
@@ -2771,11 +2898,17 @@ static void project_paint_begin(ProjPaintState *ps)
ProjPaintImage *projIma;
Image *tpage_last = NULL, *tpage;
+ TexPaintSlot *slot_last = NULL, *slot = NULL;
+ TexPaintSlot *slot_last_clone = NULL, *slot_clone;
/* Face vars */
MPoly *mpoly_orig;
MFace *mf;
- MTFace *tf;
+ MTFace **tf;
+ MTFace *tf_base;
+
+ MTFace **tf_clone;
+ MTFace *tf_clone_base;
int a, i; /* generic looping vars */
int image_index = -1, face_index;
@@ -2830,13 +2963,15 @@ static void project_paint_begin(ProjPaintState *ps)
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);
+ DM_update_materials(ps->dm, ps->ob);
ps->dm_totvert = ps->dm->getNumVerts(ps->dm);
ps->dm_totface = ps->dm->getNumTessFaces(ps->dm);
+ ps->dm_mvert = ps->dm->getVertArray(ps->dm);
+ ps->dm_mface = ps->dm->getTessFaceArray(ps->dm);
+ ps->dm_mtface = MEM_mallocN(ps->dm_totface * sizeof(MTFace *), "proj_paint_mtfaces");
+
if (ps->do_face_sel) {
index_mf_to_mpoly = ps->dm->getTessFaceDataArray(ps->dm, CD_ORIGINDEX);
index_mp_to_orig = ps->dm->getPolyDataArray(ps->dm, CD_ORIGINDEX);
@@ -2852,32 +2987,23 @@ static void project_paint_begin(ProjPaintState *ps)
}
/* 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)->pdata, CD_MTEXPOLY);
- 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;
- }
+ ps->dm_mtface_clone = MEM_mallocN(ps->dm_totface * sizeof(MTFace *), "proj_paint_mtfaces");
}
- if (ps->do_layer_stencil) {
+ if (ps->do_layer_stencil || ps->do_stencil_brush) {
//int layer_num = CustomData_get_stencil_layer(&ps->dm->faceData, CD_MTFACE);
int layer_num = CustomData_get_stencil_layer(&((Mesh *)ps->ob->data)->pdata, CD_MTEXPOLY);
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;
+ if (ps->dm_mtface_stencil == NULL) {
+ /* get active instead */
+ ps->dm_mtface_stencil = CustomData_get_layer(&ps->dm->faceData, CD_MTFACE);
}
+
+ if (ps->do_stencil_brush)
+ tf_base = ps->dm_mtface_stencil;
}
/* when using subsurf or multires, mface arrays are thrown away, we need to keep a copy */
@@ -3092,6 +3218,13 @@ static void project_paint_begin(ProjPaintState *ps)
if (reset_threads)
ps->thread_tot = 1;
+ if (ps->thread_tot > 1) {
+ ps->tile_lock = MEM_mallocN(sizeof(SpinLock), "projpaint_tile_lock");
+ BLI_spin_init(ps->tile_lock);
+ }
+
+ image_undo_init_locks();
+
for (a = 0; a < ps->thread_tot; a++) {
ps->arena_mt[a] = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "project paint arena");
}
@@ -3153,7 +3286,48 @@ static void project_paint_begin(ProjPaintState *ps)
is_face_sel = true;
}
- if (is_face_sel && (tpage = project_paint_face_image(ps, ps->dm_mtface, face_index))) {
+ if (!ps->do_stencil_brush) {
+ slot = project_paint_face_paint_slot(ps, face_index);
+ /* all faces should have a valid slot, reassert here */
+ if (slot == NULL) {
+ tf_base = CustomData_get_layer(&ps->dm->faceData, CD_MTFACE);
+ }
+ else {
+ if (slot != slot_last) {
+ if (!slot->uvname || !(tf_base = CustomData_get_layer_named(&ps->dm->faceData, CD_MTFACE, slot->uvname)))
+ tf_base = CustomData_get_layer(&ps->dm->faceData, CD_MTFACE);
+ slot_last = slot;
+ }
+
+ /* don't allow using the same inage for painting and stencilling */
+ if (slot->ima == ps->stencil_ima)
+ continue;
+ }
+ }
+
+ *tf = tf_base + face_index;
+
+ if (ps->do_layer_clone) {
+ slot_clone = project_paint_face_clone_slot(ps, face_index);
+ /* all faces should have a valid slot, reassert here */
+ if (ELEM(slot_clone, NULL, slot))
+ continue;
+
+ tf_clone = ps->dm_mtface_clone + face_index;
+
+ if (slot_clone != slot_last_clone) {
+ if (!slot->uvname || !(tf_clone_base = CustomData_get_layer_named(&ps->dm->faceData, CD_MTFACE, slot_clone->uvname)))
+ tf_clone_base = CustomData_get_layer(&ps->dm->faceData, CD_MTFACE);
+ slot_last_clone = slot_clone;
+ }
+
+ *tf_clone = tf_clone_base + face_index;
+ }
+
+ /* tfbase here should be non-null! */
+ BLI_assert (tf_base != NULL);
+
+ if (is_face_sel && ((slot && (tpage = slot->ima)) || (tpage = project_paint_face_paint_image(ps, face_index)))) {
const float *v1coSS, *v2coSS, *v3coSS, *v4coSS = NULL;
v1coSS = ps->screenCoords[mf->v1];
@@ -3251,10 +3425,19 @@ static void project_paint_begin(ProjPaintState *ps)
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++) {
+ int size;
projIma->ima = node->link;
projIma->touch = 0;
projIma->ibuf = BKE_image_acquire_ibuf(projIma->ima, NULL, NULL);
- projIma->partRedrawRect = BLI_memarena_calloc(arena, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
+ size = sizeof(void **) * IMAPAINT_TILE_NUMBER(projIma->ibuf->x) * IMAPAINT_TILE_NUMBER(projIma->ibuf->y);
+ projIma->partRedrawRect = BLI_memarena_alloc(arena, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
+ memset(projIma->partRedrawRect, 0, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
+ projIma->undoRect = (volatile void **) BLI_memarena_alloc(arena, size);
+ memset(projIma->undoRect, 0, size);
+ projIma->maskRect = (unsigned short **) BLI_memarena_alloc(arena, size);
+ memset(projIma->maskRect, 0, size);
+ projIma->valid = (bool **) BLI_memarena_alloc(arena, size);
+ memset(projIma->valid, 0, size);
}
/* we have built the array, discard the linked list */
@@ -3281,95 +3464,12 @@ 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_calloc(arena, 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 */
+ image_undo_remove_masks();
/* 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);
+ DAG_id_tag_update(&projIma->ima->id, 0);
}
BKE_image_release_ibuf(ps->reproject_image, ps->reproject_ibuf, NULL);
@@ -3378,6 +3478,14 @@ static void project_paint_end(ProjPaintState *ps)
MEM_freeN(ps->bucketRect);
MEM_freeN(ps->bucketFaces);
MEM_freeN(ps->bucketFlags);
+ MEM_freeN(ps->dm_mtface);
+ if (ps->do_layer_clone)
+ MEM_freeN(ps->dm_mtface_clone);
+ if (ps->thread_tot > 1) {
+ BLI_spin_end(ps->tile_lock);
+ MEM_freeN((void *)ps->tile_lock);
+ }
+ image_undo_end_locks();
#ifndef PROJ_DEBUG_NOSEAMBLEED
if (ps->seam_bleed_px > 0.0f) {
@@ -3388,6 +3496,11 @@ static void project_paint_end(ProjPaintState *ps)
}
#endif
+ if (ps->blurkernel) {
+ paint_delete_blur_kernel(ps->blurkernel);
+ MEM_freeN(ps->blurkernel);
+ }
+
if (ps->vertFlags) MEM_freeN(ps->vertFlags);
for (a = 0; a < ps->thread_tot; a++) {
@@ -3480,7 +3593,7 @@ static bool 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);
+ const float radius = ps->brush_size;
/* 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 :/
@@ -3518,7 +3631,7 @@ static bool project_bucket_iter_init(ProjPaintState *ps, const float mval_f[2])
static bool 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);
+ const int diameter = 2 * ps->brush_size;
if (ps->thread_tot > 1)
BLI_lock_thread(LOCK_CUSTOM1);
@@ -3580,7 +3693,7 @@ static void do_projectpaint_clone(ProjPaintState *ps, ProjPixel *projPixel, floa
clone_rgba[3] = (unsigned char)(clone_pt[3] * mask);
if (ps->do_masking) {
- IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch, clone_rgba, ps->blend);
+ IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, clone_rgba, ps->blend);
}
else {
IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->pixel.ch_pt, clone_rgba, ps->blend);
@@ -3598,7 +3711,7 @@ static void do_projectpaint_clone_f(ProjPaintState *ps, ProjPixel *projPixel, fl
mul_v4_v4fl(clone_rgba, clone_pt, mask);
if (ps->do_masking) {
- IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f, clone_rgba, ps->blend);
+ IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt, clone_rgba, ps->blend);
}
else {
IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, clone_rgba, ps->blend);
@@ -3636,42 +3749,58 @@ static void do_projectpaint_smear_f(ProjPaintState *ps, ProjPixel *projPixel, fl
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 mask,
MemArena *softenArena, LinkNode **softenPixels)
{
- unsigned int accum_tot = 0;
- unsigned int i;
-
+ float accum_tot = 0.0;
+ int xk, yk;
+ BlurKernel *kernel = ps->blurkernel;
float *rgba = projPixel->newColor.f;
- /* sigh, mask values tend to need to be a _lot_ stronger with blur */
- mask = inv_pow2(mask);
-
/* 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++;
+ for (yk = 0; yk < kernel->side; yk++) {
+ for (xk = 0; xk < kernel->side; xk++) {
+ float rgba_tmp[4];
+ float co_ofs[2] = {xk - kernel->pixel_len, yk - kernel->pixel_len};
+
+ add_v2_v2(co_ofs, projPixel->projCoSS);
+
+ if (project_paint_PickColor(ps, co_ofs, rgba_tmp, NULL, true)) {
+ float weight = kernel->wdata[xk + yk * kernel->side];
+ mul_v4_fl(rgba_tmp, weight);
+ add_v4_v4(rgba, rgba_tmp);
+ accum_tot += weight;
+ }
}
}
if (LIKELY(accum_tot != 0)) {
mul_v4_fl(rgba, 1.0f / (float)accum_tot);
- blend_color_interpolate_float(rgba, rgba, projPixel->pixel.f_pt, mask);
+
+ if (ps->mode == BRUSH_STROKE_INVERT) {
+ /* subtract blurred image from normal image gives high pass filter */
+ sub_v3_v3v3(rgba, projPixel->pixel.f_pt, rgba);
+
+ /* now rgba_ub contains the edge result, but this should be converted to luminance to avoid
+ * colored speckles appearing in final image, and also to check for threshold */
+ rgba[0] = rgba[1] = rgba[2] = rgb_to_grayscale(rgba);
+ if (fabsf(rgba[0]) > ps->brush->sharp_threshold) {
+ float alpha = projPixel->pixel.f_pt[3];
+ projPixel->pixel.f_pt[3] = rgba[3] = mask;
+
+ /* add to enhance edges */
+ blend_color_add_float(rgba, projPixel->pixel.f_pt, rgba);
+ projPixel->pixel.f_pt[3] = alpha;
+ }
+ else
+ return;
+ }
+ else {
+ blend_color_interpolate_float(rgba, rgba, projPixel->pixel.f_pt, mask);
+ }
+
BLI_linklist_prepend_arena(softenPixels, (void *)projPixel, softenArena);
}
}
@@ -3679,24 +3808,27 @@ static void do_projectpaint_soften_f(ProjPaintState *ps, ProjPixel *projPixel, f
static void do_projectpaint_soften(ProjPaintState *ps, ProjPixel *projPixel, float mask,
MemArena *softenArena, LinkNode **softenPixels)
{
- unsigned int accum_tot = 0;
- unsigned int i;
-
+ float accum_tot = 0;
+ int xk, yk;
+ BlurKernel *kernel = ps->blurkernel;
float rgba[4]; /* convert to byte after */
- /* sigh, mask values tend to need to be a _lot_ stronger with blur */
- mask = inv_pow2(mask);
-
/* 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++;
+ for (yk = 0; yk < kernel->side; yk++) {
+ for (xk = 0; xk < kernel->side; xk++) {
+ float rgba_tmp[4];
+ float co_ofs[2] = {xk - kernel->pixel_len, yk - kernel->pixel_len};
+
+ add_v2_v2(co_ofs, projPixel->projCoSS);
+
+ if (project_paint_PickColor(ps, co_ofs, rgba_tmp, NULL, true)) {
+ float weight = kernel->wdata[xk + yk * kernel->side];
+ mul_v4_fl(rgba_tmp, weight);
+ add_v4_v4(rgba, rgba_tmp);
+ accum_tot += weight;
+ }
}
}
@@ -3704,9 +3836,34 @@ static void do_projectpaint_soften(ProjPaintState *ps, ProjPixel *projPixel, flo
unsigned char *rgba_ub = projPixel->newColor.ch;
mul_v4_fl(rgba, 1.0f / (float)accum_tot);
- premul_float_to_straight_uchar(rgba_ub, rgba);
- blend_color_interpolate_byte(rgba_ub, rgba_ub, projPixel->pixel.ch_pt, mask);
+ if (ps->mode == BRUSH_STROKE_INVERT) {
+ float rgba_pixel[4];
+
+ straight_uchar_to_premul_float(rgba_pixel, projPixel->pixel.ch_pt);
+
+ /* subtract blurred image from normal image gives high pass filter */
+ sub_v3_v3v3(rgba, rgba_pixel, rgba);
+ /* now rgba_ub contains the edge result, but this should be converted to luminance to avoid
+ * colored speckles appearing in final image, and also to check for threshold */
+ rgba[0] = rgba[1] = rgba[2] = rgb_to_grayscale(rgba);
+ if (fabsf(rgba[0]) > ps->brush->sharp_threshold) {
+ float alpha = rgba_pixel[3];
+ rgba[3] = rgba_pixel[3] = mask;
+
+ /* add to enhance edges */
+ blend_color_add_float(rgba, rgba_pixel, rgba);
+
+ rgba[3] = alpha;
+ premul_float_to_straight_uchar(rgba_ub, rgba);
+ }
+ else
+ return;
+ }
+ else {
+ premul_float_to_straight_uchar(rgba_ub, rgba);
+ blend_color_interpolate_byte(rgba_ub, rgba_ub, projPixel->pixel.ch_pt, mask);
+ }
BLI_linklist_prepend_arena(softenPixels, (void *)projPixel, softenArena);
}
}
@@ -3716,7 +3873,7 @@ static void do_projectpaint_draw(ProjPaintState *ps, ProjPixel *projPixel, const
float rgb[3];
unsigned char rgba_ub[4];
- copy_v3_v3(rgb, ps->brush->rgb);
+ copy_v3_v3(rgb, ps->paint_color);
if (ps->is_texbrush) {
mul_v3_v3(rgb, texrgb);
@@ -3728,7 +3885,7 @@ static void do_projectpaint_draw(ProjPaintState *ps, ProjPixel *projPixel, const
rgba_ub[3] = f_to_char(mask);
if (ps->do_masking) {
- IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch, rgba_ub, ps->blend);
+ IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, rgba_ub, ps->blend);
}
else {
IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->pixel.ch_pt, rgba_ub, ps->blend);
@@ -3739,7 +3896,7 @@ static void do_projectpaint_draw_f(ProjPaintState *ps, ProjPixel *projPixel, con
{
float rgba[4];
- srgb_to_linearrgb_v3_v3(rgba, ps->brush->rgb);
+ copy_v3_v3(rgba, ps->paint_color_linear);
if (ps->is_texbrush)
mul_v3_v3(rgba, texrgb);
@@ -3748,13 +3905,42 @@ static void do_projectpaint_draw_f(ProjPaintState *ps, ProjPixel *projPixel, con
rgba[3] = mask;
if (ps->do_masking) {
- IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f, rgba, ps->blend);
+ IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt, rgba, ps->blend);
+ }
+ else {
+ IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, rgba, ps->blend);
+ }
+}
+
+static void do_projectpaint_mask(ProjPaintState *ps, ProjPixel *projPixel, float mask)
+{
+ unsigned char rgba_ub[4];
+ rgba_ub[0] = rgba_ub[1] = rgba_ub[2] = ps->stencil_value * 255.0f;
+ rgba_ub[3] = f_to_char(mask);
+
+ if (ps->do_masking) {
+ IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, rgba_ub, ps->blend);
+ }
+ else {
+ IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->pixel.ch_pt, rgba_ub, ps->blend);
+ }
+}
+
+static void do_projectpaint_mask_f(ProjPaintState *ps, ProjPixel *projPixel, float mask)
+{
+ float rgba[4];
+ rgba[0] = rgba[1] = rgba[2] = ps->stencil_value;
+ rgba[3] = mask;
+
+ if (ps->do_masking) {
+ IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt, rgba, ps->blend);
}
else {
IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, rgba, ps->blend);
}
}
+
/* run this for single and multithreaded painting */
static void *do_projectpaint_thread(void *ph_v)
{
@@ -3788,7 +3974,7 @@ static void *do_projectpaint_thread(void *ph_v)
float co[2];
unsigned short mask_short;
const float brush_alpha = BKE_brush_alpha_get(ps->scene, brush);
- const float brush_radius = (float)BKE_brush_size_get(ps->scene, brush);
+ const float brush_radius = ps->brush_size;
const float brush_radius_sq = brush_radius * brush_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;
@@ -3838,32 +4024,102 @@ static void *do_projectpaint_thread(void *ph_v)
}
/* 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]) {
- float newColor_f[4];
- float mask = ((float)projPixel->mask) * (1.0f / 65535.0f);
+ /* fill tools */
+ if (ps->source == PROJ_SRC_VIEW_FILL) {
+ if (brush->flag & BRUSH_USE_GRADIENT) {
+ /* these could probably be cached instead of being done per pixel */
+ float tangent[2];
+ float line_len_sq_inv, line_len;
+ float f;
+ float color_f[4];
+ float p[2] = {projPixel->projCoSS[0] - lastpos[0], projPixel->projCoSS[1] - lastpos[1]};
+
+ sub_v2_v2v2(tangent, pos, lastpos);
+ line_len = len_squared_v2(tangent);
+ line_len_sq_inv = 1.0f / line_len;
+ line_len = sqrt(line_len);
+
+ switch (brush->gradient_fill_mode) {
+ case BRUSH_GRADIENT_LINEAR:
+ {
+ f = dot_v2v2(p, tangent) * line_len_sq_inv;
+ break;
+ }
+ case BRUSH_GRADIENT_RADIAL:
+ {
+ f = len_v2(p) / line_len;
+ break;
+ }
+ }
+ do_colorband(brush->gradient, f, color_f);
+ color_f[3] *= ((float)projPixel->mask) * (1.0f / 65535.0f) * brush->alpha;
+
+ if (is_floatbuf) {
+ /* convert to premultipied */
+ mul_v3_fl(color_f, color_f[3]);
+ IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt,
+ color_f, ps->blend);
+ }
+ else {
+ rgba_float_to_uchar(projPixel->newColor.ch, color_f);
+ IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt,
+ projPixel->newColor.ch, ps->blend);
+ }
+ }
+ else {
+ if (is_floatbuf) {
+ float newColor_f[4];
+ newColor_f[3] = ((float)projPixel->mask) * (1.0f / 65535.0f) * brush->alpha;
+ copy_v3_v3(newColor_f, ps->paint_color_linear);
- straight_uchar_to_premul_float(newColor_f, projPixel->newColor.ch);
- IMB_colormanagement_colorspace_to_scene_linear_v4(newColor_f, true, ps->reproject_ibuf->rect_colorspace);
- mul_v4_v4fl(newColor_f, newColor_f, mask);
+ IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt,
+ newColor_f, ps->blend);
+ }
+ else {
+ float mask = ((float)projPixel->mask) * (1.0f / 65535.0f);
+ projPixel->newColor.ch[3] = mask * 255 * brush->alpha;
- blend_color_mix_float(projPixel->pixel.f_pt, projPixel->origColor.f,
- newColor_f);
+ rgb_float_to_uchar(projPixel->newColor.ch, ps->paint_color);
+ IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt,
+ projPixel->newColor.ch, ps->blend);
+ }
}
+
+ 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);
}
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]) {
- float mask = ((float)projPixel->mask) * (1.0f / 65535.0f);
- projPixel->newColor.ch[3] *= mask;
-
- blend_color_mix_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch,
- projPixel->newColor.ch);
+ 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]) {
+ float newColor_f[4];
+ float mask = ((float)projPixel->mask) * (1.0f / 65535.0f);
+
+ straight_uchar_to_premul_float(newColor_f, projPixel->newColor.ch);
+ IMB_colormanagement_colorspace_to_scene_linear_v4(newColor_f, true, ps->reproject_ibuf->rect_colorspace);
+ mul_v4_v4fl(newColor_f, newColor_f, mask);
+
+ blend_color_mix_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt,
+ newColor_f);
+ }
+ }
+ 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]) {
+ float mask = ((float)projPixel->mask) * (1.0f / 65535.0f);
+ projPixel->newColor.ch[3] *= mask;
+
+ blend_color_mix_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt,
+ projPixel->newColor.ch);
+ }
}
}
}
@@ -3885,7 +4141,7 @@ static void *do_projectpaint_thread(void *ph_v)
if (falloff > 0.0f) {
float texrgb[3];
- float mask = falloff;
+ float mask;
if (ps->do_masking) {
/* masking to keep brush contribution to a pixel limited. note we do not do
@@ -3894,20 +4150,24 @@ static void *do_projectpaint_thread(void *ph_v)
*
* Instead we use a formula that adds up but approaches brush_alpha slowly
* and never exceeds it, which gives nice smooth results. */
- float mask_accum = projPixel->mask_accum;
+ float mask_accum = *projPixel->mask_accum;
+ float max_mask = brush_alpha * falloff * 65535.0f;
if (ps->is_maskbrush) {
float texmask = BKE_brush_sample_masktex(ps->scene, ps->brush, projPixel->projCoSS, thread_index, pool);
- CLAMP(texmask, 0.0f, 1.0f);
- mask = mask_accum + (brush_alpha * texmask * 65535.0f - mask_accum) * mask;
- }
- else {
- mask = mask_accum + (brush_alpha * 65535.0f - mask_accum) * mask;
+ max_mask *= texmask;
}
+
+ if (brush->flag & BRUSH_ACCUMULATE)
+ mask = mask_accum + max_mask;
+ else
+ mask = mask_accum + (max_mask - mask_accum * falloff);
+
+ mask = min_ff(mask, 65535.0f);
mask_short = (unsigned short)mask;
- if (mask_short > projPixel->mask_accum) {
- projPixel->mask_accum = mask_short;
+ if (mask_short > *projPixel->mask_accum) {
+ *projPixel->mask_accum = mask_short;
mask = mask_short * (1.0f / 65535.0f);
}
else {
@@ -3916,7 +4176,7 @@ static void *do_projectpaint_thread(void *ph_v)
}
}
else {
- mask *= brush_alpha;
+ mask = brush_alpha * falloff;
if (ps->is_maskbrush) {
float texmask = BKE_brush_sample_masktex(ps->scene, ps->brush, projPixel->projCoSS, thread_index, pool);
CLAMP(texmask, 0.0f, 1.0f);
@@ -3945,10 +4205,6 @@ static void *do_projectpaint_thread(void *ph_v)
mask *= texrgba[3];
}
- if (ps->is_maskbrush_tiled) {
- mask *= BKE_brush_sample_masktex(ps->scene, ps->brush, projPixel->projCoSS, thread_index, pool);
- }
-
/* extra mask for normal, layer stencil, .. */
mask *= ((float)projPixel->mask) * (1.0f / 65535.0f);
@@ -3964,6 +4220,9 @@ static void *do_projectpaint_thread(void *ph_v)
}
/* end copy */
+ /* validate undo tile, since we will modify t*/
+ *projPixel->valid = true;
+
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);
@@ -3987,6 +4246,10 @@ static void *do_projectpaint_thread(void *ph_v)
if (is_floatbuf) do_projectpaint_soften_f(ps, projPixel, mask, softenArena, &softenPixels_f);
else do_projectpaint_soften(ps, projPixel, mask, softenArena, &softenPixels);
break;
+ case PAINT_TOOL_MASK:
+ if (is_floatbuf) do_projectpaint_mask_f(ps, projPixel, mask);
+ else do_projectpaint_mask(ps, projPixel, mask);
+ break;
default:
if (is_floatbuf) do_projectpaint_draw_f(ps, projPixel, texrgb, mask);
else do_projectpaint_draw(ps, projPixel, texrgb, mask);
@@ -3995,8 +4258,8 @@ static void *do_projectpaint_thread(void *ph_v)
}
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];
+ if (is_floatbuf) projPixel->pixel.f_pt[3] = projPixel->origColor.f_pt[3];
+ else projPixel->pixel.ch_pt[3] = projPixel->origColor.ch_pt[3];
}
/* done painting */
@@ -4114,14 +4377,17 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po
}
-void paint_proj_stroke(bContext *C, void *pps, const float prev_pos[2], const float pos[2])
+void paint_proj_stroke(const bContext *C, void *pps, const float prev_pos[2], const float pos[2], float pressure, float distance, float size)
{
ProjPaintState *ps = pps;
+ Brush *brush = ps->brush;
+ Scene *scene = ps->scene;
int a;
+ ps->brush_size = size;
+
/* 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 = ED_view3d_cursor3d_get(scene, v3d);
int mval_i[2] = {(int)pos[0], (int)pos[1]};
@@ -4136,6 +4402,25 @@ void paint_proj_stroke(bContext *C, void *pps, const float prev_pos[2], const fl
return;
}
+ /* handle gradient and inverted stroke color here */
+ if (ps->tool == PAINT_TOOL_DRAW) {
+ paint_brush_color_get(scene, brush, false, ps->mode == BRUSH_STROKE_INVERT, distance, pressure, ps->paint_color, NULL);
+ srgb_to_linearrgb_v3_v3(ps->paint_color_linear, ps->paint_color);
+ }
+ else if (ps->tool == PAINT_TOOL_FILL) {
+ copy_v3_v3(ps->paint_color, BKE_brush_color_get(scene, brush));
+ srgb_to_linearrgb_v3_v3(ps->paint_color_linear, ps->paint_color);
+ }
+ else if (ps->tool == PAINT_TOOL_MASK) {
+ ps->stencil_value = brush->weight;
+
+ if ((ps->mode == BRUSH_STROKE_INVERT) ^
+ ((scene->toolsettings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) != 0))
+ {
+ ps->stencil_value = 1.0f - ps->stencil_value;
+ }
+ }
+
/* continue adding to existing partial redraw rects until redraw */
if (!ps->need_redraw) {
for (a = 0; a < ps->image_tot; a++)
@@ -4160,30 +4445,24 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int
Brush *brush = ps->brush;
ps->tool = brush->imagepaint_tool;
ps->blend = brush->blend;
+ /* only check for inversion for the soften tool, elsewhere, a resident brush inversion flag can cause issues */
+ if (brush->imagepaint_tool == PAINT_TOOL_SOFTEN) {
+ ps->mode = ((ps->mode == BRUSH_STROKE_INVERT) ^ ((brush->flag & BRUSH_DIR_IN) != 0) ?
+ BRUSH_STROKE_INVERT : BRUSH_STROKE_NORMAL);
+
+ ps->blurkernel = paint_new_blur_kernel(brush);
+ }
/* disable for 3d mapping also because painting on mirrored mesh can create "stripes" */
- ps->do_masking = (brush->flag & BRUSH_AIRBRUSH ||
- (brush->imagepaint_tool == PAINT_TOOL_SMEAR) ||
- (brush->mtex.tex && !ELEM3(brush->mtex.brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL, MTEX_MAP_MODE_3D)))
- ? false : true;
+ ps->do_masking = paint_use_opacity_masking(brush);
ps->is_texbrush = (brush->mtex.tex && brush->imagepaint_tool == PAINT_TOOL_DRAW) ? true : false;
- ps->is_maskbrush = false;
- ps->is_maskbrush_tiled = false;
- if (brush->mask_mtex.tex) {
- if (ELEM(brush->mask_mtex.brush_map_mode, MTEX_MAP_MODE_STENCIL, MTEX_MAP_MODE_TILED)) {
- ps->is_maskbrush_tiled = true;
- }
- else {
- ps->is_maskbrush = true;
- }
- }
+ ps->is_maskbrush = (brush->mask_mtex.tex) ? true : false;
}
else {
/* brush may be NULL*/
ps->do_masking = false;
ps->is_texbrush = false;
ps->is_maskbrush = false;
- ps->is_maskbrush_tiled = false;
}
/* sizeof(ProjPixel), since we alloc this a _lot_ */
@@ -4198,6 +4477,7 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int
ps->scene = scene;
ps->ob = ob; /* allow override of active object */
+ ps->stencil_ima = settings->imapaint.stencil;
/* 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;
@@ -4207,8 +4487,11 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int
if (ps->tool == PAINT_TOOL_CLONE)
ps->do_layer_clone = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE) ? 1 : 0;
- 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;
+ ps->do_stencil_brush = ps->brush->imagepaint_tool == PAINT_TOOL_MASK;
+ /* deactivate stenciling for the stencil brush :) */
+ ps->do_layer_stencil = ((settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL) &&
+ !(ps->do_stencil_brush) && ps->stencil_ima);
+ ps->do_layer_stencil_inv = ((settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) != 0);
#ifndef PROJ_DEBUG_NOSEAMBLEED
@@ -4236,6 +4519,7 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int
void *paint_proj_new_stroke(bContext *C, Object *ob, const float 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) {
@@ -4268,6 +4552,10 @@ void *paint_proj_new_stroke(bContext *C, Object *ob, const float mouse[2], int m
paint_proj_begin_clone(ps, mouse);
+ /* special full screen draw mode for fill tool */
+ if (ps->tool == PAINT_TOOL_FILL)
+ ps->source = PROJ_SRC_VIEW_FILL;
+
return ps;
}
@@ -4316,8 +4604,11 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
int orig_brush_size;
IDProperty *idgroup;
IDProperty *view_data = NULL;
+ Object *ob = OBACT;
+
+ paint_proj_mesh_data_ensure(C, ob, op);
- project_state_init(C, OBACT, &ps, BRUSH_STROKE_NORMAL);
+ project_state_init(C, ob, &ps, BRUSH_STROKE_NORMAL);
if (ps.ob == NULL || ps.ob->type != OB_MESH) {
BKE_report(op->reports, RPT_ERROR, "No active mesh object");
@@ -4365,7 +4656,6 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
/* override */
ps.is_texbrush = false;
ps.is_maskbrush = false;
- ps.is_maskbrush_tiled = false;
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 */
@@ -4375,7 +4665,7 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
scene->toolsettings->imapaint.flag |= IMAGEPAINT_DRAWING;
ED_undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name,
- ED_image_undo_restore, ED_image_undo_free);
+ ED_image_undo_restore, ED_image_undo_free, NULL);
/* allocate and initialize spatial data structures */
project_paint_begin(&ps);
@@ -4508,3 +4798,162 @@ void PAINT_OT_image_from_view(wmOperatorType *ot)
RNA_def_string_file_name(ot->srna, "filepath", NULL, FILE_MAX, "File Path", "Name of the file");
}
+
+/* Add layer operator */
+
+static EnumPropertyItem layer_type_items[] = {
+ {MAP_COL, "DIFFUSE_COLOR", 0, "Diffuse Color", ""},
+ {MAP_REF, "DIFFUSE_INTENSITY", 0, "Diffuse Intensity", ""},
+ {MAP_ALPHA, "ALPHA", 0, "Alpha", ""},
+ {MAP_TRANSLU, "TRANSLUCENCY", 0, "Translucency", ""},
+ {MAP_COLSPEC, "SPECULAR_COLOR", 0, "Specular Color", ""},
+ {MAP_SPEC, "SPECULAR_INTENSITY", 0, "Specular Intensity", ""},
+ {MAP_HAR, "SPECULAR_HARDNESS", 0, "Specular Hardness", ""},
+ {MAP_AMB, "AMBIENT", 0, "Ambient", ""},
+ {MAP_EMIT, "EMMIT", 0, "Emmit", ""},
+ {MAP_COLMIR, "MIRROR_COLOR", 0, "Mirror Color", ""},
+ {MAP_RAYMIRR, "RAYMIRROR", 0, "Ray Mirror", ""},
+ {MAP_NORM, "NORMAL", 0, "Normal", ""},
+ {MAP_WARP, "WARP", 0, "Warp", ""},
+ {MAP_DISPLACE, "DISPLACE", 0, "Displace", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+bool proj_paint_add_slot(bContext *C, Material *ma, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ Scene *scene = CTX_data_scene(C);
+ bool use_nodes = BKE_scene_use_new_shading_nodes(scene);
+
+ if (!ob)
+ return false;
+
+ if (!ma)
+ ma = give_current_material(ob, ob->actcol);
+
+ if (ma) {
+
+ if (use_nodes) {
+ /* not supported for now */
+ }
+ else {
+ MTex *mtex = add_mtex_id(&ma->id, -1);
+
+ /* successful creation of mtex layer, now create set */
+ if (mtex) {
+ Main *bmain = CTX_data_main(C);
+ Image *ima;
+ int type = MAP_COL;
+
+ if (op)
+ type = RNA_enum_get(op->ptr, "type");
+
+ mtex->tex = add_texture(bmain, DATA_(layer_type_items[type].name));
+ mtex->mapto = type;
+
+ if (mtex->tex) {
+ float color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ char imagename[MAX_ID_NAME - 2] = "Material Diffuse Color";
+ int width = 1024;
+ int height = 1024;
+ bool use_float = false;
+ short gen_type = IMA_GENTYPE_BLANK;
+ bool alpha = false;
+
+ if (op) {
+ width = RNA_int_get(op->ptr, "width");
+ height = RNA_int_get(op->ptr, "height");
+ use_float = RNA_boolean_get(op->ptr, "float");
+ gen_type = RNA_enum_get(op->ptr, "generated_type");
+ RNA_float_get_array(op->ptr, "color", color);
+ alpha = RNA_boolean_get(op->ptr, "alpha");
+ RNA_string_get(op->ptr, "name", imagename);
+ }
+
+ if (!use_float) {
+ /* crappy workaround because we only upload straight color to OpenGL and that makes
+ * painting result on viewport too opaque */
+ color[3] = 1.0;
+ }
+
+ ima = mtex->tex->ima = BKE_image_add_generated(bmain, width, height, imagename, alpha ? 32 : 24, use_float,
+ gen_type, color);
+
+ BKE_texpaint_slot_refresh_cache(ma, false);
+ BKE_image_signal(ima, NULL, IMA_SIGNAL_USER_NEW_IMAGE);
+ WM_event_add_notifier(C, NC_TEXTURE | NA_ADDED, mtex->tex);
+ WM_event_add_notifier(C, NC_IMAGE | NA_ADDED, ima);
+ ED_area_tag_redraw(CTX_wm_area(C));
+ }
+
+ WM_event_add_notifier(C, NC_TEXTURE, CTX_data_scene(C));
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static int texture_paint_add_texture_paint_slot_exec(bContext *C, wmOperator *op)
+{
+ return proj_paint_add_slot(C, NULL, op);
+}
+
+
+static int texture_paint_add_texture_paint_slot_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ char imagename[MAX_ID_NAME - 2];
+ Object *ob = CTX_data_active_object(C);
+ Material *ma = give_current_material(ob, ob->actcol);
+ int type = RNA_enum_get(op->ptr, "type");
+
+ type = RNA_enum_from_value(layer_type_items, type);
+
+ /* get the name of the texture layer type */
+ BLI_assert(type != -1);
+
+ /* take the second letter to avoid the ID identifier */
+ BLI_snprintf(imagename, FILE_MAX, "%s %s", &ma->id.name[2], layer_type_items[type].name);
+
+ RNA_string_set(op->ptr, "name", imagename);
+ return WM_operator_props_dialog_popup(C, op, 15 * UI_UNIT_X, 5 * UI_UNIT_Y);
+}
+
+#define IMA_DEF_NAME N_("Untitled")
+
+
+void PAINT_OT_add_texture_paint_slot(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+ static float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+
+ /* identifiers */
+ ot->name = "Add Texture Paint Slot";
+ ot->description = "Add a texture paint slot";
+ ot->idname = "PAINT_OT_add_texture_paint_slot";
+
+ /* api callbacks */
+ ot->invoke = texture_paint_add_texture_paint_slot_invoke;
+ ot->exec = texture_paint_add_texture_paint_slot_exec;
+ ot->poll = ED_operator_region_view3d_active;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_enum(ot->srna, "type", layer_type_items, 0, "Type", "Merge method to use");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ RNA_def_string(ot->srna, "name", IMA_DEF_NAME, MAX_ID_NAME - 2, "Name", "Image datablock name");
+ prop = RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384);
+ RNA_def_property_subtype(prop, PROP_PIXEL);
+ prop = RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384);
+ RNA_def_property_subtype(prop, PROP_PIXEL);
+ prop = RNA_def_float_color(ot->srna, "color", 4, NULL, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f);
+ RNA_def_property_subtype(prop, PROP_COLOR_GAMMA);
+ RNA_def_property_float_array_default(prop, default_color);
+ RNA_def_boolean(ot->srna, "alpha", 1, "Alpha", "Create an image with an alpha channel");
+ RNA_def_enum(ot->srna, "generated_type", image_generated_type_items, IMA_GENTYPE_BLANK,
+ "Generated Type", "Fill the image with a grid for UV map testing");
+ RNA_def_boolean(ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth");
+}
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index b20c1756d75..fb4bedb6906 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -38,7 +38,9 @@ struct bglMats;
struct Brush;
struct ImagePool;
struct ColorSpace;
+struct ColorManagedDisplay;
struct ListBase;
+struct Material;
struct Mesh;
struct MTex;
struct Object;
@@ -65,7 +67,7 @@ typedef void (*StrokeUpdateStep)(struct bContext *C, struct PaintStroke *stroke,
typedef void (*StrokeRedraw)(const struct bContext *C, struct PaintStroke *stroke, bool final);
typedef void (*StrokeDone)(const struct bContext *C, struct PaintStroke *stroke);
-struct PaintStroke *paint_stroke_new(struct bContext *C,
+struct PaintStroke *paint_stroke_new(struct bContext *C, struct wmOperator *op,
StrokeGetLocation get_location, StrokeTestStart test_start,
StrokeUpdateStep update_step, StrokeRedraw redraw,
StrokeDone done, int event_type);
@@ -84,6 +86,7 @@ int paint_stroke_exec(struct bContext *C, struct wmOperator *op);
void paint_stroke_cancel(struct bContext *C, struct wmOperator *op);
struct ViewContext *paint_stroke_view_context(struct PaintStroke *stroke);
void *paint_stroke_mode_data(struct PaintStroke *stroke);
+float paint_stroke_distance_get(struct PaintStroke *stroke);
void paint_stroke_set_mode_data(struct PaintStroke *stroke, void *mode_data);
int paint_poll(struct bContext *C);
void paint_cursor_start(struct bContext *C, int (*poll)(struct bContext *C));
@@ -117,7 +120,7 @@ void PAINT_OT_weight_gradient(struct wmOperatorType *ot);
void PAINT_OT_vertex_paint_toggle(struct wmOperatorType *ot);
void PAINT_OT_vertex_paint(struct wmOperatorType *ot);
-unsigned int vpaint_get_current_col(struct VPaint *vp);
+unsigned int vpaint_get_current_col(struct Scene *scene, struct VPaint *vp);
/* paint_vertex_proj.c */
@@ -144,32 +147,42 @@ typedef struct ImagePaintPartialRedraw {
#define IMAPAINT_TILE_NUMBER(size) (((size) + IMAPAINT_TILE_SIZE - 1) >> IMAPAINT_TILE_BITS)
int image_texture_paint_poll(struct bContext *C);
-void *image_undo_find_tile(struct Image *ima, struct ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask);
-void *image_undo_push_tile(struct Image *ima, struct ImBuf *ibuf, struct ImBuf **tmpibuf, int x_tile, int y_tile);
+void *image_undo_find_tile(struct Image *ima, struct ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask, bool validate);
+void *image_undo_push_tile(struct Image *ima, struct ImBuf *ibuf, struct ImBuf **tmpibuf, int x_tile, int y_tile, unsigned short **, bool **valid, bool proj);
void image_undo_remove_masks(void);
+void image_undo_init_locks(void);
+void image_undo_end_locks(void);
+
void imapaint_image_update(struct SpaceImage *sima, struct Image *image, struct ImBuf *ibuf, short texpaint);
struct ImagePaintPartialRedraw *get_imapaintpartial(void);
void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr);
void imapaint_region_tiles(struct ImBuf *ibuf, int x, int y, int w, int h, int *tx, int *ty, int *tw, int *th);
int get_imapaint_zoom(struct bContext *C, float *zoomx, float *zoomy);
-void *paint_2d_new_stroke(struct bContext *, struct wmOperator *);
+void *paint_2d_new_stroke(struct bContext *, struct wmOperator *, int mode);
void paint_2d_redraw(const bContext *C, void *ps, bool final);
void paint_2d_stroke_done(void *ps);
-void paint_2d_stroke(void *ps, const float prev_mval[2], const float mval[2], int eraser);
+void paint_2d_stroke(void *ps, const float prev_mval[2], const float mval[2], int eraser, float pressure, float distance, float size);
+void paint_2d_bucket_fill(const struct bContext *C, const float color[3], struct Brush *br, const float mouse_init[2], void *ps);
+void paint_2d_gradient_fill (const struct bContext *C, struct Brush *br, const float mouse_init[2], const float mouse_final[2], void *ps);
void *paint_proj_new_stroke(struct bContext *C, struct Object *ob, const float mouse[2], int mode);
-void paint_proj_stroke(struct bContext *C, void *ps, const float prevmval_i[2], const float mval_i[2]);
-void paint_proj_redraw(const bContext *C, void *pps, bool final);
+void paint_proj_stroke(const struct bContext *C, void *ps, const float prevmval_i[2], const float mval_i[2], float pressure, float distance, float size);
+void paint_proj_redraw(const struct bContext *C, void *pps, bool final);
void paint_proj_stroke_done(void *ps);
+void paint_proj_mesh_data_ensure(bContext *C, struct Object *ob, struct wmOperator *op);
+bool proj_paint_add_slot(bContext *C, struct Material *ma, struct wmOperator *op);
+
+void paint_brush_color_get(struct Scene *scene, struct Brush *br, bool color_correction, bool invert, float distance, float pressure, float color[3], struct ColorManagedDisplay *display);
+bool paint_use_opacity_masking(struct Brush *brush);
void paint_brush_init_tex(struct Brush *brush);
void paint_brush_exit_tex(struct Brush *brush);
void PAINT_OT_grab_clone(struct wmOperatorType *ot);
void PAINT_OT_sample_color(struct wmOperatorType *ot);
+void PAINT_OT_brush_colors_flip(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_add_texture_paint_slot(struct wmOperatorType *ot);
void PAINT_OT_image_paint(struct wmOperatorType *ot);
/* uv sculpting */
@@ -202,7 +215,7 @@ float paint_calc_object_space_radius(struct ViewContext *vc, const float center[
float paint_get_tex_pixel(struct MTex *mtex, float u, float v, struct ImagePool *pool, int thread);
void paint_get_tex_pixel_col(struct MTex *mtex, float u, float v, float rgba[4], struct ImagePool *pool, int thread, bool convert, struct ColorSpace *colorspace);
-void paint_sample_color(const struct bContext *C, struct ARegion *ar, int x, int y);
+void paint_sample_color(bContext *C, struct ARegion *ar, int x, int y, bool texpaint_proj, bool palette);
void BRUSH_OT_curve_preset(struct wmOperatorType *ot);
void PAINT_OT_face_select_linked(struct wmOperatorType *ot);
@@ -213,8 +226,10 @@ 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);
+int paint_curve_poll(struct bContext *C);
int facemask_paint_poll(struct bContext *C);
void flip_v3_v3(float out[3], const float in[3], const char symm);
@@ -229,7 +244,6 @@ typedef enum BrushStrokeMode {
/* paint_undo.c */
struct ListBase *undo_paint_push_get_list(int type);
void undo_paint_push_count_alloc(int type, int size);
-bool sculpt_undo_cleanup(struct bContext *C, struct ListBase *lb);
/* paint_hide.c */
@@ -258,4 +272,29 @@ typedef enum {
void PAINT_OT_mask_flood_fill(struct wmOperatorType *ot);
void PAINT_OT_mask_lasso_gesture(struct wmOperatorType *ot);
+/* paint_curve.c */
+void PAINTCURVE_OT_new(struct wmOperatorType *ot);
+void PAINTCURVE_OT_add_point(struct wmOperatorType *ot);
+void PAINTCURVE_OT_delete_point(struct wmOperatorType *ot);
+void PAINTCURVE_OT_select(struct wmOperatorType *ot);
+void PAINTCURVE_OT_slide(struct wmOperatorType *ot);
+void PAINTCURVE_OT_draw(struct wmOperatorType *ot);
+void PAINTCURVE_OT_cursor(struct wmOperatorType *ot);
+
+/* image painting blur kernel */
+typedef struct {
+ float *wdata; /* actual kernel */
+ int side; /* kernel side */
+ int side_squared; /* data side */
+ int pixel_len; /* pixels around center that kernel is wide */
+} BlurKernel;
+
+enum BlurKernelType;
+/* can be extended to other blur kernels later */
+BlurKernel *paint_new_blur_kernel(struct Brush *br);
+void paint_delete_blur_kernel(BlurKernel *);
+
+/* paint curve defines */
+#define PAINT_CURVE_NUM_SEGMENTS 40
+
#endif /* __PAINT_INTERN_H__ */
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index b3f81f379f3..8faa4cfaf33 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -115,7 +115,7 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op)
sculpt_undo_push_begin("Mask flood fill");
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (i = 0; i < totnode; i++) {
PBVHVertexIter vi;
@@ -236,7 +236,7 @@ int ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *r
BKE_pbvh_search_gather(pbvh, BKE_pbvh_node_planes_contain_AABB, clip_planes_final, &nodes, &totnode);
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (i = 0; i < totnode; i++) {
PBVHVertexIter vi;
bool any_masked = false;
@@ -385,7 +385,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
/* gather nodes inside lasso's enclosing rectangle (should greatly help with bigger meshes) */
BKE_pbvh_search_gather(pbvh, BKE_pbvh_node_planes_contain_AABB, clip_planes_final, &nodes, &totnode);
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (i = 0; i < totnode; i++) {
PBVHVertexIter vi;
bool any_masked = false;
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index 9021581d47f..3605ce5f280 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -149,11 +149,112 @@ static void BRUSH_OT_scale_size(wmOperatorType *ot)
RNA_def_float(ot->srna, "scalar", 1, 0, 2, "Scalar", "Factor to scale brush size by", 0, 2);
}
+/* Palette operators */
+
+static int palette_new_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ Main *bmain = CTX_data_main(C);
+ Palette *palette;
+
+ palette = BKE_palette_add(bmain, "Palette");
+
+ BKE_paint_palette_set(paint, palette);
+
+ return OPERATOR_FINISHED;
+}
+
+static void PALETTE_OT_new(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add New Palette";
+ ot->description = "Add new palette";
+ ot->idname = "PALETTE_OT_new";
+
+ /* api callbacks */
+ ot->exec = palette_new_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int palette_poll(bContext *C)
+{
+ Paint *paint = BKE_paint_get_active_from_context(C);
+
+ if (paint && paint->palette != NULL)
+ return true;
+
+ return false;
+}
+
+static int palette_color_add_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ Brush *brush = paint->brush;
+ PaintMode mode = BKE_paintmode_get_active_from_context(C);
+ Palette *palette = paint->palette;
+ PaletteColor *color = BKE_palette_color_add(palette);
+
+ if (ELEM(mode, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D, PAINT_VERTEX)) {
+ copy_v3_v3(color->rgb, BKE_brush_color_get(scene, brush));
+ color->value = 0.0;
+ }
+ else if (mode == PAINT_WEIGHT) {
+ zero_v3(color->rgb);
+ color->value = brush->weight;
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static void PALETTE_OT_color_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "New Palette Color";
+ ot->description = "Add new color to active palette";
+ ot->idname = "PALETTE_OT_color_add";
+
+ /* api callbacks */
+ ot->exec = palette_color_add_exec;
+ ot->poll = palette_poll;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
+static int palette_color_delete_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ Palette *palette = paint->palette;
+
+ BKE_palette_color_delete(palette);
+
+ return OPERATOR_FINISHED;
+}
+
+static void PALETTE_OT_color_delete(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Delete Palette Color";
+ ot->description = "Remove active color from palette";
+ ot->idname = "PALETTE_OT_color_delete";
+
+ /* api callbacks */
+ ot->exec = palette_color_delete_exec;
+ ot->poll = palette_poll;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
+
static int vertex_color_set_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
Object *obact = CTX_data_active_object(C);
- unsigned int paintcol = vpaint_get_current_col(scene->toolsettings->vpaint);
+ unsigned int paintcol = vpaint_get_current_col(scene, scene->toolsettings->vpaint);
if (ED_vpaint_fill(obact, paintcol)) {
ED_region_tag_redraw(CTX_wm_region(C)); // XXX - should redraw all 3D views
@@ -332,6 +433,7 @@ static int brush_generic_tool_set(Main *bmain, Paint *paint, const int tool,
if (brush) {
BKE_paint_brush_set(paint, brush);
BKE_paint_invalidate_overlay_all();
+
WM_main_add_notifier(NC_BRUSH | NA_EDITED, brush);
return OPERATOR_FINISHED;
}
@@ -928,8 +1030,37 @@ static void ed_keymap_stencil(wmKeyMap *keymap)
/**************************** registration **********************************/
+void ED_operatormacros_paint(void)
+{
+ wmOperatorType *ot;
+ wmOperatorTypeMacro *otmacro;
+
+ ot = WM_operatortype_append_macro("PAINTCURVE_OT_add_point_slide", "Add Curve Point and Slide",
+ "Add new curve point and slide it", OPTYPE_UNDO);
+ ot->description = "Add new curve point and slide it";
+ WM_operatortype_macro_define(ot, "PAINTCURVE_OT_add_point");
+ otmacro = WM_operatortype_macro_define(ot, "PAINTCURVE_OT_slide");
+ RNA_boolean_set(otmacro->ptr, "align", true);
+ RNA_boolean_set(otmacro->ptr, "select", false);
+}
+
+
void ED_operatortypes_paint(void)
{
+ /* palette */
+ WM_operatortype_append(PALETTE_OT_new);
+ WM_operatortype_append(PALETTE_OT_color_add);
+ WM_operatortype_append(PALETTE_OT_color_delete);
+
+ /* paint curve */
+ WM_operatortype_append(PAINTCURVE_OT_new);
+ WM_operatortype_append(PAINTCURVE_OT_add_point);
+ WM_operatortype_append(PAINTCURVE_OT_delete_point);
+ WM_operatortype_append(PAINTCURVE_OT_select);
+ WM_operatortype_append(PAINTCURVE_OT_slide);
+ WM_operatortype_append(PAINTCURVE_OT_draw);
+ WM_operatortype_append(PAINTCURVE_OT_cursor);
+
/* brush */
WM_operatortype_append(BRUSH_OT_add);
WM_operatortype_append(BRUSH_OT_scale_size);
@@ -950,6 +1081,8 @@ void ED_operatortypes_paint(void)
WM_operatortype_append(PAINT_OT_grab_clone);
WM_operatortype_append(PAINT_OT_project_image);
WM_operatortype_append(PAINT_OT_image_from_view);
+ WM_operatortype_append(PAINT_OT_brush_colors_flip);
+ WM_operatortype_append(PAINT_OT_add_texture_paint_slot);
/* weight */
WM_operatortype_append(PAINT_OT_weight_paint_toggle);
@@ -1119,12 +1252,44 @@ static void paint_partial_visibility_keys(wmKeyMap *keymap)
RNA_enum_set(kmi->ptr, "area", PARTIALVIS_ALL);
}
+
+static void paint_keymap_curve(wmKeyMap *keymap)
+{
+ wmKeyMapItem *kmi;
+
+ WM_keymap_add_item(keymap, "PAINTCURVE_OT_add_point_slide", ACTIONMOUSE, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "PAINTCURVE_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
+ kmi = WM_keymap_add_item(keymap, "PAINTCURVE_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "extend", true);
+ WM_keymap_add_item(keymap, "PAINTCURVE_OT_slide", ACTIONMOUSE, KM_PRESS, 0, 0);
+ kmi = WM_keymap_add_item(keymap, "PAINTCURVE_OT_slide", ACTIONMOUSE, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "align", true);
+ kmi = WM_keymap_add_item(keymap, "PAINTCURVE_OT_select", AKEY, KM_PRESS, 0, 0);
+ RNA_boolean_set(kmi->ptr, "toggle", true);
+
+ WM_keymap_add_item(keymap, "PAINTCURVE_OT_cursor", ACTIONMOUSE, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "PAINTCURVE_OT_delete_point", XKEY, KM_PRESS, 0, 0);
+
+ WM_keymap_add_item(keymap, "PAINTCURVE_OT_draw", RETKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "PAINTCURVE_OT_draw", PADENTER, KM_PRESS, 0, 0);
+
+ WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", GKEY, KM_PRESS, 0, 0);
+ kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", EVT_TWEAK_S, KM_ANY, 0, 0);
+ WM_keymap_add_item(keymap, "TRANSFORM_OT_rotate", RKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "TRANSFORM_OT_resize", SKEY, KM_PRESS, 0, 0);
+}
+
void ED_keymap_paint(wmKeyConfig *keyconf)
{
wmKeyMap *keymap;
wmKeyMapItem *kmi;
int i;
+ keymap = WM_keymap_find(keyconf, "Paint Curve", 0, 0);
+ keymap->poll = paint_curve_poll;
+
+ paint_keymap_curve(keymap);
+
/* Sculpt mode */
keymap = WM_keymap_find(keyconf, "Sculpt", 0, 0);
keymap->poll = sculpt_mode_poll;
@@ -1191,7 +1356,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
RNA_boolean_set(kmi->ptr, "create_missing", 1);
/* */
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", AKEY, KM_PRESS, 0, 0);
+ kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", EKEY, KM_PRESS, 0, 0);
RNA_string_set(kmi->ptr, "data_path", "tool_settings.sculpt.brush.stroke_method");
kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", SKEY, KM_PRESS, KM_SHIFT, 0);
@@ -1225,7 +1390,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
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");
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", AKEY, KM_PRESS, 0, 0);
+ kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", EKEY, KM_PRESS, 0, 0);
RNA_string_set(kmi->ptr, "data_path", "tool_settings.vertex_paint.brush.stroke_method");
/* Weight Paint mode */
@@ -1250,7 +1415,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
ed_keymap_stencil(keymap);
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", AKEY, KM_PRESS, 0, 0);
+ kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", EKEY, KM_PRESS, 0, 0);
RNA_string_set(kmi->ptr, "data_path", "tool_settings.vertex_paint.brush.stroke_method");
kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", MKEY, KM_PRESS, 0, 0); /* face mask toggle */
@@ -1283,6 +1448,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
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_brush_colors_flip", XKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "PAINT_OT_grab_clone", RIGHTMOUSE, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "PAINT_OT_sample_color", SKEY, KM_PRESS, 0, 0);
@@ -1301,7 +1467,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
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");
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", AKEY, KM_PRESS, 0, 0);
+ kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", EKEY, KM_PRESS, 0, 0);
RNA_string_set(kmi->ptr, "data_path", "tool_settings.image_paint.brush.stroke_method");
/* face-mask mode */
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index 5133f51a6fd..47a772af9e4 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -36,16 +36,19 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLI_rand.h"
+#include "BLI_listbase.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_brush_types.h"
+#include "DNA_curve_types.h"
#include "RNA_access.h"
#include "BKE_context.h"
#include "BKE_paint.h"
#include "BKE_brush.h"
+#include "BKE_curve.h"
#include "BKE_colortools.h"
#include "BKE_image.h"
@@ -72,7 +75,7 @@ typedef struct PaintSample {
typedef struct PaintStroke {
void *mode_data;
- void *smooth_stroke_cursor;
+ void *stroke_cursor;
wmTimer *timer;
/* Cached values */
@@ -81,6 +84,9 @@ typedef struct PaintStroke {
Brush *brush;
UnifiedPaintSettings *ups;
+ /* used for lines and curves */
+ ListBase line;
+
/* Paint stroke can use up to PAINT_MAX_INPUT_SAMPLES prior inputs
* to smooth the stroke */
PaintSample samples[PAINT_MAX_INPUT_SAMPLES];
@@ -88,6 +94,8 @@ typedef struct PaintStroke {
int cur_sample;
float last_mouse_position[2];
+ /* space distance covered so far */
+ float stroke_distance;
/* Set whether any stroke step has yet occurred
* e.g. in sculpt mode, stroke doesn't start until cursor
@@ -116,18 +124,17 @@ typedef struct PaintStroke {
StrokeDone done;
} PaintStroke;
-/*** Cursor ***/
-static void paint_draw_smooth_stroke(bContext *C, int x, int y, void *customdata)
+/*** Cursors ***/
+static void paint_draw_smooth_cursor(bContext *C, int x, int y, void *customdata)
{
Paint *paint = BKE_paint_get_active_from_context(C);
Brush *brush = BKE_paint_brush(paint);
PaintStroke *stroke = customdata;
- if (stroke && brush && (brush->flag & BRUSH_SMOOTH_STROKE)) {
- glColor4ubv(paint->paint_cursor_col);
+ if (stroke && brush) {
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
-
+ glColor4ubv(paint->paint_cursor_col);
sdrawline(x, y, (int)stroke->last_mouse_position[0],
(int)stroke->last_mouse_position[1]);
glDisable(GL_BLEND);
@@ -135,12 +142,39 @@ static void paint_draw_smooth_stroke(bContext *C, int x, int y, void *customdata
}
}
+static void paint_draw_line_cursor(bContext *C, int x, int y, void *customdata)
+{
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ PaintStroke *stroke = customdata;
+
+ glEnable(GL_LINE_SMOOTH);
+ glEnable(GL_BLEND);
+
+ glEnable(GL_LINE_STIPPLE);
+ glLineStipple(3, 0xAAAA);
+
+ glColor4ub(0, 0, 0, paint->paint_cursor_col[3]);
+ glLineWidth(3.0);
+ sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1],
+ x, y);
+
+ glColor4ub(255, 255, 255, paint->paint_cursor_col[3]);
+ glLineWidth(1.0);
+ sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1],
+ x, y);
+
+ glDisable(GL_LINE_STIPPLE);
+
+ glDisable(GL_BLEND);
+ glDisable(GL_LINE_SMOOTH);
+}
+
static bool paint_tool_require_location(Brush *brush, PaintMode mode)
{
switch (mode) {
case PAINT_SCULPT:
- if (ELEM4(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_THUMB))
+ if (ELEM(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_THUMB))
{
return false;
}
@@ -155,13 +189,18 @@ static bool paint_tool_require_location(Brush *brush, PaintMode mode)
}
/* 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)
+static bool paint_brush_update(bContext *C,
+ Brush *brush,
+ PaintMode mode,
+ struct PaintStroke *stroke,
+ const float mouse_init[2],
+ float mouse[2], float pressure,
+ float location[3])
{
Scene *scene = CTX_data_scene(C);
- UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
-
+ UnifiedPaintSettings *ups = stroke->ups;
+ bool location_sampled = false;
+ bool location_success = false;
/* 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.
@@ -222,14 +261,14 @@ static void paint_brush_update(bContext *C, Brush *brush, PaintMode mode,
else {
copy_v2_v2(ups->tex_mouse, mouse);
}
- }
- /* take care of mask texture, if any */
- if (brush->mask_mtex.tex) {
- if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)
- BKE_brush_randomize_texture_coordinates(ups, true);
- else {
- copy_v2_v2(ups->mask_tex_mouse, mouse);
+ /* take care of mask texture, if any */
+ if (brush->mask_mtex.tex) {
+ if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)
+ BKE_brush_randomize_texture_coordinates(ups, true);
+ else {
+ copy_v2_v2(ups->mask_tex_mouse, mouse);
+ }
}
}
@@ -246,14 +285,14 @@ static void paint_brush_update(bContext *C, Brush *brush, PaintMode mode,
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)) {
+ if (stroke->get_location(C, location, halfway)) {
hit = true;
+ location_sampled = true;
+ location_success = true;
}
else if (!paint_tool_require_location(brush, mode)) {
hit = true;
@@ -266,17 +305,43 @@ static void paint_brush_update(bContext *C, Brush *brush, PaintMode mode,
if (hit) {
copy_v2_v2(ups->anchored_initial_mouse, halfway);
copy_v2_v2(ups->tex_mouse, halfway);
+ copy_v2_v2(ups->mask_tex_mouse, halfway);
+ copy_v2_v2(mouse, halfway);
ups->anchored_size /= 2.0f;
ups->pixel_radius /= 2.0f;
+ stroke->stroke_distance = ups->pixel_radius;
}
- else
+ else {
copy_v2_v2(ups->anchored_initial_mouse, stroke->initial_mouse);
-
+ copy_v2_v2(mouse, stroke->initial_mouse);
+ stroke->stroke_distance = ups->pixel_radius;
+ }
+ ups->pixel_radius /= stroke->zoom_2d;
ups->draw_anchored = true;
}
else if (brush->flag & BRUSH_RAKE) {
- paint_calculate_rake_rotation(ups, mouse);
+ /* here we are using the initial mouse coordinate because we do not want the rake
+ * result to depend on jittering */
+ if (!stroke->brush_init)
+ copy_v2_v2(ups->last_rake, mouse_init);
+ else
+ paint_calculate_rake_rotation(ups, mouse_init);
}
+
+ if (!location_sampled) {
+ if (stroke->get_location) {
+ if (stroke->get_location(C, location, mouse))
+ location_success = true;
+ else if (!paint_tool_require_location(brush, mode))
+ location_success = true;
+ }
+ else {
+ zero_v3(location);
+ location_success = true;
+ }
+ }
+
+ return location_success;
}
@@ -284,12 +349,11 @@ static void paint_brush_update(bContext *C, Brush *brush, PaintMode mode,
static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, const float mouse_in[2], float pressure)
{
Scene *scene = CTX_data_scene(C);
- wmWindow *window = CTX_wm_window(C);
- ARegion *ar = CTX_wm_region(C);
Paint *paint = BKE_paint_get_active_from_context(C);
PaintMode mode = BKE_paintmode_get_active_from_context(C);
Brush *brush = BKE_paint_brush(paint);
PaintStroke *stroke = op->customdata;
+ UnifiedPaintSettings *ups = stroke->ups;
float mouse_out[2];
PointerRNA itemptr;
float location[3];
@@ -315,8 +379,6 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, const float
copy_v2_v2(stroke->last_mouse_position, mouse_in);
stroke->last_pressure = pressure;
- paint_brush_update(C, brush, mode, stroke, mouse_in, pressure);
-
{
float delta[2];
float factor = stroke->zoom_2d;
@@ -336,22 +398,13 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, const float
}
}
- /* TODO: can remove the if statement once all modes have this */
- if (stroke->get_location) {
- if (!stroke->get_location(C, location, mouse_out)) {
- if (paint_tool_require_location(brush, mode)) {
- if (ar && (paint->flags & PAINT_SHOW_BRUSH))
- WM_paint_cursor_tag_redraw(window, ar);
- return;
- }
- }
+ if (!paint_brush_update(C, brush, mode, stroke, mouse_in, mouse_out, pressure, location)) {
+ return;
}
- else
- zero_v3(location);
/* Add to stroke */
RNA_collection_add(op->ptr, "stroke", &itemptr);
-
+ RNA_float_set(&itemptr, "size", ups->pixel_radius);
RNA_float_set_array(&itemptr, "location", location);
RNA_float_set_array(&itemptr, "mouse", mouse_out);
RNA_boolean_set(&itemptr, "pen_flip", stroke->pen_flip);
@@ -362,20 +415,12 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, const float
/* don't record this for now, it takes up a lot of memory when doing long
* strokes with small brush size, and operators have register disabled */
RNA_collection_clear(op->ptr, "stroke");
-
- /* always redraw region if brush is shown */
- if (ar && (paint->flags & PAINT_SHOW_BRUSH))
- WM_paint_cursor_tag_redraw(window, ar);
}
/* Returns zero if no sculpt changes should be made, non-zero otherwise */
static int paint_smooth_stroke(PaintStroke *stroke, float output[2], float *outpressure,
const PaintSample *sample, PaintMode mode)
{
- output[0] = sample->mouse[0];
- output[1] = sample->mouse[1];
- *outpressure = sample->pressure;
-
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;
@@ -391,6 +436,11 @@ static int paint_smooth_stroke(PaintStroke *stroke, float output[2], float *outp
output[1] = sample->mouse[1] * v + stroke->last_mouse_position[1] * u;
*outpressure = sample->pressure * v + stroke->last_pressure * u;
}
+ else {
+ output[0] = sample->mouse[0];
+ output[1] = sample->mouse[1];
+ *outpressure = sample->pressure;
+ }
return 1;
}
@@ -413,6 +463,55 @@ static float paint_space_stroke_spacing(const Scene *scene, PaintStroke *stroke,
return max_ff(1.0, size_clamp * spacing / 50.0f);
}
+
+
+static float paint_stroke_overlapped_curve(Brush *br, float x, float spacing)
+{
+ int i;
+ const int n = 100 / spacing;
+ const float h = spacing / 50.0f;
+ const float x0 = x - 1;
+
+ float sum;
+
+ sum = 0;
+ for (i = 0; i < n; i++) {
+ float xx;
+
+ xx = fabs(x0 + i * h);
+
+ if (xx < 1.0f)
+ sum += BKE_brush_curve_strength(br, xx, 1);
+ }
+
+ return sum;
+}
+
+static float paint_stroke_integrate_overlap(Brush *br, float factor)
+{
+ int i;
+ int m;
+ float g;
+ float max;
+
+ float spacing = br->spacing * factor;
+
+ if (!(br->flag & BRUSH_SPACE_ATTEN && (br->spacing < 100)))
+ return 1.0;
+
+ m = 10;
+ g = 1.0f / m;
+ max = 0;
+ for (i = 0; i < m; i++) {
+ float overlap = paint_stroke_overlapped_curve(br, i * g, spacing);
+
+ if (overlap > max)
+ max = overlap;
+ }
+
+ return 1.0f / max;
+}
+
static float paint_space_stroke_spacing_variable(const Scene *scene, PaintStroke *stroke, float pressure, float dpressure, float length)
{
if (BKE_brush_use_size_pressure(scene, stroke->brush)) {
@@ -444,40 +543,42 @@ static int paint_space_stroke(bContext *C, wmOperator *op, const float final_mou
{
const Scene *scene = CTX_data_scene(C);
PaintStroke *stroke = op->customdata;
- PaintMode mode = BKE_paintmode_get_active_from_context(C);
+ UnifiedPaintSettings *ups = stroke->ups;
int cnt = 0;
- if (paint_space_stroke_enabled(stroke->brush, mode)) {
- float pressure, dpressure;
- float mouse[2], dmouse[2];
- float length;
+ float pressure, dpressure;
+ float mouse[2], dmouse[2];
+ float length;
+ float no_pressure_spacing = paint_space_stroke_spacing(scene, stroke, 1.0f, 1.0f);
- sub_v2_v2v2(dmouse, final_mouse, stroke->last_mouse_position);
+ sub_v2_v2v2(dmouse, final_mouse, stroke->last_mouse_position);
- pressure = stroke->last_pressure;
- dpressure = final_pressure - stroke->last_pressure;
+ pressure = stroke->last_pressure;
+ dpressure = final_pressure - stroke->last_pressure;
- length = normalize_v2(dmouse);
+ length = normalize_v2(dmouse);
- while (length > 0.0f) {
- float spacing = paint_space_stroke_spacing_variable(scene, stroke, pressure, dpressure, length);
-
- if (length >= spacing) {
- mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing;
- mouse[1] = stroke->last_mouse_position[1] + dmouse[1] * spacing;
- pressure = stroke->last_pressure + (spacing / length) * dpressure;
+ while (length > 0.0f) {
+ float spacing = paint_space_stroke_spacing_variable(scene, stroke, pressure, dpressure, length);
- paint_brush_stroke_add_step(C, op, mouse, pressure);
+ if (length >= spacing) {
+ mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing;
+ mouse[1] = stroke->last_mouse_position[1] + dmouse[1] * spacing;
+ pressure = stroke->last_pressure + (spacing / length) * dpressure;
- length -= spacing;
- pressure = stroke->last_pressure;
- dpressure = final_pressure - stroke->last_pressure;
+ ups->overlap_factor = paint_stroke_integrate_overlap(stroke->brush, spacing / no_pressure_spacing);
- cnt++;
- }
- else {
- break;
- }
+ stroke->stroke_distance += spacing / stroke->zoom_2d;
+ paint_brush_stroke_add_step(C, op, mouse, pressure);
+
+ length -= spacing;
+ pressure = stroke->last_pressure;
+ dpressure = final_pressure - stroke->last_pressure;
+
+ cnt++;
+ }
+ else {
+ break;
}
}
@@ -487,6 +588,7 @@ static int paint_space_stroke(bContext *C, wmOperator *op, const float final_mou
/**** Public API ****/
PaintStroke *paint_stroke_new(bContext *C,
+ wmOperator *op,
StrokeGetLocation get_location,
StrokeTestStart test_start,
StrokeUpdateStep update_step,
@@ -497,6 +599,7 @@ PaintStroke *paint_stroke_new(bContext *C,
ToolSettings *toolsettings = CTX_data_tool_settings(C);
UnifiedPaintSettings *ups = &toolsettings->unified_paint_settings;
Brush *br = stroke->brush = BKE_paint_brush(BKE_paint_get_active_from_context(C));
+ float zoomx, zoomy;
view3d_set_viewcontext(C, &stroke->vc);
if (stroke->vc.v3d)
@@ -510,6 +613,18 @@ PaintStroke *paint_stroke_new(bContext *C,
stroke->event_type = event_type; /* for modal, return event */
stroke->ups = ups;
+ get_imapaint_zoom(C, &zoomx, &zoomy);
+ stroke->zoom_2d = max_ff(zoomx, zoomy);
+
+ if ((br->flag & BRUSH_CURVE) &&
+ RNA_struct_property_is_set(op->ptr, "mode"))
+ {
+ RNA_enum_set(op->ptr, "mode", BRUSH_STROKE_NORMAL);
+ }
+ /* initialize here */
+ ups->overlap_factor = 1.0;
+ ups->stroke_active = true;
+
/* initialize here to avoid initialization conflict with threaded strokes */
curvemapping_initialize(br->curve);
@@ -521,8 +636,7 @@ PaintStroke *paint_stroke_new(bContext *C,
void paint_stroke_data_free(struct wmOperator *op)
{
BKE_paint_set_overlay_override(0);
- MEM_freeN(op->customdata);
- op->customdata = NULL;
+ MEM_SAFE_FREE(op->customdata);
}
static void stroke_done(struct bContext *C, struct wmOperator *op)
@@ -552,8 +666,10 @@ static void stroke_done(struct bContext *C, struct wmOperator *op)
stroke->timer);
}
- if (stroke->smooth_stroke_cursor)
- WM_paint_cursor_end(CTX_wm_manager(C), stroke->smooth_stroke_cursor);
+ if (stroke->stroke_cursor)
+ WM_paint_cursor_end(CTX_wm_manager(C), stroke->stroke_cursor);
+
+ BLI_freelistN(&stroke->line);
paint_stroke_data_free(op);
}
@@ -566,7 +682,7 @@ bool paint_space_stroke_enabled(Brush *br, PaintMode mode)
static bool sculpt_is_grab_tool(Brush *br)
{
- return ELEM4(br->sculpt_tool,
+ return ELEM(br->sculpt_tool,
SCULPT_TOOL_GRAB,
SCULPT_TOOL_THUMB,
SCULPT_TOOL_ROTATE,
@@ -584,6 +700,16 @@ bool paint_supports_dynamic_size(Brush *br, PaintMode mode)
if (sculpt_is_grab_tool(br))
return false;
break;
+
+ case PAINT_TEXTURE_2D: /* fall through */
+ case PAINT_TEXTURE_PROJECTIVE:
+ if ((br->imagepaint_tool == PAINT_TOOL_FILL) &&
+ (br->flag & BRUSH_USE_GRADIENT))
+ {
+ return false;
+ }
+ break;
+
default:
break;
}
@@ -593,8 +719,7 @@ bool paint_supports_dynamic_size(Brush *br, PaintMode mode)
bool paint_supports_smooth_stroke(Brush *br, PaintMode mode)
{
if (!(br->flag & BRUSH_SMOOTH_STROKE) ||
- (br->flag & BRUSH_ANCHORED) ||
- (br->flag & BRUSH_DRAG_DOT))
+ (br->flag & (BRUSH_ANCHORED | BRUSH_DRAG_DOT | BRUSH_LINE)))
{
return false;
}
@@ -613,7 +738,7 @@ bool paint_supports_smooth_stroke(Brush *br, PaintMode mode)
bool paint_supports_texture(PaintMode mode)
{
/* ommit: PAINT_WEIGHT, PAINT_SCULPT_UV, PAINT_INVALID */
- return ELEM4(mode, PAINT_SCULPT, PAINT_VERTEX, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D);
+ return ELEM(mode, PAINT_SCULPT, PAINT_VERTEX, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D);
}
/* return true if the brush size can change during paint (normally used for pressure) */
@@ -701,28 +826,141 @@ 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);*/
}
+/**
+ * Slightly different version of spacing for line/curve strokes,
+ * makes sure the dabs stay on the line path.
+ */
+static void paint_line_strokes_spacing(
+ bContext *C, wmOperator *op, PaintStroke *stroke, float spacing, float *length_residue,
+ const float old_pos[2], const float new_pos[2])
+{
+ UnifiedPaintSettings *ups = stroke->ups;
+
+ float mouse[2], dmouse[2];
+ float length;
+
+ sub_v2_v2v2(dmouse, new_pos, old_pos);
+ copy_v2_v2(stroke->last_mouse_position, old_pos);
+
+ length = normalize_v2(dmouse);
+
+ BLI_assert(length >= 0.0f);
+
+ if (length == 0.0f)
+ return;
+
+ while (length > 0.0f) {
+ float spacing_final = spacing - *length_residue;
+ length += *length_residue;
+ *length_residue = 0.0;
+
+ if (length >= spacing) {
+ mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing_final;
+ mouse[1] = stroke->last_mouse_position[1] + dmouse[1] * spacing_final;
+
+ ups->overlap_factor = paint_stroke_integrate_overlap(stroke->brush, 1.0);
+
+ stroke->stroke_distance += spacing / stroke->zoom_2d;
+ paint_brush_stroke_add_step(C, op, mouse, 1.0);
+
+ length -= spacing;
+ spacing_final = spacing;
+ }
+ else {
+ break;
+ }
+ }
+
+ *length_residue = length;
+}
+
+
+static void paint_stroke_line_end(bContext *C, wmOperator *op, PaintStroke *stroke, float mouse[2])
+{
+ Brush *br = stroke->brush;
+ if (stroke->stroke_started && (br->flag & BRUSH_LINE)) {
+ stroke->ups->overlap_factor = paint_stroke_integrate_overlap(br, 1.0);
+
+ paint_brush_stroke_add_step(C, op, stroke->last_mouse_position, 1.0);
+ paint_space_stroke(C, op, mouse, 1.0);
+ }
+}
+
+static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *stroke)
+{
+ Brush *br = stroke->brush;
+ if (br->flag & BRUSH_CURVE) {
+ const Scene *scene = CTX_data_scene(C);
+ const float spacing = paint_space_stroke_spacing(scene, stroke, 1.0f, 1.0f);
+ PaintCurve *pc = br->paint_curve;
+ PaintCurvePoint *pcp;
+ float length_residue = 0.0f;
+ int i;
+
+ if (!pc)
+ return true;
+
+ pcp = pc->points;
+ stroke->ups->overlap_factor = paint_stroke_integrate_overlap(br, 1.0);
+
+ for (i = 0; i < pc->tot_points - 1; i++, pcp++) {
+ int j;
+ float data[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2];
+ PaintCurvePoint *pcp_next = pcp + 1;
+
+ for (j = 0; j < 2; j++)
+ BKE_curve_forward_diff_bezier(
+ pcp->bez.vec[1][j],
+ pcp->bez.vec[2][j],
+ pcp_next->bez.vec[0][j],
+ pcp_next->bez.vec[1][j],
+ data + j, PAINT_CURVE_NUM_SEGMENTS, sizeof(float[2]));
+
+
+ for (j = 0; j < PAINT_CURVE_NUM_SEGMENTS; j++) {
+ if (!stroke->stroke_started) {
+ stroke->last_pressure = 1.0;
+ copy_v2_v2(stroke->last_mouse_position, data + 2 * j);
+ stroke->stroke_started = stroke->test_start(C, op, stroke->last_mouse_position);
+
+ if (stroke->stroke_started) {
+ paint_brush_stroke_add_step(C, op, data + 2 * j, 1.0);
+ paint_line_strokes_spacing(C, op, stroke, spacing, &length_residue, data + 2 * j, data + 2 * (j + 1));
+ }
+ }
+ else {
+ paint_line_strokes_spacing(C, op, stroke, spacing, &length_residue, data + 2 * j, data + 2 * (j + 1));
+ }
+ }
+ }
+
+ stroke_done(C, op);
+ return true;
+ }
+
+ return false;
+}
+
+
int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
Paint *p = BKE_paint_get_active_from_context(C);
PaintMode mode = BKE_paintmode_get_active_from_context(C);
PaintStroke *stroke = op->customdata;
+ Brush *br = stroke->brush;
PaintSample sample_average;
float mouse[2];
bool first_dab = false;
bool first_modal = false;
- float zoomx, zoomy;
bool redraw = false;
float pressure;
- /* see if tablet affects event */
- pressure = WM_event_tablet_data(event, &stroke->pen_flip, NULL);
+ /* see if tablet affects event. Line, anchored and drag dot strokes do not support pressure */
+ pressure = (br->flag & (BRUSH_LINE | BRUSH_ANCHORED | BRUSH_DRAG_DOT)) ? 1.0f : WM_event_tablet_data(event, &stroke->pen_flip, NULL);
paint_stroke_add_sample(p, stroke, event->mval[0], event->mval[1], pressure);
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
@@ -732,8 +970,12 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* one time initialization */
if (!stroke->stroke_init) {
- stroke->smooth_stroke_cursor =
- WM_paint_cursor_activate(CTX_wm_manager(C), paint_poll, paint_draw_smooth_stroke, stroke);
+ if (paint_stroke_curve_end(C, op, stroke))
+ return OPERATOR_FINISHED;
+
+ if (paint_supports_smooth_stroke(br, mode))
+ stroke->stroke_cursor =
+ WM_paint_cursor_activate(CTX_wm_manager(C), paint_poll, paint_draw_smooth_cursor, stroke);
stroke->stroke_init = true;
first_modal = true;
@@ -747,9 +989,14 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
BLI_assert((stroke->stroke_started & ~1) == 0); /* 0/1 */
if (stroke->stroke_started) {
- if (stroke->brush->flag & BRUSH_AIRBRUSH)
+ if (br->flag & BRUSH_AIRBRUSH)
stroke->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, stroke->brush->rate);
+ if (br->flag & BRUSH_LINE) {
+ stroke->stroke_cursor =
+ WM_paint_cursor_activate(CTX_wm_manager(C), paint_poll, paint_draw_line_cursor, stroke);
+ }
+
first_dab = true;
}
}
@@ -765,20 +1012,42 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
}
- if (event->type == stroke->event_type && event->val == KM_RELEASE && !first_modal) {
+ if (event->type == stroke->event_type && !first_modal) {
+ if (event->val == KM_RELEASE) {
+ paint_stroke_line_end (C, op, stroke, sample_average.mouse);
+ stroke_done(C, op);
+ return OPERATOR_FINISHED;
+ }
+ }
+ else if (ELEM(event->type, RETKEY, SPACEKEY)) {
+ paint_stroke_line_end(C, op, stroke, sample_average.mouse);
stroke_done(C, op);
return OPERATOR_FINISHED;
}
- else if (first_modal || (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) ||
- (event->type == TIMER && (event->customdata == stroke->timer)) )
+ else if ((br->flag & BRUSH_LINE) && stroke->stroke_started &&
+ (first_modal || (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE))))
+ {
+ if (br->flag & BRUSH_RAKE) {
+ copy_v2_v2(stroke->ups->last_rake, stroke->last_mouse_position);
+ paint_calculate_rake_rotation(stroke->ups, sample_average.mouse);
+ }
+ }
+ else if (first_modal ||
+ /* regular dabs */
+ (!(br->flag & (BRUSH_AIRBRUSH)) && (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE))) ||
+ /* airbrush */
+ ((br->flag & BRUSH_AIRBRUSH) && event->type == TIMER && event->customdata == stroke->timer))
{
if (paint_smooth_stroke(stroke, mouse, &pressure, &sample_average, mode)) {
if (stroke->stroke_started) {
- if (paint_space_stroke_enabled(stroke->brush, mode)) {
+ if (paint_space_stroke_enabled(br, mode)) {
if (paint_space_stroke(C, op, mouse, pressure))
redraw = true;
}
else {
+ float dmouse[2];
+ sub_v2_v2v2(dmouse, mouse, stroke->last_mouse_position);
+ stroke->stroke_distance += len_v2(dmouse);
paint_brush_stroke_add_step(C, op, mouse, pressure);
redraw = true;
}
@@ -789,19 +1058,27 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* we want the stroke to have the first daub at the start location
* instead of waiting till we have moved the space distance */
if (first_dab &&
- paint_space_stroke_enabled(stroke->brush, mode) &&
- !(stroke->brush->flag & BRUSH_ANCHORED) &&
- !(stroke->brush->flag & BRUSH_SMOOTH_STROKE))
+ paint_space_stroke_enabled(br, mode) &&
+ !(br->flag & BRUSH_SMOOTH_STROKE))
{
- paint_brush_stroke_add_step(C, op, mouse, pressure);
+ stroke->ups->overlap_factor = paint_stroke_integrate_overlap(br, 1.0);
+ paint_brush_stroke_add_step(C, op, sample_average.mouse, sample_average.pressure);
redraw = true;
}
/* do updates for redraw. if event is inbetween mousemove there are more
* coming, so postpone potentially slow redraw updates until all are done */
- if (event->type != INBETWEEN_MOUSEMOVE)
+ if (event->type != INBETWEEN_MOUSEMOVE) {
+ wmWindow *window = CTX_wm_window(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ /* At the very least, invalidate the cursor */
+ if (ar && (p->flags & PAINT_SHOW_BRUSH))
+ WM_paint_cursor_tag_redraw(window, ar);
+
if (redraw && stroke->redraw)
stroke->redraw(C, stroke, false);
+ }
return OPERATOR_RUNNING_MODAL;
}
@@ -843,6 +1120,11 @@ void *paint_stroke_mode_data(struct PaintStroke *stroke)
return stroke->mode_data;
}
+float paint_stroke_distance_get(struct PaintStroke *stroke)
+{
+ return stroke->stroke_distance;
+}
+
void paint_stroke_set_mode_data(PaintStroke *stroke, void *mode_data)
{
stroke->mode_data = mode_data;
@@ -856,6 +1138,6 @@ int paint_poll(bContext *C)
ARegion *ar = CTX_wm_region(C);
return p && ob && BKE_paint_brush(p) &&
- (sa && sa->spacetype == SPACE_VIEW3D) &&
+ (sa && ELEM(sa->spacetype, SPACE_VIEW3D, SPACE_IMAGE)) &&
(ar && ar->regiontype == RGN_TYPE_WINDOW);
}
diff --git a/source/blender/editors/sculpt_paint/paint_undo.c b/source/blender/editors/sculpt_paint/paint_undo.c
index c5c747dbab4..20e3155c01d 100644
--- a/source/blender/editors/sculpt_paint/paint_undo.c
+++ b/source/blender/editors/sculpt_paint/paint_undo.c
@@ -51,19 +51,17 @@ typedef struct UndoElem {
UndoRestoreCb restore;
UndoFreeCb free;
+ UndoCleanupCb cleanup;
} UndoElem;
-typedef bool (*UndoCleanupCb)(struct bContext *C, ListBase *lb);
-
typedef struct UndoStack {
int type;
ListBase elems;
UndoElem *current;
- UndoCleanupCb cleanup;
} UndoStack;
-static UndoStack ImageUndoStack = {UNDO_PAINT_IMAGE, {NULL, NULL}, NULL, NULL};
-static UndoStack MeshUndoStack = {UNDO_PAINT_MESH, {NULL, NULL}, NULL, sculpt_undo_cleanup};
+static UndoStack ImageUndoStack = {UNDO_PAINT_IMAGE, {NULL, NULL}, NULL};
+static UndoStack MeshUndoStack = {UNDO_PAINT_MESH, {NULL, NULL}, NULL};
/* Generic */
@@ -81,7 +79,7 @@ static void undo_elem_free(UndoStack *UNUSED(stack), UndoElem *uel)
}
}
-static void undo_stack_push_begin(UndoStack *stack, const char *name, UndoRestoreCb restore, UndoFreeCb free)
+static void undo_stack_push_begin(UndoStack *stack, const char *name, UndoRestoreCb restore, UndoFreeCb free, UndoCleanupCb cleanup)
{
UndoElem *uel;
int nr;
@@ -101,6 +99,7 @@ static void undo_stack_push_begin(UndoStack *stack, const char *name, UndoRestor
stack->current = uel = MEM_callocN(sizeof(UndoElem), "undo file");
uel->restore = restore;
uel->free = free;
+ uel->cleanup = cleanup;
BLI_addtail(&stack->elems, uel);
/* name can be a dynamic string */
@@ -179,25 +178,24 @@ static void undo_stack_cleanup(UndoStack *stack, bContext *C)
UndoElem *uel = stack->elems.first;
bool stack_reset = false;
- if (stack->cleanup) {
- while (uel) {
- if (stack->cleanup(C, &uel->elems)) {
- UndoElem *uel_tmp = uel->next;
- if (stack->current == uel) {
- stack->current = NULL;
- stack_reset = true;
- }
- undo_elem_free(stack, uel);
- BLI_freelinkN(&stack->elems, uel);
- uel = uel_tmp;
+ while (uel) {
+ if (uel->cleanup && uel->cleanup(C, &uel->elems)) {
+ UndoElem *uel_tmp = uel->next;
+ if (stack->current == uel) {
+ stack->current = NULL;
+ stack_reset = true;
}
- else
- uel = uel->next;
- }
- if (stack_reset) {
- stack->current = stack->elems.last;
+ undo_elem_free(stack, uel);
+ BLI_freelinkN(&stack->elems, uel);
+ uel = uel_tmp;
}
+ else
+ uel = uel->next;
+ }
+ if (stack_reset) {
+ stack->current = stack->elems.last;
}
+
}
static int undo_stack_step(bContext *C, UndoStack *stack, int step, const char *name)
@@ -255,23 +253,25 @@ static void undo_stack_free(UndoStack *stack)
/* Exported Functions */
-void ED_undo_paint_push_begin(int type, const char *name, UndoRestoreCb restore, UndoFreeCb free)
+void ED_undo_paint_push_begin(int type, const char *name, UndoRestoreCb restore, UndoFreeCb free, UndoCleanupCb cleanup)
{
if (type == UNDO_PAINT_IMAGE)
- undo_stack_push_begin(&ImageUndoStack, name, restore, free);
+ undo_stack_push_begin(&ImageUndoStack, name, restore, free, cleanup);
else if (type == UNDO_PAINT_MESH)
- undo_stack_push_begin(&MeshUndoStack, name, restore, free);
+ undo_stack_push_begin(&MeshUndoStack, name, restore, free, cleanup);
}
ListBase *undo_paint_push_get_list(int type)
{
if (type == UNDO_PAINT_IMAGE) {
- if (ImageUndoStack.current)
+ if (ImageUndoStack.current) {
return &ImageUndoStack.current->elems;
+ }
}
else if (type == UNDO_PAINT_MESH) {
- if (MeshUndoStack.current)
+ if (MeshUndoStack.current) {
return &MeshUndoStack.current->elems;
+ }
}
return NULL;
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 25308f6595e..0d463172f99 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -35,23 +35,28 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
+#include "DNA_material_types.h"
#include "DNA_scene_types.h"
#include "DNA_brush_types.h"
#include "BLI_math.h"
+#include "BLI_math_color.h"
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
#include "BLI_rect.h"
#include "BLF_translation.h"
+#include "BKE_scene.h"
#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_DerivedMesh.h"
+#include "BKE_material.h"
#include "BKE_image.h"
#include "BKE_paint.h"
#include "BKE_report.h"
+#include "BKE_image.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -67,6 +72,10 @@
#include "ED_view3d.h"
#include "ED_screen.h"
+#include "ED_uvedit.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
#include "BLI_sys_types.h"
#include "ED_mesh.h" /* for face mask functions */
@@ -205,6 +214,175 @@ void paint_get_tex_pixel_col(MTex *mtex, float u, float v, float rgba[4], struct
CLAMP(rgba[3], 0.0f, 1.0f);
}
+/* 3D Paint */
+
+static void imapaint_project(float matrix[4][4], const float co[3], float pco[4])
+{
+ copy_v3_v3(pco, co);
+ pco[3] = 1.0f;
+
+ mul_m4_v4(matrix, pco);
+}
+
+static void imapaint_tri_weights(float matrix[4][4], GLint view[4],
+ const float v1[3], const float v2[3], const float v3[3],
+ const float co[2], float w[3])
+{
+ float pv1[4], pv2[4], pv3[4], h[3], divw;
+ float wmat[3][3], invwmat[3][3];
+
+ /* compute barycentric coordinates */
+
+ /* project the verts */
+ imapaint_project(matrix, v1, pv1);
+ imapaint_project(matrix, v2, pv2);
+ imapaint_project(matrix, v3, pv3);
+
+ /* do inverse view mapping, see gluProject man page */
+ h[0] = (co[0] - view[0]) * 2.0f / view[2] - 1.0f;
+ h[1] = (co[1] - view[1]) * 2.0f / view[3] - 1.0f;
+ h[2] = 1.0f;
+
+ /* solve for (w1,w2,w3)/perspdiv in:
+ * h * perspdiv = Project * Model * (w1 * v1 + w2 * v2 + w3 * v3) */
+
+ wmat[0][0] = pv1[0]; wmat[1][0] = pv2[0]; wmat[2][0] = pv3[0];
+ wmat[0][1] = pv1[1]; wmat[1][1] = pv2[1]; wmat[2][1] = pv3[1];
+ wmat[0][2] = pv1[3]; wmat[1][2] = pv2[3]; wmat[2][2] = pv3[3];
+
+ invert_m3_m3(invwmat, wmat);
+ mul_m3_v3(invwmat, h);
+
+ copy_v3_v3(w, h);
+
+ /* w is still divided by perspdiv, make it sum to one */
+ divw = w[0] + w[1] + w[2];
+ if (divw != 0.0f) {
+ mul_v3_fl(w, 1.0f / divw);
+ }
+}
+
+/* compute uv coordinates of mouse in face */
+static void imapaint_pick_uv(Scene *scene, Object *ob, unsigned int faceindex, const int xy[2], float uv[2])
+{
+ DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
+ MTFace *tf_base, *tf;
+ Material *ma;
+ TexPaintSlot *slot;
+ int numfaces = dm->getNumTessFaces(dm), a, findex;
+ float p[2], w[3], absw, minabsw;
+ MFace mf;
+ MVert mv[4];
+ float matrix[4][4], proj[4][4];
+ GLint view[4];
+
+ /* compute barycentric coordinates */
+
+ /* double lookup */
+ const int *index_mf_to_mpoly = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
+ const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
+ if (index_mf_to_mpoly == NULL) {
+ index_mp_to_orig = NULL;
+ }
+
+ /* get the needed opengl matrices */
+ glGetIntegerv(GL_VIEWPORT, view);
+ glGetFloatv(GL_MODELVIEW_MATRIX, (float *)matrix);
+ glGetFloatv(GL_PROJECTION_MATRIX, (float *)proj);
+ view[0] = view[1] = 0;
+ mul_m4_m4m4(matrix, matrix, ob->obmat);
+ mul_m4_m4m4(matrix, proj, matrix);
+
+ minabsw = 1e10;
+ uv[0] = uv[1] = 0.0;
+
+ /* test all faces in the derivedmesh with the original index of the picked face */
+ for (a = 0; a < numfaces; a++) {
+ findex = index_mf_to_mpoly ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a) : a;
+
+ if (findex == faceindex) {
+ dm->getTessFace(dm, a, &mf);
+
+ ma = dm->mat[mf.mat_nr];
+ slot = &ma->texpaintslot[ma->paint_active_slot];
+
+ dm->getVert(dm, mf.v1, &mv[0]);
+ dm->getVert(dm, mf.v2, &mv[1]);
+ dm->getVert(dm, mf.v3, &mv[2]);
+ if (mf.v4)
+ dm->getVert(dm, mf.v4, &mv[3]);
+
+ if (!slot->uvname || !(tf_base = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, slot->uvname)))
+ tf_base = CustomData_get_layer(&dm->faceData, CD_MTFACE);
+
+ tf = &tf_base[a];
+
+ p[0] = xy[0];
+ p[1] = xy[1];
+
+ if (mf.v4) {
+ /* the triangle with the largest absolute values is the one
+ * with the most negative weights */
+ imapaint_tri_weights(matrix, view, mv[0].co, mv[1].co, mv[3].co, p, w);
+ absw = fabsf(w[0]) + fabsf(w[1]) + fabsf(w[2]);
+ if (absw < minabsw) {
+ uv[0] = tf->uv[0][0] * w[0] + tf->uv[1][0] * w[1] + tf->uv[3][0] * w[2];
+ uv[1] = tf->uv[0][1] * w[0] + tf->uv[1][1] * w[1] + tf->uv[3][1] * w[2];
+ minabsw = absw;
+ }
+
+ imapaint_tri_weights(matrix, view, mv[1].co, mv[2].co, mv[3].co, p, w);
+ absw = fabsf(w[0]) + fabsf(w[1]) + fabsf(w[2]);
+ if (absw < minabsw) {
+ uv[0] = tf->uv[1][0] * w[0] + tf->uv[2][0] * w[1] + tf->uv[3][0] * w[2];
+ uv[1] = tf->uv[1][1] * w[0] + tf->uv[2][1] * w[1] + tf->uv[3][1] * w[2];
+ minabsw = absw;
+ }
+ }
+ else {
+ imapaint_tri_weights(matrix, view, mv[0].co, mv[1].co, mv[2].co, p, w);
+ absw = fabsf(w[0]) + fabsf(w[1]) + fabsf(w[2]);
+ if (absw < minabsw) {
+ uv[0] = tf->uv[0][0] * w[0] + tf->uv[1][0] * w[1] + tf->uv[2][0] * w[2];
+ uv[1] = tf->uv[0][1] * w[0] + tf->uv[1][1] * w[1] + tf->uv[2][1] * w[2];
+ minabsw = absw;
+ }
+ }
+ }
+ }
+
+ dm->release(dm);
+}
+
+/* returns 0 if not found, otherwise 1 */
+static int imapaint_pick_face(ViewContext *vc, const int mval[2], unsigned int *r_index, unsigned int totface)
+{
+ if (totface == 0)
+ return 0;
+
+ /* sample only on the exact position */
+ *r_index = view3d_sample_backbuf(vc, mval[0], mval[1]);
+
+ if ((*r_index) == 0 || (*r_index) > (unsigned int)totface) {
+ return 0;
+ }
+
+ (*r_index)--;
+
+ return 1;
+}
+
+
+static Image *imapaint_face_image(DerivedMesh *dm, int face_index)
+{
+ Image *ima;
+ MFace *mf = dm->getTessFaceArray(dm) + face_index;
+ Material *ma = dm->mat[mf->mat_nr];
+ ima = ma->texpaintslot[ma->paint_active_slot].ima;
+
+ return ima;
+}
+
/* Uses symm to selectively flip any axis of a coordinate. */
void flip_v3_v3(float out[3], const float in[3], const char symm)
{
@@ -223,25 +401,123 @@ void flip_v3_v3(float out[3], const float in[3], const char symm)
}
/* used for both 3d view and image window */
-void paint_sample_color(const bContext *C, ARegion *ar, int x, int y) /* frontbuf */
+void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_proj, bool use_palette)
{
+ Scene *scene = CTX_data_scene(C);
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ Palette *palette = BKE_paint_palette(paint);
+ PaletteColor *color;
Brush *br = BKE_paint_brush(BKE_paint_get_active_from_context(C));
unsigned int col;
- const char *cp;
+ const unsigned char *cp;
CLAMP(x, 0, ar->winx);
CLAMP(y, 0, ar->winy);
- glReadBuffer(GL_FRONT);
- glReadPixels(x + ar->winrct.xmin, y + ar->winrct.ymin, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
- glReadBuffer(GL_BACK);
+ if (use_palette) {
+ if (!palette) {
+ palette = BKE_palette_add(CTX_data_main(C), "Palette");
+ BKE_paint_palette_set(paint, palette);
+ }
+
+ color = BKE_palette_color_add(palette);
+ }
+
+
+ if (CTX_wm_view3d(C) && texpaint_proj) {
+ /* first try getting a colour directly from the mesh faces if possible */
+ Object *ob = OBACT;
+ bool sample_success = false;
+
+ if (ob) {
+ DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
+
+ ViewContext vc;
+ const int mval[2] = {x, y};
+ unsigned int faceindex;
+ unsigned int totface = dm->getNumTessFaces(dm);
+ MTFace *dm_mtface = dm->getTessFaceDataArray(dm, CD_MTFACE);
+
+ DM_update_materials(dm, ob);
+
+ if (dm_mtface) {
+ view3d_set_viewcontext(C, &vc);
+
+ view3d_operator_needs_opengl(C);
+
+ if (imapaint_pick_face(&vc, mval, &faceindex, totface)) {
+ Image *image = imapaint_face_image(dm, faceindex);
+
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
+ if (ibuf && ibuf->rect) {
+ float uv[2];
+ float u, v;
+ imapaint_pick_uv(scene, ob, faceindex, mval, uv);
+ sample_success = true;
+
+ u = fmodf(uv[0], 1.0f);
+ v = fmodf(uv[1], 1.0f);
+
+ if (u < 0.0f) u += 1.0f;
+ if (v < 0.0f) v += 1.0f;
+
+ u = u * ibuf->x - 0.5f;
+ v = v * ibuf->y - 0.5f;
+
+ if (ibuf->rect_float) {
+ float rgba_f[4];
+ bilinear_interpolation_color_wrap(ibuf, NULL, rgba_f, u, v);
+ straight_to_premul_v4(rgba_f);
+ if (use_palette) {
+ linearrgb_to_srgb_v3_v3(color->rgb, rgba_f);
+ }
+ else {
+ linearrgb_to_srgb_v3_v3(rgba_f, rgba_f);
+ BKE_brush_color_set(scene, br, rgba_f);
+ }
+ }
+ else {
+ unsigned char rgba[4];
+ bilinear_interpolation_color_wrap(ibuf, rgba, NULL, u, v);
+ if (use_palette) {
+ rgb_uchar_to_float(color->rgb, rgba);
+ }
+ else {
+ float rgba_f[3];
+ rgb_uchar_to_float(rgba_f, rgba);
+ BKE_brush_color_set(scene, br, rgba_f);
+ }
+ }
+ }
+
+ BKE_image_release_ibuf(image, ibuf, NULL);
+ }
+ }
+ dm->release(dm);
+ }
- cp = (char *)&col;
+ if (!sample_success) {
+ glReadBuffer(GL_FRONT);
+ glReadPixels(x + ar->winrct.xmin, y + ar->winrct.ymin, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
+ glReadBuffer(GL_BACK);
+ }
+ else
+ return;
+ }
+ else {
+ glReadBuffer(GL_FRONT);
+ glReadPixels(x + ar->winrct.xmin, y + ar->winrct.ymin, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
+ glReadBuffer(GL_BACK);
+ }
+ cp = (unsigned char *)&col;
- if (br) {
- br->rgb[0] = cp[0] / 255.0f;
- br->rgb[1] = cp[1] / 255.0f;
- br->rgb[2] = cp[2] / 255.0f;
+ if (use_palette) {
+ rgb_uchar_to_float(color->rgb, cp);
+ }
+ else {
+ float rgba_f[3];
+ rgb_uchar_to_float(rgba_f, cp);
+ BKE_brush_color_set(scene, br, rgba_f);
}
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 969c5a09a82..2929a96db29 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -197,11 +197,11 @@ static int *get_indexarray(Mesh *me)
return MEM_mallocN(sizeof(int) * (me->totpoly + 1), "vertexpaint");
}
-unsigned int vpaint_get_current_col(VPaint *vp)
+unsigned int vpaint_get_current_col(Scene *scene, VPaint *vp)
{
Brush *brush = BKE_paint_brush(&vp->paint);
unsigned char col[4];
- rgb_float_to_uchar(col, brush->rgb);
+ rgb_float_to_uchar(col, BKE_brush_color_get(scene, brush));
col[3] = 255; /* alpha isn't used, could even be removed to speedup paint a little */
return *(unsigned int *)col;
}
@@ -2547,14 +2547,17 @@ static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
int retval;
- op->customdata = paint_stroke_new(C, NULL, wpaint_stroke_test_start,
+ op->customdata = paint_stroke_new(C, op, NULL, wpaint_stroke_test_start,
wpaint_stroke_update_step, NULL,
wpaint_stroke_done, event->type);
+ if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
+ paint_stroke_data_free(op);
+ return OPERATOR_FINISHED;
+ }
/* add modal handler */
WM_event_add_modal_handler(C, op);
- retval = op->type->modal(C, op, event);
OPERATOR_RETVAL_CHECK(retval);
BLI_assert(retval == OPERATOR_RUNNING_MODAL);
@@ -2563,7 +2566,7 @@ static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int wpaint_exec(bContext *C, wmOperator *op)
{
- op->customdata = paint_stroke_new(C, NULL, wpaint_stroke_test_start,
+ op->customdata = paint_stroke_new(C, op, NULL, wpaint_stroke_test_start,
wpaint_stroke_update_step, NULL,
wpaint_stroke_done, 0);
@@ -2778,7 +2781,8 @@ static void vpaint_build_poly_facemap(struct VPaintData *vd, Mesh *me)
static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const float UNUSED(mouse[2]))
{
- ToolSettings *ts = CTX_data_tool_settings(C);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
struct PaintStroke *stroke = op->customdata;
VPaint *vp = ts->vpaint;
Brush *brush = BKE_paint_brush(&vp->paint);
@@ -2810,7 +2814,7 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f
vpd->vp_handle = ED_vpaint_proj_handle_create(vpd->vc.scene, ob, &vpd->vertexcosnos);
vpd->indexar = get_indexarray(me);
- vpd->paintcol = vpaint_get_current_col(vp);
+ vpd->paintcol = vpaint_get_current_col(scene, vp);
vpd->is_texbrush = !(brush->vertexpaint_tool == PAINT_BLEND_BLUR) &&
brush->mtex.tex;
@@ -3062,14 +3066,18 @@ static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
int retval;
- op->customdata = paint_stroke_new(C, NULL, vpaint_stroke_test_start,
+ op->customdata = paint_stroke_new(C, op, NULL, vpaint_stroke_test_start,
vpaint_stroke_update_step, NULL,
vpaint_stroke_done, event->type);
+ if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
+ paint_stroke_data_free(op);
+ return OPERATOR_FINISHED;
+ }
+
/* add modal handler */
WM_event_add_modal_handler(C, op);
- retval = op->type->modal(C, op, event);
OPERATOR_RETVAL_CHECK(retval);
BLI_assert(retval == OPERATOR_RUNNING_MODAL);
@@ -3078,7 +3086,7 @@ static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int vpaint_exec(bContext *C, wmOperator *op)
{
- op->customdata = paint_stroke_new(C, NULL, vpaint_stroke_test_start,
+ op->customdata = paint_stroke_new(C, op, NULL, vpaint_stroke_test_start,
vpaint_stroke_update_step, NULL,
vpaint_stroke_done, 0);
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 12223effcf5..261da79e35c 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -359,19 +359,19 @@ static int sculpt_stroke_dynamic_topology(const SculptSession *ss,
!(brush->flag & BRUSH_ANCHORED) &&
!(brush->flag & BRUSH_DRAG_DOT) &&
- (!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,
+ (!ELEM(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 ***/
@@ -396,7 +396,7 @@ static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
* entries might be inserted by sculpt_undo_push_node() into the
* GHash used internally by BM_log_original_vert_co() by a
* different thread. [#33787] */
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP && !ss->bm)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && !ss->bm && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
SculptUndoNode *unode;
SculptUndoType type = (brush->sculpt_tool == SCULPT_TOOL_MASK ?
@@ -663,47 +663,6 @@ static bool sculpt_brush_test_cyl(SculptBrushTest *test, float co[3], float loca
/* ===== Sculpting =====
*
*/
-
-static float overlapped_curve(Brush *br, float x)
-{
- int i;
- const int n = 100 / br->spacing;
- const float h = br->spacing / 50.0f;
- const float x0 = x - 1;
-
- float sum;
-
- sum = 0;
- for (i = 0; i < n; i++) {
- float xx;
-
- xx = fabsf(x0 + i * h);
-
- if (xx < 1.0f)
- sum += BKE_brush_curve_strength(br, xx, 1);
- }
-
- return sum;
-}
-
-static float integrate_overlap(Brush *br)
-{
- int i;
- int m = 10;
- float g = 1.0f / m;
- float max;
-
- max = 0;
- for (i = 0; i < m; i++) {
- float overlap = overlapped_curve(br, i * g);
-
- if (overlap > max)
- max = overlap;
- }
-
- return max;
-}
-
static void flip_v3(float v[3], const char symm)
{
flip_v3_v3(v, v, symm);
@@ -776,7 +735,7 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache)
/* Return modified brush strength. Includes the direction of the brush, positive
* values pull vertices, negative values push. Uses tablet pressure and a
* special multiplier found experimentally to scale the strength factor. */
-static float brush_strength(Sculpt *sd, StrokeCache *cache, float feather)
+static float brush_strength(Sculpt *sd, StrokeCache *cache, float feather, UnifiedPaintSettings *ups)
{
const Scene *scene = cache->vc->scene;
Brush *brush = BKE_paint_brush(&sd->paint);
@@ -788,13 +747,10 @@ static float brush_strength(Sculpt *sd, StrokeCache *cache, float feather)
float pressure = BKE_brush_use_alpha_pressure(scene, brush) ? cache->pressure : 1;
float pen_flip = cache->pen_flip ? -1 : 1;
float invert = cache->invert ? -1 : 1;
- float accum = integrate_overlap(brush);
+ float overlap = ups->overlap_factor;
/* spacing is integer percentage of radius, divide by 50 to get
* normalized diameter */
- float overlap = (brush->flag & BRUSH_SPACE_ATTEN &&
- brush->flag & BRUSH_SPACE &&
- !(brush->flag & BRUSH_ANCHORED) &&
- (brush->spacing < 100)) ? 1.0f / accum : 1;
+
float flip = dir * invert * pen_flip;
switch (brush->sculpt_tool) {
@@ -1040,7 +996,7 @@ static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nod
zero_v3(an);
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
@@ -1236,14 +1192,14 @@ static int brush_needs_sculpt_normal(const Brush *brush)
SCULPT_TOOL_SNAKE_HOOK) &&
(brush->normal_weight > 0)) ||
- ELEM7(brush->sculpt_tool,
- SCULPT_TOOL_BLOB,
- SCULPT_TOOL_CREASE,
- SCULPT_TOOL_DRAW,
- SCULPT_TOOL_LAYER,
- SCULPT_TOOL_NUDGE,
- SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_THUMB) ||
+ ELEM(brush->sculpt_tool,
+ SCULPT_TOOL_BLOB,
+ SCULPT_TOOL_CREASE,
+ SCULPT_TOOL_DRAW,
+ SCULPT_TOOL_LAYER,
+ SCULPT_TOOL_NUDGE,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_THUMB) ||
(brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA));
}
@@ -1646,7 +1602,7 @@ static void smooth(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode,
for (iteration = 0; iteration <= count; ++iteration) {
float strength = (iteration != count) ? 1.0f : last;
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
switch (type) {
case PBVH_GRIDS:
@@ -1682,7 +1638,7 @@ static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int tot
int n;
/* threaded loop over nodes */
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
@@ -1735,7 +1691,7 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
mul_v3_fl(offset, bstrength);
/* threaded loop over nodes */
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
@@ -1790,7 +1746,7 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
if (brush->sculpt_tool == SCULPT_TOOL_BLOB) flippedbstrength *= -1.0f;
/* threaded loop over nodes */
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
@@ -1833,7 +1789,7 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
float bstrength = ss->cache->bstrength;
int n;
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
@@ -1880,7 +1836,7 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
add_v3_v3(grab_delta, ss->cache->sculpt_normal_symm);
}
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
@@ -1928,7 +1884,7 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta);
cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm);
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
@@ -1976,7 +1932,7 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
add_v3_v3(grab_delta, ss->cache->sculpt_normal_symm);
}
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
@@ -2016,7 +1972,7 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta);
cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm);
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
@@ -2059,7 +2015,7 @@ static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
static const int flip[8] = { 1, -1, -1, 1, -1, 1, 1, -1 };
float angle = ss->cache->vertex_rotation * flip[ss->cache->mirror_symmetry_pass];
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
@@ -2112,7 +2068,7 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
mul_v3_v3v3(offset, ss->cache->scale, ss->cache->sculpt_normal_symm);
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
@@ -2175,7 +2131,7 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
float bstrength = ss->cache->bstrength;
int n;
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
@@ -2220,7 +2176,7 @@ static void calc_flatten_center(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
zero_v3(fc);
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
@@ -2327,7 +2283,7 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob,
/* for flatten center */
zero_v3(fc);
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
@@ -2579,7 +2535,7 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
mul_v3_fl(temp, displace);
add_v3_v3(fc, temp);
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
@@ -2651,7 +2607,7 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
/* add_v3_v3v3(p, ss->cache->location, an); */
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
@@ -2752,7 +2708,7 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
mul_m4_m4m4(tmat, mat, scale);
invert_m4_m4(mat, tmat);
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
@@ -2816,7 +2772,7 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
mul_v3_fl(temp, displace);
add_v3_v3(fc, temp);
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
@@ -2880,7 +2836,7 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
mul_v3_fl(temp, displace);
add_v3_v3(fc, temp);
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
@@ -2934,7 +2890,7 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl
mul_v3_fl(offset, bstrength);
/* threaded loop over nodes */
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
@@ -3030,11 +2986,11 @@ static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush)
radius = ss->cache->radius * 1.25f;
data.radius_squared = radius * radius;
- data.original = ELEM4(brush->sculpt_tool,
- SCULPT_TOOL_GRAB,
- SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_THUMB,
- SCULPT_TOOL_LAYER) ? true : ss->cache->original;
+ data.original = ELEM(brush->sculpt_tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_LAYER) ? true : ss->cache->original;
BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode);
@@ -3092,18 +3048,18 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush)
data.ss = ss;
data.sd = sd;
data.radius_squared = ss->cache->radius_squared;
- data.original = ELEM4(brush->sculpt_tool,
- SCULPT_TOOL_GRAB,
- SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_THUMB,
- SCULPT_TOOL_LAYER) ? true : ss->cache->original;
+ data.original = ELEM(brush->sculpt_tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_LAYER) ? true : ss->cache->original;
BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode);
/* Only act if some verts are inside the brush area */
if (totnode) {
float location[3];
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
sculpt_undo_push_node(ob, nodes[n],
brush->sculpt_tool == SCULPT_TOOL_MASK ?
@@ -3233,10 +3189,10 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
ss->cache->supports_gravity)
{
/* these brushes start from original coordinates */
- const bool use_orco = ELEM3(brush->sculpt_tool, SCULPT_TOOL_GRAB,
- SCULPT_TOOL_ROTATE, SCULPT_TOOL_THUMB);
+ const bool use_orco = ELEM(brush->sculpt_tool, SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ROTATE, SCULPT_TOOL_THUMB);
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
PBVHProxyNode *proxies;
@@ -3329,7 +3285,7 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob)
BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
@@ -3377,7 +3333,7 @@ static void calc_brushdata_symm(Sculpt *sd, StrokeCache *cache, const char symm,
/* XXX This reduces the length of the grab delta if it approaches the line of symmetry
* XXX However, a different approach appears to be needed */
#if 0
- if (sd->flags & SCULPT_SYMMETRY_FEATHER) {
+ if (sd->paint.symmetry_flags & SCULPT_SYMMETRY_FEATHER) {
float frac = 1.0f / max_overlap_count(sd);
float reduce = (feather - frac) / (1 - frac);
@@ -3437,7 +3393,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, UnifiedPaintSettings *ups)
{
Brush *brush = BKE_paint_brush(&sd->paint);
SculptSession *ss = ob->sculpt;
@@ -3447,7 +3403,7 @@ static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob,
float feather = calc_symmetry_feather(sd, ss->cache);
- cache->bstrength = brush_strength(sd, cache, feather);
+ cache->bstrength = brush_strength(sd, cache, feather, ups);
cache->symmetry = symm;
/* symm is a bit combination of XYZ - 1 is mirror X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
@@ -3733,8 +3689,8 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
/* not very nice, but with current events system implementation
* we can't handle brush appearance inversion hotkey separately (sergey) */
- if (cache->invert) brush->flag |= BRUSH_INVERTED;
- else brush->flag &= ~BRUSH_INVERTED;
+ if (cache->invert) ups->draw_inverted = true;
+ else ups->draw_inverted = false;
/* Alt-Smooth */
if (cache->alt_smooth) {
@@ -3780,7 +3736,7 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
mul_m3_v3(mat, viewDir);
normalize_v3_v3(cache->true_view_normal, viewDir);
- cache->supports_gravity = (!ELEM3(brush->sculpt_tool, SCULPT_TOOL_MASK, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_SIMPLIFY) &&
+ cache->supports_gravity = (!ELEM(brush->sculpt_tool, SCULPT_TOOL_MASK, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_SIMPLIFY) &&
(sd->gravity_factor > 0.0f));
/* get gravity vector in world space */
if (cache->supports_gravity) {
@@ -3838,10 +3794,10 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
cache->original = 1;
}
- if (ELEM9(brush->sculpt_tool,
- SCULPT_TOOL_DRAW, SCULPT_TOOL_CREASE, SCULPT_TOOL_BLOB,
- SCULPT_TOOL_LAYER, SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY,
- SCULPT_TOOL_CLAY_STRIPS, SCULPT_TOOL_ROTATE, SCULPT_TOOL_FLATTEN))
+ if (ELEM(brush->sculpt_tool,
+ SCULPT_TOOL_DRAW, SCULPT_TOOL_CREASE, SCULPT_TOOL_BLOB,
+ SCULPT_TOOL_LAYER, SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY,
+ SCULPT_TOOL_CLAY_STRIPS, SCULPT_TOOL_ROTATE, SCULPT_TOOL_FLATTEN))
{
if (!(brush->flag & BRUSH_ACCUMULATE)) {
cache->original = 1;
@@ -3868,10 +3824,10 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
};
int tool = brush->sculpt_tool;
- if (ELEM5(tool,
- SCULPT_TOOL_GRAB, SCULPT_TOOL_NUDGE,
- SCULPT_TOOL_CLAY_STRIPS, SCULPT_TOOL_SNAKE_HOOK,
- SCULPT_TOOL_THUMB))
+ if (ELEM(tool,
+ SCULPT_TOOL_GRAB, SCULPT_TOOL_NUDGE,
+ SCULPT_TOOL_CLAY_STRIPS, SCULPT_TOOL_SNAKE_HOOK,
+ SCULPT_TOOL_THUMB))
{
float grab_location[3], imat[4][4], delta[3], loc[3];
@@ -3992,16 +3948,9 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob,
cache->radius_squared = cache->radius * cache->radius;
if (brush->flag & BRUSH_ANCHORED) {
+ /* true location has been calculated as part of the stroke system already here */
if (brush->flag & BRUSH_EDGE_TO_EDGE) {
- float halfway[2];
- float out[3];
- 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(cache->anchored_location, out);
- copy_v3_v3(cache->true_location, cache->anchored_location);
- }
+ RNA_float_get_array(ptr, "location", cache->true_location);
}
cache->radius = paint_calc_object_space_radius(cache->vc,
@@ -4393,10 +4342,10 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *UNUSED(st
}
if (sculpt_stroke_dynamic_topology(ss, brush)) {
- do_symmetrical_brush_actions(sd, ob, sculpt_topology_update);
+ do_symmetrical_brush_actions(sd, ob, sculpt_topology_update, ups);
}
- do_symmetrical_brush_actions(sd, ob, do_brush_action);
+ do_symmetrical_brush_actions(sd, ob, do_brush_action, ups);
sculpt_combine_proxies(sd, ob);
@@ -4446,8 +4395,9 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
/* Finished */
if (ss->cache) {
+ UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
Brush *brush = BKE_paint_brush(&sd->paint);
- brush->flag &= ~BRUSH_INVERTED;
+ ups->draw_inverted = false;
sculpt_stroke_modifiers_check(C, ob);
@@ -4506,7 +4456,7 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent
if (!sculpt_brush_stroke_init(C, op))
return OPERATOR_CANCELLED;
- stroke = paint_stroke_new(C, sculpt_stroke_get_location,
+ stroke = paint_stroke_new(C, op, sculpt_stroke_get_location,
sculpt_stroke_test_start,
sculpt_stroke_update_step, NULL,
sculpt_stroke_done, event->type);
@@ -4521,10 +4471,13 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_PASS_THROUGH;
}
+ if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
+ paint_stroke_data_free(op);
+ return OPERATOR_FINISHED;
+ }
/* add modal handler */
WM_event_add_modal_handler(C, op);
- retval = op->type->modal(C, op, event);
OPERATOR_RETVAL_CHECK(retval);
BLI_assert(retval == OPERATOR_RUNNING_MODAL);
@@ -4536,7 +4489,7 @@ static int sculpt_brush_stroke_exec(bContext *C, wmOperator *op)
if (!sculpt_brush_stroke_init(C, op))
return OPERATOR_CANCELLED;
- op->customdata = paint_stroke_new(C, sculpt_stroke_get_location, sculpt_stroke_test_start,
+ op->customdata = paint_stroke_new(C, op, sculpt_stroke_get_location, sculpt_stroke_test_start,
sculpt_stroke_update_step, NULL, sculpt_stroke_done, 0);
/* frees op->customdata */
@@ -4856,7 +4809,7 @@ static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, co
bool modifiers = false;
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 (!ELEM(i, CD_MVERT, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX) &&
(CustomData_has_layer(&me->vdata, i) ||
CustomData_has_layer(&me->edata, i) ||
CustomData_has_layer(&me->fdata, i)))
@@ -5062,11 +5015,11 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
ts->sculpt->paint.flags |= PAINT_SHOW_BRUSH;
/* Make sure at least dyntopo subdivision is enabled */
- ts->sculpt->flags |= SCULPT_DYNTOPO_SUBDIVIDE;
+ ts->sculpt->flags |= SCULPT_DYNTOPO_SUBDIVIDE | SCULPT_DYNTOPO_COLLAPSE;
}
if (!ts->sculpt->detail_size) {
- ts->sculpt->detail_size = 30;
+ ts->sculpt->detail_size = 12;
}
if (ts->sculpt->constant_detail == 0.0f)
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index cd79f525d82..a61f571fdf6 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -130,4 +130,11 @@ void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3]);
void sculpt_update_object_bounding_box(struct Object *ob);
+/* Setting zero so we can catch bugs in OpenMP/sculpt. */
+#ifdef DEBUG
+# define SCULPT_OMP_LIMIT 0
+#else
+# define SCULPT_OMP_LIMIT 4
+#endif
+
#endif
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index 0d49049c78e..91f80a4fc40 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -291,7 +291,7 @@ static void sculpt_undo_bmesh_restore_generic(bContext *C,
BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (i = 0; i < totnode; i++) {
BKE_pbvh_node_mark_redraw(nodes[i]);
}
@@ -543,7 +543,7 @@ static void sculpt_undo_free(ListBase *lb)
}
}
-bool sculpt_undo_cleanup(bContext *C, ListBase *lb)
+static bool sculpt_undo_cleanup(bContext *C, ListBase *lb)
{
Object *ob = CTX_data_active_object(C);
SculptUndoNode *unode;
@@ -551,10 +551,8 @@ bool sculpt_undo_cleanup(bContext *C, ListBase *lb)
unode = lb->first;
if (unode && strcmp(unode->idname, ob->id.name) != 0) {
- for (unode = lb->first; unode; unode = unode->next) {
- if (unode->bm_entry)
- BM_log_cleanup_entry(unode->bm_entry);
- }
+ if (unode->bm_entry)
+ BM_log_cleanup_entry(unode->bm_entry);
return true;
}
@@ -881,7 +879,7 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node,
void sculpt_undo_push_begin(const char *name)
{
ED_undo_paint_push_begin(UNDO_PAINT_MESH, name,
- sculpt_undo_restore, sculpt_undo_free);
+ sculpt_undo_restore, sculpt_undo_free, sculpt_undo_cleanup);
}
void sculpt_undo_push_end(void)
diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c
index 797a881ce79..292d6236bab 100644
--- a/source/blender/editors/sculpt_paint/sculpt_uv.c
+++ b/source/blender/editors/sculpt_paint/sculpt_uv.c
@@ -239,12 +239,14 @@ void ED_space_image_uv_sculpt_update(wmWindowManager *wm, ToolSettings *settings
BKE_paint_init(&settings->uvsculpt->paint, PAINT_CURSOR_SCULPT);
- WM_paint_cursor_activate(wm, uv_sculpt_brush_poll,
- brush_drawcursor_uvsculpt, NULL);
+ settings->uvsculpt->paint.paint_cursor = WM_paint_cursor_activate(wm, uv_sculpt_brush_poll,
+ brush_drawcursor_uvsculpt, NULL);
}
else {
- if (settings->uvsculpt)
- settings->uvsculpt->paint.flags &= ~PAINT_SHOW_BRUSH;
+ if (settings->uvsculpt) {
+ WM_paint_cursor_end(wm, settings->uvsculpt->paint.paint_cursor);
+ settings->uvsculpt->paint.paint_cursor = NULL;
+ }
}
}
diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c
index b2e55085579..335949e8495 100644
--- a/source/blender/editors/space_action/action_draw.c
+++ b/source/blender/editors/space_action/action_draw.c
@@ -219,7 +219,7 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
if (acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT))
sel = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT);
- if (ELEM3(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_SHAPEKEY)) {
+ if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_SHAPEKEY)) {
switch (ale->type) {
case ANIMTYPE_SUMMARY:
{
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index cf18cffefb6..ddfca98a119 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -1086,8 +1086,9 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_
View2D *v2d = &ac->ar->v2d;
bDopeSheet *ads = NULL;
int channel_index;
- short found = 0;
- float selx = 0.0f;
+ bool found = false;
+ float frame = 0.0f; /* frame of keyframe under mouse - NLA corrections not applied/included */
+ float selx = 0.0f; /* frame of keyframe under mouse */
float x, y;
rctf rectf;
@@ -1179,7 +1180,8 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_
* requiring to map each frame once again...
*/
selx = BKE_nla_tweakedit_remap(adt, ak->cfra, NLATIME_CONVERT_UNMAP);
- found = 1;
+ frame = ak->cfra;
+ found = true;
break;
}
else if (ak->cfra < rectf.xmin)
@@ -1258,8 +1260,11 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_
if (found) {
/* apply selection to keyframes */
if (column) {
- /* select all keyframes in the same frame as the one we hit on the active channel */
- actkeys_mselect_column(ac, select_mode, selx);
+ /* select all keyframes in the same frame as the one we hit on the active channel
+ * [T41077]: "frame" not "selx" here (i.e. no NLA corrections yet) as the code here
+ * does that itself again as it needs to work on multiple datablocks
+ */
+ actkeys_mselect_column(ac, select_mode, frame);
}
else if (same_channel) {
/* select all keyframes in the active channel */
diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c
index 7a74a58c69d..b171e7a5f88 100644
--- a/source/blender/editors/space_api/spacetypes.c
+++ b/source/blender/editors/space_api/spacetypes.c
@@ -144,6 +144,7 @@ void ED_spacetypes_init(void)
ED_operatormacros_curve();
ED_operatormacros_mask();
ED_operatormacros_sequencer();
+ ED_operatormacros_paint();
/* register dropboxes (can use macros) */
spacetypes = BKE_spacetypes_list();
diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c
index 8917704b731..524a42ba388 100644
--- a/source/blender/editors/space_buttons/buttons_context.c
+++ b/source/blender/editors/space_buttons/buttons_context.c
@@ -200,7 +200,7 @@ static int buttons_context_path_data(ButsContextPath *path, int type)
/* if we already have a data, we're done */
if (RNA_struct_is_a(ptr->type, &RNA_Mesh) && (type == -1 || type == OB_MESH)) return 1;
- else if (RNA_struct_is_a(ptr->type, &RNA_Curve) && (type == -1 || ELEM3(type, OB_CURVE, OB_SURF, OB_FONT))) return 1;
+ else if (RNA_struct_is_a(ptr->type, &RNA_Curve) && (type == -1 || ELEM(type, OB_CURVE, OB_SURF, OB_FONT))) return 1;
else if (RNA_struct_is_a(ptr->type, &RNA_Armature) && (type == -1 || type == OB_ARMATURE)) return 1;
else if (RNA_struct_is_a(ptr->type, &RNA_MetaBall) && (type == -1 || type == OB_MBALL)) return 1;
else if (RNA_struct_is_a(ptr->type, &RNA_Lattice) && (type == -1 || type == OB_LATTICE)) return 1;
@@ -230,7 +230,7 @@ static int buttons_context_path_modifier(ButsContextPath *path)
if (buttons_context_path_object(path)) {
ob = path->ptr[path->len - 1].data;
- if (ob && ELEM5(ob->type, OB_MESH, OB_CURVE, OB_FONT, OB_SURF, OB_LATTICE))
+ if (ob && ELEM(ob->type, OB_MESH, OB_CURVE, OB_FONT, OB_SURF, OB_LATTICE))
return 1;
}
@@ -638,7 +638,7 @@ static int buttons_shading_context(const bContext *C, int mainb)
{
Object *ob = CTX_data_active_object(C);
- if (ELEM3(mainb, BCONTEXT_MATERIAL, BCONTEXT_WORLD, BCONTEXT_TEXTURE))
+ if (ELEM(mainb, BCONTEXT_MATERIAL, BCONTEXT_WORLD, BCONTEXT_TEXTURE))
return 1;
if (mainb == BCONTEXT_DATA && ob && ELEM(ob->type, OB_LAMP, OB_CAMERA))
return 1;
@@ -1120,7 +1120,7 @@ void buttons_context_draw(const bContext *C, uiLayout *layout)
name = RNA_struct_name_get_alloc(ptr, namebuf, sizeof(namebuf), NULL);
if (name) {
- if (!ELEM3(sbuts->mainb, BCONTEXT_RENDER, BCONTEXT_SCENE, BCONTEXT_RENDER_LAYER) && ptr->type == &RNA_Scene)
+ if (!ELEM(sbuts->mainb, BCONTEXT_RENDER, BCONTEXT_SCENE, BCONTEXT_RENDER_LAYER) && ptr->type == &RNA_Scene)
uiItemLDrag(row, ptr, "", icon); /* save some space */
else
uiItemLDrag(row, ptr, name, icon);
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index 1c3bad9757d..8c6bf67c9a8 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -358,7 +358,7 @@ static void buttons_area_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *
case NC_ANIMATION:
switch (wmn->data) {
case ND_KEYFRAME:
- if (ELEM3(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED))
+ if (ELEM(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED))
ED_area_tag_redraw(sa);
break;
}
diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c
index 9a939bdc2ca..b5c08e7a08a 100644
--- a/source/blender/editors/space_clip/clip_draw.c
+++ b/source/blender/editors/space_clip/clip_draw.c
@@ -1728,7 +1728,7 @@ void clip_draw_main(const bContext *C, SpaceClip *sc, ARegion *ar)
smat[1][1] = 1.0f / height;
invert_m4_m4(ismat, smat);
- mul_serie_m4(sc->unistabmat, smat, sc->stabmat, ismat, NULL, NULL, NULL, NULL, NULL);
+ mul_m4_series(sc->unistabmat, smat, sc->stabmat, ismat);
}
}
else if ((sc->flag & SC_MUTE_FOOTAGE) == 0) {
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index d3be25050c8..a6fbb0c399d 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -846,7 +846,7 @@ static int clip_context(const bContext *C, const char *member, bContextDataResul
static int clip_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
{
if (drag->type == WM_DRAG_PATH)
- if (ELEM4(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE, ICON_FILE_BLANK)) /* rule might not work? */
+ if (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE, ICON_FILE_BLANK)) /* rule might not work? */
return true;
return false;
diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c
index ce14471f608..abbffcd8546 100644
--- a/source/blender/editors/space_clip/tracking_ops.c
+++ b/source/blender/editors/space_clip/tracking_ops.c
@@ -2277,7 +2277,7 @@ static void set_axis(Scene *scene, Object *ob, MovieClip *clip, MovieTrackingOb
copy_v3_v3(lmat[3], obmat[3]);
invert_m4_m4(ilmat, lmat);
- mul_serie_m4(mat, lmat, mat, ilmat, obmat, NULL, NULL, NULL, NULL);
+ mul_m4_series(mat, lmat, mat, ilmat, obmat);
}
else {
mul_m4_m4m4(mat, obmat, mat);
@@ -2996,7 +2996,7 @@ void CLIP_OT_detect_features(wmOperatorType *ot)
/* properties */
RNA_def_enum(ot->srna, "placement", placement_items, 0, "Placement", "Placement for detected features");
RNA_def_int(ot->srna, "margin", 16, 0, INT_MAX, "Margin", "Only features further than margin pixels from the image edges are considered", 0, 300);
- RNA_def_float(ot->srna, "threshold", 1.0f, 0.0001f, FLT_MAX, "Threshold", "Threshold level to consider feature good enough for tracking", 0.0001f, FLT_MAX);
+ RNA_def_float(ot->srna, "threshold", 0.5f, 0.0001f, FLT_MAX, "Threshold", "Threshold level to consider feature good enough for tracking", 0.0001f, FLT_MAX);
RNA_def_int(ot->srna, "min_distance", 120, 0, INT_MAX, "Distance", "Minimal distance accepted between two features", 0, 300);
}
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index 3a493c0338c..d5be04cff20 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -422,7 +422,7 @@ static void file_keymap(struct wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "FILE_OT_select", LEFTMOUSE, KM_CLICK, 0, 0);
kmi = WM_keymap_add_item(keymap, "FILE_OT_select", LEFTMOUSE, KM_CLICK, KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "extend", true);
- kmi = WM_keymap_add_item(keymap, "FILE_OT_select", LEFTMOUSE, KM_CLICK, KM_ALT, 0);
+ kmi = WM_keymap_add_item(keymap, "FILE_OT_select", LEFTMOUSE, KM_CLICK, KM_CTRL | KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "extend", true);
RNA_boolean_set(kmi->ptr, "fill", true);
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index 1f1aac8c456..c8298927f7d 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -1707,7 +1707,7 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op)
*/
if (strstr(fcu->rna_path, "rotation_euler") == NULL)
continue;
- else if (ELEM3(fcu->array_index, 0, 1, 2) == 0) {
+ else if (ELEM(fcu->array_index, 0, 1, 2) == 0) {
BKE_reportf(op->reports, RPT_WARNING,
"Euler Rotation F-Curve has invalid index (ID='%s', Path='%s', Index=%d)",
(ale->id) ? ale->id->name : TIP_("<No ID>"), fcu->rna_path, fcu->array_index);
@@ -1750,7 +1750,7 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op)
/* sanity check: ensure that there are enough F-Curves to work on in this group */
/* TODO: also enforce assumption that there be a full set of keyframes at each position by ensuring that totvert counts are same? */
- if (ELEM3(NULL, euf->fcurves[0], euf->fcurves[1], euf->fcurves[2])) {
+ if (ELEM(NULL, euf->fcurves[0], euf->fcurves[1], euf->fcurves[2])) {
/* report which components are missing */
BKE_reportf(op->reports, RPT_WARNING,
"Missing %s%s%s component(s) of euler rotation for ID='%s' and RNA-Path='%s'",
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index 3675282654f..7e90008d8d2 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -843,14 +843,14 @@ void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, int color_man
uiItemR(sub, imfptr, "color_mode", UI_ITEM_R_EXPAND, IFACE_("Color"), ICON_NONE);
/* only display depth setting if multiple depths can be used */
- if ((ELEM7(depth_ok,
- R_IMF_CHAN_DEPTH_1,
- R_IMF_CHAN_DEPTH_8,
- R_IMF_CHAN_DEPTH_10,
- R_IMF_CHAN_DEPTH_12,
- R_IMF_CHAN_DEPTH_16,
- R_IMF_CHAN_DEPTH_24,
- R_IMF_CHAN_DEPTH_32)) == 0)
+ if ((ELEM(depth_ok,
+ R_IMF_CHAN_DEPTH_1,
+ R_IMF_CHAN_DEPTH_8,
+ R_IMF_CHAN_DEPTH_10,
+ R_IMF_CHAN_DEPTH_12,
+ R_IMF_CHAN_DEPTH_16,
+ R_IMF_CHAN_DEPTH_24,
+ R_IMF_CHAN_DEPTH_32)) == 0)
{
row = uiLayoutRow(col, false);
diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c
index a2f7d9e7d6c..24b1c54dd9f 100644
--- a/source/blender/editors/space_image/image_edit.c
+++ b/source/blender/editors/space_image/image_edit.c
@@ -28,6 +28,7 @@
* \ingroup spimage
*/
+#include "DNA_brush_types.h"
#include "DNA_mask_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -297,44 +298,51 @@ bool ED_space_image_show_render(SpaceImage *sima)
bool ED_space_image_show_paint(SpaceImage *sima)
{
if (ED_space_image_show_render(sima))
- return 0;
+ return false;
return (sima->mode == SI_MODE_PAINT);
}
+bool ED_space_image_show_texpaint(SpaceImage *sima, Object *ob)
+{
+ return (ob && ob->type == OB_MESH &&
+ ob->mode == OB_MODE_TEXTURE_PAINT &&
+ !(sima->flag & SI_NO_DRAW_TEXPAINT));
+}
+
bool ED_space_image_show_uvedit(SpaceImage *sima, Object *obedit)
{
if (sima && (ED_space_image_show_render(sima) || ED_space_image_show_paint(sima)))
- return 0;
+ return false;
if (obedit && obedit->type == OB_MESH) {
struct BMEditMesh *em = BKE_editmesh_from_object(obedit);
- int ret;
+ bool ret;
ret = EDBM_mtexpoly_check(em);
return ret;
}
- return 0;
+ return false;
}
bool ED_space_image_show_uvshadow(SpaceImage *sima, Object *obedit)
{
if (ED_space_image_show_render(sima))
- return 0;
+ return false;
if (ED_space_image_show_paint(sima))
if (obedit && obedit->type == OB_MESH) {
struct BMEditMesh *em = BKE_editmesh_from_object(obedit);
- int ret;
+ bool ret;
ret = EDBM_mtexpoly_check(em);
- return ret;
+ return ret && !(sima->flag & SI_NO_DRAW_TEXPAINT);
}
- return 0;
+ return false;
}
/* matches clip function */
@@ -361,6 +369,21 @@ int ED_space_image_maskedit_poll(bContext *C)
return false;
}
+bool ED_space_image_paint_curve(const bContext *C)
+{
+ SpaceImage *sima = CTX_wm_space_image(C);
+
+ if (sima && sima->mode == SI_MODE_PAINT) {
+ Brush *br = CTX_data_tool_settings(C)->imapaint.paint.brush;
+
+ if (br && (br->flag & BRUSH_CURVE))
+ return true;
+ }
+
+ return false;
+}
+
+
int ED_space_image_maskedit_mask_poll(bContext *C)
{
if (ED_space_image_maskedit_poll(C)) {
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 4ae05d8f64f..66bd346ae69 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -1383,7 +1383,7 @@ static int save_image_options_init(SaveImageOptions *simopts, SpaceImage *sima,
/* sanitize all settings */
/* unlikely but just in case */
- if (ELEM3(simopts->im_format.planes, R_IMF_PLANES_BW, R_IMF_PLANES_RGB, R_IMF_PLANES_RGBA) == 0) {
+ if (ELEM(simopts->im_format.planes, R_IMF_PLANES_BW, R_IMF_PLANES_RGB, R_IMF_PLANES_RGBA) == 0) {
simopts->im_format.planes = R_IMF_PLANES_RGBA;
}
@@ -1904,6 +1904,7 @@ static int image_new_exec(bContext *C, wmOperator *op)
char *name = _name;
float color[4];
int width, height, floatbuf, gen_type, alpha;
+ bool stencil;
/* retrieve state */
sima = CTX_wm_space_image(C);
@@ -1923,7 +1924,8 @@ static int image_new_exec(bContext *C, wmOperator *op)
gen_type = RNA_enum_get(op->ptr, "generated_type");
RNA_float_get_array(op->ptr, "color", color);
alpha = RNA_boolean_get(op->ptr, "alpha");
-
+ stencil = RNA_boolean_get(op->ptr, "texstencil");
+
if (!alpha)
color[3] = 1.0f;
@@ -1955,6 +1957,13 @@ static int image_new_exec(bContext *C, wmOperator *op)
tex->ima = ima;
ED_area_tag_redraw(CTX_wm_area(C));
}
+ else if (stencil) {
+ ImagePaintSettings *imapaint = &(CTX_data_tool_settings(C)->imapaint);
+
+ if (imapaint->stencil)
+ id_us_min(&imapaint->stencil->id);
+ imapaint->stencil = ima;
+ }
}
BKE_image_signal(ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_USER_NEW_IMAGE);
@@ -2003,6 +2012,9 @@ void IMAGE_OT_new(wmOperatorType *ot)
RNA_def_enum(ot->srna, "generated_type", image_generated_type_items, IMA_GENTYPE_BLANK,
"Generated Type", "Fill the image with a grid for UV map testing");
RNA_def_boolean(ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth");
+ prop = RNA_def_boolean(ot->srna, "texstencil", 0, "Stencil", "Set Image as stencil");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+
}
#undef IMA_DEF_NAME
@@ -2037,7 +2049,7 @@ static int image_invert_exec(bContext *C, wmOperator *op)
if (support_undo) {
ED_undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name,
- ED_image_undo_restore, ED_image_undo_free);
+ ED_image_undo_restore, ED_image_undo_free, NULL);
/* not strictly needed, because we only imapaint_dirty_region to invalidate all tiles
* but better do this right in case someone copies this for a tool that uses partial redraw better */
ED_imapaint_clear_partial_redraw();
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index 0fb93ad27ee..375a0ddeac3 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -349,7 +349,7 @@ static void image_keymap(struct wmKeyConfig *keyconf)
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? */
+ if (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_BLANK)) /* rule might not work? */
return 1;
return 0;
}
@@ -633,6 +633,12 @@ static void image_main_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
/* image paint polls for mode */
+ keymap = WM_keymap_find(wm->defaultconf, "Curve", 0, 0);
+ WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
+
+ keymap = WM_keymap_find(wm->defaultconf, "Paint Curve", 0, 0);
+ WM_event_add_keymap_handler(&ar->handlers, keymap);
+
keymap = WM_keymap_find(wm->defaultconf, "Image Paint", 0, 0);
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
@@ -657,6 +663,7 @@ static void image_main_area_draw(const bContext *C, ARegion *ar)
Object *obact = CTX_data_active_object(C);
Object *obedit = CTX_data_edit_object(C);
Mask *mask = NULL;
+ bool curve = false;
Scene *scene = CTX_data_scene(C);
View2D *v2d = &ar->v2d;
//View2DScrollers *scrollers;
@@ -702,6 +709,9 @@ static void image_main_area_draw(const bContext *C, ARegion *ar)
else if (sima->mode == SI_MODE_MASK) {
mask = ED_space_image_get_mask(sima);
}
+ else if (ED_space_image_paint_curve(C)) {
+ curve = true;
+ }
ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW);
@@ -753,6 +763,11 @@ static void image_main_area_draw(const bContext *C, ARegion *ar)
draw_image_cursor(ar, sima->cursor);
UI_view2d_view_restore(C);
}
+ else if (curve) {
+ UI_view2d_view_ortho(v2d);
+ draw_image_cursor(ar, sima->cursor);
+ UI_view2d_view_restore(C);
+ }
draw_image_cache(C, ar);
diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c
index 9f3fc53482a..dd152022762 100644
--- a/source/blender/editors/space_logic/logic_window.c
+++ b/source/blender/editors/space_logic/logic_window.c
@@ -1832,7 +1832,7 @@ static void draw_actuator_motion(uiLayout *layout, PointerRNA *ptr)
uiItemR(row, ptr, "offset_rotation", 0, NULL, ICON_NONE);
uiItemR(split, ptr, "use_local_rotation", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
- if (ELEM3(physics_type, OB_BODY_TYPE_DYNAMIC, OB_BODY_TYPE_RIGID, OB_BODY_TYPE_SOFT)) {
+ if (ELEM(physics_type, OB_BODY_TYPE_DYNAMIC, OB_BODY_TYPE_RIGID, OB_BODY_TYPE_SOFT)) {
uiItemL(layout, IFACE_("Dynamic Object Settings:"), ICON_NONE);
split = uiLayoutSplit(layout, 0.9, false);
row = uiLayoutRow(split, false);
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index ef23fc24194..6fa9290c732 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -2307,6 +2307,12 @@ static void node_composit_buts_cornerpin(uiLayout *UNUSED(layout), bContext *UNU
{
}
+static void node_composit_buts_sunbeams(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "source", UI_ITEM_R_EXPAND, "", ICON_NONE);
+ uiItemR(layout, ptr, "ray_length", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+}
+
/* only once called */
static void node_composit_set_butfunc(bNodeType *ntype)
{
@@ -2531,6 +2537,9 @@ static void node_composit_set_butfunc(bNodeType *ntype)
case CMP_NODE_CORNERPIN:
ntype->draw_buttons = node_composit_buts_cornerpin;
break;
+ case CMP_NODE_SUNBEAMS:
+ ntype->draw_buttons = node_composit_buts_sunbeams;
+ break;
}
}
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index 1c41ce9d86d..8422df35063 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -640,10 +640,10 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
/* tree specific activate calls */
if (ntree->type == NTREE_SHADER) {
/* when we select a material, active texture is cleared, for buttons */
- if (node->id && ELEM3(GS(node->id->name), ID_MA, ID_LA, ID_WO))
+ if (node->id && ELEM(GS(node->id->name), ID_MA, ID_LA, ID_WO))
nodeClearActiveID(ntree, ID_TE);
- if (ELEM4(node->type, SH_NODE_OUTPUT, SH_NODE_OUTPUT_MATERIAL,
+ if (ELEM(node->type, SH_NODE_OUTPUT, SH_NODE_OUTPUT_MATERIAL,
SH_NODE_OUTPUT_WORLD, SH_NODE_OUTPUT_LAMP))
{
bNode *tnode;
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 1f728b380d6..7eb90953df4 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -638,7 +638,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar
uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
layflag++; /* is lay_xor */
- if (ELEM8(passflag, SCE_PASS_SPEC, SCE_PASS_SHADOW, SCE_PASS_AO, SCE_PASS_REFLECT, SCE_PASS_REFRACT,
+ if (ELEM(passflag, SCE_PASS_SPEC, SCE_PASS_SHADOW, SCE_PASS_AO, SCE_PASS_REFLECT, SCE_PASS_REFRACT,
SCE_PASS_INDIRECT, SCE_PASS_EMIT, SCE_PASS_ENVIRONMENT))
{
bt = uiDefIconButBitI(block, TOG, passflag, 0, (*layflag & passflag) ? ICON_DOT : ICON_BLANK1,
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 17e1e032bbf..ef621407abd 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -215,15 +215,15 @@ void OUTLINER_OT_item_openclose(wmOperatorType *ot)
static void do_item_rename(ARegion *ar, TreeElement *te, TreeStoreElem *tselem, ReportList *reports)
{
/* can't rename rna datablocks entries or listbases */
- if (ELEM4(tselem->type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM, TSE_ID_BASE)) {
+ if (ELEM(tselem->type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM, TSE_ID_BASE)) {
/* do nothing */;
}
- else if (ELEM10(tselem->type, TSE_ANIM_DATA, TSE_NLA, TSE_DEFGROUP_BASE, TSE_CONSTRAINT_BASE, TSE_MODIFIER_BASE,
- TSE_DRIVER_BASE, TSE_POSE_BASE, TSE_POSEGRP_BASE, TSE_R_LAYER_BASE, TSE_R_PASS))
+ else if (ELEM(tselem->type, TSE_ANIM_DATA, TSE_NLA, TSE_DEFGROUP_BASE, TSE_CONSTRAINT_BASE, TSE_MODIFIER_BASE,
+ TSE_DRIVER_BASE, TSE_POSE_BASE, TSE_POSEGRP_BASE, TSE_R_LAYER_BASE, TSE_R_PASS))
{
BKE_report(reports, RPT_WARNING, "Cannot edit builtin name");
}
- else if (ELEM3(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) {
+ else if (ELEM(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) {
BKE_report(reports, RPT_WARNING, "Cannot edit sequence name");
}
else if (tselem->id->lib) {
@@ -1654,7 +1654,7 @@ static int outliner_parenting_poll(bContext *C)
SpaceOops *soops = CTX_wm_space_outliner(C);
if (soops) {
- return ELEM4(soops->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_GROUPS);
+ return ELEM(soops->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_GROUPS);
}
return false;
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index d7521edd57a..6f5bf712d55 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -948,7 +948,7 @@ static bool do_outliner_item_activate(bContext *C, Scene *scene, ARegion *ar, Sp
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
- else if (ELEM5(te->idcode, ID_ME, ID_CU, ID_MB, ID_LT, ID_AR)) {
+ else if (ELEM(te->idcode, ID_ME, ID_CU, ID_MB, ID_LT, ID_AR)) {
WM_operator_name_call(C, "OBJECT_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL);
}
else { // rest of types
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index d1e9b3d34b7..d09ed1a100e 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -1339,7 +1339,7 @@ static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, S
else if (datalevel == TSE_DRIVER_BASE) {
/* do nothing... no special ops needed yet */
}
- else if (ELEM3(datalevel, TSE_R_LAYER_BASE, TSE_R_LAYER, TSE_R_PASS)) {
+ else if (ELEM(datalevel, TSE_R_LAYER_BASE, TSE_R_LAYER, TSE_R_PASS)) {
/*WM_operator_name_call(C, "OUTLINER_OT_renderdata_operation", WM_OP_INVOKE_REGION_WIN, NULL)*/
}
else {
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index 520cd9a544d..5801dd126e3 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -821,7 +821,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
TreeStoreElem *tselem;
ID *id = idv;
- if (ELEM3(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
+ if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
id = ((PointerRNA *)idv)->id.data;
if (!id) id = ((PointerRNA *)idv)->data;
}
@@ -847,10 +847,10 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
te->parent = parent;
te->index = index; // for data arays
- if (ELEM3(type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) {
+ if (ELEM(type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) {
/* pass */
}
- else if (ELEM3(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
+ else if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
/* pass */
}
else if (type == TSE_ANIM_DATA) {
@@ -985,7 +985,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
te->directdata = seq;
te->name = seq->strip->stripdata->name;
}
- else if (ELEM3(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
+ else if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
PointerRNA pptr, propptr, *ptr = (PointerRNA *)idv;
PropertyRNA *prop, *iterprop;
PropertyType proptype;
@@ -1062,7 +1062,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
else if (tot)
te->flag |= TE_LAZY_CLOSED;
}
- else if (ELEM3(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
+ else if (ELEM(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
tot = RNA_property_array_length(ptr, prop);
if (TSELEM_OPEN(tselem, soops)) {
diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c
index 41c5b00b381..504d9628d98 100644
--- a/source/blender/editors/space_outliner/space_outliner.c
+++ b/source/blender/editors/space_outliner/space_outliner.c
@@ -143,7 +143,7 @@ static int outliner_parent_clear_poll(bContext *C, wmDrag *drag, const wmEvent *
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
- if (!ELEM4(soops->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_GROUPS)) {
+ if (!ELEM(soops->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_GROUPS)) {
return false;
}
@@ -156,7 +156,7 @@ static int outliner_parent_clear_poll(bContext *C, wmDrag *drag, const wmEvent *
switch (te->idcode) {
case ID_SCE:
- return (ELEM3(tselem->type, TSE_R_LAYER_BASE, TSE_R_LAYER, TSE_R_PASS));
+ return (ELEM(tselem->type, TSE_R_LAYER_BASE, TSE_R_LAYER, TSE_R_PASS));
case ID_OB:
return (ELEM(tselem->type, TSE_MODIFIER_BASE, TSE_CONSTRAINT_BASE));
/* Other codes to ignore? */
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 4ad5ed8bb80..dab51f752b4 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -142,19 +142,21 @@ static void get_seq_color3ubv(Scene *curscene, Sequence *seq, unsigned char col[
case SEQ_TYPE_GLOW:
case SEQ_TYPE_MULTICAM:
case SEQ_TYPE_ADJUSTMENT:
+ case SEQ_TYPE_GAUSSIAN_BLUR:
UI_GetThemeColor3ubv(TH_SEQ_EFFECT, col);
/* slightly offset hue to distinguish different effects */
- if (seq->type == SEQ_TYPE_ADD) rgb_byte_set_hue_float_offset(col, 0.04);
- else if (seq->type == SEQ_TYPE_SUB) rgb_byte_set_hue_float_offset(col, 0.08);
- else if (seq->type == SEQ_TYPE_MUL) rgb_byte_set_hue_float_offset(col, 0.12);
- else if (seq->type == SEQ_TYPE_ALPHAOVER) rgb_byte_set_hue_float_offset(col, 0.16);
- else if (seq->type == SEQ_TYPE_ALPHAUNDER) rgb_byte_set_hue_float_offset(col, 0.20);
- else if (seq->type == SEQ_TYPE_OVERDROP) rgb_byte_set_hue_float_offset(col, 0.24);
- else if (seq->type == SEQ_TYPE_GLOW) rgb_byte_set_hue_float_offset(col, 0.28);
- else if (seq->type == SEQ_TYPE_TRANSFORM) rgb_byte_set_hue_float_offset(col, 0.36);
- else if (seq->type == SEQ_TYPE_MULTICAM) rgb_byte_set_hue_float_offset(col, 0.32);
- else if (seq->type == SEQ_TYPE_ADJUSTMENT) rgb_byte_set_hue_float_offset(col, 0.40);
+ if (seq->type == SEQ_TYPE_ADD) rgb_byte_set_hue_float_offset(col, 0.04);
+ else if (seq->type == SEQ_TYPE_SUB) rgb_byte_set_hue_float_offset(col, 0.08);
+ else if (seq->type == SEQ_TYPE_MUL) rgb_byte_set_hue_float_offset(col, 0.12);
+ else if (seq->type == SEQ_TYPE_ALPHAOVER) rgb_byte_set_hue_float_offset(col, 0.16);
+ else if (seq->type == SEQ_TYPE_ALPHAUNDER) rgb_byte_set_hue_float_offset(col, 0.20);
+ else if (seq->type == SEQ_TYPE_OVERDROP) rgb_byte_set_hue_float_offset(col, 0.24);
+ else if (seq->type == SEQ_TYPE_GLOW) rgb_byte_set_hue_float_offset(col, 0.28);
+ else if (seq->type == SEQ_TYPE_TRANSFORM) rgb_byte_set_hue_float_offset(col, 0.36);
+ else if (seq->type == SEQ_TYPE_MULTICAM) rgb_byte_set_hue_float_offset(col, 0.32);
+ else if (seq->type == SEQ_TYPE_ADJUSTMENT) rgb_byte_set_hue_float_offset(col, 0.40);
+ else if (seq->type == SEQ_TYPE_GAUSSIAN_BLUR) rgb_byte_set_hue_float_offset(col, 0.42);
break;
case SEQ_TYPE_COLOR:
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 3c17b2986ff..dcf13dbf43f 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -86,6 +86,7 @@ EnumPropertyItem sequencer_prop_effect_types[] = {
{SEQ_TYPE_SPEED, "SPEED", 0, "Speed", "Color effect strip type"},
{SEQ_TYPE_MULTICAM, "MULTICAM", 0, "Multicam Selector", ""},
{SEQ_TYPE_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", ""},
+ {SEQ_TYPE_GAUSSIAN_BLUR, "GAUSSIAN_BLUR", 0, "Gaussian Blur", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -1918,9 +1919,12 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
strip_new = seq_new->strip;
strip_new->us = 1;
- /* new stripdata */
- se_new = strip_new->stripdata;
+ /* new stripdata (only one element now!) */
+ /* Note this assume all elements (images) have the same dimension, since we only copy the name here. */
+ se_new = MEM_reallocN(strip_new->stripdata, sizeof(*se_new));
BLI_strncpy(se_new->name, se->name, sizeof(se_new->name));
+ strip_new->stripdata = se_new;
+
BKE_sequence_calc(scene, seq_new);
if (step > 1) {
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index 9826ef10902..8e49d5649f3 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -912,7 +912,7 @@ static EnumPropertyItem sequencer_prop_select_grouped_types[] = {
#define SEQ_IS_EFFECT(_seq) ((_seq->type & SEQ_TYPE_EFFECT) != 0)
-#define SEQ_USE_DATA(_seq) (ELEM3(_seq->type, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIECLIP, SEQ_TYPE_MASK) || SEQ_HAS_PATH(_seq))
+#define SEQ_USE_DATA(_seq) (ELEM(_seq->type, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIECLIP, SEQ_TYPE_MASK) || SEQ_HAS_PATH(_seq))
static bool select_grouped_type(Editing *ed, Sequence *actseq)
{
@@ -1035,7 +1035,7 @@ static bool select_grouped_effect(Editing *ed, Sequence *actseq)
SEQP_BEGIN (ed, seq)
{
- if (ELEM3(actseq, seq->seq1, seq->seq2, seq->seq3)) {
+ if (ELEM(actseq, seq->seq1, seq->seq2, seq->seq3)) {
effects[seq->type] = true;
}
}
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index a94b73802b2..c0cfaed7867 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -279,24 +279,40 @@ static void sequencer_refresh(const bContext *C, ScrArea *sa)
}
break;
case SEQ_VIEW_SEQUENCE_PREVIEW:
- if (ar_main && (ar_main->flag & RGN_FLAG_HIDDEN)) {
- ar_main->flag &= ~RGN_FLAG_HIDDEN;
- ar_main->v2d.flag &= ~V2D_IS_INITIALISED;
- view_changed = true;
- }
- if (ar_preview && (ar_preview->flag & RGN_FLAG_HIDDEN)) {
- ar_preview->flag &= ~RGN_FLAG_HIDDEN;
- ar_preview->v2d.flag &= ~V2D_IS_INITIALISED;
- ar_preview->v2d.cur = ar_preview->v2d.tot;
- view_changed = true;
- }
- if (ar_main && ar_main->alignment != RGN_ALIGN_NONE) {
- ar_main->alignment = RGN_ALIGN_NONE;
- view_changed = true;
- }
- if (ar_preview && ar_preview->alignment != RGN_ALIGN_TOP) {
- ar_preview->alignment = RGN_ALIGN_TOP;
- view_changed = true;
+ if (ar_main && ar_preview) {
+ /* Get available height (without DPI correction). */
+ const float height = (sa->winy - ED_area_headersize()) / UI_DPI_FAC;
+
+ /* We reuse hidden area's size, allows to find same layout as before if we just switch
+ * between one 'full window' view and the combined one. This gets lost if we switch to both
+ * 'full window' views before, though... Better than nothing. */
+ if (ar_main->flag & RGN_FLAG_HIDDEN) {
+ ar_main->flag &= ~RGN_FLAG_HIDDEN;
+ ar_main->v2d.flag &= ~V2D_IS_INITIALISED;
+ ar_preview->sizey = (int)(height - ar_main->sizey);
+ view_changed = true;
+ }
+ if (ar_preview->flag & RGN_FLAG_HIDDEN) {
+ ar_preview->flag &= ~RGN_FLAG_HIDDEN;
+ ar_preview->v2d.flag &= ~V2D_IS_INITIALISED;
+ ar_preview->v2d.cur = ar_preview->v2d.tot;
+ ar_main->sizey = (int)(height - ar_preview->sizey);
+ view_changed = true;
+ }
+ if (ar_main->alignment != RGN_ALIGN_NONE) {
+ ar_main->alignment = RGN_ALIGN_NONE;
+ view_changed = true;
+ }
+ if (ar_preview->alignment != RGN_ALIGN_TOP) {
+ ar_preview->alignment = RGN_ALIGN_TOP;
+ view_changed = true;
+ }
+ /* Final check that both preview and main height are reasonable! */
+ if (ar_preview->sizey < 10 || ar_main->sizey < 10 || ar_preview->sizey + ar_main->sizey > height) {
+ ar_preview->sizey = (int)(height * 0.4f + 0.5f);
+ ar_main->sizey = (int)(height - ar_preview->sizey);
+ view_changed = true;
+ }
}
break;
}
@@ -339,40 +355,6 @@ static void sequencer_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn
}
}
-/* *********************** sequencer (main) region ************************ */
-/* add handlers, stuff you only do once or on area/region changes */
-static void sequencer_main_area_init(wmWindowManager *wm, ARegion *ar)
-{
- wmKeyMap *keymap;
- ListBase *lb;
-
- UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy);
-
-// keymap = WM_keymap_find(wm->defaultconf, "Mask Editing", 0, 0);
-// WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
-
- keymap = WM_keymap_find(wm->defaultconf, "SequencerCommon", SPACE_SEQ, 0);
- WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
-
- /* own keymap */
- keymap = WM_keymap_find(wm->defaultconf, "Sequencer", SPACE_SEQ, 0);
- WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
-
- /* add drop boxes */
- lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_WINDOW);
-
- WM_event_add_dropbox_handler(&ar->handlers, lb);
-
-}
-
-static void sequencer_main_area_draw(const bContext *C, ARegion *ar)
-{
-// ScrArea *sa = CTX_wm_area(C);
-
- /* NLE - strip editing timeline interface */
- draw_timeline_seq(C, ar);
-}
-
/* ************* dropboxes ************* */
static int image_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
@@ -396,7 +378,7 @@ static int movie_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
int hand;
if (drag->type == WM_DRAG_PATH)
- if (ELEM3(drag->icon, 0, ICON_FILE_MOVIE, ICON_FILE_BLANK)) /* rule might not work? */
+ if (ELEM(drag->icon, 0, ICON_FILE_MOVIE, ICON_FILE_BLANK)) /* rule might not work? */
if (find_nearest_seq(scene, &ar->v2d, &hand, event->mval) == NULL)
return 1;
return 0;
@@ -439,7 +421,7 @@ static void sequencer_drop_copy(wmDrag *drag, wmDropBox *drop)
static void sequencer_dropboxes(void)
{
ListBase *lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_WINDOW);
-
+
WM_dropbox_add(lb, "SEQUENCER_OT_image_strip_add", image_drop_poll, sequencer_drop_copy);
WM_dropbox_add(lb, "SEQUENCER_OT_movie_strip_add", movie_drop_poll, sequencer_drop_copy);
WM_dropbox_add(lb, "SEQUENCER_OT_sound_strip_add", sound_drop_poll, sequencer_drop_copy);
@@ -469,16 +451,37 @@ static int sequencer_context(const bContext *C, const char *member, bContextData
return false;
}
-
+/* *********************** sequencer (main) region ************************ */
/* add handlers, stuff you only do once or on area/region changes */
-static void sequencer_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar)
+static void sequencer_main_area_init(wmWindowManager *wm, ARegion *ar)
{
- ED_region_header_init(ar);
+ wmKeyMap *keymap;
+ ListBase *lb;
+
+ UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy);
+
+#if 0
+ keymap = WM_keymap_find(wm->defaultconf, "Mask Editing", 0, 0);
+ WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
+#endif
+
+ keymap = WM_keymap_find(wm->defaultconf, "SequencerCommon", SPACE_SEQ, 0);
+ WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
+
+ /* own keymap */
+ keymap = WM_keymap_find(wm->defaultconf, "Sequencer", SPACE_SEQ, 0);
+ WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
+
+ /* add drop boxes */
+ lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_WINDOW);
+
+ WM_event_add_dropbox_handler(&ar->handlers, lb);
}
-static void sequencer_header_area_draw(const bContext *C, ARegion *ar)
+static void sequencer_main_area_draw(const bContext *C, ARegion *ar)
{
- ED_region_header(C, ar);
+ /* NLE - strip editing timeline interface */
+ draw_timeline_seq(C, ar);
}
static void sequencer_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
@@ -512,15 +515,29 @@ static void sequencer_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa
}
}
+/* *********************** header region ************************ */
+/* add handlers, stuff you only do once or on area/region changes */
+static void sequencer_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar)
+{
+ ED_region_header_init(ar);
+}
+
+static void sequencer_header_area_draw(const bContext *C, ARegion *ar)
+{
+ ED_region_header(C, ar);
+}
+
/* *********************** preview region ************************ */
static void sequencer_preview_area_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy);
-
-// keymap = WM_keymap_find(wm->defaultconf, "Mask Editing", 0, 0);
-// WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
+
+#if 0
+ keymap = WM_keymap_find(wm->defaultconf, "Mask Editing", 0, 0);
+ WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
+#endif
keymap = WM_keymap_find(wm->defaultconf, "SequencerCommon", SPACE_SEQ, 0);
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
@@ -593,7 +610,6 @@ static void sequencer_preview_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED
break;
}
break;
-
case NC_MASK:
if (wmn->action == NA_EDITED) {
ED_region_tag_redraw(ar);
@@ -654,10 +670,10 @@ void ED_spacetype_sequencer(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype sequencer");
ARegionType *art;
-
+
st->spaceid = SPACE_SEQ;
strncpy(st->name, "Sequencer", BKE_ST_MAXNAME);
-
+
st->new = sequencer_new;
st->free = sequencer_free;
st->init = sequencer_init;
@@ -682,13 +698,12 @@ void ED_spacetype_sequencer(void)
/* preview */
art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region");
art->regionid = RGN_TYPE_PREVIEW;
- art->prefsizey = 240; // XXX
art->init = sequencer_preview_area_init;
art->draw = sequencer_preview_area_draw;
art->listener = sequencer_preview_area_listener;
art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_GPENCIL;
BLI_addhead(&st->regiontypes, art);
-
+
/* regions: listview/buttons */
art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region");
art->regionid = RGN_TYPE_UI;
@@ -698,7 +713,7 @@ void ED_spacetype_sequencer(void)
art->init = sequencer_buttons_area_init;
art->draw = sequencer_buttons_area_draw;
BLI_addhead(&st->regiontypes, art);
-
+
sequencer_buttons_register(art);
/* regions: header */
@@ -706,13 +721,13 @@ void ED_spacetype_sequencer(void)
art->regionid = RGN_TYPE_HEADER;
art->prefsizey = HEADERY;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
-
+
art->init = sequencer_header_area_init;
art->draw = sequencer_header_area_draw;
art->listener = sequencer_main_area_listener;
-
+
BLI_addhead(&st->regiontypes, art);
-
+
BKE_spacetype_register(st);
/* set the sequencer callback when not in background mode */
diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c
index 6a98fd802f9..6ca6b2af1fd 100644
--- a/source/blender/editors/space_text/text_draw.c
+++ b/source/blender/editors/space_text/text_draw.c
@@ -1460,7 +1460,7 @@ void text_scroll_to_cursor(SpaceText *st, ScrArea *sa)
ARegion *ar = NULL;
int i, x, winx = 0;
- if (ELEM3(NULL, st, st->text, st->text->curl)) return;
+ if (ELEM(NULL, st, st->text, st->text->curl)) return;
text = st->text;
diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c
index 245cdadc7a2..e01a9d4b470 100644
--- a/source/blender/editors/space_view3d/drawarmature.c
+++ b/source/blender/editors/space_view3d/drawarmature.c
@@ -67,6 +67,7 @@
#include "view3d_intern.h"
+#include "GPU_select.h"
/* *************** Armature Drawing - Coloring API ***************************** */
@@ -93,7 +94,7 @@ static void set_pchan_colorset(Object *ob, bPoseChannel *pchan)
short color_index = 0;
/* sanity check */
- if (ELEM4(NULL, ob, arm, pose, pchan)) {
+ if (ELEM(NULL, ob, arm, pose, pchan)) {
bcolor = NULL;
return;
}
@@ -551,7 +552,7 @@ static void draw_bone_points(const short dt, int armflag, unsigned int boneflag,
/* Draw root point if we are not connected */
if ((boneflag & BONE_CONNECTED) == 0) {
if (id != -1)
- glLoadName(id | BONESEL_ROOT);
+ GPU_select_load_id(id | BONESEL_ROOT);
if (dt <= OB_WIRE) {
if (armflag & ARM_EDITMODE) {
@@ -574,7 +575,7 @@ static void draw_bone_points(const short dt, int armflag, unsigned int boneflag,
/* Draw tip point */
if (id != -1)
- glLoadName(id | BONESEL_TIP);
+ GPU_select_load_id(id | BONESEL_TIP);
if (dt <= OB_WIRE) {
if (armflag & ARM_EDITMODE) {
@@ -787,7 +788,7 @@ static void draw_sphere_bone_wire(float smat[4][4], float imat[4][4],
/* Draw root point if we are not connected */
if ((boneflag & BONE_CONNECTED) == 0) {
if (id != -1)
- glLoadName(id | BONESEL_ROOT);
+ GPU_select_load_id(id | BONESEL_ROOT);
drawcircball(GL_LINE_LOOP, headvec, head, imat);
}
@@ -799,7 +800,7 @@ static void draw_sphere_bone_wire(float smat[4][4], float imat[4][4],
}
if (id != -1)
- glLoadName(id | BONESEL_TIP);
+ GPU_select_load_id(id | BONESEL_TIP);
drawcircball(GL_LINE_LOOP, tailvec, tail, imat);
@@ -830,7 +831,7 @@ static void draw_sphere_bone_wire(float smat[4][4], float imat[4][4],
cross_v3_v3v3(norvect, vec, imat[2]);
if (id != -1)
- glLoadName(id | BONESEL_BONE);
+ GPU_select_load_id(id | BONESEL_BONE);
glBegin(GL_LINES);
@@ -907,7 +908,7 @@ static void draw_sphere_bone(const short dt, int armflag, int boneflag, short co
/* Draw root point if we are not connected */
if ((boneflag & BONE_CONNECTED) == 0) {
if (id != -1)
- glLoadName(id | BONESEL_ROOT);
+ GPU_select_load_id(id | BONESEL_ROOT);
gluSphere(qobj, head, 16, 10);
}
@@ -918,7 +919,7 @@ static void draw_sphere_bone(const short dt, int armflag, int boneflag, short co
}
if (id != -1)
- glLoadName(id | BONESEL_TIP);
+ GPU_select_load_id(id | BONESEL_TIP);
glTranslatef(0.0f, 0.0f, length);
gluSphere(qobj, tail, 16, 10);
@@ -939,7 +940,7 @@ static void draw_sphere_bone(const short dt, int armflag, int boneflag, short co
if (length > (head + tail)) {
if (id != -1)
- glLoadName(id | BONESEL_BONE);
+ GPU_select_load_id(id | BONESEL_BONE);
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(-1.0f, -1.0f);
@@ -1009,7 +1010,7 @@ static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned
/* Draw root point if we are not connected */
if ((boneflag & BONE_CONNECTED) == 0) {
if (G.f & G_PICKSEL) { /* no bitmap in selection mode, crashes 3d cards... */
- glLoadName(id | BONESEL_ROOT);
+ GPU_select_load_id(id | BONESEL_ROOT);
glBegin(GL_POINTS);
glVertex3f(0.0f, 0.0f, 0.0f);
glEnd();
@@ -1021,7 +1022,7 @@ static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned
}
if (id != -1)
- glLoadName((GLuint) id | BONESEL_BONE);
+ GPU_select_load_id((GLuint) id | BONESEL_BONE);
glBegin(GL_LINES);
glVertex3f(0.0f, 0.0f, 0.0f);
@@ -1031,7 +1032,7 @@ static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned
/* tip */
if (G.f & G_PICKSEL) {
/* no bitmap in selection mode, crashes 3d cards... */
- glLoadName(id | BONESEL_TIP);
+ GPU_select_load_id(id | BONESEL_TIP);
glBegin(GL_POINTS);
glVertex3f(0.0f, 1.0f, 0.0f);
glEnd();
@@ -1043,7 +1044,7 @@ static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned
/* further we send no names */
if (id != -1)
- glLoadName(id & 0xFFFF); /* object tag, for bordersel optim */
+ GPU_select_load_id(id & 0xFFFF); /* object tag, for bordersel optim */
if (armflag & ARM_POSEMODE)
set_pchan_glColor(PCHAN_COLOR_LINEBONE, boneflag, constflag);
@@ -1161,7 +1162,7 @@ static void draw_b_bone(const short dt, int armflag, int boneflag, short constfl
}
if (id != -1) {
- glLoadName((GLuint) id | BONESEL_BONE);
+ GPU_select_load_id((GLuint) id | BONESEL_BONE);
}
/* set up solid drawing */
@@ -1266,13 +1267,13 @@ static void draw_wire_bone(const short dt, int armflag, int boneflag, short cons
/* this chunk not in object mode */
if (armflag & (ARM_EDITMODE | ARM_POSEMODE)) {
if (id != -1)
- glLoadName((GLuint) id | BONESEL_BONE);
+ GPU_select_load_id((GLuint) id | BONESEL_BONE);
draw_wire_bone_segments(pchan, bbones, length, segments);
/* further we send no names */
if (id != -1)
- glLoadName(id & 0xFFFF); /* object tag, for bordersel optim */
+ GPU_select_load_id(id & 0xFFFF); /* object tag, for bordersel optim */
}
/* colors for modes */
@@ -1315,7 +1316,7 @@ static void draw_bone(const short dt, int armflag, int boneflag, short constflag
/* now draw the bone itself */
if (id != -1) {
- glLoadName((GLuint) id | BONESEL_BONE);
+ GPU_select_load_id((GLuint) id | BONESEL_BONE);
}
/* wire? */
@@ -1370,7 +1371,7 @@ static void draw_custom_bone(Scene *scene, View3D *v3d, RegionView3D *rv3d, Obje
}
if (id != -1) {
- glLoadName((GLuint) id | BONESEL_BONE);
+ GPU_select_load_id((GLuint) id | BONESEL_BONE);
}
draw_object_instance(scene, v3d, rv3d, ob, dt, armflag & ARM_POSEMODE);
@@ -1812,12 +1813,12 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
index += 0x10000; /* pose bones count in higher 2 bytes only */
}
- /* very very confusing... but in object mode, solid draw, we cannot do glLoadName yet,
+ /* very very confusing... but in object mode, solid draw, we cannot do GPU_select_load_id yet,
* stick bones and/or wire custom-shapes are drawn in next loop
*/
- if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE) == 0 && (draw_wire == false)) {
+ if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE) == 0 && (draw_wire == false) && index != -1) {
/* object tag, for bordersel optim */
- glLoadName(index & 0xFFFF);
+ GPU_select_load_id(index & 0xFFFF);
index = -1;
}
}
@@ -1881,9 +1882,9 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
index += 0x10000; /* pose bones count in higher 2 bytes only */
}
/* stick or wire bones have not been drawn yet so don't clear object selection in this case */
- if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE) == 0 && draw_wire) {
+ if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE) == 0 && draw_wire && index != -1) {
/* object tag, for bordersel optim */
- glLoadName(index & 0xFFFF);
+ GPU_select_load_id(index & 0xFFFF);
index = -1;
}
}
@@ -1926,7 +1927,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
*/
if ((do_dashed & 2) && ((bone->flag & BONE_CONNECTED) == 0)) {
if (arm->flag & ARM_POSEMODE) {
- glLoadName(index & 0xFFFF); /* object tag, for bordersel optim */
+ GPU_select_load_id(index & 0xFFFF); /* object tag, for bordersel optim */
UI_ThemeColor(TH_WIRE);
}
setlinestyle(3);
@@ -1946,7 +1947,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
if (constflag & PCHAN_HAS_TARGET) glColor3ub(200, 120, 0);
else glColor3ub(200, 200, 50); /* add theme! */
- glLoadName(index & 0xFFFF);
+ GPU_select_load_id(index & 0xFFFF);
pchan_draw_IK_root_lines(pchan, !(do_dashed & 2));
}
}
@@ -1954,7 +1955,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
if (bone->flag & BONE_SELECTED) {
glColor3ub(150, 200, 50); /* add theme! */
- glLoadName(index & 0xFFFF);
+ GPU_select_load_id(index & 0xFFFF);
pchan_draw_IK_root_lines(pchan, !(do_dashed & 2));
}
}
@@ -2020,7 +2021,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
/* draw DoFs */
if (arm->flag & ARM_POSEMODE) {
- if (((base->flag & OB_FROMDUPLI) == 0)) {
+ if (((base->flag & OB_FROMDUPLI) == 0) && ((v3d->flag & V3D_HIDE_HELPLINES) == 0)) {
draw_pose_dofs(ob);
}
}
@@ -2174,7 +2175,7 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt)
/* if wire over solid, set offset */
index = -1;
- glLoadName(-1);
+ GPU_select_load_id(-1);
if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) {
if (G.f & G_PICKSEL)
index = 0;
@@ -2223,7 +2224,7 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt)
/* offset to parent */
if (eBone->parent) {
UI_ThemeColor(TH_WIRE_EDIT);
- glLoadName(-1); /* -1 here is OK! */
+ GPU_select_load_id(-1); /* -1 here is OK! */
setlinestyle(3);
glBegin(GL_LINES);
@@ -2240,7 +2241,7 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt)
/* restore */
if (index != -1) {
- glLoadName(-1);
+ GPU_select_load_id(-1);
}
if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) {
diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c
index bf0b7850839..89babf977e1 100644
--- a/source/blender/editors/space_view3d/drawmesh.c
+++ b/source/blender/editors/space_view3d/drawmesh.c
@@ -212,12 +212,16 @@ static Material *give_current_material_or_def(Object *ob, int matnr)
static struct TextureDrawState {
Object *ob;
+ Image *stencil;
+ bool stencil_invert;
bool use_game_mat;
int is_lit, is_tex;
int color_profile;
bool use_backface_culling;
unsigned char obcol[4];
-} Gtexdraw = {NULL, false, 0, 0, 0, false, {0, 0, 0, 0}};
+ float stencil_col[4];
+ bool is_texpaint;
+} Gtexdraw = {NULL, NULL, false, false, 0, 0, 0, false, {0, 0, 0, 0}, {0.0f, 0.0f, 0.0f, 1.0f}, false};
static bool set_draw_settings_cached(int clearcache, MTFace *texface, Material *ma, struct TextureDrawState gtexdraw)
{
@@ -229,13 +233,15 @@ static bool set_draw_settings_cached(int clearcache, MTFace *texface, Material *
static int c_lit;
static int c_has_texface;
- Object *litob = NULL; /* to get mode to turn off mipmap in painting mode */
int backculled = 1;
int alphablend = GPU_BLEND_SOLID;
int textured = 0;
int lit = 0;
int has_texface = texface != NULL;
bool need_set_tpage = false;
+ bool texpaint = ((gtexdraw.ob->mode & OB_MODE_TEXTURE_PAINT) != 0);
+
+ Image *ima = NULL;
if (ma != NULL) {
if (ma->mode & MA_TRANSP) {
@@ -248,10 +254,10 @@ static bool set_draw_settings_cached(int clearcache, MTFace *texface, Material *
memset(&c_texface, 0, sizeof(MTFace));
c_badtex = false;
c_has_texface = -1;
+ c_ma = NULL;
}
else {
textured = gtexdraw.is_tex;
- litob = gtexdraw.ob;
}
/* convert number of lights into boolean */
@@ -266,14 +272,16 @@ static bool set_draw_settings_cached(int clearcache, MTFace *texface, Material *
}
}
- if (texface) {
+ if (texface && !texpaint) {
textured = textured && (texface->tpage);
/* no material, render alpha if texture has depth=32 */
if (!ma && BKE_image_has_alpha(texface->tpage))
alphablend = GPU_BLEND_ALPHA;
}
-
+ else if (texpaint && ma) {
+ ima = ma->texpaintslot ? ma->texpaintslot[ma->paint_active_slot].ima : NULL;
+ }
else
textured = 0;
@@ -287,11 +295,25 @@ static bool set_draw_settings_cached(int clearcache, MTFace *texface, Material *
/* need to re-set tpage if textured flag changed or existsment of texface changed.. */
need_set_tpage = textured != c_textured || has_texface != c_has_texface;
/* ..or if settings inside texface were changed (if texface was used) */
- need_set_tpage |= texface && memcmp(&c_texface, texface, sizeof(c_texface));
+ need_set_tpage |= (texpaint && c_ma != ma) || (texface && memcmp(&c_texface, texface, sizeof(c_texface)));
if (need_set_tpage) {
if (textured) {
- c_badtex = !GPU_set_tpage(texface, !(litob->mode & OB_MODE_TEXTURE_PAINT), alphablend);
+ if (texpaint) {
+ c_badtex = false;
+ if (GPU_verify_image(ima, NULL, 0, 1, 0, false)) {
+ glEnable(GL_TEXTURE_2D);
+ }
+ else {
+ c_badtex = true;
+ GPU_clear_tpage(true);
+ glDisable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+ }
+ else {
+ c_badtex = !GPU_set_tpage(texface, !texpaint, alphablend);
+ }
}
else {
GPU_set_tpage(NULL, 0, 0);
@@ -325,6 +347,7 @@ static bool set_draw_settings_cached(int clearcache, MTFace *texface, Material *
glDisable(GL_COLOR_MATERIAL);
}
c_lit = lit;
+ c_ma = ma;
}
return c_badtex;
@@ -335,6 +358,7 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O
unsigned char obcol[4];
bool is_tex, solidtex;
Mesh *me = ob->data;
+ ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
/* XXX scene->obedit warning */
@@ -364,8 +388,34 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O
else is_tex = false;
Gtexdraw.ob = ob;
+ Gtexdraw.stencil = (imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL) ? imapaint->stencil : NULL;
+ Gtexdraw.stencil_invert = ((imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) != 0);
+ Gtexdraw.is_texpaint = (ob->mode == OB_MODE_TEXTURE_PAINT);
+ copy_v3_v3(Gtexdraw.stencil_col, imapaint->stencil_col);
Gtexdraw.is_tex = is_tex;
+ /* load the stencil texture here */
+ if (Gtexdraw.is_texpaint && (Gtexdraw.stencil != NULL)) {
+ glActiveTexture(GL_TEXTURE1);
+ if (GPU_verify_image(Gtexdraw.stencil, NULL, false, false, false, false)) {
+ glEnable(GL_TEXTURE_2D);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_TEXTURE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
+ glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, Gtexdraw.stencil_col);
+ if (!Gtexdraw.stencil_invert) {
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_ONE_MINUS_SRC_COLOR);
+ }
+ else {
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR);
+ }
+ }
+ glActiveTexture(GL_TEXTURE0);
+ }
+
Gtexdraw.color_profile = BKE_scene_check_color_management_enabled(scene);
Gtexdraw.use_game_mat = (RE_engines_find(scene->r.engine)->flag & RE_GAME) != 0;
Gtexdraw.use_backface_culling = (v3d->flag2 & V3D_BACKFACE_CULLING) != 0;
@@ -379,8 +429,24 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O
static void draw_textured_end(void)
{
- /* switch off textures */
- GPU_set_tpage(NULL, 0, 0);
+ if (Gtexdraw.ob->mode & OB_MODE_TEXTURE_PAINT) {
+ if (Gtexdraw.stencil != NULL) {
+ glActiveTexture(GL_TEXTURE1);
+ glDisable(GL_TEXTURE_2D);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glActiveTexture(GL_TEXTURE0);
+ }
+ /* manual reset, since we don't use tpage */
+ glBindTexture(GL_TEXTURE_2D, 0);
+ /* force switch off textures */
+ GPU_clear_tpage(true);
+ }
+ else {
+ /* switch off textures */
+ GPU_set_tpage(NULL, 0, 0);
+ }
glShadeModel(GL_FLAT);
glDisable(GL_CULL_FACE);
@@ -456,7 +522,7 @@ static DMDrawOption draw_tface__set_draw(MTFace *tface, const bool UNUSED(has_mc
if (ma && (ma->game.flag & GEMAT_INVISIBLE)) return 0;
- if (tface)
+ if (tface || Gtexdraw.is_texpaint)
set_draw_settings_cached(0, tface, ma, Gtexdraw);
/* always use color from mcol, as set in update_tface_color_layer */
@@ -770,7 +836,8 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d
Object *ob, DerivedMesh *dm, const int draw_flags)
{
Mesh *me = ob->data;
-
+ DMDrawFlag uvflag = DM_DRAW_USE_ACTIVE_UV;
+
/* correct for negative scale */
if (ob->transflag & OB_NEG_SCALE) glFrontFace(GL_CW);
else glFrontFace(GL_CCW);
@@ -780,6 +847,10 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+ if (ob->mode & OB_MODE_TEXTURE_PAINT) {
+ uvflag = DM_DRAW_USE_TEXPAINT_UV;
+ }
+
if (ob->mode & OB_MODE_EDIT) {
drawEMTFMapped_userData data;
@@ -789,7 +860,7 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d
data.mf = DM_get_tessface_data_layer(dm, CD_MFACE);
data.tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
- dm->drawMappedFacesTex(dm, draw_em_tf_mapped__set_draw, compareDrawOptionsEm, &data);
+ dm->drawMappedFacesTex(dm, draw_em_tf_mapped__set_draw, compareDrawOptionsEm, &data, 0);
}
else if (draw_flags & DRAW_FACE_SELECT) {
if (ob->mode & OB_MODE_WEIGHT_PAINT)
@@ -801,15 +872,15 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d
userData.mf = DM_get_tessface_data_layer(dm, CD_MFACE);
userData.tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
userData.me = me;
- dm->drawMappedFacesTex(dm, me->mpoly ? draw_tface_mapped__set_draw : NULL, compareDrawOptions, &userData);
+ dm->drawMappedFacesTex(dm, me->mpoly ? draw_tface_mapped__set_draw : NULL, compareDrawOptions, &userData, uvflag);
}
}
else {
if (GPU_buffer_legacy(dm)) {
if (draw_flags & DRAW_MODIFIERS_PREVIEW)
- dm->drawFacesTex(dm, draw_mcol__set_draw_legacy, NULL, NULL);
+ dm->drawFacesTex(dm, draw_mcol__set_draw_legacy, NULL, NULL, uvflag);
else
- dm->drawFacesTex(dm, draw_tface__set_draw_legacy, NULL, NULL);
+ dm->drawFacesTex(dm, draw_tface__set_draw_legacy, NULL, NULL, uvflag);
}
else {
drawTFace_userData userData;
@@ -820,7 +891,7 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d
userData.tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
userData.me = NULL;
- dm->drawFacesTex(dm, draw_tface__set_draw, compareDrawOptions, &userData);
+ dm->drawFacesTex(dm, draw_tface__set_draw, compareDrawOptions, &userData, uvflag);
}
}
@@ -870,7 +941,7 @@ static void tex_mat_set_texture_cb(void *userData, int mat_nr, void *attribs)
int texture_set = 0;
/* draw image texture if we find one */
- if (ED_object_get_active_image(data->ob, mat_nr, &ima, &iuser, &node)) {
+ if (ED_object_get_active_image(data->ob, mat_nr, &ima, &iuser, &node, NULL)) {
/* get openl texture */
int mipmap = 1;
int bindcode = (ima) ? GPU_verify_image(ima, iuser, 0, 0, mipmap, false) : 0;
@@ -955,7 +1026,8 @@ void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d,
/* if not cycles, or preview-modifiers, or drawing matcaps */
if ((draw_flags & DRAW_MODIFIERS_PREVIEW) ||
(v3d->flag2 & V3D_SHOW_SOLID_MATCAP) ||
- (BKE_scene_use_new_shading_nodes(scene) == false))
+ (BKE_scene_use_new_shading_nodes(scene) == false) ||
+ ((ob->mode & OB_MODE_TEXTURE_PAINT) && ELEM(v3d->drawtype, OB_TEXTURE, OB_SOLID)))
{
draw_mesh_textured_old(scene, v3d, rv3d, ob, dm, draw_flags);
return;
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index c1689ef06db..13e010d2f97 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -86,6 +86,7 @@
#include "GPU_draw.h"
#include "GPU_extensions.h"
+#include "GPU_select.h"
#include "ED_mesh.h"
#include "ED_particle.h"
@@ -301,7 +302,7 @@ bool draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, const char dt)
if (BKE_scene_use_new_shading_nodes(scene))
return false;
- return (scene->gm.matmode == GAME_MAT_GLSL) && (dt > OB_SOLID);
+ return ((scene->gm.matmode == GAME_MAT_GLSL) || (v3d->drawtype == OB_MATERIAL)) && (dt > OB_SOLID);
}
static bool check_alpha_pass(Base *base)
@@ -1586,7 +1587,7 @@ static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D
continue;
if (dflag & DRAW_PICKING)
- glLoadName(base->selcol + (tracknr << 16));
+ GPU_select_load_id(base->selcol + (tracknr << 16));
glPushMatrix();
glTranslatef(track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
@@ -1737,7 +1738,7 @@ static void draw_viewport_reconstruction(Scene *scene, Base *base, View3D *v3d,
}
if (dflag & DRAW_PICKING)
- glLoadName(base->selcol);
+ GPU_select_load_id(base->selcol);
}
/* flag similar to draw_object() */
@@ -4868,7 +4869,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
normalize_v3(imat[1]);
}
- if (ELEM3(draw_as, PART_DRAW_DOT, PART_DRAW_CROSS, PART_DRAW_LINE) &&
+ if (ELEM(draw_as, PART_DRAW_DOT, PART_DRAW_CROSS, PART_DRAW_LINE) &&
(part->draw_col > PART_DRAW_COL_MAT))
{
create_cdata = 1;
@@ -6479,7 +6480,7 @@ static bool drawmball(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
if (G.f & G_PICKSEL) {
ml->selcol1 = code;
- glLoadName(code++);
+ GPU_select_load_id(code++);
}
}
drawcircball(GL_LINE_LOOP, &(ml->x), ml->rad, imat);
@@ -6493,7 +6494,7 @@ static bool drawmball(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
if (G.f & G_PICKSEL) {
ml->selcol2 = code;
- glLoadName(code++);
+ GPU_select_load_id(code++);
}
drawcircball(GL_LINE_LOOP, &(ml->x), ml->rad * atanf(ml->s) / (float)M_PI_2, imat);
}
@@ -6782,7 +6783,7 @@ static void draw_bounding_volume(Object *ob, char type)
if (ob->type == OB_MESH) {
bb = BKE_mesh_boundbox_get(ob);
}
- else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
+ else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
bb = BKE_curve_boundbox_get(ob);
}
else if (ob->type == OB_MBALL) {
@@ -6839,7 +6840,7 @@ static void drawtexspace(Object *ob)
if (ob->type == OB_MESH) {
BKE_mesh_texspace_get(ob->data, loc, NULL, size);
}
- else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
+ else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
BKE_curve_texspace_get(ob->data, loc, NULL, size);
}
else if (ob->type == OB_MBALL) {
@@ -6877,7 +6878,7 @@ static void drawObjectSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f);
glDepthMask(0);
- if (ELEM3(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {
+ if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {
DerivedMesh *dm = ob->derivedFinal;
bool has_faces = false;
@@ -6921,7 +6922,7 @@ static void drawObjectSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
static void draw_wire_extra(Scene *scene, RegionView3D *rv3d, Object *ob, const unsigned char ob_wire_col[4])
{
- if (ELEM4(ob->type, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL)) {
+ if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL)) {
if (scene->obedit == ob) {
UI_ThemeColor(TH_WIRE_EDIT);
@@ -6933,7 +6934,7 @@ static void draw_wire_extra(Scene *scene, RegionView3D *rv3d, Object *ob, const
ED_view3d_polygon_offset(rv3d, 1.0);
glDepthMask(0); /* disable write in zbuffer, selected edge wires show better */
- if (ELEM3(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {
+ if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {
if (ED_view3d_boundbox_clip(rv3d, ob->bb)) {
if (ob->derivedFinal) {
@@ -7182,7 +7183,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
if (ob->restrictflag & OB_RESTRICT_RENDER)
return;
- if (!has_particles && (ob->transflag & OB_DUPLI))
+ if (!has_particles && (ob->transflag & (OB_DUPLI & ~OB_DUPLIFRAMES)))
return;
}
}
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 77a5ac1f689..8b76ec3a56d 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -43,6 +43,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_depsgraph.h"
#include "BKE_icons.h"
#include "BKE_library.h"
#include "BKE_main.h"
@@ -286,7 +287,7 @@ static void view3d_stop_render_preview(wmWindowManager *wm, ARegion *ar)
}
}
-void ED_view3d_shade_update(Main *bmain, View3D *v3d, ScrArea *sa)
+void ED_view3d_shade_update(Main *bmain, Scene *scene, View3D *v3d, ScrArea *sa)
{
wmWindowManager *wm = bmain->wm.first;
@@ -298,6 +299,10 @@ void ED_view3d_shade_update(Main *bmain, View3D *v3d, ScrArea *sa)
view3d_stop_render_preview(wm, ar);
}
}
+ else if (scene->obedit != NULL && scene->obedit->type == OB_MESH) {
+ /* Tag mesh to load edit data. */
+ DAG_id_tag_update(scene->obedit->data, 0);
+ }
}
/* ******************** default callbacks for view3d space ***************** */
@@ -483,6 +488,12 @@ static void view3d_main_area_init(wmWindowManager *wm, ARegion *ar)
keymap = WM_keymap_find(wm->defaultconf, "Object Mode", 0, 0);
WM_event_add_keymap_handler(&ar->handlers, keymap);
+ keymap = WM_keymap_find(wm->defaultconf, "Paint Curve", 0, 0);
+ WM_event_add_keymap_handler(&ar->handlers, keymap);
+
+ keymap = WM_keymap_find(wm->defaultconf, "Curve", 0, 0);
+ WM_event_add_keymap_handler(&ar->handlers, keymap);
+
keymap = WM_keymap_find(wm->defaultconf, "Image Paint", 0, 0);
WM_event_add_keymap_handler(&ar->handlers, keymap);
@@ -673,7 +684,7 @@ static void view3d_dropboxes(void)
WM_dropbox_add(lb, "MESH_OT_drop_named_image", view3d_ima_mesh_drop_poll, view3d_id_path_drop_copy);
WM_dropbox_add(lb, "OBJECT_OT_drop_named_image", view3d_ima_empty_drop_poll, view3d_id_path_drop_copy);
WM_dropbox_add(lb, "VIEW3D_OT_background_image_add", view3d_ima_bg_drop_poll, view3d_id_path_drop_copy);
- WM_dropbox_add(lb, "OBJECT_OT_group_instance_add", view3d_group_drop_poll, view3d_group_drop_copy);
+ WM_dropbox_add(lb, "OBJECT_OT_group_instance_add", view3d_group_drop_poll, view3d_group_drop_copy);
}
@@ -779,7 +790,7 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN
break;
case ND_NLA:
case ND_KEYFRAME:
- if (ELEM3(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED))
+ if (ELEM(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED))
ED_region_tag_redraw(ar);
break;
case ND_ANIMCHAN:
@@ -860,14 +871,18 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN
switch (wmn->data) {
case ND_SHADING:
case ND_NODES:
+ {
+ Object *ob = OBACT;
if ((v3d->drawtype == OB_MATERIAL) ||
+ (ob && (ob->mode == OB_MODE_TEXTURE_PAINT)) ||
(v3d->drawtype == OB_TEXTURE &&
- (scene->gm.matmode == GAME_MAT_GLSL ||
- BKE_scene_use_new_shading_nodes(scene))))
+ (scene->gm.matmode == GAME_MAT_GLSL ||
+ BKE_scene_use_new_shading_nodes(scene))))
{
ED_region_tag_redraw(ar);
}
break;
+ }
case ND_SHADING_DRAW:
case ND_SHADING_LINKS:
ED_region_tag_redraw(ar);
@@ -905,7 +920,7 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN
ED_region_tag_redraw(ar);
break;
case NC_MOVIECLIP:
- if (wmn->data == ND_DISPLAY)
+ if (wmn->data == ND_DISPLAY || wmn->action == NA_EDITED)
ED_region_tag_redraw(ar);
break;
case NC_SPACE:
@@ -1030,7 +1045,7 @@ static void view3d_buttons_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa
break;
case ND_NLA:
case ND_KEYFRAME:
- if (ELEM3(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED))
+ if (ELEM(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED))
ED_region_tag_redraw(ar);
break;
}
@@ -1099,6 +1114,11 @@ static void view3d_buttons_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa
if (wmn->data == ND_DATA || wmn->action == NA_EDITED)
ED_region_tag_redraw(ar);
break;
+ case NC_IMAGE:
+ /* Update for the image layers in texture paint. */
+ if (wmn->action == NA_EDITED)
+ ED_region_tag_redraw(ar);
+ break;
}
}
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index dd08339cc94..004b3e1b7d3 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -881,7 +881,7 @@ static void draw_selected_name(Scene *scene, Object *ob, rcti *rect)
}
}
}
- else if (ELEM3(ob->type, OB_MESH, OB_LATTICE, OB_CURVE)) {
+ else if (ELEM(ob->type, OB_MESH, OB_LATTICE, OB_CURVE)) {
Key *key = NULL;
KeyBlock *kb = NULL;
@@ -1287,6 +1287,12 @@ static void backdrawview3d(Scene *scene, ARegion *ar, View3D *v3d)
{
/* do nothing */
}
+ /* texture paint mode sampling */
+ else if (base && (base->object->mode & OB_MODE_TEXTURE_PAINT) &&
+ (v3d->drawtype > OB_WIRE))
+ {
+ /* do nothing */
+ }
else if ((base && (base->object->mode & OB_MODE_PARTICLE_EDIT)) &&
v3d->drawtype > OB_WIRE && (v3d->flag & V3D_ZBUF_SELECT))
{
@@ -2509,7 +2515,7 @@ CustomDataMask ED_view3d_datamask(Scene *scene, View3D *v3d)
mask |= CD_MASK_ORCO;
}
else {
- if (scene->gm.matmode == GAME_MAT_GLSL)
+ if (scene->gm.matmode == GAME_MAT_GLSL || v3d->drawtype == OB_MATERIAL)
mask |= CD_MASK_ORCO;
}
}
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index e3260dba485..4ca9eea578c 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -307,12 +307,12 @@ static void view3d_boxview_clip(ScrArea *sa)
}
for (val = 0; val < 8; val++) {
- if (ELEM4(val, 0, 3, 4, 7))
+ if (ELEM(val, 0, 3, 4, 7))
bb->vec[val][0] = -x1 - ofs[0];
else
bb->vec[val][0] = x1 - ofs[0];
- if (ELEM4(val, 0, 1, 4, 5))
+ if (ELEM(val, 0, 1, 4, 5))
bb->vec[val][1] = -y1 - ofs[1];
else
bb->vec[val][1] = y1 - ofs[1];
@@ -465,11 +465,13 @@ void ED_view3d_quadview_update(ScrArea *sa, ARegion *ar, bool do_clip)
* properties are always being edited, weak */
viewlock = rv3d->viewlock;
- if ((viewlock & RV3D_LOCKED) == 0)
+ if ((viewlock & RV3D_LOCKED) == 0) {
+ do_clip = (viewlock & RV3D_BOXCLIP) != 0;
viewlock = 0;
- else if ((viewlock & RV3D_BOXVIEW) == 0) {
- viewlock &= ~RV3D_BOXCLIP;
+ }
+ else if ((viewlock & RV3D_BOXVIEW) == 0 && (viewlock & RV3D_BOXCLIP) != 0) {
do_clip = true;
+ viewlock &= ~RV3D_BOXCLIP;
}
for (; ar; ar = ar->prev) {
@@ -3243,6 +3245,8 @@ static int render_border_exec(bContext *C, wmOperator *op)
void VIEW3D_OT_render_border(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Set Render Border";
ot->description = "Set the boundaries of the border render and enable border render";
@@ -3262,7 +3266,8 @@ void VIEW3D_OT_render_border(wmOperatorType *ot)
/* rna */
WM_operator_properties_border(ot);
- RNA_def_boolean(ot->srna, "camera_only", 0, "Camera Only", "Set render border for camera view and final render only");
+ prop = RNA_def_boolean(ot->srna, "camera_only", 0, "Camera Only", "Set render border for camera view and final render only");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
/* ********************* Clear render border operator ****************** */
@@ -4435,7 +4440,7 @@ void ED_view3d_cursor3d_position(bContext *C, float fp[3], const int mval[2])
}
}
-static void view3d_cursor3d_update(bContext *C, const int *mval)
+void ED_view3d_cursor3d_update(bContext *C, const int mval[2])
{
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
@@ -4451,7 +4456,7 @@ static void view3d_cursor3d_update(bContext *C, const int *mval)
static int view3d_cursor3d_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- view3d_cursor3d_update(C, event->mval);
+ ED_view3d_cursor3d_update(C, event->mval);
op->customdata = SET_INT_IN_POINTER(event->type);
WM_event_add_modal_handler(C, op);
@@ -4468,7 +4473,7 @@ static int view3d_cursor3d_modal(bContext *C, wmOperator *op, const wmEvent *eve
switch (event->type) {
case MOUSEMOVE:
- view3d_cursor3d_update(C, event->mval);
+ ED_view3d_cursor3d_update(C, event->mval);
break;
case LEFTMOUSE:
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c
index e3d0e87066b..a88724a1cdd 100644
--- a/source/blender/editors/space_view3d/view3d_header.c
+++ b/source/blender/editors/space_view3d/view3d_header.c
@@ -32,6 +32,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include "DNA_brush_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
@@ -45,6 +46,7 @@
#include "BKE_depsgraph.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
+#include "BKE_paint.h"
#include "BKE_screen.h"
#include "BKE_editmesh.h"
@@ -308,7 +310,7 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
/* mode */
if (ob) {
modeselect = ob->mode;
- is_paint = ELEM4(ob->mode, OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT, OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT);
+ is_paint = ELEM(ob->mode, OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT, OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT);
}
else {
modeselect = OB_MODE_OBJECT;
@@ -336,8 +338,7 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
uiItemR(layout, &v3dptr, "viewport_shade", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
if (obedit == NULL && is_paint) {
-
- if (ob->mode & OB_MODE_WEIGHT_PAINT) {
+ if (ob->mode & OB_MODE_ALL_PAINT) {
/* Only for Weight Paint. makes no sense in other paint modes. */
row = uiLayoutRow(layout, true);
uiItemR(row, &v3dptr, "pivot_point", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index f61f58c12db..46ea52054c5 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -1194,15 +1194,32 @@ static short selectbuffer_ret_hits_5(unsigned int *buffer, const short hits15, c
/* we want a select buffer with bones, if there are... */
/* so check three selection levels and compare */
-static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buffer, const int mval[2])
+static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buffer, const int mval[2], bool *p_do_nearest, bool enumerate)
{
rcti rect;
int offs;
short hits15, hits9 = 0, hits5 = 0;
bool has_bones15 = false, has_bones9 = false, has_bones5 = false;
-
+ static int last_mval[2] = {-100, -100};
+ bool do_nearest = false;
+ View3D *v3d = vc->v3d;
+
+ /* define if we use solid nearest select or not */
+ if (v3d->drawtype > OB_WIRE) {
+ do_nearest = true;
+ if (len_manhattan_v2v2_int(mval, last_mval) < 3) {
+ do_nearest = false;
+ }
+ }
+ copy_v2_v2_int(last_mval, mval);
+
+ if (p_do_nearest)
+ *p_do_nearest = do_nearest;
+
+ do_nearest = do_nearest && !enumerate;
+
BLI_rcti_init(&rect, mval[0] - 14, mval[0] + 14, mval[1] - 14, mval[1] + 14);
- hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect);
+ hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, do_nearest);
if (hits15 == 1) {
return selectbuffer_ret_hits_15(buffer, hits15);
}
@@ -1211,7 +1228,7 @@ static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buff
offs = 4 * hits15;
BLI_rcti_init(&rect, mval[0] - 9, mval[0] + 9, mval[1] - 9, mval[1] + 9);
- hits9 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect);
+ hits9 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, do_nearest);
if (hits9 == 1) {
return selectbuffer_ret_hits_9(buffer, hits15, hits9);
}
@@ -1220,7 +1237,7 @@ static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buff
offs += 4 * hits9;
BLI_rcti_init(&rect, mval[0] - 5, mval[0] + 5, mval[1] - 5, mval[1] + 5);
- hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect);
+ hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, do_nearest);
if (hits5 == 1) {
return selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5);
}
@@ -1242,25 +1259,13 @@ static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buff
}
/* returns basact */
-static Base *mouse_select_eval_buffer(ViewContext *vc, unsigned int *buffer, int hits, const int mval[2],
- Base *startbase, bool has_bones)
+static Base *mouse_select_eval_buffer(ViewContext *vc, unsigned int *buffer, int hits,
+ Base *startbase, bool has_bones, bool do_nearest)
{
Scene *scene = vc->scene;
View3D *v3d = vc->v3d;
Base *base, *basact = NULL;
- static int lastmval[2] = {-100, -100};
int a;
- bool do_nearest = false;
-
- /* define if we use solid nearest select or not */
- if (v3d->drawtype > OB_WIRE) {
- do_nearest = true;
- if (ABS(mval[0] - lastmval[0]) < 3 && ABS(mval[1] - lastmval[1]) < 3) {
- if (!has_bones) /* hrms, if theres bones we always do nearest */
- do_nearest = false;
- }
- }
- lastmval[0] = mval[0]; lastmval[1] = mval[1];
if (do_nearest) {
unsigned int min = 0xFFFFFFFF;
@@ -1343,16 +1348,17 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
Base *basact = NULL;
unsigned int buffer[4 * MAXPICKBUF];
int hits;
+ bool do_nearest;
/* setup view context for argument to callbacks */
view3d_operator_needs_opengl(C);
view3d_set_viewcontext(C, &vc);
- hits = mixed_bones_object_selectbuffer(&vc, buffer, mval);
+ hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, &do_nearest, false);
if (hits > 0) {
const bool has_bones = selectbuffer_has_bones(buffer, hits);
- basact = mouse_select_eval_buffer(&vc, buffer, hits, mval, vc.scene->base.first, has_bones);
+ basact = mouse_select_eval_buffer(&vc, buffer, hits, vc.scene->base.first, has_bones, do_nearest);
}
return basact;
@@ -1439,10 +1445,11 @@ static bool mouse_select(bContext *C, const int mval[2],
}
else {
unsigned int buffer[4 * MAXPICKBUF];
+ bool do_nearest;
/* if objects have posemode set, the bones are in the same selection buffer */
- hits = mixed_bones_object_selectbuffer(&vc, buffer, mval);
+ hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, &do_nearest, enumerate);
if (hits > 0) {
/* note: bundles are handling in the same way as bones */
@@ -1453,7 +1460,7 @@ static bool mouse_select(bContext *C, const int mval[2],
basact = object_mouse_select_menu(C, &vc, buffer, hits, mval, toggle);
}
else {
- basact = mouse_select_eval_buffer(&vc, buffer, hits, mval, startbase, has_bones);
+ basact = mouse_select_eval_buffer(&vc, buffer, hits, startbase, has_bones, do_nearest);
}
if (has_bones && basact) {
@@ -1511,7 +1518,7 @@ static bool mouse_select(bContext *C, const int mval[2],
if (!changed) {
/* fallback to regular object selection if no new bundles were selected,
* allows to select object parented to reconstruction object */
- basact = mouse_select_eval_buffer(&vc, buffer, hits, mval, startbase, 0);
+ basact = mouse_select_eval_buffer(&vc, buffer, hits, startbase, 0, do_nearest);
}
}
}
@@ -1873,7 +1880,7 @@ static int do_meta_box_select(ViewContext *vc, rcti *rect, bool select, bool ext
unsigned int buffer[4 * MAXPICKBUF];
short hits;
- hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect);
+ hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, false);
if (extend == false && select)
BKE_mball_deselect_all(mb);
@@ -1907,7 +1914,7 @@ static int do_armature_box_select(ViewContext *vc, rcti *rect, bool select, bool
unsigned int buffer[4 * MAXPICKBUF];
short hits;
- hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect);
+ hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, false);
/* clear flag we use to detect point was affected */
for (ebone = arm->edbo->first; ebone; ebone = ebone->next)
@@ -2001,7 +2008,7 @@ static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, b
/* selection buffer now has bones potentially too, so we add MAXPICKBUF */
vbuffer = MEM_mallocN(4 * (totobj + MAXPICKBUF) * sizeof(unsigned int), "selection buffer");
- hits = view3d_opengl_select(vc, vbuffer, 4 * (totobj + MAXPICKBUF), rect);
+ hits = view3d_opengl_select(vc, vbuffer, 4 * (totobj + MAXPICKBUF), rect, false);
/*
* LOGIC NOTES (theeth):
* The buffer and ListBase have the same relative order, which makes the selection
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index 716f4b10fae..6d28accbc7b 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -56,6 +56,7 @@
#include "BIF_glutil.h"
#include "GPU_draw.h"
+#include "GPU_select.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -955,6 +956,78 @@ void view3d_viewmatrix_set(Scene *scene, View3D *v3d, RegionView3D *rv3d)
}
}
+static void view3d_select_loop(ViewContext *vc, Scene *scene, View3D *v3d, ARegion *ar, bool use_obedit_skip)
+{
+ short code = 1;
+ char dt;
+ short dtx;
+
+ if (vc->obedit && vc->obedit->type == OB_MBALL) {
+ draw_object(scene, ar, v3d, BASACT, DRAW_PICKING | DRAW_CONSTCOLOR);
+ }
+ else if ((vc->obedit && vc->obedit->type == OB_ARMATURE)) {
+ /* if not drawing sketch, draw bones */
+ if (!BDR_drawSketchNames(vc)) {
+ draw_object(scene, ar, v3d, BASACT, DRAW_PICKING | DRAW_CONSTCOLOR);
+ }
+ }
+ else {
+ Base *base;
+
+ v3d->xray = true; /* otherwise it postpones drawing */
+ for (base = scene->base.first; base; base = base->next) {
+ if (base->lay & v3d->lay) {
+
+ if ((base->object->restrictflag & OB_RESTRICT_SELECT) ||
+ (use_obedit_skip && (scene->obedit->data == base->object->data)))
+ {
+ base->selcol = 0;
+ }
+ else {
+ base->selcol = code;
+
+ if (GPU_select_load_id(code)) {
+ draw_object(scene, ar, v3d, base, DRAW_PICKING | DRAW_CONSTCOLOR);
+
+ /* we draw duplicators for selection too */
+ if ((base->object->transflag & OB_DUPLI)) {
+ ListBase *lb;
+ DupliObject *dob;
+ Base tbase;
+
+ tbase.flag = OB_FROMDUPLI;
+ lb = object_duplilist(G.main->eval_ctx, scene, base->object);
+
+ for (dob = lb->first; dob; dob = dob->next) {
+ float omat[4][4];
+
+ tbase.object = dob->ob;
+ copy_m4_m4(omat, dob->ob->obmat);
+ copy_m4_m4(dob->ob->obmat, dob->mat);
+
+ /* extra service: draw the duplicator in drawtype of parent */
+ /* MIN2 for the drawtype to allow bounding box objects in groups for lods */
+ dt = tbase.object->dt; tbase.object->dt = MIN2(tbase.object->dt, base->object->dt);
+ dtx = tbase.object->dtx; tbase.object->dtx = base->object->dtx;
+
+ draw_object(scene, ar, v3d, &tbase, DRAW_PICKING | DRAW_CONSTCOLOR);
+
+ tbase.object->dt = dt;
+ tbase.object->dtx = dtx;
+
+ copy_m4_m4(dob->ob->obmat, omat);
+ }
+ free_object_duplilist(lb);
+ }
+ }
+ code++;
+ }
+ }
+ }
+ v3d->xray = false; /* restore */
+ }
+}
+
/**
* \warning be sure to account for a negative return value
* This is an error, "Too many objects in select buffer"
@@ -962,17 +1035,16 @@ void view3d_viewmatrix_set(Scene *scene, View3D *v3d, RegionView3D *rv3d)
*
* \note (vc->obedit == NULL) can be set to explicitly skip edit-object selection.
*/
-short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const rcti *input)
+short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const rcti *input, bool do_nearest)
{
Scene *scene = vc->scene;
View3D *v3d = vc->v3d;
ARegion *ar = vc->ar;
- rctf rect;
- short code, hits;
- char dt;
- short dtx;
+ rctf rect, selrect;
+ short hits;
const bool use_obedit_skip = (scene->obedit != NULL) && (vc->obedit == NULL);
-
+ const bool do_passes = do_nearest && GPU_select_query_check_active();
+
G.f |= G_PICKSEL;
/* case not a border select */
@@ -985,6 +1057,8 @@ short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int b
else {
BLI_rctf_rcti_copy(&rect, input);
}
+
+ selrect = rect;
view3d_winmatrix_set(ar, v3d, &rect);
mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->winmat, vc->rv3d->viewmat);
@@ -997,78 +1071,24 @@ short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int b
if (vc->rv3d->rflag & RV3D_CLIPPING)
ED_view3d_clipping_set(vc->rv3d);
- glSelectBuffer(bufsize, (GLuint *)buffer);
- glRenderMode(GL_SELECT);
- glInitNames(); /* these two calls whatfor? It doesnt work otherwise */
- glPushName(-1);
- code = 1;
+ if (do_passes)
+ GPU_select_begin(buffer, bufsize, &selrect, GPU_SELECT_NEAREST_FIRST_PASS, 0);
+ else
+ GPU_select_begin(buffer, bufsize, &selrect, GPU_SELECT_ALL, 0);
+
+ view3d_select_loop(vc, scene, v3d, ar, use_obedit_skip);
+
+ hits = GPU_select_end();
- if (vc->obedit && vc->obedit->type == OB_MBALL) {
- draw_object(scene, ar, v3d, BASACT, DRAW_PICKING | DRAW_CONSTCOLOR);
- }
- else if ((vc->obedit && vc->obedit->type == OB_ARMATURE)) {
- /* if not drawing sketch, draw bones */
- if (!BDR_drawSketchNames(vc)) {
- draw_object(scene, ar, v3d, BASACT, DRAW_PICKING | DRAW_CONSTCOLOR);
- }
- }
- else {
- Base *base;
-
- v3d->xray = true; /* otherwise it postpones drawing */
- for (base = scene->base.first; base; base = base->next) {
- if (base->lay & v3d->lay) {
-
- if ((base->object->restrictflag & OB_RESTRICT_SELECT) ||
- (use_obedit_skip && (scene->obedit->data == base->object->data)))
- {
- base->selcol = 0;
- }
- else {
- base->selcol = code;
- glLoadName(code);
- draw_object(scene, ar, v3d, base, DRAW_PICKING | DRAW_CONSTCOLOR);
-
- /* we draw duplicators for selection too */
- if ((base->object->transflag & OB_DUPLI)) {
- ListBase *lb;
- DupliObject *dob;
- Base tbase;
-
- tbase.flag = OB_FROMDUPLI;
- lb = object_duplilist(G.main->eval_ctx, scene, base->object);
-
- for (dob = lb->first; dob; dob = dob->next) {
- float omat[4][4];
-
- tbase.object = dob->ob;
- copy_m4_m4(omat, dob->ob->obmat);
- copy_m4_m4(dob->ob->obmat, dob->mat);
-
- /* extra service: draw the duplicator in drawtype of parent */
- /* MIN2 for the drawtype to allow bounding box objects in groups for lods */
- dt = tbase.object->dt; tbase.object->dt = MIN2(tbase.object->dt, base->object->dt);
- dtx = tbase.object->dtx; tbase.object->dtx = base->object->dtx;
-
- draw_object(scene, ar, v3d, &tbase, DRAW_PICKING | DRAW_CONSTCOLOR);
-
- tbase.object->dt = dt;
- tbase.object->dtx = dtx;
-
- copy_m4_m4(dob->ob->obmat, omat);
- }
- free_object_duplilist(lb);
- }
- code++;
- }
- }
- }
- v3d->xray = false; /* restore */
+ /* second pass, to get the closest object to camera */
+ if (do_passes) {
+ GPU_select_begin(buffer, bufsize, &selrect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
+
+ view3d_select_loop(vc, scene, v3d, ar, use_obedit_skip);
+
+ GPU_select_end();
}
-
- glPopName(); /* see above (pushname) */
- hits = glRenderMode(GL_RENDER);
-
+
G.f &= ~G_PICKSEL;
view3d_winmatrix_set(ar, v3d, NULL);
mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->winmat, vc->rv3d->viewmat);
@@ -1285,7 +1305,7 @@ static bool view3d_localview_init(
return ok;
}
-static void restore_localviewdata(wmWindowManager *wm, wmWindow *win, Main *bmain, ScrArea *sa, const int smooth_viewtx)
+static void restore_localviewdata(wmWindowManager *wm, wmWindow *win, Main *bmain, Scene *scene, ScrArea *sa, const int smooth_viewtx)
{
const bool free = true;
ARegion *ar;
@@ -1335,7 +1355,7 @@ static void restore_localviewdata(wmWindowManager *wm, wmWindow *win, Main *bmai
}
}
- ED_view3d_shade_update(bmain, v3d, sa);
+ ED_view3d_shade_update(bmain, scene, v3d, sa);
}
}
}
@@ -1352,7 +1372,7 @@ static bool view3d_localview_exit(
locallay = v3d->lay & 0xFF000000;
- restore_localviewdata(wm, win, bmain, sa, smooth_viewtx);
+ restore_localviewdata(wm, win, bmain, scene, sa, smooth_viewtx);
/* for when in other window the layers have changed */
if (v3d->scenelock) v3d->lay = scene->lay;
diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt
index 7765dd511b4..3ad5d94efd6 100644
--- a/source/blender/editors/transform/CMakeLists.txt
+++ b/source/blender/editors/transform/CMakeLists.txt
@@ -24,6 +24,7 @@ set(INC
../../blenkernel
../../blenlib
../../bmesh
+ ../../gpu
../../ikplugin
../../makesdna
../../makesrna
diff --git a/source/blender/editors/transform/SConscript b/source/blender/editors/transform/SConscript
index f3c8c13647a..4f47062e3a3 100644
--- a/source/blender/editors/transform/SConscript
+++ b/source/blender/editors/transform/SConscript
@@ -40,6 +40,7 @@ incs = [
'../../ikplugin',
'../../makesdna',
'../../makesrna',
+ '../../gpu',
'../../windowmanager',
]
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index a53b4a75b20..58dee620a61 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -86,6 +86,9 @@
#include "transform.h"
+/* Disabling, since when you type you know what you are doing, and being able to set it to zero is handy. */
+// #define USE_NUM_NO_ZERO
+
#define MAX_INFO_LEN 256
static void drawTransformApply(const struct bContext *C, ARegion *ar, void *arg);
@@ -190,9 +193,9 @@ static bool transdata_check_local_center(TransInfo *t, short around)
{
return ((around == V3D_LOCAL) && (
(t->flag & (T_OBJECT | T_POSE)) ||
- (t->obedit && ELEM4(t->obedit->type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE)) ||
+ (t->obedit && ELEM(t->obedit->type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE)) ||
(t->spacetype == SPACE_IPO) ||
- (t->options & (CTX_MOVIECLIP | CTX_MASK)))
+ (t->options & (CTX_MOVIECLIP | CTX_MASK | CTX_PAINT_CURVE)))
);
}
@@ -263,17 +266,27 @@ static void convertViewVec2D_mask(View2D *v2d, float r_vec[3], int dx, int dy)
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, t->zfac);
+ if (t->options & CTX_PAINT_CURVE) {
+ r_vec[0] = dx;
+ r_vec[1] = dy;
+ }
+ else { const float mval_f[2] = {(float)dx, (float)dy};
+ ED_view3d_win_to_delta(t->ar, mval_f, r_vec, t->zfac);
+ }
}
else if (t->spacetype == SPACE_IMAGE) {
float aspx, aspy;
if (t->options & CTX_MASK) {
-
convertViewVec2D_mask(t->view, r_vec, dx, dy);
ED_space_image_get_aspect(t->sa->spacedata.first, &aspx, &aspy);
}
+ else if (t->options & CTX_PAINT_CURVE) {
+ r_vec[0] = dx;
+ r_vec[1] = dy;
+
+ aspx = aspy = 1.0;
+ }
else {
convertViewVec2D(t->view, r_vec, dx, dy);
ED_space_image_get_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
@@ -351,6 +364,10 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr
adr[0] = v[0];
adr[1] = v[1];
}
+ else if (t->options & CTX_PAINT_CURVE) {
+ adr[0] = vec[0];
+ adr[1] = vec[1];
+ }
else {
float aspx, aspy, v[2];
@@ -452,7 +469,11 @@ void projectFloatViewEx(TransInfo *t, const float vec[3], float adr[2], const eV
switch (t->spacetype) {
case SPACE_VIEW3D:
{
- if (t->ar->regiontype == RGN_TYPE_WINDOW) {
+ if (t->options & CTX_PAINT_CURVE) {
+ adr[0] = vec[0];
+ adr[1] = vec[1];
+ }
+ else if (t->ar->regiontype == RGN_TYPE_WINDOW) {
/* allow points behind the view [#33643] */
if (ED_view3d_project_float_global(t->ar, vec, adr, flag) != V3D_PROJ_RET_OK) {
/* XXX, 2.64 and prior did this, weak! */
@@ -480,7 +501,7 @@ void projectFloatView(TransInfo *t, const float vec[3], float adr[2])
void applyAspectRatio(TransInfo *t, float vec[2])
{
- if ((t->spacetype == SPACE_IMAGE) && (t->mode == TFM_TRANSLATION)) {
+ if ((t->spacetype == SPACE_IMAGE) && (t->mode == TFM_TRANSLATION) && !(t->options & CTX_PAINT_CURVE)) {
SpaceImage *sima = t->sa->spacedata.first;
float aspx, aspy;
@@ -557,17 +578,23 @@ void removeAspectRatio(TransInfo *t, float vec[2])
static void viewRedrawForce(const bContext *C, TransInfo *t)
{
if (t->spacetype == SPACE_VIEW3D) {
- /* Do we need more refined tags? */
- if (t->flag & T_POSE)
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
- else
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
+ if (t->options & CTX_PAINT_CURVE) {
+ wmWindow *window = CTX_wm_window(C);
+ WM_paint_cursor_tag_redraw(window, t->ar);
+ }
+ else {
+ /* Do we need more refined tags? */
+ if (t->flag & T_POSE)
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+ else
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
- /* for realtime animation record - send notifiers recognised by animation editors */
- // XXX: is this notifier a lame duck?
- if ((t->animtimer) && IS_AUTOKEY_ON(t->scene))
- WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, NULL);
-
+ /* for realtime animation record - send notifiers recognised by animation editors */
+ // XXX: is this notifier a lame duck?
+ if ((t->animtimer) && IS_AUTOKEY_ON(t->scene))
+ WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, NULL);
+
+ }
}
else if (t->spacetype == SPACE_ACTION) {
//SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
@@ -593,6 +620,10 @@ static void viewRedrawForce(const bContext *C, TransInfo *t)
WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
}
+ else if (t->options & CTX_PAINT_CURVE) {
+ wmWindow *window = CTX_wm_window(C);
+ WM_paint_cursor_tag_redraw(window, t->ar);
+ }
else {
// XXX how to deal with lock?
SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first;
@@ -646,7 +677,7 @@ static void viewRedrawPost(bContext *C, TransInfo *t)
allqueue(REDRAWIMAGE, 0);
allqueue(REDRAWVIEW3D, 0);
}
- else if (ELEM3(t->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_IPO)) {
+ else if (ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_IPO)) {
allqueue(REDRAWVIEW3D, 0);
allqueue(REDRAWACTION, 0);
allqueue(REDRAWNLA, 0);
@@ -969,7 +1000,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case TFM_MODAL_TRANSLATE:
/* only switch when... */
- if (ELEM5(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) {
+ if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) {
resetTransModal(t);
resetTransRestrictions(t);
restoreTransObjects(t);
@@ -1025,7 +1056,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
case TFM_MODAL_ROTATE:
/* only switch when... */
if (!(t->options & CTX_TEXTURE) && !(t->options & (CTX_MOVIECLIP | CTX_MASK))) {
- if (ELEM6(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) {
+ if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) {
resetTransModal(t);
resetTransRestrictions(t);
@@ -1045,7 +1076,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case TFM_MODAL_RESIZE:
/* only switch when... */
- if (ELEM5(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) {
+ if (ELEM(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) {
/* Scale isn't normally very useful after extrude along normals, see T39756 */
if ((t->con.mode & CON_APPLY) && (t->con.orientation == V3D_MANIP_NORMAL)) {
@@ -1308,7 +1339,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case GKEY:
/* only switch when... */
- if (ELEM3(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL) ) {
+ if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) {
resetTransModal(t);
resetTransRestrictions(t);
restoreTransObjects(t);
@@ -1320,7 +1351,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case SKEY:
/* only switch when... */
- if (ELEM3(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL) ) {
+ if (ELEM(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL)) {
resetTransModal(t);
resetTransRestrictions(t);
restoreTransObjects(t);
@@ -1333,7 +1364,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
case RKEY:
/* only switch when... */
if (!(t->options & CTX_TEXTURE)) {
- if (ELEM4(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION) ) {
+ if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION)) {
resetTransModal(t);
resetTransRestrictions(t);
@@ -2065,7 +2096,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
* moded are available from manipulator and doing such check could
* lead to keymap conflicts for other modes (see #31584)
*/
- if (ELEM3(mode, TFM_TRANSLATION, TFM_ROTATION, TFM_RESIZE)) {
+ if (ELEM(mode, TFM_TRANSLATION, TFM_ROTATION, TFM_RESIZE)) {
wmKeyMapItem *kmi;
for (kmi = t->keymap->items.first; kmi; kmi = kmi->next) {
@@ -3085,9 +3116,11 @@ static void initResize(TransInfo *t)
t->num.flag |= NUM_AFFECT_ALL;
if (!t->obedit) {
t->flag |= T_NO_ZERO;
+#ifdef USE_NUM_NO_ZERO
t->num.val_flag[0] |= NUM_NO_ZERO;
t->num.val_flag[1] |= NUM_NO_ZERO;
t->num.val_flag[2] |= NUM_NO_ZERO;
+#endif
}
t->idx_max = 2;
@@ -3377,9 +3410,11 @@ static void initSkinResize(TransInfo *t)
t->num.flag |= NUM_AFFECT_ALL;
if (!t->obedit) {
t->flag |= T_NO_ZERO;
+#ifdef USE_NUM_NO_ZERO
t->num.val_flag[0] |= NUM_NO_ZERO;
t->num.val_flag[1] |= NUM_NO_ZERO;
t->num.val_flag[2] |= NUM_NO_ZERO;
+#endif
}
t->idx_max = 2;
@@ -3592,8 +3627,15 @@ static void initRotation(TransInfo *t)
if (t->flag & T_2D_EDIT)
t->flag |= T_NO_CONSTRAINT;
- negate_v3_v3(t->axis, t->viewinv[2]);
- normalize_v3(t->axis);
+ if (t->options & CTX_PAINT_CURVE) {
+ t->axis[0] = 0.0;
+ t->axis[1] = 0.0;
+ t->axis[2] = -1.0;
+ }
+ else {
+ negate_v3_v3(t->axis, t->viewinv[2]);
+ normalize_v3(t->axis);
+ }
copy_v3_v3(t->axis_orig, t->axis);
}
@@ -3627,7 +3669,7 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short
if (td->flag & TD_USEQUAT) {
- mul_serie_m3(fmat, td->mtx, mat, td->smtx, NULL, NULL, NULL, NULL, NULL);
+ mul_m3_series(fmat, td->smtx, mat, td->mtx);
mat3_to_quat(quat, fmat); // Actual transform
if (td->ext->quat) {
@@ -3697,7 +3739,7 @@ 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/axis-angle? */
if (td->ext->rotOrder == ROT_MODE_QUAT) {
- mul_serie_m3(fmat, td->ext->r_mtx, mat, td->ext->r_smtx, NULL, NULL, NULL, NULL, NULL);
+ mul_m3_series(fmat, td->ext->r_smtx, mat, td->ext->r_mtx);
mat3_to_quat(quat, fmat); /* Actual transform */
@@ -3712,7 +3754,7 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short
axis_angle_to_quat(iquat, td->ext->irotAxis, td->ext->irotAngle);
- mul_serie_m3(fmat, td->ext->r_mtx, mat, td->ext->r_smtx, NULL, NULL, NULL, NULL, NULL);
+ mul_m3_series(fmat, td->ext->r_smtx, mat, td->ext->r_mtx);
mat3_to_quat(quat, fmat); /* Actual transform */
mul_qt_qtqt(tquat, quat, iquat);
@@ -3769,7 +3811,7 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short
if ((td->ext->rotOrder == ROT_MODE_QUAT) || (td->flag & TD_USEQUAT)) {
/* 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);
+ mul_m3_series(fmat, td->smtx, mat, td->mtx);
mat3_to_quat(quat, fmat); // Actual transform
mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat);
@@ -3783,7 +3825,7 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short
axis_angle_to_quat(iquat, td->ext->irotAxis, td->ext->irotAngle);
- mul_serie_m3(fmat, td->mtx, mat, td->smtx, NULL, NULL, NULL, NULL, NULL);
+ mul_m3_series(fmat, td->smtx, mat, td->mtx);
mat3_to_quat(quat, fmat); // Actual transform
mul_qt_qtqt(tquat, quat, iquat);
@@ -4480,7 +4522,9 @@ static void initCurveShrinkFatten(TransInfo *t)
t->num.unit_type[0] = B_UNIT_NONE;
t->flag |= T_NO_ZERO;
+#ifdef USE_NUM_NO_ZERO
t->num.val_flag[0] |= NUM_NO_ZERO;
+#endif
t->flag |= T_NO_CONSTRAINT;
}
@@ -4555,7 +4599,9 @@ static void initMaskShrinkFatten(TransInfo *t)
t->num.unit_type[0] = B_UNIT_NONE;
t->flag |= T_NO_ZERO;
+#ifdef USE_NUM_NO_ZERO
t->num.val_flag[0] |= NUM_NO_ZERO;
+#endif
t->flag |= T_NO_CONSTRAINT;
}
@@ -7707,7 +7753,7 @@ bool checkUseAxisMatrix(TransInfo *t)
{
/* currently only checks for editmode */
if (t->flag & T_EDIT) {
- if ((t->around == V3D_LOCAL) && (ELEM4(t->obedit->type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE))) {
+ if ((t->around == V3D_LOCAL) && (ELEM(t->obedit->type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE))) {
/* not all editmode supports axis-matrix */
return true;
}
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 0bccf177128..012f9185d8b 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -130,15 +130,15 @@ typedef struct TransDataExtension {
// float drotAxis[3]; /* Initial object drotAxis, TODO: not yet implemented */
float dquat[4]; /* Initial object dquat */
float dscale[3]; /* Initial object dscale */
- float *rot; /* Rotation of the data to transform (Faculative) */
+ float *rot; /* Rotation of the data to transform */
float irot[3]; /* Initial rotation */
- float *quat; /* Rotation quaternion of the data to transform (Faculative) */
+ float *quat; /* Rotation quaternion of the data to transform */
float iquat[4]; /* Initial rotation quaternion */
- float *rotAngle; /* Rotation angle of the data to transform (Faculative) */
+ float *rotAngle; /* Rotation angle of the data to transform */
float irotAngle; /* Initial rotation angle */
- float *rotAxis; /* Rotation axis of the data to transform (Faculative) */
+ float *rotAxis; /* Rotation axis of the data to transform */
float irotAxis[4]; /* Initial rotation axis */
- float *size; /* Size of the data to transform (Faculative) */
+ float *size; /* Size of the data to transform */
float isize[3]; /* Initial size */
float obmat[4][4]; /* Object matrix */
float l_smtx[3][3]; /* use instead of td->smtx, It is the same but without the 'bone->bone_mat', see TD_PBONE_LOCAL_MTX_C */
@@ -532,6 +532,7 @@ void flushTransNodes(TransInfo *t);
void flushTransSeq(TransInfo *t);
void flushTransTracking(TransInfo *t);
void flushTransMasking(TransInfo *t);
+void flushTransPaintCurve(TransInfo *t);
void restoreBones(TransInfo *t);
/*********************** exported from transform_manipulator.c ********** */
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index 79f266df607..d8f17315c01 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -663,7 +663,7 @@ void drawConstraint(TransInfo *t)
{
TransCon *tc = &(t->con);
- if (!ELEM3(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE))
+ if (!ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE))
return;
if (!(tc->mode & CON_APPLY))
return;
@@ -756,6 +756,9 @@ void drawPropCircle(const struct bContext *C, TransInfo *t)
/* untested - mask aspect is TODO */
ED_space_image_get_aspect(t->sa->spacedata.first, &aspx, &aspy);
}
+ else if (t->options & CTX_PAINT_CURVE) {
+ aspx = aspy = 1.0;
+ }
else {
ED_space_image_get_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
}
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index 0696ca55431..a5f57a0c464 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -33,6 +33,7 @@
#include <math.h>
#include "DNA_anim_types.h"
+#include "DNA_brush_types.h"
#include "DNA_armature_types.h"
#include "DNA_lattice_types.h"
#include "DNA_mesh_types.h"
@@ -80,6 +81,7 @@
#include "BKE_node.h"
#include "BKE_object.h"
#include "BKE_particle.h"
+#include "BKE_paint.h"
#include "BKE_pointcache.h"
#include "BKE_report.h"
#include "BKE_rigidbody.h"
@@ -124,8 +126,8 @@
static void transform_around_single_fallback(TransInfo *t)
{
if ((t->total == 1) &&
- (ELEM3(t->around, V3D_CENTER, V3D_CENTROID, V3D_ACTIVE)) &&
- (ELEM3(t->mode, TFM_RESIZE, TFM_ROTATION, TFM_TRACKBALL)))
+ (ELEM(t->around, V3D_CENTER, V3D_CENTROID, V3D_ACTIVE)) &&
+ (ELEM(t->mode, TFM_RESIZE, TFM_ROTATION, TFM_TRACKBALL)))
{
t->around = V3D_LOCAL;
}
@@ -282,7 +284,7 @@ static void createTransTexspace(TransInfo *t)
}
id = ob->data;
- if (id == NULL || !ELEM3(GS(id->name), ID_ME, ID_CU, ID_MB)) {
+ if (id == NULL || !ELEM(GS(id->name), ID_ME, ID_CU, ID_MB)) {
BKE_report(t->reports, RPT_ERROR, "Unsupported object type for text-space transform");
t->total = 0;
return;
@@ -584,12 +586,12 @@ static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, Tr
if (constraints_list_needinv(t, &pchan->constraints)) {
copy_m3_m4(tmat, pchan->constinv);
invert_m3_m3(cmat, tmat);
- mul_serie_m3(td->mtx, pmat, omat, cmat, NULL, NULL, NULL, NULL, NULL);
- mul_serie_m3(td->ext->r_mtx, rpmat, omat, cmat, NULL, NULL, NULL, NULL, NULL);
+ mul_m3_series(td->mtx, cmat, omat, pmat);
+ mul_m3_series(td->ext->r_mtx, cmat, omat, rpmat);
}
else {
- mul_serie_m3(td->mtx, pmat, omat, NULL, NULL, NULL, NULL, NULL, NULL);
- mul_serie_m3(td->ext->r_mtx, rpmat, omat, NULL, NULL, NULL, NULL, NULL, NULL);
+ mul_m3_series(td->mtx, omat, pmat);
+ mul_m3_series(td->ext->r_mtx, omat, rpmat);
}
invert_m3_m3(td->ext->r_smtx, td->ext->r_mtx);
}
@@ -2368,8 +2370,7 @@ static void createTransEditVerts(TransInfo *t)
quat_to_mat3(qmat, quats[BM_elem_index_get(eve)]);
if (defmats)
- mul_serie_m3(mat, mtx, qmat, defmats[a],
- NULL, NULL, NULL, NULL, NULL);
+ mul_m3_series(mat, defmats[a], qmat, mtx);
else
mul_m3_m3m3(mat, mtx, qmat);
}
@@ -3707,7 +3708,7 @@ static void bezt_to_transdata(TransData *td, TransData2D *td2d, TransDataGraph *
static bool graph_edit_is_translation_mode(TransInfo *t)
{
- return ELEM4(t->mode, TFM_TRANSLATION, TFM_TIME_TRANSLATE, TFM_TIME_SLIDE, TFM_TIME_DUPLICATE);
+ return ELEM(t->mode, TFM_TRANSLATION, TFM_TIME_TRANSLATE, TFM_TIME_SLIDE, TFM_TIME_DUPLICATE);
}
static bool graph_edit_use_local_center(TransInfo *t)
@@ -4767,12 +4768,12 @@ static bool constraints_list_needinv(TransInfo *t, ListBase *list)
if ((con->flag & CONSTRAINT_DISABLE) == 0 && (con->enforce != 0.0f)) {
/* (affirmative) returns for specific constraints here... */
/* constraints that require this regardless */
- if (ELEM5(con->type,
- CONSTRAINT_TYPE_CHILDOF,
- CONSTRAINT_TYPE_FOLLOWPATH,
- CONSTRAINT_TYPE_CLAMPTO,
- CONSTRAINT_TYPE_OBJECTSOLVER,
- CONSTRAINT_TYPE_FOLLOWTRACK))
+ if (ELEM(con->type,
+ CONSTRAINT_TYPE_CHILDOF,
+ CONSTRAINT_TYPE_FOLLOWPATH,
+ CONSTRAINT_TYPE_CLAMPTO,
+ CONSTRAINT_TYPE_OBJECTSOLVER,
+ CONSTRAINT_TYPE_FOLLOWTRACK))
{
return true;
}
@@ -5848,6 +5849,9 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
+ else if (t->options & CTX_PAINT_CURVE) {
+ /* pass */
+ }
else if ((t->scene->basact) &&
(ob = t->scene->basact->object) &&
(ob->mode & OB_MODE_PARTICLE_EDIT) &&
@@ -7027,6 +7031,173 @@ void flushTransMasking(TransInfo *t)
}
}
+typedef struct TransDataPaintCurve {
+ PaintCurvePoint *pcp; /* initial curve point */
+ char id;
+} TransDataPaintCurve;
+
+
+#define PC_IS_ANY_SEL(pc) (((pc)->bez.f1 | (pc)->bez.f2 | (pc)->bez.f3) & SELECT)
+
+static void PaintCurveConvertHandle(PaintCurvePoint *pcp, int id, TransData2D *td2d, TransDataPaintCurve *tdpc, TransData *td)
+{
+ BezTriple *bezt = &pcp->bez;
+ copy_v2_v2(td2d->loc, bezt->vec[id]);
+ td2d->loc[2] = 0.0f;
+ td2d->loc2d = bezt->vec[id];
+
+ td->flag = 0;
+ td->loc = td2d->loc;
+ copy_v3_v3(td->center, bezt->vec[1]);
+ copy_v3_v3(td->iloc, td->loc);
+
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext = NULL;
+ td->val = NULL;
+ td->flag |= TD_SELECTED;
+ td->dist = 0.0;
+
+ unit_m3(td->mtx);
+ unit_m3(td->smtx);
+
+ tdpc->id = id;
+ tdpc->pcp = pcp;
+}
+
+static void PaintCurvePointToTransData(PaintCurvePoint *pcp, TransData *td, TransData2D *td2d, TransDataPaintCurve *tdpc)
+{
+ BezTriple *bezt = &pcp->bez;
+
+ if (pcp->bez.f2 == SELECT) {
+ int i;
+ for (i = 0; i < 3; i++) {
+ copy_v2_v2(td2d->loc, bezt->vec[i]);
+ td2d->loc[2] = 0.0f;
+ td2d->loc2d = bezt->vec[i];
+
+ td->flag = 0;
+ td->loc = td2d->loc;
+ copy_v3_v3(td->center, bezt->vec[1]);
+ copy_v3_v3(td->iloc, td->loc);
+
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext = NULL;
+ td->val = NULL;
+ td->flag |= TD_SELECTED;
+ td->dist = 0.0;
+
+ unit_m3(td->mtx);
+ unit_m3(td->smtx);
+
+ tdpc->id = i;
+ tdpc->pcp = pcp;
+
+ td++;
+ td2d++;
+ tdpc++;
+ }
+ }
+ else {
+ if (bezt->f3 & SELECT) {
+ PaintCurveConvertHandle(pcp, 2, td2d, tdpc, td);
+ td2d++;
+ tdpc++;
+ td++;
+ }
+
+ if (bezt->f1 & SELECT) {
+ PaintCurveConvertHandle(pcp, 0, td2d, tdpc, td);
+ }
+ }
+}
+
+static void createTransPaintCurveVerts(bContext *C, TransInfo *t)
+{
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ PaintCurve *pc;
+ PaintCurvePoint *pcp;
+ Brush *br;
+ TransData *td = NULL;
+ TransData2D *td2d = NULL;
+ TransDataPaintCurve *tdpc = NULL;
+ int i;
+ int total = 0;
+
+ t->total = 0;
+
+ if (!paint || !paint->brush || !paint->brush->paint_curve)
+ return;
+
+ br = paint->brush;
+ pc = br->paint_curve;
+
+ for (pcp = pc->points, i = 0; i < pc->tot_points; i++, pcp++) {
+ if (PC_IS_ANY_SEL(pcp)) {
+ if (pcp->bez.f2 & SELECT) {
+ total += 3;
+ continue;
+ }
+ else {
+ if (pcp->bez.f1 & SELECT)
+ total++;
+ if (pcp->bez.f3 & SELECT)
+ total++;
+ }
+ }
+ }
+
+ if (!total)
+ return;
+
+ t->total = total;
+ td2d = t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransData2D");
+ td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransData");
+ tdpc = t->customData = MEM_callocN(t->total * sizeof(TransDataPaintCurve), "TransDataPaintCurve");
+ t->flag |= T_FREE_CUSTOMDATA;
+
+ for (pcp = pc->points, i = 0; i < pc->tot_points; i++, pcp++) {
+ if (PC_IS_ANY_SEL(pcp)) {
+ PaintCurvePointToTransData (pcp, td, td2d, tdpc);
+
+ if (pcp->bez.f2 & SELECT) {
+ td += 3;
+ td2d += 3;
+ tdpc += 3;
+ }
+ else {
+ if (pcp->bez.f1 & SELECT) {
+ td++;
+ td2d++;
+ tdpc++;
+ }
+ if (pcp->bez.f3 & SELECT) {
+ td++;
+ td2d++;
+ tdpc++;
+ }
+ }
+ }
+ }
+}
+
+
+void flushTransPaintCurve(TransInfo *t)
+{
+ int i;
+ TransData2D *td2d = t->data2d;
+ TransDataPaintCurve *tdpc = (TransDataPaintCurve *)t->customData;
+
+ for (i = 0; i < t->total; i++, tdpc++, td2d++) {
+ PaintCurvePoint *pcp = tdpc->pcp;
+ copy_v2_v2(pcp->bez.vec[tdpc->id], td2d->loc);
+ }
+}
+
+
void createTransData(bContext *C, TransInfo *t)
{
Scene *scene = t->scene;
@@ -7059,6 +7230,10 @@ void createTransData(bContext *C, TransInfo *t)
sort_trans_data_dist(t);
}
}
+ else if (t->options & CTX_PAINT_CURVE) {
+ if (!ELEM(t->mode, TFM_SHEAR, TFM_SHRINKFATTEN))
+ createTransPaintCurveVerts(C, t);
+ }
else if (t->obedit) {
createTransUVs(C, t);
if (t->data && (t->flag & T_PROP_EDIT)) {
@@ -7165,7 +7340,7 @@ void createTransData(bContext *C, TransInfo *t)
// XXX active-layer checking isn't done as that should probably be checked through context instead
createTransPose(t, ob);
}
- else if (ob && (ob->mode & OB_MODE_WEIGHT_PAINT)) {
+ else if (ob && (ob->mode & OB_MODE_WEIGHT_PAINT) && !(t->options & CTX_PAINT_CURVE)) {
/* important that ob_armature can be set even when its not selected [#23412]
* lines below just check is also visible */
Object *ob_armature = modifiers_isDeformedByArmature(ob);
@@ -7190,12 +7365,11 @@ void createTransData(bContext *C, TransInfo *t)
sort_trans_data_dist(t);
}
}
- 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.
- *
- * Could use 'OB_MODE_ALL_PAINT' since there are key conflicts,
- * transform + paint isn't well supported. */
+ else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) {
+ if ((t->options & CTX_PAINT_CURVE) && !ELEM(t->mode, TFM_SHEAR, TFM_SHRINKFATTEN)) {
+ t->flag |= T_POINTS | T_2D_EDIT;
+ createTransPaintCurveVerts(C, t);
+ }
}
else {
createTransObject(C, t);
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 7d30af0c144..03f09d3b758 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -38,6 +38,7 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
+#include "DNA_brush_types.h"
#include "DNA_lattice_types.h"
#include "DNA_screen_types.h"
#include "DNA_sequence_types.h"
@@ -75,6 +76,7 @@
#include "BKE_lattice.h"
#include "BKE_nla.h"
#include "BKE_context.h"
+#include "BKE_paint.h"
#include "BKE_sequencer.h"
#include "BKE_editmesh.h"
#include "BKE_tracking.h"
@@ -100,6 +102,7 @@
#include "WM_api.h"
#include "UI_resources.h"
+#include "UI_view2d.h"
#include "transform.h"
@@ -264,7 +267,7 @@ static void animrecord_check_state(Scene *scene, ID *id, wmTimer *animtimer)
ScreenAnimData *sad = (animtimer) ? animtimer->customdata : NULL;
/* sanity checks */
- if (ELEM3(NULL, scene, id, sad))
+ if (ELEM(NULL, scene, id, sad))
return;
/* check if we need a new strip if:
@@ -655,6 +658,9 @@ static void recalcData_image(TransInfo *t)
if (t->options & CTX_MASK) {
recalcData_mask_common(t);
}
+ else if (t->options & CTX_PAINT_CURVE) {
+ flushTransPaintCurve(t);
+ }
else if (t->obedit && t->obedit->type == OB_MESH) {
SpaceImage *sima = t->sa->spacedata.first;
@@ -819,7 +825,7 @@ static void recalcData_objects(TransInfo *t)
}
}
- if (!ELEM3(t->mode, TFM_BONE_ROLL, TFM_BONE_ENVELOPE, TFM_BONESIZE)) {
+ if (!ELEM(t->mode, TFM_BONE_ROLL, TFM_BONE_ENVELOPE, TFM_BONESIZE)) {
/* fix roll */
for (i = 0; i < t->total; i++, td++) {
if (td->extra) {
@@ -967,6 +973,9 @@ void recalcData(TransInfo *t)
else if (t->options & CTX_EDGE) {
recalcData_objects(t);
}
+ else if (t->options & CTX_PAINT_CURVE) {
+ flushTransPaintCurve(t);
+ }
else if (t->spacetype == SPACE_IMAGE) {
recalcData_image(t);
}
@@ -1075,6 +1084,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
ARegion *ar = CTX_wm_region(C);
ScrArea *sa = CTX_wm_area(C);
Object *obedit = CTX_data_edit_object(C);
+ Object *ob = CTX_data_active_object(C);
PropertyRNA *prop;
t->scene = sce;
@@ -1195,11 +1205,18 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
/* exceptional case */
if (t->around == V3D_LOCAL && (t->settings->selectmode & SCE_SELECT_FACE)) {
- if (ELEM3(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) {
+ if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) {
t->options |= CTX_NO_PET;
}
}
+ if (ob && ob->mode & OB_MODE_ALL_PAINT) {
+ Paint *p = BKE_paint_get_active_from_context(C);
+ if (p && p->brush && (p->brush->flag & BRUSH_CURVE)) {
+ t->options |= CTX_PAINT_CURVE;
+ }
+ }
+
/* initialize UV transform from */
if (op && ((prop = RNA_struct_find_property(op->ptr, "correct_uv")))) {
if (RNA_property_is_set(op->ptr, prop)) {
@@ -1228,9 +1245,13 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
else if (sima->mode == SI_MODE_MASK) {
t->options |= CTX_MASK;
}
- else {
- /* image not in uv edit, nor in mask mode, can happen for some tools */
+ else if (sima->mode == SI_MODE_PAINT) {
+ Paint *p = &sce->toolsettings->imapaint.paint;
+ if (p->brush && (p->brush->flag & BRUSH_CURVE)) {
+ t->options |= CTX_PAINT_CURVE;
+ }
}
+ /* image not in uv edit, nor in mask mode, can happen for some tools */
}
else if (t->spacetype == SPACE_NODE) {
// XXX for now, get View2D from the active region
@@ -1411,7 +1432,7 @@ void postTrans(bContext *C, TransInfo *t)
}
if (t->spacetype == SPACE_IMAGE) {
- if (t->options & CTX_MASK) {
+ if (t->options & (CTX_MASK | CTX_PAINT_CURVE)) {
/* pass */
}
else {
@@ -1541,6 +1562,13 @@ void calculateCenterCursor(TransInfo *t, float r_center[3])
invert_m3_m3(imat, mat);
mul_m3_v3(imat, r_center);
}
+ else if (t->options & CTX_PAINT_CURVE) {
+ if (ED_view3d_project_float_global(t->ar, cursor, r_center, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) {
+ r_center[0] = t->ar->winx / 2.0f;
+ r_center[1] = t->ar->winy / 2.0f;
+ }
+ r_center[2] = 0.0f;
+ }
}
void calculateCenterCursor2D(TransInfo *t, float r_center[2])
@@ -1588,6 +1616,12 @@ void calculateCenterCursor2D(TransInfo *t, float r_center[2])
r_center[0] = co[0] * aspx;
r_center[1] = co[1] * aspy;
}
+ else if (t->options & CTX_PAINT_CURVE) {
+ if (t->spacetype == SPACE_IMAGE) {
+ r_center[0] = UI_view2d_view_to_region_x(&t->ar->v2d, cursor[0]);
+ r_center[1] = UI_view2d_view_to_region_y(&t->ar->v2d, cursor[1]);
+ }
+ }
else {
r_center[0] = cursor[0] * aspx;
r_center[1] = cursor[1] * aspy;
@@ -1775,6 +1809,14 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3])
}
}
}
+ else if (t->options & CTX_PAINT_CURVE) {
+ Paint *p = BKE_paint_get_active(t->scene);
+ Brush *br = p->brush;
+ PaintCurve *pc = br->paint_curve;
+ copy_v3_v3(r_center, pc->points[pc->add_index - 1].bez.vec[1]);
+ r_center[2] = 0.0f;
+ ok = true;
+ }
else {
/* object mode */
Scene *scene = t->scene;
diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c
index b1512f7b855..df501ca5da9 100644
--- a/source/blender/editors/transform/transform_manipulator.c
+++ b/source/blender/editors/transform/transform_manipulator.c
@@ -75,6 +75,8 @@
/* local module include */
#include "transform.h"
+#include "GPU_select.h"
+
/* return codes for select, and drawing flags */
#define MAN_TRANS_X (1 << 0)
@@ -878,8 +880,8 @@ static void draw_manipulator_axes_single(View3D *v3d, RegionView3D *rv3d, int co
/* axes */
if (flagx) {
if (is_picksel) {
- if (flagx & MAN_SCALE_X) glLoadName(MAN_SCALE_X);
- else if (flagx & MAN_TRANS_X) glLoadName(MAN_TRANS_X);
+ if (flagx & MAN_SCALE_X) GPU_select_load_id(MAN_SCALE_X);
+ else if (flagx & MAN_TRANS_X) GPU_select_load_id(MAN_TRANS_X);
}
else {
manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0]));
@@ -893,8 +895,8 @@ static void draw_manipulator_axes_single(View3D *v3d, RegionView3D *rv3d, int co
case 1:
if (flagy) {
if (is_picksel) {
- if (flagy & MAN_SCALE_Y) glLoadName(MAN_SCALE_Y);
- else if (flagy & MAN_TRANS_Y) glLoadName(MAN_TRANS_Y);
+ if (flagy & MAN_SCALE_Y) GPU_select_load_id(MAN_SCALE_Y);
+ else if (flagy & MAN_TRANS_Y) GPU_select_load_id(MAN_TRANS_Y);
}
else {
manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1]));
@@ -908,8 +910,8 @@ static void draw_manipulator_axes_single(View3D *v3d, RegionView3D *rv3d, int co
case 2:
if (flagz) {
if (is_picksel) {
- if (flagz & MAN_SCALE_Z) glLoadName(MAN_SCALE_Z);
- else if (flagz & MAN_TRANS_Z) glLoadName(MAN_TRANS_Z);
+ if (flagz & MAN_SCALE_Z) GPU_select_load_id(MAN_SCALE_Z);
+ else if (flagz & MAN_TRANS_Z) GPU_select_load_id(MAN_TRANS_Z);
}
else {
manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2]));
@@ -995,7 +997,7 @@ static void draw_manipulator_rotate(
/* Screen aligned trackball rot circle */
if (drawflags & MAN_ROT_T) {
- if (is_picksel) glLoadName(MAN_ROT_T);
+ if (is_picksel) GPU_select_load_id(MAN_ROT_T);
else UI_ThemeColor(TH_TRANSFORM);
drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f * size, unitmat);
@@ -1003,7 +1005,7 @@ static void draw_manipulator_rotate(
/* Screen aligned view rot circle */
if (drawflags & MAN_ROT_V) {
- if (is_picksel) glLoadName(MAN_ROT_V);
+ if (is_picksel) GPU_select_load_id(MAN_ROT_V);
else UI_ThemeColor(TH_TRANSFORM);
drawcircball(GL_LINE_LOOP, unitmat[3], 1.2f * size, unitmat);
@@ -1082,7 +1084,7 @@ static void draw_manipulator_rotate(
/* Z circle */
if (drawflags & MAN_ROT_Z) {
preOrthoFront(ortho, matt, 2);
- if (is_picksel) glLoadName(MAN_ROT_Z);
+ if (is_picksel) GPU_select_load_id(MAN_ROT_Z);
else manipulator_setcolor(v3d, 'Z', colcode, 255);
drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat);
postOrtho(ortho);
@@ -1090,7 +1092,7 @@ static void draw_manipulator_rotate(
/* X circle */
if (drawflags & MAN_ROT_X) {
preOrthoFront(ortho, matt, 0);
- if (is_picksel) glLoadName(MAN_ROT_X);
+ if (is_picksel) GPU_select_load_id(MAN_ROT_X);
else manipulator_setcolor(v3d, 'X', colcode, 255);
glRotatef(90.0, 0.0, 1.0, 0.0);
drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat);
@@ -1100,7 +1102,7 @@ static void draw_manipulator_rotate(
/* Y circle */
if (drawflags & MAN_ROT_Y) {
preOrthoFront(ortho, matt, 1);
- if (is_picksel) glLoadName(MAN_ROT_Y);
+ if (is_picksel) GPU_select_load_id(MAN_ROT_Y);
else manipulator_setcolor(v3d, 'Y', colcode, 255);
glRotatef(-90.0, 1.0, 0.0, 0.0);
drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat);
@@ -1117,7 +1119,7 @@ static void draw_manipulator_rotate(
/* Z circle */
if (drawflags & MAN_ROT_Z) {
preOrthoFront(ortho, rv3d->twmat, 2);
- if (is_picksel) glLoadName(MAN_ROT_Z);
+ if (is_picksel) GPU_select_load_id(MAN_ROT_Z);
else manipulator_setcolor(v3d, 'Z', colcode, 255);
partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48);
postOrtho(ortho);
@@ -1125,7 +1127,7 @@ static void draw_manipulator_rotate(
/* X circle */
if (drawflags & MAN_ROT_X) {
preOrthoFront(ortho, rv3d->twmat, 0);
- if (is_picksel) glLoadName(MAN_ROT_X);
+ if (is_picksel) GPU_select_load_id(MAN_ROT_X);
else manipulator_setcolor(v3d, 'X', colcode, 255);
glRotatef(90.0, 0.0, 1.0, 0.0);
partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48);
@@ -1135,7 +1137,7 @@ static void draw_manipulator_rotate(
/* Y circle */
if (drawflags & MAN_ROT_Y) {
preOrthoFront(ortho, rv3d->twmat, 1);
- if (is_picksel) glLoadName(MAN_ROT_Y);
+ if (is_picksel) GPU_select_load_id(MAN_ROT_Y);
else manipulator_setcolor(v3d, 'Y', colcode, 255);
glRotatef(-90.0, 1.0, 0.0, 0.0);
partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48);
@@ -1152,7 +1154,7 @@ static void draw_manipulator_rotate(
if (drawflags & MAN_ROT_Z) {
preOrthoFront(ortho, rv3d->twmat, 2);
glPushMatrix();
- if (is_picksel) glLoadName(MAN_ROT_Z);
+ if (is_picksel) GPU_select_load_id(MAN_ROT_Z);
else manipulator_setcolor(v3d, 'Z', colcode, 255);
partial_doughnut(0.7f * cusize, 1.0f, 31, 33, 8, 64);
@@ -1165,7 +1167,7 @@ static void draw_manipulator_rotate(
if (drawflags & MAN_ROT_Y) {
preOrthoFront(ortho, rv3d->twmat, 1);
glPushMatrix();
- if (is_picksel) glLoadName(MAN_ROT_Y);
+ if (is_picksel) GPU_select_load_id(MAN_ROT_Y);
else manipulator_setcolor(v3d, 'Y', colcode, 255);
glRotatef(90.0, 1.0, 0.0, 0.0);
@@ -1180,7 +1182,7 @@ static void draw_manipulator_rotate(
if (drawflags & MAN_ROT_X) {
preOrthoFront(ortho, rv3d->twmat, 0);
glPushMatrix();
- if (is_picksel) glLoadName(MAN_ROT_X);
+ if (is_picksel) GPU_select_load_id(MAN_ROT_X);
else manipulator_setcolor(v3d, 'X', colcode, 255);
glRotatef(-90.0, 0.0, 1.0, 0.0);
@@ -1283,7 +1285,7 @@ static void draw_manipulator_scale(
int shift = 0; // XXX
/* center circle, do not add to selection when shift is pressed (planar constraint) */
- if (is_picksel && shift == 0) glLoadName(MAN_SCALE_C);
+ if (is_picksel && shift == 0) GPU_select_load_id(MAN_SCALE_C);
else manipulator_setcolor(v3d, 'C', colcode, 255);
glPushMatrix();
@@ -1324,7 +1326,7 @@ static void draw_manipulator_scale(
case 0: /* X cube */
if (drawflags & MAN_SCALE_X) {
glTranslatef(dz, 0.0, 0.0);
- if (is_picksel) glLoadName(MAN_SCALE_X);
+ if (is_picksel) GPU_select_load_id(MAN_SCALE_X);
else manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0]));
drawsolidcube(cusize);
glTranslatef(-dz, 0.0, 0.0);
@@ -1333,7 +1335,7 @@ static void draw_manipulator_scale(
case 1: /* Y cube */
if (drawflags & MAN_SCALE_Y) {
glTranslatef(0.0, dz, 0.0);
- if (is_picksel) glLoadName(MAN_SCALE_Y);
+ if (is_picksel) GPU_select_load_id(MAN_SCALE_Y);
else manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1]));
drawsolidcube(cusize);
glTranslatef(0.0, -dz, 0.0);
@@ -1342,7 +1344,7 @@ static void draw_manipulator_scale(
case 2: /* Z cube */
if (drawflags & MAN_SCALE_Z) {
glTranslatef(0.0, 0.0, dz);
- if (is_picksel) glLoadName(MAN_SCALE_Z);
+ if (is_picksel) GPU_select_load_id(MAN_SCALE_Z);
else manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2]));
drawsolidcube(cusize);
glTranslatef(0.0, 0.0, -dz);
@@ -1357,7 +1359,7 @@ static void draw_manipulator_scale(
if (shift) {
glTranslatef(0.0, -dz, 0.0);
- glLoadName(MAN_SCALE_C);
+ GPU_select_load_id(MAN_SCALE_C);
glBegin(GL_POINTS);
glVertex3f(0.0, 0.0, 0.0);
glEnd();
@@ -1419,7 +1421,7 @@ static void draw_manipulator_translate(
glDisable(GL_DEPTH_TEST);
/* center circle, do not add to selection when shift is pressed (planar constraint) */
- if (is_picksel && shift == 0) glLoadName(MAN_TRANS_C);
+ if (is_picksel && shift == 0) GPU_select_load_id(MAN_TRANS_C);
else manipulator_setcolor(v3d, 'C', colcode, 255);
glPushMatrix();
@@ -1432,7 +1434,7 @@ static void draw_manipulator_translate(
glMultMatrixf(rv3d->twmat);
/* axis */
- glLoadName(-1);
+ GPU_select_load_id(-1);
// translate drawn as last, only axis when no combo with scale, or for ghosting
if ((combo & V3D_MANIP_SCALE) == 0 || colcode == MAN_GHOST) {
@@ -1455,7 +1457,7 @@ static void draw_manipulator_translate(
case 0: /* Z Cone */
if (drawflags & MAN_TRANS_Z) {
glTranslatef(0.0, 0.0, dz);
- if (is_picksel) glLoadName(MAN_TRANS_Z);
+ if (is_picksel) GPU_select_load_id(MAN_TRANS_Z);
else manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2]));
draw_cone(qobj, cylen, cywid);
glTranslatef(0.0, 0.0, -dz);
@@ -1464,7 +1466,7 @@ static void draw_manipulator_translate(
case 1: /* X Cone */
if (drawflags & MAN_TRANS_X) {
glTranslatef(dz, 0.0, 0.0);
- if (is_picksel) glLoadName(MAN_TRANS_X);
+ if (is_picksel) GPU_select_load_id(MAN_TRANS_X);
else manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0]));
glRotatef(90.0, 0.0, 1.0, 0.0);
draw_cone(qobj, cylen, cywid);
@@ -1475,7 +1477,7 @@ static void draw_manipulator_translate(
case 2: /* Y Cone */
if (drawflags & MAN_TRANS_Y) {
glTranslatef(0.0, dz, 0.0);
- if (is_picksel) glLoadName(MAN_TRANS_Y);
+ if (is_picksel) GPU_select_load_id(MAN_TRANS_Y);
else manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1]));
glRotatef(-90.0, 1.0, 0.0, 0.0);
draw_cone(qobj, cylen, cywid);
@@ -1523,7 +1525,7 @@ static void draw_manipulator_rotate_cyl(
unit_m4(unitmat);
- if (is_picksel) glLoadName(MAN_ROT_V);
+ if (is_picksel) GPU_select_load_id(MAN_ROT_V);
UI_ThemeColor(TH_TRANSFORM);
drawcircball(GL_LINE_LOOP, unitmat[3], 1.2f * size, unitmat);
@@ -1576,7 +1578,7 @@ static void draw_manipulator_rotate_cyl(
case 0: /* X cylinder */
if (drawflags & MAN_ROT_X) {
glTranslatef(1.0, 0.0, 0.0);
- if (is_picksel) glLoadName(MAN_ROT_X);
+ if (is_picksel) GPU_select_load_id(MAN_ROT_X);
glRotatef(90.0, 0.0, 1.0, 0.0);
manipulator_setcolor(v3d, 'X', colcode, 255);
draw_cylinder(qobj, cylen, cywid);
@@ -1587,7 +1589,7 @@ static void draw_manipulator_rotate_cyl(
case 1: /* Y cylinder */
if (drawflags & MAN_ROT_Y) {
glTranslatef(0.0, 1.0, 0.0);
- if (is_picksel) glLoadName(MAN_ROT_Y);
+ if (is_picksel) GPU_select_load_id(MAN_ROT_Y);
glRotatef(-90.0, 1.0, 0.0, 0.0);
manipulator_setcolor(v3d, 'Y', colcode, 255);
draw_cylinder(qobj, cylen, cywid);
@@ -1598,7 +1600,7 @@ static void draw_manipulator_rotate_cyl(
case 2: /* Z cylinder */
if (drawflags & MAN_ROT_Z) {
glTranslatef(0.0, 0.0, 1.0);
- if (is_picksel) glLoadName(MAN_ROT_Z);
+ if (is_picksel) GPU_select_load_id(MAN_ROT_Z);
manipulator_setcolor(v3d, 'Z', colcode, 255);
draw_cylinder(qobj, cylen, cywid);
glTranslatef(0.0, 0.0, -1.0);
@@ -1710,10 +1712,11 @@ static int manipulator_selectbuf(ScrArea *sa, ARegion *ar, const int mval[2], fl
{
View3D *v3d = sa->spacedata.first;
RegionView3D *rv3d = ar->regiondata;
- rctf rect;
+ rctf rect, selrect;
GLuint buffer[64]; // max 4 items per select, so large enuf
short hits;
const bool is_picksel = true;
+ const bool do_passes = GPU_select_query_check_active();
/* XXX check a bit later on this... (ton) */
extern void view3d_winmatrix_set(ARegion *ar, View3D *v3d, rctf *rect);
@@ -1728,13 +1731,15 @@ static int manipulator_selectbuf(ScrArea *sa, ARegion *ar, const int mval[2], fl
rect.ymin = mval[1] - hotspot;
rect.ymax = mval[1] + hotspot;
+ selrect = rect;
+
view3d_winmatrix_set(ar, v3d, &rect);
mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
- glSelectBuffer(64, buffer);
- glRenderMode(GL_SELECT);
- glInitNames(); /* these two calls whatfor? It doesn't work otherwise */
- glPushName(-2);
+ if (do_passes)
+ GPU_select_begin(buffer, 64, &selrect, GPU_SELECT_NEAREST_FIRST_PASS, 0);
+ else
+ GPU_select_begin(buffer, 64, &selrect, GPU_SELECT_ALL, 0);
/* do the drawing */
if (v3d->twtype & V3D_MANIP_ROTATE) {
@@ -1746,8 +1751,23 @@ static int manipulator_selectbuf(ScrArea *sa, ARegion *ar, const int mval[2], fl
if (v3d->twtype & V3D_MANIP_TRANSLATE)
draw_manipulator_translate(v3d, rv3d, MAN_TRANS_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel);
- glPopName();
- hits = glRenderMode(GL_RENDER);
+ hits = GPU_select_end();
+
+ if (do_passes) {
+ GPU_select_begin(buffer, 64, &selrect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
+
+ /* do the drawing */
+ if (v3d->twtype & V3D_MANIP_ROTATE) {
+ if (G.debug_value == 3) draw_manipulator_rotate_cyl(v3d, rv3d, MAN_ROT_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel);
+ else draw_manipulator_rotate(v3d, rv3d, MAN_ROT_C & rv3d->twdrawflag, v3d->twtype, false, is_picksel);
+ }
+ if (v3d->twtype & V3D_MANIP_SCALE)
+ draw_manipulator_scale(v3d, rv3d, MAN_SCALE_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel);
+ if (v3d->twtype & V3D_MANIP_TRANSLATE)
+ draw_manipulator_translate(v3d, rv3d, MAN_TRANS_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel);
+
+ GPU_select_end();
+ }
view3d_winmatrix_set(ar, v3d, NULL);
mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index ba90926df3b..69d135b8550 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -756,7 +756,7 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3],
if (flag) {
float tvec[3];
if ((v3d->around == V3D_LOCAL) ||
- ELEM3(flag, SEL_F2, SEL_F1 | SEL_F3, SEL_F1 | SEL_F2 | SEL_F3))
+ ELEM(flag, SEL_F2, SEL_F1 | SEL_F3, SEL_F1 | SEL_F2 | SEL_F3))
{
BKE_nurb_bezt_calc_normal(nu, bezt, tvec);
add_v3_v3(normal, tvec);
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 451837fd311..abef2c9fc30 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -117,8 +117,8 @@ int BIF_snappingSupported(Object *obedit)
{
int status = 0;
- if (obedit == NULL || ELEM5(obedit->type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL)) /* only support object mesh, armature, curves */
- {
+ /* only support object mesh, armature, curves */
+ if (obedit == NULL || ELEM(obedit->type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL)) {
status = 1;
}
@@ -337,6 +337,46 @@ void applyProject(TransInfo *t)
mul_m3_v3(td->smtx, tvec);
add_v3_v3(td->loc, tvec);
+
+ if (t->tsnap.align && (t->flag & T_OBJECT)) {
+ /* handle alignment as well */
+ const float *original_normal;
+ float axis[3];
+ float mat[3][3];
+ float angle;
+ float totmat[3][3], smat[3][3];
+ float eul[3], fmat[3][3], quat[4];
+ float obmat[3][3];
+
+ /* In pose mode, we want to align normals with Y axis of bones... */
+ original_normal = td->axismtx[2];
+
+ cross_v3_v3v3(axis, original_normal, no);
+ angle = saacos(dot_v3v3(original_normal, no));
+
+ axis_angle_to_quat(quat, axis, angle);
+
+ quat_to_mat3(mat, quat);
+
+ mul_m3_m3m3(totmat, mat, td->mtx);
+ mul_m3_m3m3(smat, td->smtx, totmat);
+
+ /* calculate the total rotatation in eulers */
+ add_v3_v3v3(eul, td->ext->irot, td->ext->drot); /* we have to correct for delta rot */
+ eulO_to_mat3(obmat, eul, td->ext->rotOrder);
+ /* mat = transform, obmat = object rotation */
+ mul_m3_m3m3(fmat, smat, obmat);
+
+ mat3_to_compatible_eulO(eul, td->ext->rot, td->ext->rotOrder, fmat);
+
+ /* correct back for delta rot */
+ sub_v3_v3v3(eul, eul, td->ext->drot);
+
+ /* and apply */
+ copy_v3_v3(td->ext->rot, eul);
+
+ /* TODO support constraints for rotation too? see ElementRotation */
+ }
}
}
@@ -505,7 +545,7 @@ static void initSnappingMode(TransInfo *t)
/* Edit mode */
if (t->tsnap.applySnap != NULL && // A snapping function actually exist
- (obedit != NULL && ELEM5(obedit->type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL)) ) // Temporary limited to edit mode meshes, armature, curves, mballs
+ (obedit != NULL && ELEM(obedit->type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL)) ) // Temporary limited to edit mode meshes, armature, curves, mballs
{
/* Exclude editmesh if using proportional edit */
if ((obedit->type == OB_MESH) && (t->flag & T_PROP_EDIT)) {
@@ -588,7 +628,7 @@ void initSnapping(TransInfo *t, wmOperator *op)
}
/* use scene defaults only when transform is modal */
else if (t->flag & T_MODAL) {
- if (ELEM3(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE)) {
+ if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE)) {
if (ts->snap_flag & SCE_SNAP) {
t->modifiers |= MOD_SNAP;
}
@@ -658,7 +698,8 @@ static void setSnappingCallback(TransInfo *t)
void addSnapPoint(TransInfo *t)
{
- if (t->tsnap.status & POINT_INIT) {
+ /* Currently only 3D viewport works for snapping points. */
+ if (t->tsnap.status & POINT_INIT && t->spacetype == SPACE_VIEW3D) {
TransSnapPoint *p = MEM_callocN(sizeof(TransSnapPoint), "SnapPoint");
t->tsnap.selectedPoint = p;
@@ -1492,6 +1533,8 @@ static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMes
const float mval[2], float r_loc[3], float r_no[3], float *r_dist_px, float *r_depth, bool do_bb)
{
bool retval = false;
+ const bool do_ray_start_correction = (snap_mode == SCE_SNAP_MODE_FACE && ar &&
+ !((RegionView3D *)ar->regiondata)->is_persp);
int totvert = dm->getNumVerts(dm);
if (totvert > 0) {
@@ -1518,6 +1561,28 @@ static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMes
return retval;
}
}
+ else if (do_ray_start_correction) {
+ /* We *need* a reasonably valid len_diff in this case.
+ * Use BHVTree to find the closest face from ray_start_local.
+ */
+ BVHTreeFromMesh treeData;
+ BVHTreeNearest nearest;
+ len_diff = 0.0f; /* In case BVHTree would fail for some reason... */
+
+ treeData.em_evil = em;
+ bvhtree_from_mesh_faces(&treeData, dm, 0.0f, 2, 6);
+ if (treeData.tree != NULL) {
+ nearest.index = -1;
+ nearest.dist_sq = FLT_MAX;
+ /* Compute and store result. */
+ BLI_bvhtree_find_nearest(treeData.tree, ray_start_local, &nearest,
+ treeData.nearest_callback, &treeData);
+ if (nearest.index != -1) {
+ len_diff = sqrtf(nearest.dist_sq);
+ }
+ }
+ free_bvhtree_from_mesh(&treeData);
+ }
switch (snap_mode) {
case SCE_SNAP_MODE_FACE:
@@ -1529,7 +1594,7 @@ static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMes
* been *inside* boundbox, leading to snap failures (see T38409).
* Note also ar might be null (see T38435), in this case we assume ray_start is ok!
*/
- if (ar && !((RegionView3D *)ar->regiondata)->is_persp) {
+ if (do_ray_start_correction) {
float ray_org_local[3];
copy_v3_v3(ray_org_local, ray_origin);
@@ -2383,6 +2448,9 @@ static void applyGridIncrement(TransInfo *t, float *val, int max_index, float fa
if (t->options & CTX_MASK) {
ED_space_image_get_aspect(t->sa->spacedata.first, asp, asp + 1);
}
+ else if (t->options & CTX_PAINT_CURVE) {
+ asp[0] = asp[1] = 1.0;
+ }
else {
ED_space_image_get_uv_aspect(t->sa->spacedata.first, asp, asp + 1);
}
diff --git a/source/blender/editors/util/ed_transverts.c b/source/blender/editors/util/ed_transverts.c
index 3bd927e5b25..104b628c25a 100644
--- a/source/blender/editors/util/ed_transverts.c
+++ b/source/blender/editors/util/ed_transverts.c
@@ -192,7 +192,7 @@ static void set_mapped_co(void *vuserdata, int index, const float co[3],
bool ED_transverts_check_obedit(Object *obedit)
{
- return (ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL));
+ return (ELEM(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL));
}
void ED_transverts_create_from_obedit(TransVertStore *tvs, Object *obedit, const int mode)
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index 47fbfbe3eba..56b12fcdcda 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -86,7 +86,7 @@ void ED_editors_init(bContext *C)
/* This is called during initialization, so we don't want to store any reports */
ReportList *reports = CTX_wm_reports(C);
- int reports_flag_prev = reports->flag &= ~RPT_STORE;
+ int reports_flag_prev = reports->flag & ~RPT_STORE;
SWAP(int, reports->flag, reports_flag_prev);
diff --git a/source/blender/editors/util/numinput.c b/source/blender/editors/util/numinput.c
index a618ab8419b..fd8f16f5d02 100644
--- a/source/blender/editors/util/numinput.c
+++ b/source/blender/editors/util/numinput.c
@@ -98,7 +98,7 @@ void outputNumInput(NumInput *n, char *str, const float scale_length)
const short i = (n->flag & NUM_AFFECT_ALL && n->idx != j && !(n->val_flag[j] & NUM_EDITED)) ? 0 : j;
/* Use scale_length if needed! */
- const float fac = ELEM3(n->unit_type[j], B_UNIT_LENGTH, B_UNIT_AREA, B_UNIT_VOLUME) ? scale_length : 1.0f;
+ const float fac = ELEM(n->unit_type[j], B_UNIT_LENGTH, B_UNIT_AREA, B_UNIT_VOLUME) ? scale_length : 1.0f;
if (n->val_flag[i] & NUM_EDITED) {
/* Get the best precision, allows us to draw '10.0001' as '10' instead! */
@@ -189,15 +189,15 @@ bool applyNumInput(NumInput *n, float *vec)
if (n->val_flag[i] & NUM_NO_NEGATIVE && val < 0.0f) {
val = 0.0f;
}
- if (n->val_flag[i] & NUM_NO_ZERO && val == 0.0f) {
- val = 0.0001f;
- }
if (n->val_flag[i] & NUM_NO_FRACTION && val != floorf(val)) {
val = floorf(val + 0.5f);
if (n->val_flag[i] & NUM_NO_ZERO && val == 0.0f) {
val = 1.0f;
}
}
+ else if (n->val_flag[i] & NUM_NO_ZERO && val == 0.0f) {
+ val = 0.0001f;
+ }
}
vec[j] = val;
}
@@ -480,7 +480,7 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
default_unit = "r";
/* Use scale_length if needed! */
- if (ELEM3(n->unit_type[idx], B_UNIT_LENGTH, B_UNIT_AREA, B_UNIT_VOLUME))
+ if (ELEM(n->unit_type[idx], B_UNIT_LENGTH, B_UNIT_AREA, B_UNIT_VOLUME))
fac /= sce->unit.scale_length;
BLI_strncpy(str_unit_convert, n->str, sizeof(str_unit_convert));
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index a1cc23f735b..36c96a8d011 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -33,6 +33,7 @@
#include <stdlib.h>
#include <string.h>
+#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
@@ -48,6 +49,8 @@
#include "BKE_DerivedMesh.h"
#include "BKE_editmesh.h"
+#include "BKE_material.h"
+
#include "BKE_scene.h"
#include "BIF_gl.h"
@@ -403,20 +406,28 @@ static void draw_uvs_other_mesh_new_shading(Object *ob, const Image *curimage)
int a;
BLI_bitmap *mat_test_array;
bool ok = false;
+ int totcol = 0;
if (me->mloopuv == NULL) {
return;
}
- if (ob->totcol == 0) {
+ if (curimage && ob->totcol == 0) {
return;
}
- mat_test_array = BLI_BITMAP_NEW_ALLOCA(ob->totcol);
+ totcol = max_ii(ob->totcol, 1);
+ mat_test_array = BLI_BITMAP_NEW_ALLOCA(totcol);
- for (a = 0; a < ob->totcol; a++) {
+ for (a = 0; a < totcol; a++) {
Image *image;
- ED_object_get_active_image(ob, a + 1, &image, NULL, NULL);
+
+ /* if no materials, assume a default material with no image */
+ if (ob->totcol)
+ ED_object_get_active_image(ob, a + 1, &image, NULL, NULL, NULL);
+ else
+ image = NULL;
+
if (image == curimage) {
BLI_BITMAP_ENABLE(mat_test_array, a);
ok = true;
@@ -429,7 +440,7 @@ static void draw_uvs_other_mesh_new_shading(Object *ob, const Image *curimage)
for (a = me->totpoly; a != 0; a--, mpoly++) {
const int mat_nr = mpoly->mat_nr;
- if ((mat_nr >= ob->totcol) ||
+ if ((mat_nr >= totcol) ||
(BLI_BITMAP_TEST(mat_test_array, mat_nr)) == 0)
{
continue;
@@ -471,13 +482,39 @@ static void draw_uvs_texpaint(SpaceImage *sima, Scene *scene, Object *ob)
{
const bool new_shading_nodes = BKE_scene_use_new_shading_nodes(scene);
Image *curimage = ED_space_image(sima);
+ Mesh *me = ob->data;
+ Material *ma;
if (sima->flag & SI_DRAW_OTHER) {
draw_uvs_other(scene, ob, curimage, new_shading_nodes);
}
UI_ThemeColor(TH_UV_SHADOW);
- draw_uvs_other_mesh(ob, curimage, new_shading_nodes);
+
+ ma = give_current_material(ob, ob->actcol);
+
+ if (me->mtpoly) {
+ MPoly *mpoly = me->mpoly;
+ MLoopUV *mloopuv, *mloopuv_base;
+ int a, b;
+ if (!(ma && ma->texpaintslot && ma->texpaintslot[ma->paint_active_slot].uvname &&
+ (mloopuv = CustomData_get_layer_named(&me->ldata, CD_MLOOPUV, ma->texpaintslot[ma->paint_active_slot].uvname))))
+ {
+ mloopuv = me->mloopuv;
+ }
+
+ mloopuv_base = mloopuv;
+
+ for (a = me->totpoly; a > 0; a--, mpoly++) {
+ glBegin(GL_LINE_LOOP);
+
+ mloopuv = mloopuv_base + mpoly->loopstart;
+ for (b = 0; b < mpoly->totloop; b++, mloopuv++) {
+ glVertex2fv(mloopuv->uv);
+ }
+ glEnd();
+ }
+ }
}
#ifdef USE_EDBM_LOOPTRIS
@@ -540,7 +577,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
if (new_shading_nodes) {
if (efa_act) {
- ED_object_get_active_image(obedit, efa_act->mat_nr + 1, &curimage, NULL, NULL);
+ ED_object_get_active_image(obedit, efa_act->mat_nr + 1, &curimage, NULL, NULL, NULL);
}
else {
curimage = ima;
@@ -914,7 +951,7 @@ void draw_uvedit_main(SpaceImage *sima, ARegion *ar, Scene *scene, Object *obedi
ToolSettings *toolsettings = scene->toolsettings;
int show_uvedit, show_uvshadow, show_texpaint_uvshadow;
- show_texpaint_uvshadow = (obact && obact->type == OB_MESH && obact->mode == OB_MODE_TEXTURE_PAINT);
+ show_texpaint_uvshadow = ED_space_image_show_texpaint(sima, obact);
show_uvedit = ED_space_image_show_uvedit(sima, obedit);
show_uvshadow = ED_space_image_show_uvshadow(sima, obedit);
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index 6cf34d9f93f..0d8b5a524b6 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -137,21 +137,24 @@ static bool is_image_texture_node(bNode *node)
}
bool ED_object_get_active_image(Object *ob, int mat_nr,
- Image **r_ima, ImageUser **r_iuser, bNode **r_node)
+ Image **r_ima, ImageUser **r_iuser, bNode **r_node, bNodeTree **r_ntree)
{
Material *ma = give_current_material(ob, mat_nr);
- bNode *node = (ma && ma->use_nodes) ? nodeGetActiveTexture(ma->nodetree) : NULL;
+ bNodeTree *ntree = (ma && ma->use_nodes) ? ma->nodetree : NULL;
+ bNode *node = (ntree) ? nodeGetActiveTexture(ntree) : NULL;
if (node && is_image_texture_node(node)) {
if (r_ima) *r_ima = (Image *)node->id;
if (r_iuser) *r_iuser = NULL;
if (r_node) *r_node = node;
+ if (r_ntree) *r_ntree = ntree;
return true;
}
if (r_ima) *r_ima = NULL;
if (r_iuser) *r_iuser = NULL;
if (r_node) *r_node = node;
+ if (r_ntree) *r_ntree = ntree;
return false;
}
@@ -3827,7 +3830,8 @@ static void UV_OT_reveal(wmOperatorType *ot)
static int uv_set_2d_cursor_poll(bContext *C)
{
return ED_operator_uvedit_space_image(C) ||
- ED_space_image_maskedit_poll(C);
+ ED_space_image_maskedit_poll(C) ||
+ ED_space_image_paint_curve(C);
}
static int uv_set_2d_cursor_exec(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 21e7bb00204..335d8e6589e 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -201,7 +201,7 @@ void uvedit_get_aspect(Scene *scene, Object *ob, BMEditMesh *em, float *aspx, fl
if (efa) {
if (BKE_scene_use_new_shading_nodes(scene)) {
- ED_object_get_active_image(ob, efa->mat_nr + 1, &ima, NULL, NULL);
+ ED_object_get_active_image(ob, efa->mat_nr + 1, &ima, NULL, NULL, NULL);
}
else {
MTexPoly *tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
@@ -938,7 +938,7 @@ static void uv_map_rotation_matrix(float result[4][4], RegionView3D *rv3d, Objec
rotup[0][0] = 1.0f / radius;
/* calculate transforms*/
- mul_serie_m4(result, rotup, rotside, viewmatrix, rotobj, NULL, NULL, NULL, NULL);
+ mul_m4_series(result, rotup, rotside, viewmatrix, rotobj);
}
static void uv_map_transform(bContext *C, wmOperator *op, float center[3], float rotmat[4][4])