doxygen: add newline after \file
[blender.git] / source / blender / editors / lattice / editlattice_tools.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup edlattice
22  */
23
24
25 #include "MEM_guardedalloc.h"
26
27 #include "BLI_math.h"
28 #include "BLI_utildefines.h"
29
30 #include "DNA_curve_types.h"
31 #include "DNA_lattice_types.h"
32 #include "DNA_object_types.h"
33 #include "DNA_scene_types.h"
34
35 #include "RNA_access.h"
36 #include "RNA_define.h"
37
38 #include "BKE_context.h"
39 #include "BKE_lattice.h"
40 #include "BKE_layer.h"
41
42 #include "DEG_depsgraph.h"
43
44 #include "ED_screen.h"
45
46 #include "WM_api.h"
47 #include "WM_types.h"
48
49 #include "lattice_intern.h"
50
51 /** \} */
52
53 /* -------------------------------------------------------------------- */
54 /** \name Make Regular Operator
55  * \{ */
56
57 static bool make_regular_poll(bContext *C)
58 {
59         Object *ob;
60
61         if (ED_operator_editlattice(C)) return 1;
62
63         ob = CTX_data_active_object(C);
64         return (ob && ob->type == OB_LATTICE);
65 }
66
67 static int make_regular_exec(bContext *C, wmOperator *UNUSED(op))
68 {
69         ViewLayer *view_layer = CTX_data_view_layer(C);
70         View3D *v3d = CTX_wm_view3d(C);
71         const bool is_editmode = CTX_data_edit_object(C) != NULL;
72
73         if (is_editmode) {
74                 uint objects_len;
75                 Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
76                 for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
77                         Object *ob = objects[ob_index];
78                         Lattice *lt = ob->data;
79
80                         if (lt->editlatt->latt == NULL) {
81                                 continue;
82                         }
83
84                         BKE_lattice_resize(lt->editlatt->latt, lt->pntsu, lt->pntsv, lt->pntsw, NULL);
85
86                         DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
87                         WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
88                 }
89                 MEM_freeN(objects);
90         }
91         else {
92                 FOREACH_SELECTED_OBJECT_BEGIN(view_layer, v3d, ob) {
93                         if (ob->type != OB_LATTICE) {
94                                 continue;
95                         }
96
97                         Lattice *lt = ob->data;
98                         BKE_lattice_resize(lt, lt->pntsu, lt->pntsv, lt->pntsw, NULL);
99
100                         DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
101                         WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
102                 } FOREACH_SELECTED_OBJECT_END;
103         }
104         return OPERATOR_FINISHED;
105 }
106
107 void LATTICE_OT_make_regular(wmOperatorType *ot)
108 {
109         /* identifiers */
110         ot->name = "Make Regular";
111         ot->description = "Set UVW control points a uniform distance apart";
112         ot->idname = "LATTICE_OT_make_regular";
113
114         /* api callbacks */
115         ot->exec = make_regular_exec;
116         ot->poll = make_regular_poll;
117
118         /* flags */
119         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
120 }
121
122 /** \} */
123
124 /* -------------------------------------------------------------------- */
125 /** \name Flip Verts Operator
126  * \{ */
127
128 /* flipping options */
129 typedef enum eLattice_FlipAxes {
130         LATTICE_FLIP_U = 0,
131         LATTICE_FLIP_V = 1,
132         LATTICE_FLIP_W = 2,
133 } eLattice_FlipAxes;
134
135 /**
136  * Flip midpoint value so that relative distances between midpoint and neighbor-pair is maintained
137  * ! Assumes that uvw <=> xyz (i.e. axis-aligned index-axes with coordinate-axes)
138  * - Helper for lattice_flip_exec()
139  */
140 static void lattice_flip_point_value(Lattice *lt, int u, int v, int w, float mid, eLattice_FlipAxes axis)
141 {
142         BPoint *bp;
143         float diff;
144
145         /* just the point in the middle (unpaired) */
146         bp = &lt->def[BKE_lattice_index_from_uvw(lt, u, v, w)];
147
148         /* flip over axis */
149         diff = mid - bp->vec[axis];
150         bp->vec[axis] = mid + diff;
151 }
152
153 /**
154  * Swap pairs of lattice points along a specified axis
155  * - Helper for lattice_flip_exec()
156  */
157 static void lattice_swap_point_pairs(Lattice *lt, int u, int v, int w, float mid, eLattice_FlipAxes axis)
158 {
159         BPoint *bpA, *bpB;
160
161         int numU = lt->pntsu;
162         int numV = lt->pntsv;
163         int numW = lt->pntsw;
164
165         int u0 = u, u1 = u;
166         int v0 = v, v1 = v;
167         int w0 = w, w1 = w;
168
169         /* get pair index by just overriding the relevant pair-value
170          * - "-1" else buffer overflow
171          */
172         switch (axis) {
173                 case LATTICE_FLIP_U:
174                         u1 = numU - u - 1;
175                         break;
176                 case LATTICE_FLIP_V:
177                         v1 = numV - v - 1;
178                         break;
179                 case LATTICE_FLIP_W:
180                         w1 = numW - w - 1;
181                         break;
182         }
183
184         /* get points to operate on */
185         bpA = &lt->def[BKE_lattice_index_from_uvw(lt, u0, v0, w0)];
186         bpB = &lt->def[BKE_lattice_index_from_uvw(lt, u1, v1, w1)];
187
188         /* Swap all coordinates, so that flipped coordinates belong to
189          * the indices on the correct side of the lattice.
190          *
191          *   Coords:  (-2 4) |0| (3 4)   --> (3 4) |0| (-2 4)
192          *   Indices:  (0,L)     (1,R)   --> (0,L)     (1,R)
193          */
194         swap_v3_v3(bpA->vec, bpB->vec);
195
196         /* However, we need to mirror the coordinate values on the axis we're dealing with,
197          * otherwise we'd have effectively only rotated the points around. If we don't do this,
198          * we'd just be reimplementing the naive mirroring algorithm, which causes unwanted deforms
199          * such as flipped normals, etc.
200          *
201          *   Coords:  (3 4) |0| (-2 4)  --\
202          *                                 \-> (-3 4) |0| (2 4)
203          *   Indices: (0,L)     (1,R)   -->     (0,L)     (1,R)
204          */
205         lattice_flip_point_value(lt, u0, v0, w0, mid, axis);
206         lattice_flip_point_value(lt, u1, v1, w1, mid, axis);
207 }
208
209 static int lattice_flip_exec(bContext *C, wmOperator *op)
210 {
211         ViewLayer *view_layer = CTX_data_view_layer(C);
212         uint objects_len;
213         bool changed = false;
214         const eLattice_FlipAxes axis = RNA_enum_get(op->ptr, "axis");
215
216         Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
217         for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
218                 Object *obedit = objects[ob_index];
219                 Lattice *lt;
220
221                 int numU, numV, numW;
222                 int totP;
223
224                 float mid = 0.0f;
225                 short isOdd = 0;
226
227                 /* get lattice - we need the "edit lattice" from the lattice... confusing... */
228                 lt = (Lattice *)obedit->data;
229                 lt = lt->editlatt->latt;
230
231                 numU = lt->pntsu;
232                 numV = lt->pntsv;
233                 numW = lt->pntsw;
234                 totP = numU * numV * numW;
235
236                 /* First Pass: determine midpoint - used for flipping center verts if there
237                  * are odd number of points on axis */
238                 switch (axis) {
239                         case LATTICE_FLIP_U:
240                                 isOdd = numU & 1;
241                                 break;
242                         case LATTICE_FLIP_V:
243                                 isOdd = numV & 1;
244                                 break;
245                         case LATTICE_FLIP_W:
246                                 isOdd = numW & 1;
247                                 break;
248
249                         default:
250                                 printf("lattice_flip(): Unknown flipping axis (%u)\n", axis);
251                                 return OPERATOR_CANCELLED;
252                 }
253
254                 if (isOdd) {
255                         BPoint *bp;
256                         float avgInv = 1.0f / (float)totP;
257                         int i;
258
259                         /* midpoint calculation - assuming that u/v/w are axis-aligned */
260                         for (i = 0, bp = lt->def; i < totP; i++, bp++) {
261                                 mid += bp->vec[axis] * avgInv;
262                         }
263                 }
264
265                 /* Second Pass: swap pairs of vertices per axis, assuming they are all sorted */
266                 switch (axis) {
267                         case LATTICE_FLIP_U:
268                         {
269                                 int u, v, w;
270
271                                 /* v/w strips - front to back, top to bottom */
272                                 for (w = 0; w < numW; w++) {
273                                         for (v = 0; v < numV; v++) {
274                                                 /* swap coordinates of pairs of vertices on u */
275                                                 for (u = 0; u < (numU / 2); u++) {
276                                                         lattice_swap_point_pairs(lt, u, v, w, mid, axis);
277                                                 }
278
279                                                 /* flip u-coordinate of midpoint (i.e. unpaired point on u) */
280                                                 if (isOdd) {
281                                                         u = (numU / 2);
282                                                         lattice_flip_point_value(lt, u, v, w, mid, axis);
283                                                 }
284                                         }
285                                 }
286                                 break;
287                         }
288                         case LATTICE_FLIP_V:
289                         {
290                                 int u, v, w;
291
292                                 /* u/w strips - front to back, left to right */
293                                 for (w = 0; w < numW; w++) {
294                                         for (u = 0; u < numU; u++) {
295                                                 /* swap coordinates of pairs of vertices on v */
296                                                 for (v = 0; v < (numV / 2); v++) {
297                                                         lattice_swap_point_pairs(lt, u, v, w, mid, axis);
298                                                 }
299
300                                                 /* flip v-coordinate of midpoint (i.e. unpaired point on v) */
301                                                 if (isOdd) {
302                                                         v = (numV / 2);
303                                                         lattice_flip_point_value(lt, u, v, w, mid, axis);
304                                                 }
305                                         }
306                                 }
307                                 break;
308                         }
309                         case LATTICE_FLIP_W:
310                         {
311                                 int u, v, w;
312
313                                 for (v = 0; v < numV; v++) {
314                                         for (u = 0; u < numU; u++) {
315                                                 /* swap coordinates of pairs of vertices on w */
316                                                 for (w = 0; w < (numW / 2); w++) {
317                                                         lattice_swap_point_pairs(lt, u, v, w, mid, axis);
318                                                 }
319
320                                                 /* flip w-coordinate of midpoint (i.e. unpaired point on w) */
321                                                 if (isOdd) {
322                                                         w = (numW / 2);
323                                                         lattice_flip_point_value(lt, u, v, w, mid, axis);
324                                                 }
325                                         }
326                                 }
327                                 break;
328                         }
329                         default: /* shouldn't happen, but just in case */
330                                 break;
331                 }
332
333                 /* updates */
334                 DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
335                 WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
336                 changed = true;
337         }
338         MEM_freeN(objects);
339
340         return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
341 }
342
343 void LATTICE_OT_flip(wmOperatorType *ot)
344 {
345         static const EnumPropertyItem flip_items[] = {
346                 {LATTICE_FLIP_U, "U", 0, "U (X) Axis", ""},
347                 {LATTICE_FLIP_V, "V", 0, "V (Y) Axis", ""},
348                 {LATTICE_FLIP_W, "W", 0, "W (Z) Axis", ""},
349                 {0, NULL, 0, NULL, NULL},
350         };
351
352         /* identifiers */
353         ot->name = "Flip (Distortion Free)";
354         ot->description = "Mirror all control points without inverting the lattice deform";
355         ot->idname = "LATTICE_OT_flip";
356
357         /* api callbacks */
358         ot->poll = ED_operator_editlattice;
359         ot->invoke = WM_menu_invoke;
360         ot->exec = lattice_flip_exec;
361
362         /* flags */
363         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
364
365         /* properties */
366         ot->prop = RNA_def_enum(ot->srna, "axis", flip_items, LATTICE_FLIP_U, "Flip Axis", "Coordinates along this axis get flipped");
367 }
368
369 /** \} */