a3c74b33f9e9ee31c28d86b02e1f9b7d7778313c
[blender-staging.git] / source / blender / editors / sculpt_paint / paint_hide.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) 2010 by Nicholas Bishop
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s):
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  *
27  * Implements the PBVH node hiding operator
28  *
29  */
30
31 /** \file blender/editors/sculpt_paint/paint_hide.c
32  *  \ingroup edsculpt
33  */
34
35 #include "MEM_guardedalloc.h"
36
37 #include "BLI_bitmap.h"
38 #include "BLI_listbase.h"
39 #include "BLI_math_vector.h"
40 #include "BLI_pbvh.h"
41 #include "BLI_utildefines.h"
42
43 #include "DNA_mesh_types.h"
44 #include "DNA_meshdata_types.h"
45 #include "DNA_object_types.h"
46 #include "DNA_scene_types.h"
47
48 #include "BKE_context.h"
49 #include "BKE_DerivedMesh.h"
50 #include "BKE_mesh.h"
51 #include "BKE_multires.h"
52 #include "BKE_paint.h"
53 #include "BKE_subsurf.h"
54
55 #include "BIF_glutil.h"
56
57 #include "WM_api.h"
58 #include "WM_types.h"
59
60 #include "ED_screen.h"
61 #include "ED_view3d.h"
62
63 #include "RNA_access.h"
64 #include "RNA_define.h"
65
66 #include "paint_intern.h"
67 #include "sculpt_intern.h" /* for undo push */
68
69 #include <assert.h>
70
71 static int planes_contain_v3(float (*planes)[4], int totplane, const float p[3])
72 {
73         int i;
74
75         for (i = 0; i < totplane; i++) {
76                 if (dot_v3v3(planes[i], p) + planes[i][3] > 0)
77                         return 0;
78         }
79
80         return 1;
81 }
82
83 /* return true if the element should be hidden/shown */
84 static int is_effected(PartialVisArea area,
85                        float planes[4][4],
86                        const float co[3])
87 {
88         if (area == PARTIALVIS_ALL)
89                 return 1;
90         else {
91                 int inside = planes_contain_v3(planes, 4, co);
92                 return ((inside && area == PARTIALVIS_INSIDE) ||
93                         (!inside && area == PARTIALVIS_OUTSIDE));
94         }
95 }
96
97 static void partialvis_update_mesh(Object *ob,
98                                    PBVH *pbvh,
99                                    PBVHNode *node,
100                                    PartialVisAction action,
101                                    PartialVisArea area,
102                                    float planes[4][4])
103 {
104         MVert *mvert;
105         int *vert_indices;
106         int any_changed = 0, any_visible = 0, totvert, i;
107                         
108         BLI_pbvh_node_num_verts(pbvh, node, NULL, &totvert);
109         BLI_pbvh_node_get_verts(pbvh, node, &vert_indices, &mvert);
110
111         sculpt_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN);
112
113         for (i = 0; i < totvert; i++) {
114                 MVert *v = &mvert[vert_indices[i]];
115
116                 /* hide vertex if in the hide volume */
117                 if (is_effected(area, planes, v->co)) {
118                         if (action == PARTIALVIS_HIDE)
119                                 v->flag |= ME_HIDE;
120                         else
121                                 v->flag &= ~ME_HIDE;
122                         any_changed = 1;
123                 }
124
125                 if (!(v->flag & ME_HIDE))
126                         any_visible = 1;
127         }
128
129         if (any_changed) {
130                 BLI_pbvh_node_mark_rebuild_draw(node);
131                 BLI_pbvh_node_fully_hidden_set(node, !any_visible);
132         }
133 }
134
135 /* Hide or show elements in multires grids with a special GridFlags
136  * customdata layer. */
137 static void partialvis_update_grids(Object *ob,
138                                     PBVH *pbvh,
139                                     PBVHNode *node,
140                                     PartialVisAction action,
141                                     PartialVisArea area,
142                                     float planes[4][4])
143 {
144         DMGridData **grids;
145         BLI_bitmap *grid_hidden;
146         int any_visible = 0;
147         int *grid_indices, gridsize, totgrid, any_changed, i;
148
149         /* get PBVH data */
150         BLI_pbvh_node_get_grids(pbvh, node,
151                                 &grid_indices, &totgrid, NULL, &gridsize,
152                                 &grids, NULL);
153         grid_hidden = BLI_pbvh_grid_hidden(pbvh);
154         
155         sculpt_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN);
156         
157         any_changed = 0;
158         for (i = 0; i < totgrid; i++) {
159                 int any_hidden = 0;
160                 int g = grid_indices[i], x, y;
161                 BLI_bitmap gh = grid_hidden[g];
162
163                 if (!gh) {
164                         switch (action) {
165                                 case PARTIALVIS_HIDE:
166                                         /* create grid flags data */
167                                         gh = grid_hidden[g] = BLI_BITMAP_NEW(gridsize * gridsize,
168                                                                              "partialvis_update_grids");
169                                         break;
170                                 case PARTIALVIS_SHOW:
171                                         /* entire grid is visible, nothing to show */
172                                         continue;
173                         }
174                 }
175                 else if (action == PARTIALVIS_SHOW && area == PARTIALVIS_ALL) {
176                         /* special case if we're showing all, just free the
177                          * grid */
178                         MEM_freeN(gh);
179                         grid_hidden[g] = NULL;
180                         any_changed = 1;
181                         any_visible = 1;
182                         continue;
183                 }
184
185                 for (y = 0; y < gridsize; y++) {
186                         for (x = 0; x < gridsize; x++) {
187                                 const float *co = grids[g][y * gridsize + x].co;
188
189                                 /* skip grid element if not in the effected area */
190                                 if (is_effected(area, planes, co)) {
191                                         /* set or clear the hide flag */
192                                         BLI_BITMAP_MODIFY(gh, y * gridsize + x,
193                                                           action == PARTIALVIS_HIDE);
194
195                                         any_changed = 1;
196                                 }
197
198                                 /* keep track of whether any elements are still hidden */
199                                 if (BLI_BITMAP_GET(gh, y * gridsize + x))
200                                         any_hidden = 1;
201                                 else
202                                         any_visible = 1;
203                         }
204                 }
205
206                 /* if everything in the grid is now visible, free the grid
207                  * flags */
208                 if (!any_hidden) {
209                         MEM_freeN(gh);
210                         grid_hidden[g] = NULL;
211                 }
212         }
213
214         /* mark updates if anything was hidden/shown */
215         if (any_changed) {
216                 BLI_pbvh_node_mark_rebuild_draw(node);
217                 BLI_pbvh_node_fully_hidden_set(node, !any_visible);
218                 multires_mark_as_modified(ob, MULTIRES_HIDDEN_MODIFIED);
219         }
220 }
221
222 static void rect_from_props(rcti *rect, PointerRNA *ptr)
223 {
224         rect->xmin = RNA_int_get(ptr, "xmin");
225         rect->ymin = RNA_int_get(ptr, "ymin");
226         rect->xmax = RNA_int_get(ptr, "xmax");
227         rect->ymax = RNA_int_get(ptr, "ymax");
228 }
229
230 static void clip_planes_from_rect(bContext *C,
231                                   float clip_planes[4][4],
232                                   const rcti *rect)
233 {
234         ViewContext vc;
235         BoundBox bb;
236         bglMats mats = {{0}};
237         
238         view3d_operator_needs_opengl(C);
239         view3d_set_viewcontext(C, &vc);
240         view3d_get_transformation(vc.ar, vc.rv3d, vc.obact, &mats);
241         ED_view3d_calc_clipping(&bb, clip_planes, &mats, rect);
242         mul_m4_fl(clip_planes, -1.0f);
243 }
244
245 /* If mode is inside, get all PBVH nodes that lie at least partially
246  * inside the clip_planes volume. If mode is outside, get all nodes
247  * that lie at least partially outside the volume. If showing all, get
248  * all nodes. */
249 static void get_pbvh_nodes(PBVH *pbvh,
250                            PBVHNode ***nodes,
251                            int *totnode,
252                            float clip_planes[4][4],
253                            PartialVisArea mode)
254 {
255         BLI_pbvh_SearchCallback cb;
256
257         /* select search callback */
258         switch (mode) {
259                 case PARTIALVIS_INSIDE:
260                         cb = BLI_pbvh_node_planes_contain_AABB;
261                         break;
262                 case PARTIALVIS_OUTSIDE:
263                         cb = BLI_pbvh_node_planes_exclude_AABB;
264                         break;
265                 case PARTIALVIS_ALL:
266                         cb = NULL;
267         }
268         
269         BLI_pbvh_search_gather(pbvh, cb, clip_planes, nodes, totnode);
270 }
271
272 static int hide_show_exec(bContext *C, wmOperator *op)
273 {
274         ARegion *ar = CTX_wm_region(C);
275         Object *ob = CTX_data_active_object(C);
276         Mesh *me = ob->data;
277         PartialVisAction action;
278         PartialVisArea area;
279         PBVH *pbvh;
280         PBVHNode **nodes;
281         DerivedMesh *dm;
282         PBVHType pbvh_type;
283         float clip_planes[4][4];
284         rcti rect;
285         int totnode, i;
286
287         /* read operator properties */
288         action = RNA_enum_get(op->ptr, "action");
289         area = RNA_enum_get(op->ptr, "area");
290         rect_from_props(&rect, op->ptr);
291
292         clip_planes_from_rect(C, clip_planes, &rect);
293
294         dm = mesh_get_derived_final(CTX_data_scene(C), ob, CD_MASK_BAREMESH);
295         pbvh = dm->getPBVH(ob, dm);
296         ob->sculpt->pbvh = pbvh;
297
298         get_pbvh_nodes(pbvh, &nodes, &totnode, clip_planes, area);
299         pbvh_type = BLI_pbvh_type(pbvh);
300
301         /* start undo */
302         switch (action) {
303                 case PARTIALVIS_HIDE:
304                         sculpt_undo_push_begin("Hide area");
305                         break;
306                 case PARTIALVIS_SHOW:
307                         sculpt_undo_push_begin("Show area");
308                         break;
309         }
310
311         for (i = 0; i < totnode; i++) {
312                 switch (pbvh_type) {
313                         case PBVH_FACES:
314                                 partialvis_update_mesh(ob, pbvh, nodes[i], action, area, clip_planes);
315                                 break;
316                         case PBVH_GRIDS:
317                                 partialvis_update_grids(ob, pbvh, nodes[i], action, area, clip_planes);
318                                 break;
319                 }
320         }
321
322         if (nodes)
323                 MEM_freeN(nodes);
324         
325         /* end undo */
326         sculpt_undo_push_end();
327
328         /* ensure that edges and faces get hidden as well (not used by
329          * sculpt but it looks wrong when entering editmode otherwise) */
330         if (pbvh_type == PBVH_FACES) {
331                 BKE_mesh_flush_hidden_from_verts(me->mvert, me->mloop,
332                                                  me->medge, me->totedge,
333                                                  me->mpoly, me->totpoly);
334         }
335
336         ED_region_tag_redraw(ar);
337         
338         return OPERATOR_FINISHED;
339 }
340
341 static int hide_show_invoke(bContext *C, wmOperator *op, wmEvent *event)
342 {
343         PartialVisArea area = RNA_enum_get(op->ptr, "area");
344
345         if (area != PARTIALVIS_ALL)
346                 return WM_border_select_invoke(C, op, event);
347         else
348                 return op->type->exec(C, op);
349 }
350
351 void PAINT_OT_hide_show(struct wmOperatorType *ot)
352 {
353         static EnumPropertyItem action_items[] = {
354                 {PARTIALVIS_HIDE, "HIDE", 0, "Hide", "Hide vertices"},
355                 {PARTIALVIS_SHOW, "SHOW", 0, "Show", "Show vertices"},
356                 {0, NULL, 0, NULL, NULL}};
357
358         static EnumPropertyItem area_items[] = {
359                 {PARTIALVIS_OUTSIDE, "OUTSIDE", 0, "Outside", "Hide or show vertices outside the selection"},
360                 {PARTIALVIS_INSIDE, "INSIDE", 0, "Inside", "Hide or show vertices inside the selection"},
361                 {PARTIALVIS_ALL, "ALL", 0, "All", "Hide or show all vertices"},
362                 {0, NULL, 0, NULL, NULL}};
363         
364         /* identifiers */
365         ot->name = "Hide/Show";
366         ot->idname = "PAINT_OT_hide_show";
367         ot->description = "Hide/show some vertices";
368
369         /* api callbacks */
370         ot->invoke = hide_show_invoke;
371         ot->modal = WM_border_select_modal;
372         ot->exec = hide_show_exec;
373         /* sculpt-only for now */
374         ot->poll = sculpt_mode_poll;
375
376         ot->flag = OPTYPE_REGISTER;
377
378         /* rna */
379         RNA_def_enum(ot->srna, "action", action_items, PARTIALVIS_HIDE,
380                      "Action", "Whether to hide or show vertices");
381         RNA_def_enum(ot->srna, "area", area_items, PARTIALVIS_INSIDE,
382                      "Area", "Which vertices to hide or show");
383         
384         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
385         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
386         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
387         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
388 }