Cleanup: split lattice into own library
[blender.git] / source / blender / editors / lattice / editlattice_select.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  * Contributor(s): Blender Foundation
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/lattice/editlattice_select.c
27  *  \ingroup edlattice
28  */
29
30 #include <stdlib.h>
31
32 #include "MEM_guardedalloc.h"
33
34 #include "BLI_listbase.h"
35 #include "BLI_math.h"
36 #include "BLI_utildefines.h"
37 #include "BLI_rand.h"
38 #include "BLI_bitmap.h"
39
40 #include "DNA_curve_types.h"
41 #include "DNA_lattice_types.h"
42 #include "DNA_meshdata_types.h"
43 #include "DNA_object_types.h"
44 #include "DNA_scene_types.h"
45
46 #include "RNA_access.h"
47 #include "RNA_define.h"
48 #include "RNA_enum_types.h"
49
50 #include "BKE_context.h"
51 #include "BKE_lattice.h"
52 #include "BKE_report.h"
53
54 #include "ED_screen.h"
55 #include "ED_lattice.h"
56 #include "ED_view3d.h"
57
58 #include "WM_api.h"
59 #include "WM_types.h"
60
61 #include "lattice_intern.h"
62
63 /* -------------------------------------------------------------------- */
64 /** \name Utility Functions
65  * \{ */
66
67 static void bpoint_select_set(BPoint *bp, bool select)
68 {
69         if (select) {
70                 if (!bp->hide) {
71                         bp->f1 |= SELECT;
72                 }
73         }
74         else {
75                 bp->f1 &= ~SELECT;
76         }
77 }
78
79 /** \} */
80
81 /* -------------------------------------------------------------------- */
82 /** \name Select Random Operator
83  * \{ */
84
85 static int lattice_select_random_exec(bContext *C, wmOperator *op)
86 {
87         Object *obedit = CTX_data_edit_object(C);
88         Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt;
89
90         const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f;
91         const int seed = WM_operator_properties_select_random_seed_increment_get(op);
92         const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
93
94         RNG *rng = BLI_rng_new_srandom(seed);
95
96         int tot;
97         BPoint *bp;
98
99         tot = lt->pntsu * lt->pntsv * lt->pntsw;
100         bp = lt->def;
101         while (tot--) {
102                 if (!bp->hide) {
103                         if (BLI_rng_get_float(rng) < randfac) {
104                                 bpoint_select_set(bp, select);
105                         }
106                 }
107                 bp++;
108         }
109
110         if (select == false) {
111                 lt->actbp = LT_ACTBP_NONE;
112         }
113
114         BLI_rng_free(rng);
115
116         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
117
118         return OPERATOR_FINISHED;
119 }
120
121 void LATTICE_OT_select_random(wmOperatorType *ot)
122 {
123         /* identifiers */
124         ot->name = "Select Random";
125         ot->description = "Randomly select UVW control points";
126         ot->idname = "LATTICE_OT_select_random";
127
128         /* api callbacks */
129         ot->exec = lattice_select_random_exec;
130         ot->poll = ED_operator_editlattice;
131
132         /* flags */
133         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
134
135         /* props */
136         WM_operator_properties_select_random(ot);
137 }
138
139 /** \} */
140
141 /* -------------------------------------------------------------------- */
142 /** \name Select Mirror Operator
143  * \{ */
144
145 static void ed_lattice_select_mirrored(Lattice *lt, const int axis, const bool extend)
146 {
147         const int tot = lt->pntsu * lt->pntsv * lt->pntsw;
148         int i;
149         BPoint *bp;
150         BLI_bitmap *selpoints;
151
152         bool flip_uvw[3] = {false};
153         flip_uvw[axis] = true;
154
155         /* we could flip this too */
156         if (!extend) {
157                 lt->actbp = LT_ACTBP_NONE;
158         }
159
160         /* store "original" selection */
161         selpoints = BLI_BITMAP_NEW(tot, __func__);
162         BKE_lattice_bitmap_from_flag(lt, selpoints, SELECT, false, false);
163
164         /* actual (de)selection */
165         for (i = 0; i < tot; i++) {
166                 const int i_flip = BKE_lattice_index_flip(lt, i, flip_uvw[0], flip_uvw[1], flip_uvw[2]);
167                 bp = &lt->def[i];
168                 if (!bp->hide) {
169                         if (BLI_BITMAP_TEST(selpoints, i_flip)) {
170                                 bp->f1 |= SELECT;
171                         }
172                         else {
173                                 if (!extend) {
174                                         bp->f1 &= ~SELECT;
175                                 }
176                         }
177                 }
178         }
179
180
181         MEM_freeN(selpoints);
182 }
183
184 static int lattice_select_mirror_exec(bContext *C, wmOperator *op)
185 {
186         Object *obedit = CTX_data_edit_object(C);
187         Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt;
188         const int axis_flag = RNA_enum_get(op->ptr, "axis");
189         const bool extend = RNA_boolean_get(op->ptr, "extend");
190
191         for (int axis = 0; axis < 3; axis++) {
192                 if ((1 << axis) & axis_flag) {
193                         ed_lattice_select_mirrored(lt, axis, extend);
194                 }
195         }
196
197         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
198
199         return OPERATOR_FINISHED;
200 }
201
202 void LATTICE_OT_select_mirror(wmOperatorType *ot)
203 {
204         /* identifiers */
205         ot->name = "Select Mirror";
206         ot->description = "Select mirrored lattice points";
207         ot->idname = "LATTICE_OT_select_mirror";
208
209         /* api callbacks */
210         ot->exec = lattice_select_mirror_exec;
211         ot->poll = ED_operator_editlattice;
212
213         /* flags */
214         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
215
216         /* props */
217         RNA_def_enum_flag(ot->srna, "axis", rna_enum_axis_flag_xyz_items, (1 << 0), "Axis", "");
218
219         RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
220 }
221
222 /** \} */
223
224 /* -------------------------------------------------------------------- */
225 /** \name Select More/Less Operator
226  * \{ */
227
228 static bool lattice_test_bitmap_uvw(Lattice *lt, BLI_bitmap *selpoints, int u, int v, int w, const bool selected)
229 {
230         if ((u < 0 || u >= lt->pntsu) ||
231             (v < 0 || v >= lt->pntsv) ||
232             (w < 0 || w >= lt->pntsw))
233         {
234                 return false;
235         }
236         else {
237                 int i = BKE_lattice_index_from_uvw(lt, u, v, w);
238                 if (lt->def[i].hide == 0) {
239                         return (BLI_BITMAP_TEST(selpoints, i) != 0) == selected;
240                 }
241                 return false;
242         }
243 }
244
245 static int lattice_select_more_less(bContext *C, const bool select)
246 {
247         Object *obedit = CTX_data_edit_object(C);
248         Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt;
249         BPoint *bp;
250         const int tot = lt->pntsu * lt->pntsv * lt->pntsw;
251         int u, v, w;
252         BLI_bitmap *selpoints;
253
254         lt->actbp = LT_ACTBP_NONE;
255
256         selpoints = BLI_BITMAP_NEW(tot, __func__);
257         BKE_lattice_bitmap_from_flag(lt, selpoints, SELECT, false, false);
258
259         bp = lt->def;
260         for (w = 0; w < lt->pntsw; w++) {
261                 for (v = 0; v < lt->pntsv; v++) {
262                         for (u = 0; u < lt->pntsu; u++) {
263                                 if ((bp->hide == 0) && (((bp->f1 & SELECT) == 0) == select)) {
264                                         if (lattice_test_bitmap_uvw(lt, selpoints, u + 1, v, w, select) ||
265                                             lattice_test_bitmap_uvw(lt, selpoints, u - 1, v, w, select) ||
266                                             lattice_test_bitmap_uvw(lt, selpoints, u, v + 1, w, select) ||
267                                             lattice_test_bitmap_uvw(lt, selpoints, u, v - 1, w, select) ||
268                                             lattice_test_bitmap_uvw(lt, selpoints, u, v, w + 1, select) ||
269                                             lattice_test_bitmap_uvw(lt, selpoints, u, v, w - 1, select))
270                                         {
271                                                 SET_FLAG_FROM_TEST(bp->f1, select, SELECT);
272                                         }
273                                 }
274                                 bp++;
275                         }
276                 }
277         }
278
279         MEM_freeN(selpoints);
280
281         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
282         return OPERATOR_FINISHED;
283 }
284
285 static int lattice_select_more_exec(bContext *C, wmOperator *UNUSED(op))
286 {
287         return lattice_select_more_less(C, true);
288 }
289
290 static int lattice_select_less_exec(bContext *C, wmOperator *UNUSED(op))
291 {
292         return lattice_select_more_less(C, false);
293 }
294
295 void LATTICE_OT_select_more(wmOperatorType *ot)
296 {
297         /* identifiers */
298         ot->name = "Select More";
299         ot->description = "Select vertex directly linked to already selected ones";
300         ot->idname = "LATTICE_OT_select_more";
301
302         /* api callbacks */
303         ot->exec = lattice_select_more_exec;
304         ot->poll = ED_operator_editlattice;
305
306         /* flags */
307         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
308 }
309
310 void LATTICE_OT_select_less(wmOperatorType *ot)
311 {
312         /* identifiers */
313         ot->name = "Select Less";
314         ot->description = "Deselect vertices at the boundary of each selection region";
315         ot->idname = "LATTICE_OT_select_less";
316
317         /* api callbacks */
318         ot->exec = lattice_select_less_exec;
319         ot->poll = ED_operator_editlattice;
320
321         /* flags */
322         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
323 }
324
325 /** \} */
326
327 /* -------------------------------------------------------------------- */
328 /** \name Select All Operator
329  * \{ */
330
331 void ED_lattice_flags_set(Object *obedit, int flag)
332 {
333         Lattice *lt = obedit->data;
334         BPoint *bp;
335         int a;
336
337         bp = lt->editlatt->latt->def;
338
339         a = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw;
340         lt->editlatt->latt->actbp = LT_ACTBP_NONE;
341
342         while (a--) {
343                 if (bp->hide == 0) {
344                         bp->f1 = flag;
345                 }
346                 bp++;
347         }
348 }
349
350 static int lattice_select_all_exec(bContext *C, wmOperator *op)
351 {
352         Object *obedit = CTX_data_edit_object(C);
353         Lattice *lt = obedit->data;
354         BPoint *bp;
355         int a;
356         int action = RNA_enum_get(op->ptr, "action");
357
358         if (action == SEL_TOGGLE) {
359                 action = SEL_SELECT;
360
361                 bp = lt->editlatt->latt->def;
362                 a = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw;
363
364                 while (a--) {
365                         if (bp->hide == 0) {
366                                 if (bp->f1 & SELECT) {
367                                         action = SEL_DESELECT;
368                                         break;
369                                 }
370                         }
371                         bp++;
372                 }
373         }
374
375         switch (action) {
376                 case SEL_SELECT:
377                         ED_lattice_flags_set(obedit, 1);
378                         break;
379                 case SEL_DESELECT:
380                         ED_lattice_flags_set(obedit, 0);
381                         break;
382                 case SEL_INVERT:
383                         bp = lt->editlatt->latt->def;
384                         a = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw;
385                         lt->editlatt->latt->actbp = LT_ACTBP_NONE;
386
387                         while (a--) {
388                                 if (bp->hide == 0) {
389                                         bp->f1 ^= SELECT;
390                                 }
391                                 bp++;
392                         }
393                         break;
394         }
395
396         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
397
398         return OPERATOR_FINISHED;
399 }
400
401 void LATTICE_OT_select_all(wmOperatorType *ot)
402 {
403         /* identifiers */
404         ot->name = "(De)select All";
405         ot->description = "Change selection of all UVW control points";
406         ot->idname = "LATTICE_OT_select_all";
407
408         /* api callbacks */
409         ot->exec = lattice_select_all_exec;
410         ot->poll = ED_operator_editlattice;
411
412         /* flags */
413         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
414
415         WM_operator_properties_select_all(ot);
416 }
417
418 /** \} */
419
420 /* -------------------------------------------------------------------- */
421 /** \name Select Ungrouped Verts Operator
422  * \{ */
423
424 static int lattice_select_ungrouped_exec(bContext *C, wmOperator *op)
425 {
426         Object *obedit = CTX_data_edit_object(C);
427         Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt;
428         MDeformVert *dv;
429         BPoint *bp;
430         int a, tot;
431
432         if (BLI_listbase_is_empty(&obedit->defbase) || lt->dvert == NULL) {
433                 BKE_report(op->reports, RPT_ERROR, "No weights/vertex groups on object");
434                 return OPERATOR_CANCELLED;
435         }
436
437         if (!RNA_boolean_get(op->ptr, "extend")) {
438                 ED_lattice_flags_set(obedit, 0);
439         }
440
441         dv = lt->dvert;
442         tot = lt->pntsu * lt->pntsv * lt->pntsw;
443
444         for (a = 0, bp = lt->def; a < tot; a++, bp++, dv++) {
445                 if (bp->hide == 0) {
446                         if (dv->dw == NULL) {
447                                 bp->f1 |= SELECT;
448                         }
449                 }
450         }
451
452         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
453
454         return OPERATOR_FINISHED;
455 }
456
457 void LATTICE_OT_select_ungrouped(wmOperatorType *ot)
458 {
459         /* identifiers */
460         ot->name = "Select Ungrouped";
461         ot->idname = "LATTICE_OT_select_ungrouped";
462         ot->description = "Select vertices without a group";
463
464         /* api callbacks */
465         ot->exec = lattice_select_ungrouped_exec;
466         ot->poll = ED_operator_editlattice;
467
468         /* flags */
469         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
470
471         RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
472 }
473
474 /** \} */
475
476
477 /* -------------------------------------------------------------------- */
478 /** \name Select Picking API
479  *
480  * Here actual select happens,
481  * Gets called via generic mouse select operator.
482  * \{ */
483
484
485 static void findnearestLattvert__doClosest(void *userData, BPoint *bp, const float screen_co[2])
486 {
487         struct { BPoint *bp; float dist; int select; float mval_fl[2]; } *data = userData;
488         float dist_test = len_manhattan_v2v2(data->mval_fl, screen_co);
489
490         if ((bp->f1 & SELECT) && data->select)
491                 dist_test += 5.0f;
492
493         if (dist_test < data->dist) {
494                 data->dist = dist_test;
495
496                 data->bp = bp;
497         }
498 }
499
500 static BPoint *findnearestLattvert(ViewContext *vc, const int mval[2], int sel)
501 {
502         /* (sel == 1): selected gets a disadvantage */
503         /* in nurb and bezt or bp the nearest is written */
504         /* return 0 1 2: handlepunt */
505         struct { BPoint *bp; float dist; int select; float mval_fl[2]; } data = {NULL};
506
507         data.dist = ED_view3d_select_dist_px();
508         data.select = sel;
509         data.mval_fl[0] = mval[0];
510         data.mval_fl[1] = mval[1];
511
512         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
513         lattice_foreachScreenVert(vc, findnearestLattvert__doClosest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
514
515         return data.bp;
516 }
517
518 bool ED_lattice_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
519 {
520         ViewContext vc;
521         BPoint *bp = NULL;
522         Lattice *lt;
523
524         ED_view3d_viewcontext_init(C, &vc);
525         lt = ((Lattice *)vc.obedit->data)->editlatt->latt;
526         bp = findnearestLattvert(&vc, mval, true);
527
528         if (bp) {
529                 if (extend) {
530                         bp->f1 |= SELECT;
531                 }
532                 else if (deselect) {
533                         bp->f1 &= ~SELECT;
534                 }
535                 else if (toggle) {
536                         bp->f1 ^= SELECT;  /* swap */
537                 }
538                 else {
539                         ED_lattice_flags_set(vc.obedit, 0);
540                         bp->f1 |= SELECT;
541                 }
542
543                 if (bp->f1 & SELECT) {
544                         lt->actbp = bp - lt->def;
545                 }
546                 else {
547                         lt->actbp = LT_ACTBP_NONE;
548                 }
549
550                 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
551
552                 return true;
553         }
554
555         return false;
556 }
557
558 /** \} */