f34d0ff3f7b1ac1beb2c4e072373a24fa695c6d5
[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 "BLF_translation.h"
50
51 #include "BKE_scene.h"
52 #include "BKE_brush.h"
53 #include "BKE_context.h"
54 #include "BKE_DerivedMesh.h"
55 #include "BKE_material.h"
56 #include "BKE_image.h"
57 #include "BKE_paint.h"
58 #include "BKE_report.h"
59 #include "BKE_image.h"
60
61 #include "RNA_access.h"
62 #include "RNA_define.h"
63
64 #include "BIF_gl.h"
65 #include "BIF_glutil.h"
66
67 #include "IMB_colormanagement.h"
68 #include "IMB_imbuf_types.h"
69
70 #include "RE_shader_ext.h"
71 #include "RE_render_ext.h"
72
73 #include "ED_view3d.h"
74 #include "ED_screen.h"
75 #include "ED_uvedit.h"
76
77 #include "IMB_imbuf_types.h"
78 #include "IMB_imbuf.h"
79
80 #include "BLI_sys_types.h"
81 #include "ED_mesh.h" /* for face mask functions */
82
83 #include "WM_api.h"
84 #include "WM_types.h"
85
86 #include "paint_intern.h"
87
88 /* Convert the object-space axis-aligned bounding box (expressed as
89  * its minimum and maximum corners) into a screen-space rectangle,
90  * returns zero if the result is empty */
91 bool paint_convert_bb_to_rect(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(float planes[4][4],
138                               const ARegion *ar,
139                               RegionView3D *rv3d,
140                               Object *ob,
141                               const rcti *screen_rect)
142 {
143         BoundBox bb;
144         bglMats mats;
145         rcti rect;
146
147         memset(&bb, 0, sizeof(BoundBox));
148         view3d_get_transformation(ar, rv3d, ob, &mats);
149
150         /* use some extra space just in case */
151         rect = *screen_rect;
152         rect.xmin -= 2;
153         rect.xmax += 2;
154         rect.ymin -= 2;
155         rect.ymax += 2;
156
157         ED_view3d_clipping_calc(&bb, planes, &mats, &rect);
158         negate_m4(planes);
159 }
160
161 float paint_calc_object_space_radius(ViewContext *vc, const float center[3],
162                                      float pixel_radius)
163 {
164         Object *ob = vc->obact;
165         float delta[3], scale, loc[3];
166         const float mval_f[2] = {pixel_radius, 0.0f};
167         float zfac;
168
169         mul_v3_m4v3(loc, ob->obmat, center);
170
171         zfac = ED_view3d_calc_zfac(vc->rv3d, loc, NULL);
172         ED_view3d_win_to_delta(vc->ar, mval_f, delta, zfac);
173
174         scale = fabsf(mat4_to_scale(ob->obmat));
175         scale = (scale == 0.0f) ? 1.0f : scale;
176
177         return len_v3(delta) / scale;
178 }
179
180 float paint_get_tex_pixel(MTex *mtex, float u, float v, struct ImagePool *pool, int thread)
181 {
182         float intensity, rgba[4];
183         float co[3] = {u, v, 0.0f};
184
185         externtex(mtex, co, &intensity,
186                   rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool);
187
188         return intensity;
189 }
190
191 void paint_get_tex_pixel_col(MTex *mtex, float u, float v, float rgba[4], struct ImagePool *pool, int thread, bool convert_to_linear, struct ColorSpace *colorspace)
192 {
193         float co[3] = {u, v, 0.0f};
194         int hasrgb;
195         float intensity;
196
197         hasrgb = externtex(mtex, co, &intensity,
198                            rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool);
199         if (!hasrgb) {
200                 rgba[0] = intensity;
201                 rgba[1] = intensity;
202                 rgba[2] = intensity;
203                 rgba[3] = 1.0f;
204         }
205
206         if (convert_to_linear)
207                 IMB_colormanagement_colorspace_to_scene_linear_v3(rgba, colorspace);
208
209         linearrgb_to_srgb_v3_v3(rgba, rgba);
210
211         CLAMP(rgba[0], 0.0f, 1.0f);
212         CLAMP(rgba[1], 0.0f, 1.0f);
213         CLAMP(rgba[2], 0.0f, 1.0f);
214         CLAMP(rgba[3], 0.0f, 1.0f);
215 }
216
217 void paint_stroke_operator_properties(wmOperatorType *ot)
218 {
219         static EnumPropertyItem stroke_mode_items[] = {
220                 {BRUSH_STROKE_NORMAL, "NORMAL", 0, "Normal", "Apply brush normally"},
221                 {BRUSH_STROKE_INVERT, "INVERT", 0, "Invert", "Invert action of brush for duration of stroke"},
222                 {BRUSH_STROKE_SMOOTH, "SMOOTH", 0, "Smooth", "Switch brush to smooth mode for duration of stroke"},
223                 {0}
224         };
225
226         RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
227
228         RNA_def_enum(ot->srna, "mode", stroke_mode_items, BRUSH_STROKE_NORMAL, 
229                      "Stroke Mode",
230                      "Action taken when a paint stroke is made");
231         
232 }
233
234 /* 3D Paint */
235
236 static void imapaint_project(float matrix[4][4], const float co[3], float pco[4])
237 {
238         copy_v3_v3(pco, co);
239         pco[3] = 1.0f;
240
241         mul_m4_v4(matrix, pco);
242 }
243
244 static void imapaint_tri_weights(float matrix[4][4], GLint view[4],
245                                  const float v1[3], const float v2[3], const float v3[3],
246                                  const float co[2], float w[3])
247 {
248         float pv1[4], pv2[4], pv3[4], h[3], divw;
249         float wmat[3][3], invwmat[3][3];
250
251         /* compute barycentric coordinates */
252
253         /* project the verts */
254         imapaint_project(matrix, v1, pv1);
255         imapaint_project(matrix, v2, pv2);
256         imapaint_project(matrix, v3, pv3);
257
258         /* do inverse view mapping, see gluProject man page */
259         h[0] = (co[0] - view[0]) * 2.0f / view[2] - 1.0f;
260         h[1] = (co[1] - view[1]) * 2.0f / view[3] - 1.0f;
261         h[2] = 1.0f;
262
263         /* solve for (w1,w2,w3)/perspdiv in:
264          * h * perspdiv = Project * Model * (w1 * v1 + w2 * v2 + w3 * v3) */
265
266         wmat[0][0] = pv1[0];  wmat[1][0] = pv2[0];  wmat[2][0] = pv3[0];
267         wmat[0][1] = pv1[1];  wmat[1][1] = pv2[1];  wmat[2][1] = pv3[1];
268         wmat[0][2] = pv1[3];  wmat[1][2] = pv2[3];  wmat[2][2] = pv3[3];
269
270         invert_m3_m3(invwmat, wmat);
271         mul_m3_v3(invwmat, h);
272
273         copy_v3_v3(w, h);
274
275         /* w is still divided by perspdiv, make it sum to one */
276         divw = w[0] + w[1] + w[2];
277         if (divw != 0.0f) {
278                 mul_v3_fl(w, 1.0f / divw);
279         }
280 }
281
282 /* compute uv coordinates of mouse in face */
283 static void imapaint_pick_uv(Scene *scene, Object *ob, unsigned int faceindex, const int xy[2], float uv[2])
284 {
285         DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
286         MTFace *tf_base, *tf;
287         Material *ma;
288         TexPaintSlot *slot;
289         int numfaces = dm->getNumTessFaces(dm), a, findex;
290         float p[2], w[3], absw, minabsw;
291         MFace mf;
292         MVert mv[4];
293         float matrix[4][4], proj[4][4];
294         GLint view[4];
295
296         /* compute barycentric coordinates */
297
298         /* double lookup */
299         const int *index_mf_to_mpoly = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
300         const int *index_mp_to_orig  = dm->getPolyDataArray(dm, CD_ORIGINDEX);
301         if (index_mf_to_mpoly == NULL) {
302                 index_mp_to_orig = NULL;
303         }
304
305         /* get the needed opengl matrices */
306         glGetIntegerv(GL_VIEWPORT, view);
307         glGetFloatv(GL_MODELVIEW_MATRIX,  (float *)matrix);
308         glGetFloatv(GL_PROJECTION_MATRIX, (float *)proj);
309         view[0] = view[1] = 0;
310         mul_m4_m4m4(matrix, matrix, ob->obmat);
311         mul_m4_m4m4(matrix, proj, matrix);
312
313         minabsw = 1e10;
314         uv[0] = uv[1] = 0.0;
315
316         /* test all faces in the derivedmesh with the original index of the picked face */
317         for (a = 0; a < numfaces; a++) {
318                 findex = index_mf_to_mpoly ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a) : a;
319
320                 if (findex == faceindex) {
321                         dm->getTessFace(dm, a, &mf);
322
323                         ma = dm->mat[mf.mat_nr];
324                         slot = &ma->texpaintslot[ma->paint_active_slot];
325
326                         dm->getVert(dm, mf.v1, &mv[0]);
327                         dm->getVert(dm, mf.v2, &mv[1]);
328                         dm->getVert(dm, mf.v3, &mv[2]);
329                         if (mf.v4)
330                                 dm->getVert(dm, mf.v4, &mv[3]);
331
332                         if (!(slot && slot->uvname && (tf_base = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, slot->uvname))))
333                                 tf_base = CustomData_get_layer(&dm->faceData, CD_MTFACE);
334
335                         tf = &tf_base[a];
336
337                         p[0] = xy[0];
338                         p[1] = xy[1];
339
340                         if (mf.v4) {
341                                 /* the triangle with the largest absolute values is the one
342                                  * with the most negative weights */
343                                 imapaint_tri_weights(matrix, view, mv[0].co, mv[1].co, mv[3].co, p, w);
344                                 absw = fabsf(w[0]) + fabsf(w[1]) + fabsf(w[2]);
345                                 if (absw < minabsw) {
346                                         uv[0] = tf->uv[0][0] * w[0] + tf->uv[1][0] * w[1] + tf->uv[3][0] * w[2];
347                                         uv[1] = tf->uv[0][1] * w[0] + tf->uv[1][1] * w[1] + tf->uv[3][1] * w[2];
348                                         minabsw = absw;
349                                 }
350
351                                 imapaint_tri_weights(matrix, view, mv[1].co, mv[2].co, mv[3].co, p, w);
352                                 absw = fabsf(w[0]) + fabsf(w[1]) + fabsf(w[2]);
353                                 if (absw < minabsw) {
354                                         uv[0] = tf->uv[1][0] * w[0] + tf->uv[2][0] * w[1] + tf->uv[3][0] * w[2];
355                                         uv[1] = tf->uv[1][1] * w[0] + tf->uv[2][1] * w[1] + tf->uv[3][1] * w[2];
356                                         minabsw = absw;
357                                 }
358                         }
359                         else {
360                                 imapaint_tri_weights(matrix, view, mv[0].co, mv[1].co, mv[2].co, p, w);
361                                 absw = fabsf(w[0]) + fabsf(w[1]) + fabsf(w[2]);
362                                 if (absw < minabsw) {
363                                         uv[0] = tf->uv[0][0] * w[0] + tf->uv[1][0] * w[1] + tf->uv[2][0] * w[2];
364                                         uv[1] = tf->uv[0][1] * w[0] + tf->uv[1][1] * w[1] + tf->uv[2][1] * w[2];
365                                         minabsw = absw;
366                                 }
367                         }
368                 }
369         }
370
371         dm->release(dm);
372 }
373
374 /* returns 0 if not found, otherwise 1 */
375 static int imapaint_pick_face(ViewContext *vc, const int mval[2], unsigned int *r_index, unsigned int totface)
376 {
377         if (totface == 0)
378                 return 0;
379
380         /* sample only on the exact position */
381         *r_index = view3d_sample_backbuf(vc, mval[0], mval[1]);
382
383         if ((*r_index) == 0 || (*r_index) > (unsigned int)totface) {
384                 return 0;
385         }
386
387         (*r_index)--;
388
389         return 1;
390 }
391
392
393 static Image *imapaint_face_image(DerivedMesh *dm, int face_index)
394 {
395         Image *ima;
396         MFace *mf = dm->getTessFaceArray(dm) + face_index;
397         Material *ma = dm->mat[mf->mat_nr];
398         ima = ma->texpaintslot[ma->paint_active_slot].ima;
399
400         return ima;
401 }
402
403 /* Uses symm to selectively flip any axis of a coordinate. */
404 void flip_v3_v3(float out[3], const float in[3], const char symm)
405 {
406         if (symm & PAINT_SYMM_X)
407                 out[0] = -in[0];
408         else
409                 out[0] = in[0];
410         if (symm & PAINT_SYMM_Y)
411                 out[1] = -in[1];
412         else
413                 out[1] = in[1];
414         if (symm & PAINT_SYMM_Z)
415                 out[2] = -in[2];
416         else
417                 out[2] = in[2];
418 }
419
420 /* used for both 3d view and image window */
421 void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_proj, bool use_palette)
422 {
423         Scene *scene = CTX_data_scene(C);
424         Paint *paint = BKE_paint_get_active_from_context(C);
425         Palette *palette = BKE_paint_palette(paint);
426         PaletteColor *color;
427         Brush *br = BKE_paint_brush(BKE_paint_get_active_from_context(C));
428         unsigned int col;
429         const unsigned char *cp;
430
431         CLAMP(x, 0, ar->winx);
432         CLAMP(y, 0, ar->winy);
433         
434         if (use_palette) {
435                 if (!palette) {
436                         palette = BKE_palette_add(CTX_data_main(C), "Palette");
437                         BKE_paint_palette_set(paint, palette);
438                 }
439
440                 color = BKE_palette_color_add(palette);
441         }
442
443
444         if (CTX_wm_view3d(C) && texpaint_proj) {
445                 /* first try getting a colour directly from the mesh faces if possible */
446                 Object *ob = OBACT;
447                 bool sample_success = false;
448                 ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
449                 bool use_material = (imapaint->mode == IMAGEPAINT_MODE_MATERIAL);
450
451                 if (ob) {
452                         DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
453
454                         ViewContext vc;
455                         const int mval[2] = {x, y};
456                         unsigned int faceindex;
457                         unsigned int totface = dm->getNumTessFaces(dm);
458                         MTFace *dm_mtface = dm->getTessFaceDataArray(dm, CD_MTFACE);
459
460                         DM_update_materials(dm, ob);
461
462                         if (dm_mtface) {
463                                 view3d_set_viewcontext(C, &vc);
464
465                                 view3d_operator_needs_opengl(C);
466
467                                 if (imapaint_pick_face(&vc, mval, &faceindex, totface)) {
468                                         Image *image;
469                                         
470                                         if (use_material) 
471                                                 image = imapaint_face_image(dm, faceindex);
472                                         else
473                                                 image = imapaint->canvas;
474                                         
475                                         if (image) {
476                                                 ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
477                                                 if (ibuf && ibuf->rect) {
478                                                         float uv[2];
479                                                         float u, v;
480                                                         imapaint_pick_uv(scene, ob, faceindex, mval, uv);
481                                                         sample_success = true;
482                                                         
483                                                         u = fmodf(uv[0], 1.0f);
484                                                         v = fmodf(uv[1], 1.0f);
485                                                         
486                                                         if (u < 0.0f) u += 1.0f;
487                                                         if (v < 0.0f) v += 1.0f;
488                                                         
489                                                         u = u * ibuf->x - 0.5f;
490                                                         v = v * ibuf->y - 0.5f;
491                                                         
492                                                         if (ibuf->rect_float) {
493                                                                 float rgba_f[4];
494                                                                 bilinear_interpolation_color_wrap(ibuf, NULL, rgba_f, u, v);
495                                                                 straight_to_premul_v4(rgba_f);
496                                                                 if (use_palette) {
497                                                                         linearrgb_to_srgb_v3_v3(color->rgb, rgba_f);
498                                                                 }
499                                                                 else {
500                                                                         linearrgb_to_srgb_v3_v3(rgba_f, rgba_f);
501                                                                         BKE_brush_color_set(scene, br, rgba_f);
502                                                                 }
503                                                         }
504                                                         else {
505                                                                 unsigned char rgba[4];
506                                                                 bilinear_interpolation_color_wrap(ibuf, rgba, NULL, u, v);
507                                                                 if (use_palette) {
508                                                                         rgb_uchar_to_float(color->rgb, rgba);
509                                                                 }
510                                                                 else {
511                                                                         float rgba_f[3];
512                                                                         rgb_uchar_to_float(rgba_f, rgba);
513                                                                         BKE_brush_color_set(scene, br, rgba_f);
514                                                                 }
515                                                         }
516                                                 }
517                                         
518                                                 BKE_image_release_ibuf(image, ibuf, NULL);
519                                         }
520                                 }
521                         }
522                         dm->release(dm);
523                 }
524
525                 if (!sample_success) {
526                         glReadBuffer(GL_FRONT);
527                         glReadPixels(x + ar->winrct.xmin, y + ar->winrct.ymin, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
528                         glReadBuffer(GL_BACK);
529                 }
530                 else
531                         return;
532         }
533         else {
534                 glReadBuffer(GL_FRONT);
535                 glReadPixels(x + ar->winrct.xmin, y + ar->winrct.ymin, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
536                 glReadBuffer(GL_BACK);
537         }
538         cp = (unsigned char *)&col;
539         
540         if (use_palette) {
541                 rgb_uchar_to_float(color->rgb, cp);
542         }
543         else {
544                 float rgba_f[3];
545                 rgb_uchar_to_float(rgba_f, cp);
546                 BKE_brush_color_set(scene, br, rgba_f);
547         }
548 }
549
550 static int brush_curve_preset_exec(bContext *C, wmOperator *op)
551 {
552         Brush *br = BKE_paint_brush(BKE_paint_get_active_from_context(C));
553
554         if (br) {
555                 Scene *scene = CTX_data_scene(C);
556                 BKE_brush_curve_preset(br, RNA_enum_get(op->ptr, "shape"));
557                 BKE_paint_invalidate_cursor_overlay(scene, br->curve);
558         }
559
560         return OPERATOR_FINISHED;
561 }
562
563 static int brush_curve_preset_poll(bContext *C)
564 {
565         Brush *br = BKE_paint_brush(BKE_paint_get_active_from_context(C));
566
567         return br && br->curve;
568 }
569
570 void BRUSH_OT_curve_preset(wmOperatorType *ot)
571 {
572         PropertyRNA *prop;
573         static EnumPropertyItem prop_shape_items[] = {
574                 {CURVE_PRESET_SHARP, "SHARP", 0, "Sharp", ""},
575                 {CURVE_PRESET_SMOOTH, "SMOOTH", 0, "Smooth", ""},
576                 {CURVE_PRESET_MAX, "MAX", 0, "Max", ""},
577                 {CURVE_PRESET_LINE, "LINE", 0, "Line", ""},
578                 {CURVE_PRESET_ROUND, "ROUND", 0, "Round", ""},
579                 {CURVE_PRESET_ROOT, "ROOT", 0, "Root", ""},
580                 {0, NULL, 0, NULL, NULL}};
581
582         ot->name = "Preset";
583         ot->description = "Set brush shape";
584         ot->idname = "BRUSH_OT_curve_preset";
585
586         ot->exec = brush_curve_preset_exec;
587         ot->poll = brush_curve_preset_poll;
588
589         prop = RNA_def_enum(ot->srna, "shape", prop_shape_items, CURVE_PRESET_SMOOTH, "Mode", "");
590         RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
591 }
592
593
594 /* face-select ops */
595 static int paint_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
596 {
597         paintface_select_linked(C, CTX_data_active_object(C), NULL, true);
598         ED_region_tag_redraw(CTX_wm_region(C));
599         return OPERATOR_FINISHED;
600 }
601
602 void PAINT_OT_face_select_linked(wmOperatorType *ot)
603 {
604         ot->name = "Select Linked";
605         ot->description = "Select linked faces";
606         ot->idname = "PAINT_OT_face_select_linked";
607
608         ot->exec = paint_select_linked_exec;
609         ot->poll = facemask_paint_poll;
610
611         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
612 }
613
614 static int paint_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
615 {
616         const bool select = !RNA_boolean_get(op->ptr, "deselect");
617         view3d_operator_needs_opengl(C);
618         paintface_select_linked(C, CTX_data_active_object(C), event->mval, select);
619         ED_region_tag_redraw(CTX_wm_region(C));
620         return OPERATOR_FINISHED;
621 }
622
623 void PAINT_OT_face_select_linked_pick(wmOperatorType *ot)
624 {
625         ot->name = "Select Linked Pick";
626         ot->description = "Select linked faces under the cursor";
627         ot->idname = "PAINT_OT_face_select_linked_pick";
628
629         ot->invoke = paint_select_linked_pick_invoke;
630         ot->poll = facemask_paint_poll;
631
632         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
633
634         RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect rather than select items");
635 }
636
637
638 static int face_select_all_exec(bContext *C, wmOperator *op)
639 {
640         Object *ob = CTX_data_active_object(C);
641         paintface_deselect_all_visible(ob, RNA_enum_get(op->ptr, "action"), true);
642         ED_region_tag_redraw(CTX_wm_region(C));
643         return OPERATOR_FINISHED;
644 }
645
646
647 void PAINT_OT_face_select_all(wmOperatorType *ot)
648 {
649         ot->name = "(De)select All";
650         ot->description = "Change selection for all faces";
651         ot->idname = "PAINT_OT_face_select_all";
652
653         ot->exec = face_select_all_exec;
654         ot->poll = facemask_paint_poll;
655
656         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
657
658         WM_operator_properties_select_all(ot);
659 }
660
661
662 static int vert_select_all_exec(bContext *C, wmOperator *op)
663 {
664         Object *ob = CTX_data_active_object(C);
665         paintvert_deselect_all_visible(ob, RNA_enum_get(op->ptr, "action"), true);
666         ED_region_tag_redraw(CTX_wm_region(C));
667         return OPERATOR_FINISHED;
668 }
669
670
671 void PAINT_OT_vert_select_all(wmOperatorType *ot)
672 {
673         ot->name = "(De)select All";
674         ot->description = "Change selection for all vertices";
675         ot->idname = "PAINT_OT_vert_select_all";
676
677         ot->exec = vert_select_all_exec;
678         ot->poll = vert_paint_poll;
679
680         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
681
682         WM_operator_properties_select_all(ot);
683 }
684
685
686 static int vert_select_ungrouped_exec(bContext *C, wmOperator *op)
687 {
688         Object *ob = CTX_data_active_object(C);
689         Mesh *me = ob->data;
690
691         if (BLI_listbase_is_empty(&ob->defbase) || (me->dvert == NULL)) {
692                 BKE_report(op->reports, RPT_ERROR, "No weights/vertex groups on object");
693                 return OPERATOR_CANCELLED;
694         }
695
696         paintvert_select_ungrouped(ob, RNA_boolean_get(op->ptr, "extend"), true);
697         ED_region_tag_redraw(CTX_wm_region(C));
698         return OPERATOR_FINISHED;
699 }
700
701 void PAINT_OT_vert_select_ungrouped(wmOperatorType *ot)
702 {
703         /* identifiers */
704         ot->name = "Select Ungrouped";
705         ot->idname = "PAINT_OT_vert_select_ungrouped";
706         ot->description = "Select vertices without a group";
707
708         /* api callbacks */
709         ot->exec = vert_select_ungrouped_exec;
710         ot->poll = vert_paint_poll;
711
712         /* flags */
713         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
714
715         RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
716 }
717
718 static int face_select_hide_exec(bContext *C, wmOperator *op)
719 {
720         const bool unselected = RNA_boolean_get(op->ptr, "unselected");
721         Object *ob = CTX_data_active_object(C);
722         paintface_hide(ob, unselected);
723         ED_region_tag_redraw(CTX_wm_region(C));
724         return OPERATOR_FINISHED;
725 }
726
727 void PAINT_OT_face_select_hide(wmOperatorType *ot)
728 {
729         ot->name = "Face Select Hide";
730         ot->description = "Hide selected faces";
731         ot->idname = "PAINT_OT_face_select_hide";
732
733         ot->exec = face_select_hide_exec;
734         ot->poll = facemask_paint_poll;
735
736         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
737
738         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected objects");
739 }
740
741 static int face_select_reveal_exec(bContext *C, wmOperator *UNUSED(op))
742 {
743         Object *ob = CTX_data_active_object(C);
744         paintface_reveal(ob);
745         ED_region_tag_redraw(CTX_wm_region(C));
746         return OPERATOR_FINISHED;
747 }
748
749 void PAINT_OT_face_select_reveal(wmOperatorType *ot)
750 {
751         ot->name = "Face Select Reveal";
752         ot->description = "Reveal hidden faces";
753         ot->idname = "PAINT_OT_face_select_reveal";
754
755         ot->exec = face_select_reveal_exec;
756         ot->poll = facemask_paint_poll;
757
758         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
759
760         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected objects");
761 }