Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / sculpt_paint / paint_utils.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/sculpt_paint/paint_utils.c
29  *  \ingroup edsculpt
30  */
31
32 #include <math.h>
33 #include <stdlib.h>
34
35 #include "DNA_mesh_types.h"
36 #include "DNA_meshdata_types.h"
37 #include "DNA_object_types.h"
38 #include "DNA_material_types.h"
39
40 #include "DNA_scene_types.h"
41 #include "DNA_brush_types.h"
42
43 #include "BLI_math.h"
44 #include "BLI_math_color.h"
45 #include "BLI_utildefines.h"
46 #include "BLI_listbase.h"
47 #include "BLI_rect.h"
48
49 #include "BLT_translation.h"
50
51 #include "BKE_brush.h"
52 #include "BKE_context.h"
53 #include "BKE_customdata.h"
54 #include "BKE_image.h"
55 #include "BKE_material.h"
56 #include "BKE_object.h"
57 #include "BKE_paint.h"
58 #include "BKE_report.h"
59
60 #include "DEG_depsgraph.h"
61 #include "DEG_depsgraph_query.h"
62
63 #include "RNA_access.h"
64 #include "RNA_define.h"
65
66 #include "GPU_glew.h"
67 #include "GPU_matrix.h"
68 #include "GPU_state.h"
69
70 #include "IMB_colormanagement.h"
71 #include "IMB_imbuf_types.h"
72 #include "IMB_imbuf.h"
73
74 #include "RE_render_ext.h"
75
76 #include "ED_view3d.h"
77 #include "ED_screen.h"
78
79 #include "BLI_sys_types.h"
80 #include "ED_mesh.h" /* for face mask functions */
81
82 #include "WM_api.h"
83 #include "WM_types.h"
84
85 #include "paint_intern.h"
86
87 /* Convert the object-space axis-aligned bounding box (expressed as
88  * its minimum and maximum corners) into a screen-space rectangle,
89  * returns zero if the result is empty */
90 bool paint_convert_bb_to_rect(
91         rcti *rect,
92         const float bb_min[3],
93         const float bb_max[3],
94         const ARegion *ar,
95         RegionView3D *rv3d,
96         Object *ob)
97 {
98         float projection_mat[4][4];
99         int i, j, k;
100
101         BLI_rcti_init_minmax(rect);
102
103         /* return zero if the bounding box has non-positive volume */
104         if (bb_min[0] > bb_max[0] || bb_min[1] > bb_max[1] || bb_min[2] > bb_max[2])
105                 return 0;
106
107         ED_view3d_ob_project_mat_get(rv3d, ob, projection_mat);
108
109         for (i = 0; i < 2; ++i) {
110                 for (j = 0; j < 2; ++j) {
111                         for (k = 0; k < 2; ++k) {
112                                 float vec[3], proj[2];
113                                 int proj_i[2];
114                                 vec[0] = i ? bb_min[0] : bb_max[0];
115                                 vec[1] = j ? bb_min[1] : bb_max[1];
116                                 vec[2] = k ? bb_min[2] : bb_max[2];
117                                 /* convert corner to screen space */
118                                 ED_view3d_project_float_v2_m4(ar, vec, proj, projection_mat);
119                                 /* expand 2D rectangle */
120
121                                 /* we could project directly to int? */
122                                 proj_i[0] = proj[0];
123                                 proj_i[1] = proj[1];
124
125                                 BLI_rcti_do_minmax_v(rect, proj_i);
126                         }
127                 }
128         }
129
130         /* return false if the rectangle has non-positive area */
131         return rect->xmin < rect->xmax && rect->ymin < rect->ymax;
132 }
133
134 /* Get four planes in object-space that describe the projection of
135  * screen_rect from screen into object-space (essentially converting a
136  * 2D screens-space bounding box into four 3D planes) */
137 void paint_calc_redraw_planes(
138         float planes[4][4],
139         const ARegion *ar,
140         Object *ob,
141         const rcti *screen_rect)
142 {
143         BoundBox bb;
144         rcti rect;
145
146         /* use some extra space just in case */
147         rect = *screen_rect;
148         rect.xmin -= 2;
149         rect.xmax += 2;
150         rect.ymin -= 2;
151         rect.ymax += 2;
152
153         ED_view3d_clipping_calc(&bb, planes, ar, ob, &rect);
154         negate_m4(planes);
155 }
156
157 float paint_calc_object_space_radius(
158         ViewContext *vc, const float center[3],
159         float pixel_radius)
160 {
161         Object *ob = vc->obact;
162         float delta[3], scale, loc[3];
163         const float mval_f[2] = {pixel_radius, 0.0f};
164         float zfac;
165
166         mul_v3_m4v3(loc, ob->obmat, center);
167
168         zfac = ED_view3d_calc_zfac(vc->rv3d, loc, NULL);
169         ED_view3d_win_to_delta(vc->ar, mval_f, delta, zfac);
170
171         scale = fabsf(mat4_to_scale(ob->obmat));
172         scale = (scale == 0.0f) ? 1.0f : scale;
173
174         return len_v3(delta) / scale;
175 }
176
177 float paint_get_tex_pixel(const MTex *mtex, float u, float v, struct ImagePool *pool, int thread)
178 {
179         float intensity, rgba[4];
180         float co[3] = {u, v, 0.0f};
181
182         externtex(mtex, co, &intensity,
183                   rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
184
185         return intensity;
186 }
187
188 void paint_get_tex_pixel_col(
189         const MTex *mtex, float u, float v, float rgba[4], struct ImagePool *pool,
190         int thread, bool convert_to_linear, struct ColorSpace *colorspace)
191 {
192         float co[3] = {u, v, 0.0f};
193         int hasrgb;
194         float intensity;
195
196         hasrgb = externtex(mtex, co, &intensity,
197                            rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
198         if (!hasrgb) {
199                 rgba[0] = intensity;
200                 rgba[1] = intensity;
201                 rgba[2] = intensity;
202                 rgba[3] = 1.0f;
203         }
204
205         if (convert_to_linear)
206                 IMB_colormanagement_colorspace_to_scene_linear_v3(rgba, colorspace);
207
208         linearrgb_to_srgb_v3_v3(rgba, rgba);
209
210         CLAMP(rgba[0], 0.0f, 1.0f);
211         CLAMP(rgba[1], 0.0f, 1.0f);
212         CLAMP(rgba[2], 0.0f, 1.0f);
213         CLAMP(rgba[3], 0.0f, 1.0f);
214 }
215
216 void paint_stroke_operator_properties(wmOperatorType *ot)
217 {
218         static const EnumPropertyItem stroke_mode_items[] = {
219                 {BRUSH_STROKE_NORMAL, "NORMAL", 0, "Normal", "Apply brush normally"},
220                 {BRUSH_STROKE_INVERT, "INVERT", 0, "Invert", "Invert action of brush for duration of stroke"},
221                 {BRUSH_STROKE_SMOOTH, "SMOOTH", 0, "Smooth", "Switch brush to smooth mode for duration of stroke"},
222                 {0}
223         };
224
225         PropertyRNA *prop;
226
227         prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
228         RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
229
230         RNA_def_enum(ot->srna, "mode", stroke_mode_items, BRUSH_STROKE_NORMAL,
231                      "Stroke Mode",
232                      "Action taken when a paint stroke is made");
233
234 }
235
236 /* 3D Paint */
237
238 static void imapaint_project(float matrix[4][4], const float co[3], float pco[4])
239 {
240         copy_v3_v3(pco, co);
241         pco[3] = 1.0f;
242
243         mul_m4_v4(matrix, pco);
244 }
245
246 static void imapaint_tri_weights(
247         float matrix[4][4], GLint view[4],
248         const float v1[3], const float v2[3], const float v3[3],
249         const float co[2], float w[3])
250 {
251         float pv1[4], pv2[4], pv3[4], h[3], divw;
252         float wmat[3][3], invwmat[3][3];
253
254         /* compute barycentric coordinates */
255
256         /* project the verts */
257         imapaint_project(matrix, v1, pv1);
258         imapaint_project(matrix, v2, pv2);
259         imapaint_project(matrix, v3, pv3);
260
261         /* do inverse view mapping, see gluProject man page */
262         h[0] = (co[0] - view[0]) * 2.0f / view[2] - 1.0f;
263         h[1] = (co[1] - view[1]) * 2.0f / view[3] - 1.0f;
264         h[2] = 1.0f;
265
266         /* solve for (w1,w2,w3)/perspdiv in:
267          * h * perspdiv = Project * Model * (w1 * v1 + w2 * v2 + w3 * v3) */
268
269         wmat[0][0] = pv1[0];  wmat[1][0] = pv2[0];  wmat[2][0] = pv3[0];
270         wmat[0][1] = pv1[1];  wmat[1][1] = pv2[1];  wmat[2][1] = pv3[1];
271         wmat[0][2] = pv1[3];  wmat[1][2] = pv2[3];  wmat[2][2] = pv3[3];
272
273         invert_m3_m3(invwmat, wmat);
274         mul_m3_v3(invwmat, h);
275
276         copy_v3_v3(w, h);
277
278         /* w is still divided by perspdiv, make it sum to one */
279         divw = w[0] + w[1] + w[2];
280         if (divw != 0.0f) {
281                 mul_v3_fl(w, 1.0f / divw);
282         }
283 }
284
285 /* compute uv coordinates of mouse in face */
286 static void imapaint_pick_uv(Mesh *me_eval, Scene *scene, Object *ob_eval, unsigned int faceindex, const int xy[2], float uv[2])
287 {
288         const int tottri = me_eval->runtime.looptris.len;
289         int i, findex;
290         float p[2], w[3], absw, minabsw;
291         float matrix[4][4], proj[4][4];
292         GLint view[4];
293         const eImagePaintMode mode = scene->toolsettings->imapaint.mode;
294         const MLoopTri *lt = me_eval->runtime.looptris.array;
295         const MVert *mvert = me_eval->mvert;
296         const MPoly *mpoly = me_eval->mpoly;
297         const MLoop *mloop = me_eval->mloop;
298         const int *index_mp_to_orig  = CustomData_get_layer(&me_eval->pdata, CD_ORIGINDEX);
299
300         /* get the needed opengl matrices */
301         GPU_viewport_size_get_i(view);
302         gpuGetModelViewMatrix(matrix);
303         gpuGetProjectionMatrix(proj);
304         view[0] = view[1] = 0;
305         mul_m4_m4m4(matrix, matrix, ob_eval->obmat);
306         mul_m4_m4m4(matrix, proj, matrix);
307
308         minabsw = 1e10;
309         uv[0] = uv[1] = 0.0;
310
311         /* test all faces in the derivedmesh with the original index of the picked face */
312         /* face means poly here, not triangle, indeed */
313         for (i = 0; i < tottri; i++, lt++) {
314                 findex = index_mp_to_orig ? index_mp_to_orig[lt->poly] : lt->poly;
315
316                 if (findex == faceindex) {
317                         const MLoopUV *mloopuv;
318                         const MPoly *mp = &mpoly[lt->poly];
319                         const MLoopUV *tri_uv[3];
320                         float  tri_co[3][3];
321
322                         for (int j = 3; j--; ) {
323                                 copy_v3_v3(tri_co[j], mvert[mloop[lt->tri[j]].v].co);
324                         }
325
326                         if (mode == IMAGEPAINT_MODE_MATERIAL) {
327                                 const Material *ma;
328                                 const TexPaintSlot *slot;
329
330                                 ma = give_current_material(ob_eval, mp->mat_nr);
331                                 slot = &ma->texpaintslot[ma->paint_active_slot];
332
333                                 if (!(slot && slot->uvname &&
334                                       (mloopuv = CustomData_get_layer_named(&me_eval->ldata, CD_MLOOPUV, slot->uvname))))
335                                 {
336                                         mloopuv = CustomData_get_layer(&me_eval->ldata, CD_MLOOPUV);
337                                 }
338                         }
339                         else {
340                                 mloopuv = CustomData_get_layer(&me_eval->ldata, CD_MLOOPUV);
341                         }
342
343                         tri_uv[0] = &mloopuv[lt->tri[0]];
344                         tri_uv[1] = &mloopuv[lt->tri[1]];
345                         tri_uv[2] = &mloopuv[lt->tri[2]];
346
347                         p[0] = xy[0];
348                         p[1] = xy[1];
349
350                         imapaint_tri_weights(matrix, view, UNPACK3(tri_co), p, w);
351                         absw = fabsf(w[0]) + fabsf(w[1]) + fabsf(w[2]);
352                         if (absw < minabsw) {
353                                 uv[0] = tri_uv[0]->uv[0] * w[0] + tri_uv[1]->uv[0] * w[1] + tri_uv[2]->uv[0] * w[2];
354                                 uv[1] = tri_uv[0]->uv[1] * w[0] + tri_uv[1]->uv[1] * w[1] + tri_uv[2]->uv[1] * w[2];
355                                 minabsw = absw;
356                         }
357                 }
358         }
359 }
360
361 /* returns 0 if not found, otherwise 1 */
362 static int imapaint_pick_face(
363         ViewContext *vc, const int mval[2],
364         unsigned int *r_index, unsigned int totpoly)
365 {
366         if (totpoly == 0)
367                 return 0;
368
369         /* sample only on the exact position */
370         *r_index = ED_view3d_backbuf_sample(vc, mval[0], mval[1]);
371
372         if ((*r_index) == 0 || (*r_index) > (unsigned int)totpoly) {
373                 return 0;
374         }
375
376         (*r_index)--;
377
378         return 1;
379 }
380
381
382 static Image *imapaint_face_image(Object *ob, Mesh *me, int face_index)
383 {
384         Image *ima;
385         MPoly *mp = me->mpoly + face_index;
386         Material *ma = give_current_material(ob, mp->mat_nr + 1);
387         ima = ma && ma->texpaintslot ? ma->texpaintslot[ma->paint_active_slot].ima : NULL;
388
389         return ima;
390 }
391
392 /* Uses symm to selectively flip any axis of a coordinate. */
393 void flip_v3_v3(float out[3], const float in[3], const char symm)
394 {
395         if (symm & PAINT_SYMM_X)
396                 out[0] = -in[0];
397         else
398                 out[0] = in[0];
399         if (symm & PAINT_SYMM_Y)
400                 out[1] = -in[1];
401         else
402                 out[1] = in[1];
403         if (symm & PAINT_SYMM_Z)
404                 out[2] = -in[2];
405         else
406                 out[2] = in[2];
407 }
408
409 void flip_qt_qt(float out[4], const float in[4], const char symm)
410 {
411         float axis[3], angle;
412
413         quat_to_axis_angle(axis, &angle, in);
414         normalize_v3(axis);
415
416         if (symm & PAINT_SYMM_X) {
417                 axis[0] *= -1.0f;
418                 angle *= -1.0f;
419         }
420         if (symm & PAINT_SYMM_Y) {
421                 axis[1] *= -1.0f;
422                 angle *= -1.0f;
423         }
424         if (symm & PAINT_SYMM_Z) {
425                 axis[2] *= -1.0f;
426                 angle *= -1.0f;
427         }
428
429         axis_angle_normalized_to_quat(out, axis, angle);
430 }
431
432 /* used for both 3d view and image window */
433 void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_proj, bool use_palette)
434 {
435         Scene *scene = CTX_data_scene(C);
436         Depsgraph *depsgraph = CTX_data_depsgraph(C);
437         Paint *paint = BKE_paint_get_active_from_context(C);
438         Palette *palette = BKE_paint_palette(paint);
439         PaletteColor *color = NULL;
440         Brush *br = BKE_paint_brush(BKE_paint_get_active_from_context(C));
441         unsigned int col;
442         const unsigned char *cp;
443
444         CLAMP(x, 0, ar->winx);
445         CLAMP(y, 0, ar->winy);
446
447         if (use_palette) {
448                 if (!palette) {
449                         palette = BKE_palette_add(CTX_data_main(C), "Palette");
450                         BKE_paint_palette_set(paint, palette);
451                 }
452
453                 color = BKE_palette_color_add(palette);
454                 palette->active_color = BLI_listbase_count(&palette->colors) - 1;
455         }
456
457
458         if (CTX_wm_view3d(C) && texpaint_proj) {
459                 /* first try getting a colour directly from the mesh faces if possible */
460                 ViewLayer *view_layer = CTX_data_view_layer(C);
461                 Object *ob = OBACT(view_layer);
462                 Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
463                 bool sample_success = false;
464                 ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
465                 bool use_material = (imapaint->mode == IMAGEPAINT_MODE_MATERIAL);
466
467                 if (ob) {
468                         Mesh *me = (Mesh *)ob->data;
469                         Mesh *me_eval = BKE_object_get_evaluated_mesh(depsgraph, ob);  /* Or shall we just do ob_eval->mesh_eval ? */
470
471                         ViewContext vc;
472                         const int mval[2] = {x, y};
473                         unsigned int faceindex;
474                         unsigned int totpoly = me->totpoly;
475
476                         if (CustomData_has_layer(&me_eval->ldata, CD_MLOOPUV)) {
477                                 ED_view3d_viewcontext_init(C, &vc);
478
479                                 view3d_operator_needs_opengl(C);
480
481                                 if (imapaint_pick_face(&vc, mval, &faceindex, totpoly)) {
482                                         Image *image;
483
484                                         if (use_material)
485                                                 image = imapaint_face_image(ob_eval, me_eval, faceindex);
486                                         else
487                                                 image = imapaint->canvas;
488
489                                         if (image) {
490                                                 ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
491                                                 if (ibuf && ibuf->rect) {
492                                                         float uv[2];
493                                                         float u, v;
494                                                         imapaint_pick_uv(me_eval, scene, ob_eval, faceindex, mval, uv);
495                                                         sample_success = true;
496
497                                                         u = fmodf(uv[0], 1.0f);
498                                                         v = fmodf(uv[1], 1.0f);
499
500                                                         if (u < 0.0f) u += 1.0f;
501                                                         if (v < 0.0f) v += 1.0f;
502
503                                                         u = u * ibuf->x;
504                                                         v = v * ibuf->y;
505
506                                                         if (ibuf->rect_float) {
507                                                                 float rgba_f[4];
508                                                                 bilinear_interpolation_color_wrap(ibuf, NULL, rgba_f, u, v);
509                                                                 straight_to_premul_v4(rgba_f);
510                                                                 if (use_palette) {
511                                                                         linearrgb_to_srgb_v3_v3(color->rgb, rgba_f);
512                                                                 }
513                                                                 else {
514                                                                         linearrgb_to_srgb_v3_v3(rgba_f, rgba_f);
515                                                                         BKE_brush_color_set(scene, br, rgba_f);
516                                                                 }
517                                                         }
518                                                         else {
519                                                                 unsigned char rgba[4];
520                                                                 bilinear_interpolation_color_wrap(ibuf, rgba, NULL, u, v);
521                                                                 if (use_palette) {
522                                                                         rgb_uchar_to_float(color->rgb, rgba);
523                                                                 }
524                                                                 else {
525                                                                         float rgba_f[3];
526                                                                         rgb_uchar_to_float(rgba_f, rgba);
527                                                                         BKE_brush_color_set(scene, br, rgba_f);
528                                                                 }
529                                                         }
530                                                 }
531
532                                                 BKE_image_release_ibuf(image, ibuf, NULL);
533                                         }
534                                 }
535                         }
536                 }
537
538                 if (!sample_success) {
539                         glReadBuffer(GL_FRONT);
540                         glReadPixels(x + ar->winrct.xmin, y + ar->winrct.ymin, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
541                         glReadBuffer(GL_BACK);
542                 }
543                 else
544                         return;
545         }
546         else {
547                 glReadBuffer(GL_FRONT);
548                 glReadPixels(x + ar->winrct.xmin, y + ar->winrct.ymin, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
549                 glReadBuffer(GL_BACK);
550         }
551         cp = (unsigned char *)&col;
552
553         if (use_palette) {
554                 rgb_uchar_to_float(color->rgb, cp);
555         }
556         else {
557                 float rgba_f[3];
558                 rgb_uchar_to_float(rgba_f, cp);
559                 BKE_brush_color_set(scene, br, rgba_f);
560         }
561 }
562
563 static int brush_curve_preset_exec(bContext *C, wmOperator *op)
564 {
565         Brush *br = BKE_paint_brush(BKE_paint_get_active_from_context(C));
566
567         if (br) {
568                 Scene *scene = CTX_data_scene(C);
569                 ViewLayer *view_layer = CTX_data_view_layer(C);
570                 BKE_brush_curve_preset(br, RNA_enum_get(op->ptr, "shape"));
571                 BKE_paint_invalidate_cursor_overlay(scene, view_layer, br->curve);
572         }
573
574         return OPERATOR_FINISHED;
575 }
576
577 static bool brush_curve_preset_poll(bContext *C)
578 {
579         Brush *br = BKE_paint_brush(BKE_paint_get_active_from_context(C));
580
581         return br && br->curve;
582 }
583
584 void BRUSH_OT_curve_preset(wmOperatorType *ot)
585 {
586         PropertyRNA *prop;
587         static const EnumPropertyItem prop_shape_items[] = {
588                 {CURVE_PRESET_SHARP, "SHARP", 0, "Sharp", ""},
589                 {CURVE_PRESET_SMOOTH, "SMOOTH", 0, "Smooth", ""},
590                 {CURVE_PRESET_MAX, "MAX", 0, "Max", ""},
591                 {CURVE_PRESET_LINE, "LINE", 0, "Line", ""},
592                 {CURVE_PRESET_ROUND, "ROUND", 0, "Round", ""},
593                 {CURVE_PRESET_ROOT, "ROOT", 0, "Root", ""},
594                 {0, NULL, 0, NULL, NULL}};
595
596         ot->name = "Preset";
597         ot->description = "Set brush shape";
598         ot->idname = "BRUSH_OT_curve_preset";
599
600         ot->exec = brush_curve_preset_exec;
601         ot->poll = brush_curve_preset_poll;
602
603         prop = RNA_def_enum(ot->srna, "shape", prop_shape_items, CURVE_PRESET_SMOOTH, "Mode", "");
604         RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
605 }
606
607
608 /* face-select ops */
609 static int paint_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
610 {
611         paintface_select_linked(C, CTX_data_active_object(C), NULL, true);
612         ED_region_tag_redraw(CTX_wm_region(C));
613         return OPERATOR_FINISHED;
614 }
615
616 void PAINT_OT_face_select_linked(wmOperatorType *ot)
617 {
618         ot->name = "Select Linked";
619         ot->description = "Select linked faces";
620         ot->idname = "PAINT_OT_face_select_linked";
621
622         ot->exec = paint_select_linked_exec;
623         ot->poll = facemask_paint_poll;
624
625         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
626 }
627
628 static int paint_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
629 {
630         const bool select = !RNA_boolean_get(op->ptr, "deselect");
631         view3d_operator_needs_opengl(C);
632         paintface_select_linked(C, CTX_data_active_object(C), event->mval, select);
633         ED_region_tag_redraw(CTX_wm_region(C));
634         return OPERATOR_FINISHED;
635 }
636
637 void PAINT_OT_face_select_linked_pick(wmOperatorType *ot)
638 {
639         ot->name = "Select Linked Pick";
640         ot->description = "Select linked faces under the cursor";
641         ot->idname = "PAINT_OT_face_select_linked_pick";
642
643         ot->invoke = paint_select_linked_pick_invoke;
644         ot->poll = facemask_paint_poll;
645
646         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
647
648         RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect rather than select items");
649 }
650
651
652 static int face_select_all_exec(bContext *C, wmOperator *op)
653 {
654         Object *ob = CTX_data_active_object(C);
655         paintface_deselect_all_visible(ob, RNA_enum_get(op->ptr, "action"), true);
656         ED_region_tag_redraw(CTX_wm_region(C));
657         return OPERATOR_FINISHED;
658 }
659
660
661 void PAINT_OT_face_select_all(wmOperatorType *ot)
662 {
663         ot->name = "(De)select All";
664         ot->description = "Change selection for all faces";
665         ot->idname = "PAINT_OT_face_select_all";
666
667         ot->exec = face_select_all_exec;
668         ot->poll = facemask_paint_poll;
669
670         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
671
672         WM_operator_properties_select_all(ot);
673 }
674
675
676 static int vert_select_all_exec(bContext *C, wmOperator *op)
677 {
678         Object *ob = CTX_data_active_object(C);
679         paintvert_deselect_all_visible(ob, RNA_enum_get(op->ptr, "action"), true);
680         ED_region_tag_redraw(CTX_wm_region(C));
681         return OPERATOR_FINISHED;
682 }
683
684
685 void PAINT_OT_vert_select_all(wmOperatorType *ot)
686 {
687         ot->name = "(De)select All";
688         ot->description = "Change selection for all vertices";
689         ot->idname = "PAINT_OT_vert_select_all";
690
691         ot->exec = vert_select_all_exec;
692         ot->poll = vert_paint_poll;
693
694         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
695
696         WM_operator_properties_select_all(ot);
697 }
698
699
700 static int vert_select_ungrouped_exec(bContext *C, wmOperator *op)
701 {
702         Object *ob = CTX_data_active_object(C);
703         Mesh *me = ob->data;
704
705         if (BLI_listbase_is_empty(&ob->defbase) || (me->dvert == NULL)) {
706                 BKE_report(op->reports, RPT_ERROR, "No weights/vertex groups on object");
707                 return OPERATOR_CANCELLED;
708         }
709
710         paintvert_select_ungrouped(ob, RNA_boolean_get(op->ptr, "extend"), true);
711         ED_region_tag_redraw(CTX_wm_region(C));
712         return OPERATOR_FINISHED;
713 }
714
715 void PAINT_OT_vert_select_ungrouped(wmOperatorType *ot)
716 {
717         /* identifiers */
718         ot->name = "Select Ungrouped";
719         ot->idname = "PAINT_OT_vert_select_ungrouped";
720         ot->description = "Select vertices without a group";
721
722         /* api callbacks */
723         ot->exec = vert_select_ungrouped_exec;
724         ot->poll = vert_paint_poll;
725
726         /* flags */
727         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
728
729         RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
730 }
731
732 static int face_select_hide_exec(bContext *C, wmOperator *op)
733 {
734         const bool unselected = RNA_boolean_get(op->ptr, "unselected");
735         Object *ob = CTX_data_active_object(C);
736         paintface_hide(ob, unselected);
737         ED_region_tag_redraw(CTX_wm_region(C));
738         return OPERATOR_FINISHED;
739 }
740
741 void PAINT_OT_face_select_hide(wmOperatorType *ot)
742 {
743         ot->name = "Face Select Hide";
744         ot->description = "Hide selected faces";
745         ot->idname = "PAINT_OT_face_select_hide";
746
747         ot->exec = face_select_hide_exec;
748         ot->poll = facemask_paint_poll;
749
750         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
751
752         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected objects");
753 }
754
755 static int face_select_reveal_exec(bContext *C, wmOperator *op)
756 {
757         const bool select = RNA_boolean_get(op->ptr, "select");
758         Object *ob = CTX_data_active_object(C);
759         paintface_reveal(ob, select);
760         ED_region_tag_redraw(CTX_wm_region(C));
761         return OPERATOR_FINISHED;
762 }
763
764 void PAINT_OT_face_select_reveal(wmOperatorType *ot)
765 {
766         ot->name = "Face Select Reveal";
767         ot->description = "Reveal hidden faces";
768         ot->idname = "PAINT_OT_face_select_reveal";
769
770         ot->exec = face_select_reveal_exec;
771         ot->poll = facemask_paint_poll;
772
773         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
774
775         RNA_def_boolean(ot->srna, "select", true, "Select", "");
776 }