Blender V5.0
paint_utils.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cmath>
10
11#include "DNA_mesh_types.h"
12#include "DNA_object_types.h"
13
14#include "DNA_brush_types.h"
15#include "DNA_scene_types.h"
16
17#include "BLI_listbase.h"
18#include "BLI_math_color.h"
19#include "BLI_math_matrix.h"
20#include "BLI_math_matrix.hh"
21#include "BLI_rect.h"
22
23#include "BLT_translation.hh"
24
25#include "BKE_brush.hh"
26#include "BKE_bvhutils.hh"
27#include "BKE_colortools.hh"
28#include "BKE_context.hh"
29#include "BKE_layer.hh"
30#include "BKE_mesh.hh"
31#include "BKE_mesh_sample.hh"
32#include "BKE_paint.hh"
33#include "BKE_report.hh"
34
35#include "RNA_access.hh"
36#include "RNA_define.hh"
37#include "RNA_prototypes.hh"
38
39#include "RE_texture.h"
40
41#include "ED_screen.hh"
42#include "ED_select_utils.hh"
43#include "ED_view3d.hh"
44
45#include "ED_mesh.hh" /* for face mask functions */
46
47#include "WM_api.hh"
48#include "WM_types.hh"
49
50#include "paint_intern.hh"
51
53 const float bb_min[3],
54 const float bb_max[3],
55 const ARegion &region,
56 const RegionView3D &rv3d,
57 const Object &ob)
58{
59 int i, j, k;
60
62
63 /* return zero if the bounding box has non-positive volume */
64 if (bb_min[0] > bb_max[0] || bb_min[1] > bb_max[1] || bb_min[2] > bb_max[2]) {
65 return false;
66 }
67
68 const blender::float4x4 projection = ED_view3d_ob_project_mat_get(&rv3d, &ob);
69
70 for (i = 0; i < 2; i++) {
71 for (j = 0; j < 2; j++) {
72 for (k = 0; k < 2; k++) {
73 float vec[3];
74 int proj_i[2];
75 vec[0] = i ? bb_min[0] : bb_max[0];
76 vec[1] = j ? bb_min[1] : bb_max[1];
77 vec[2] = k ? bb_min[2] : bb_max[2];
78 /* convert corner to screen space */
79 const blender::float2 proj = ED_view3d_project_float_v2_m4(&region, vec, projection);
80 /* expand 2D rectangle */
81
82 /* we could project directly to int? */
83 proj_i[0] = proj[0];
84 proj_i[1] = proj[1];
85
86 BLI_rcti_do_minmax_v(rect, proj_i);
87 }
88 }
89 }
90
91 /* return false if the rectangle has non-positive area */
92 return rect->xmin < rect->xmax && rect->ymin < rect->ymax;
93}
94
96 const blender::float3 &center,
97 const float pixel_radius)
98{
99 Object *ob = vc.obact;
100 float delta[3], scale, loc[3];
101 const float xy_delta[2] = {pixel_radius, 0.0f};
102
103 mul_v3_m4v3(loc, ob->object_to_world().ptr(), center);
104
105 const float zfac = ED_view3d_calc_zfac(vc.rv3d, loc);
106 ED_view3d_win_to_delta(vc.region, xy_delta, zfac, delta);
107
108 scale = fabsf(mat4_to_scale(ob->object_to_world().ptr()));
109 scale = (scale == 0.0f) ? 1.0f : scale;
110
111 return len_v3(delta) / scale;
112}
113
114bool paint_get_tex_pixel(const MTex *mtex,
115 float u,
116 float v,
117 ImagePool *pool,
118 int thread,
119 /* Return arguments. */
120 float *r_intensity,
121 float r_rgba[4])
122{
123 const float co[3] = {u, v, 0.0f};
124 float intensity;
125 const bool has_rgb = RE_texture_evaluate(
126 mtex, co, thread, pool, false, false, &intensity, r_rgba);
127 *r_intensity = intensity;
128
129 if (!has_rgb) {
130 r_rgba[0] = intensity;
131 r_rgba[1] = intensity;
132 r_rgba[2] = intensity;
133 r_rgba[3] = 1.0f;
134 }
135
136 return has_rgb;
137}
138
140{
141 static const EnumPropertyItem stroke_mode_items[] = {
142 {BRUSH_STROKE_NORMAL, "NORMAL", 0, "Regular", "Apply brush normally"},
144 "INVERT",
145 0,
146 "Invert",
147 "Invert action of brush for duration of stroke"},
149 "SMOOTH",
150 0,
151 "Smooth",
152 "Switch brush to smooth mode for duration of stroke"},
154 "ERASE",
155 0,
156 "Erase",
157 "Switch brush to erase mode for duration of stroke"},
158 {0},
159 };
160
161 PropertyRNA *prop;
162
163 prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
165
166 prop = RNA_def_enum(ot->srna,
167 "mode",
168 stroke_mode_items,
170 "Stroke Mode",
171 "Action taken when a paint stroke is made");
174
175 /* TODO: Pen flip logic should likely be combined into the stroke mode logic instead of being
176 * an entirely separate concept. */
177 prop = RNA_def_boolean(
178 ot->srna, "pen_flip", false, "Pen Flip", "Whether a tablet's eraser mode is being used");
180}
181
182/* face-select ops */
189
191{
192 ot->name = "Select Linked";
193 ot->description = "Select linked faces";
194 ot->idname = "PAINT_OT_face_select_linked";
195
197 ot->poll = facemask_paint_poll;
198
200}
201
212
214{
215 ot->name = "Select Linked Pick";
216 ot->description = "Select linked faces under the cursor";
217 ot->idname = "PAINT_OT_face_select_linked_pick";
218
220 ot->poll = facemask_paint_poll;
221
223
224 RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Deselect rather than select items");
225}
226
236
238{
239 ot->name = "(De)select All";
240 ot->description = "Change selection for all faces";
241 ot->idname = "PAINT_OT_face_select_all";
242
243 ot->exec = face_select_all_exec;
244 ot->poll = facemask_paint_poll;
245
247
249}
250
252{
254 Mesh *mesh = BKE_mesh_from_object(ob);
255 if (mesh == nullptr || mesh->faces_num == 0) {
256 return OPERATOR_CANCELLED;
257 }
258
259 const bool face_step = RNA_boolean_get(op->ptr, "face_step");
261 paintface_flush_flags(C, ob, true, false);
262
264 return OPERATOR_FINISHED;
265}
266
268{
269 ot->name = "Select More";
270 ot->description = "Select Faces connected to existing selection";
271 ot->idname = "PAINT_OT_face_select_more";
272
274 ot->poll = facemask_paint_poll;
275
277
279 ot->srna, "face_step", true, "Face Step", "Also select faces that only touch on a corner");
280}
281
283{
285 Mesh *mesh = BKE_mesh_from_object(ob);
286 if (mesh == nullptr || mesh->faces_num == 0) {
287 return OPERATOR_CANCELLED;
288 }
289
290 const bool face_step = RNA_boolean_get(op->ptr, "face_step");
292 paintface_flush_flags(C, ob, true, false);
293
295 return OPERATOR_FINISHED;
296}
297
299{
300 ot->name = "Select Less";
301 ot->description = "Deselect Faces connected to existing selection";
302 ot->idname = "PAINT_OT_face_select_less";
303
305 ot->poll = facemask_paint_poll;
306
308
310 ot->srna, "face_step", true, "Face Step", "Also deselect faces that only touch on a corner");
311}
312
314 wmOperator *op,
315 const wmEvent *event)
316{
317 const bool select = RNA_boolean_get(op->ptr, "select");
318 const bool extend = RNA_boolean_get(op->ptr, "extend");
319 if (!extend) {
321 }
325 return OPERATOR_FINISHED;
326}
327
329{
330 ot->name = "Select Loop";
331 ot->description = "Select face loop under the cursor";
332 ot->idname = "PAINT_OT_face_select_loop";
333
335 ot->poll = facemask_paint_poll;
336
338
339 RNA_def_boolean(ot->srna, "select", true, "Select", "If false, faces will be deselected");
340 RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
341}
342
351
353{
354 ot->name = "(De)select All";
355 ot->description = "Change selection for all vertices";
356 ot->idname = "PAINT_OT_vert_select_all";
357
358 ot->exec = vert_select_all_exec;
359 ot->poll = vert_paint_poll;
360
362
364}
365
367{
369 Mesh *mesh = static_cast<Mesh *>(ob->data);
370
371 if (BLI_listbase_is_empty(&mesh->vertex_group_names) || mesh->deform_verts().is_empty()) {
372 BKE_report(op->reports, RPT_ERROR, "No weights/vertex groups on object");
373 return OPERATOR_CANCELLED;
374 }
375
376 paintvert_select_ungrouped(ob, RNA_boolean_get(op->ptr, "extend"), true);
379 return OPERATOR_FINISHED;
380}
381
383{
384 /* identifiers */
385 ot->name = "Select Ungrouped";
386 ot->idname = "PAINT_OT_vert_select_ungrouped";
387 ot->description = "Select vertices without a group";
388
389 /* API callbacks. */
391 ot->poll = vert_paint_poll;
392
393 /* flags */
395
396 RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
397}
398
405
407{
408 ot->name = "Select Linked Vertices";
409 ot->description = "Select linked vertices";
410 ot->idname = "PAINT_OT_vert_select_linked";
411
413 ot->poll = vert_paint_poll;
414
416}
417
429
431{
432 ot->name = "Select Linked Vertices Pick";
433 ot->description = "Select linked vertices under the cursor";
434 ot->idname = "PAINT_OT_vert_select_linked_pick";
435
437 ot->poll = vert_paint_poll;
438
440
441 RNA_def_boolean(ot->srna,
442 "select",
443 true,
444 "Select",
445 "Whether to select or deselect linked vertices under the cursor");
446}
447
449{
451 Mesh *mesh = BKE_mesh_from_object(ob);
452 if (mesh == nullptr || mesh->faces_num == 0) {
453 return OPERATOR_CANCELLED;
454 }
455
456 const bool face_step = RNA_boolean_get(op->ptr, "face_step");
458
462
463 return OPERATOR_FINISHED;
464}
465
467{
468 ot->name = "Select More";
469 ot->description = "Select Vertices connected to existing selection";
470 ot->idname = "PAINT_OT_vert_select_more";
471
473 ot->poll = vert_paint_poll;
474
476
478 ot->srna, "face_step", true, "Face Step", "Also select faces that only touch on a corner");
479}
480
482{
484 Mesh *mesh = BKE_mesh_from_object(ob);
485 if (mesh == nullptr || mesh->faces_num == 0) {
486 return OPERATOR_CANCELLED;
487 }
488
489 const bool face_step = RNA_boolean_get(op->ptr, "face_step");
491
495
496 return OPERATOR_FINISHED;
497}
498
500{
501 ot->name = "Select Less";
502 ot->description = "Deselect Vertices connected to existing selection";
503 ot->idname = "PAINT_OT_vert_select_less";
504
506 ot->poll = vert_paint_poll;
507
509
511 ot->srna, "face_step", true, "Face Step", "Also deselect faces that only touch on a corner");
512}
513
515{
516 const bool unselected = RNA_boolean_get(op->ptr, "unselected");
518 paintface_hide(C, ob, unselected);
520 return OPERATOR_FINISHED;
521}
522
524{
525 ot->name = "Face Select Hide";
526 ot->description = "Hide selected faces";
527 ot->idname = "PAINT_OT_face_select_hide";
528
530 ot->poll = facemask_paint_poll;
531
533
535 ot->srna, "unselected", false, "Unselected", "Hide unselected rather than selected objects");
536}
537
539{
540 const bool unselected = RNA_boolean_get(op->ptr, "unselected");
542 paintvert_hide(C, ob, unselected);
544 return OPERATOR_FINISHED;
545}
546
548{
549 ot->name = "Vertex Select Hide";
550 ot->description = "Hide selected vertices";
551 ot->idname = "PAINT_OT_vert_select_hide";
552
554 ot->poll = vert_paint_poll;
555
557
558 RNA_def_boolean(ot->srna,
559 "unselected",
560 false,
561 "Unselected",
562 "Hide unselected rather than selected vertices");
563}
564
566{
567 const bool select = RNA_boolean_get(op->ptr, "select");
569
572 }
573 else {
575 }
576
578 return OPERATOR_FINISHED;
579}
580
582{
584
585 /* Allow using this operator when no selection is enabled but hiding is applied. */
587}
588
590{
591 ot->name = "Reveal Faces/Vertices";
592 ot->description = "Reveal hidden faces and vertices";
593 ot->idname = "PAINT_OT_face_vert_reveal";
594
597
599
600 RNA_def_boolean(ot->srna,
601 "select",
602 true,
603 "Select",
604 "Specifies whether the newly revealed geometry should be selected");
605}
Object * CTX_data_active_object(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
Mesh * BKE_mesh_from_object(Object *ob)
bool BKE_paint_always_hide_test(const Object *ob)
Definition paint.cc:1671
bool BKE_paint_select_elem_test(const Object *ob)
Definition paint.cc:1665
bool BKE_paint_select_vert_test(const Object *ob)
Definition paint.cc:1647
@ RPT_ERROR
Definition BKE_report.hh:39
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
float mat4_to_scale(const float mat[4][4])
void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3])
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
void BLI_rcti_init_minmax(struct rcti *rect)
Definition rct.cc:474
void BLI_rcti_do_minmax_v(struct rcti *rect, const int xy[2])
Definition rct.cc:486
#define BLT_I18NCONTEXT_OPERATOR_DEFAULT
Object is a sort of wrapper for general info.
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
void paintvert_reveal(bContext *C, Object *ob, bool select)
Definition editface.cc:1192
void paintvert_select_more(Mesh *mesh, bool face_step)
Definition editface.cc:933
void paintvert_select_less(Mesh *mesh, bool face_step)
Definition editface.cc:991
void paintvert_flush_flags(Object *ob)
Definition editface.cc:787
void paintface_select_less(Mesh *mesh, bool face_step)
Definition editface.cc:578
void paintvert_tag_select_update(bContext *C, Object *ob)
Definition editface.cc:1046
void paintvert_hide(bContext *C, Object *ob, bool unselected)
Definition editface.cc:1158
void paintvert_select_ungrouped(Object *ob, bool extend, bool flush_flags)
Definition editface.cc:1120
void paintface_reveal(bContext *C, Object *ob, bool select)
Definition editface.cc:184
void paintface_flush_flags(bContext *C, Object *ob, bool flush_selection, bool flush_hidden)
Definition editface.cc:40
bool paintvert_deselect_all_visible(Object *ob, int action, bool flush_flags)
Definition editface.cc:1052
void paintvert_select_linked(bContext *C, Object *ob)
Definition editface.cc:910
void paintvert_select_linked_pick(bContext *C, Object *ob, const int region_coordinates[2], bool select)
Definition editface.cc:896
void paintface_select_linked(bContext *C, Object *ob, const int mval[2], bool select)
Definition editface.cc:310
void paintface_select_loop(bContext *C, Object *ob, const int mval[2], bool select)
Definition editface.cc:418
void paintface_hide(bContext *C, Object *ob, bool unselected)
Definition editface.cc:150
bool paintface_deselect_all_visible(bContext *C, Object *ob, int action, bool flush_flags)
Definition editface.cc:623
void paintface_select_more(Mesh *mesh, bool face_step)
Definition editface.cc:524
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:618
@ SEL_DESELECT
blender::float2 ED_view3d_project_float_v2_m4(const ARegion *region, const float co[3], const blender::float4x4 &mat)
void ED_view3d_win_to_delta(const ARegion *region, const float xy_delta[2], float zfac, float r_out[3], bool precise=false)
blender::float4x4 ED_view3d_ob_project_mat_get(const RegionView3D *rv3d, const Object *ob)
float ED_view3d_calc_zfac(const RegionView3D *rv3d, const float co[3])
void view3d_operator_needs_gpu(const bContext *C)
@ PROP_SKIP_SAVE
Definition RNA_types.hh:344
@ PROP_HIDDEN
Definition RNA_types.hh:338
#define C
Definition RandGen.cpp:29
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
ATTR_WARN_UNUSED_RESULT const BMVert * v
#define select(A, B, C)
static BMFace * face_step(BMEdge *edge, BMFace *f)
MatBase< float, 4, 4 > float4x4
VecBase< float, 2 > float2
VecBase< float, 3 > float3
bool vert_paint_poll(bContext *C)
bool facemask_paint_poll(bContext *C)
@ BRUSH_STROKE_SMOOTH
@ BRUSH_STROKE_NORMAL
@ BRUSH_STROKE_INVERT
@ BRUSH_STROKE_ERASE
void PAINT_OT_face_select_more(wmOperatorType *ot)
void PAINT_OT_vert_select_less(wmOperatorType *ot)
static wmOperatorStatus paintface_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
bool paint_convert_bb_to_rect(rcti *rect, const float bb_min[3], const float bb_max[3], const ARegion &region, const RegionView3D &rv3d, const Object &ob)
void PAINT_OT_face_select_hide(wmOperatorType *ot)
void PAINT_OT_face_select_loop(wmOperatorType *ot)
void PAINT_OT_vert_select_linked(wmOperatorType *ot)
void PAINT_OT_face_select_linked_pick(wmOperatorType *ot)
static wmOperatorStatus face_select_all_exec(bContext *C, wmOperator *op)
static wmOperatorStatus face_select_hide_exec(bContext *C, wmOperator *op)
void PAINT_OT_vert_select_linked_pick(wmOperatorType *ot)
void PAINT_OT_vert_select_ungrouped(wmOperatorType *ot)
static wmOperatorStatus paintvert_select_less_exec(bContext *C, wmOperator *op)
static wmOperatorStatus paint_select_less_exec(bContext *C, wmOperator *op)
static wmOperatorStatus vert_select_ungrouped_exec(bContext *C, wmOperator *op)
void PAINT_OT_face_select_less(wmOperatorType *ot)
void PAINT_OT_vert_select_all(wmOperatorType *ot)
static wmOperatorStatus paintvert_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void PAINT_OT_face_select_all(wmOperatorType *ot)
static wmOperatorStatus paintvert_select_more_exec(bContext *C, wmOperator *op)
void PAINT_OT_face_select_linked(wmOperatorType *ot)
static bool face_vert_reveal_poll(bContext *C)
static wmOperatorStatus paint_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static wmOperatorStatus vert_select_hide_exec(bContext *C, wmOperator *op)
static wmOperatorStatus vert_select_all_exec(bContext *C, wmOperator *op)
static wmOperatorStatus paintvert_select_linked_exec(bContext *C, wmOperator *)
void PAINT_OT_vert_select_hide(wmOperatorType *ot)
void PAINT_OT_vert_select_more(wmOperatorType *ot)
bool paint_get_tex_pixel(const MTex *mtex, float u, float v, ImagePool *pool, int thread, float *r_intensity, float r_rgba[4])
static wmOperatorStatus face_vert_reveal_exec(bContext *C, wmOperator *op)
void PAINT_OT_face_vert_reveal(wmOperatorType *ot)
void paint_stroke_operator_properties(wmOperatorType *ot)
static wmOperatorStatus paint_select_more_exec(bContext *C, wmOperator *op)
float paint_calc_object_space_radius(const ViewContext &vc, const blender::float3 &center, const float pixel_radius)
static wmOperatorStatus paint_select_linked_exec(bContext *C, wmOperator *)
#define fabsf
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_collection_runtime(StructOrFunctionRNA *cont_, const char *identifier, StructRNA *type, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_translation_context(PropertyRNA *prop, const char *context)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
ListBase vertex_group_names
int faces_num
RegionView3D * rv3d
Definition ED_view3d.hh:80
ARegion * region
Definition ED_view3d.hh:77
Object * obact
Definition ED_view3d.hh:75
int ymin
int ymax
int xmin
int xmax
int mval[2]
Definition WM_types.hh:763
struct ReportList * reports
struct PointerRNA * ptr
i
Definition text_draw.cc:230
bool RE_texture_evaluate(const MTex *mtex, const float vec[3], const int thread, ImagePool *pool, const bool skip_load_image, const bool texnode_preview, float *r_intensity, float r_rgba[4])
wmOperatorType * ot
Definition wm_files.cc:4237
void WM_operator_properties_select_all(wmOperatorType *ot)