4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * The Original Code is Copyright (C) 2010 by Nicholas Bishop
21 * All rights reserved.
23 * The Original Code is: all of this file.
27 * ***** END GPL LICENSE BLOCK *****
29 * Implements the PBVH node hiding operator
33 /** \file blender/editors/sculpt_paint/paint_hide.c
37 #include "MEM_guardedalloc.h"
39 #include "BLI_bitmap.h"
40 #include "BLI_listbase.h"
41 #include "BLI_math_vector.h"
43 #include "BLI_utildefines.h"
45 #include "DNA_mesh_types.h"
46 #include "DNA_meshdata_types.h"
47 #include "DNA_object_types.h"
48 #include "DNA_scene_types.h"
50 #include "BKE_context.h"
51 #include "BKE_DerivedMesh.h"
53 #include "BKE_multires.h"
54 #include "BKE_paint.h"
55 #include "BKE_subsurf.h"
57 #include "BIF_glutil.h"
62 #include "ED_screen.h"
63 #include "ED_view3d.h"
65 #include "RNA_access.h"
66 #include "RNA_define.h"
68 #include "paint_intern.h"
69 #include "sculpt_intern.h" /* for undo push */
73 static int planes_contain_v3(float (*planes)[4], int totplane, const float p[3])
77 for (i = 0; i < totplane; i++) {
78 if (dot_v3v3(planes[i], p) + planes[i][3] > 0)
85 /* return true if the element should be hidden/shown */
86 static int is_effected(PartialVisArea area,
90 if (area == PARTIALVIS_ALL)
93 int inside = planes_contain_v3(planes, 4, co);
94 return ((inside && area == PARTIALVIS_INSIDE) ||
95 (!inside && area == PARTIALVIS_OUTSIDE));
99 static void partialvis_update_mesh(Object *ob,
102 PartialVisAction action,
108 int any_changed = 0, any_visible = 0, totvert, i;
110 BLI_pbvh_node_num_verts(pbvh, node, NULL, &totvert);
111 BLI_pbvh_node_get_verts(pbvh, node, &vert_indices, &mvert);
113 sculpt_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN);
115 for (i = 0; i < totvert; i++) {
116 MVert *v = &mvert[vert_indices[i]];
118 /* hide vertex if in the hide volume */
119 if (is_effected(area, planes, v->co)) {
120 if (action == PARTIALVIS_HIDE)
127 if (!(v->flag & ME_HIDE))
132 BLI_pbvh_node_mark_rebuild_draw(node);
133 BLI_pbvh_node_fully_hidden_set(node, !any_visible);
137 /* Hide or show elements in multires grids with a special GridFlags
139 static void partialvis_update_grids(Object *ob,
142 PartialVisAction action,
147 BLI_bitmap *grid_hidden;
149 int *grid_indices, gridsize, totgrid, any_changed, i;
152 BLI_pbvh_node_get_grids(pbvh, node,
153 &grid_indices, &totgrid, NULL, &gridsize,
155 grid_hidden = BLI_pbvh_grid_hidden(pbvh);
157 sculpt_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN);
160 for (i = 0; i < totgrid; i++) {
162 int g = grid_indices[i], x, y;
163 BLI_bitmap gh = grid_hidden[g];
167 case PARTIALVIS_HIDE:
168 /* create grid flags data */
169 gh = grid_hidden[g] = BLI_BITMAP_NEW(gridsize * gridsize,
170 "partialvis_update_grids");
172 case PARTIALVIS_SHOW:
173 /* entire grid is visible, nothing to show */
177 else if (action == PARTIALVIS_SHOW && area == PARTIALVIS_ALL) {
178 /* special case if we're showing all, just free the
181 grid_hidden[g] = NULL;
187 for (y = 0; y < gridsize; y++) {
188 for (x = 0; x < gridsize; x++) {
189 const float *co = grids[g][y * gridsize + x].co;
191 /* skip grid element if not in the effected area */
192 if (is_effected(area, planes, co)) {
193 /* set or clear the hide flag */
194 BLI_BITMAP_MODIFY(gh, y * gridsize + x,
195 action == PARTIALVIS_HIDE);
200 /* keep track of whether any elements are still hidden */
201 if (BLI_BITMAP_GET(gh, y * gridsize + x))
208 /* if everything in the grid is now visible, free the grid
212 grid_hidden[g] = NULL;
216 /* mark updates if anything was hidden/shown */
218 BLI_pbvh_node_mark_rebuild_draw(node);
219 BLI_pbvh_node_fully_hidden_set(node, !any_visible);
220 multires_mark_as_modified(ob, MULTIRES_HIDDEN_MODIFIED);
224 static void rect_from_props(rcti *rect, PointerRNA *ptr)
226 rect->xmin = RNA_int_get(ptr, "xmin");
227 rect->ymin = RNA_int_get(ptr, "ymin");
228 rect->xmax = RNA_int_get(ptr, "xmax");
229 rect->ymax = RNA_int_get(ptr, "ymax");
232 static void clip_planes_from_rect(bContext *C,
233 float clip_planes[4][4],
240 view3d_operator_needs_opengl(C);
241 view3d_set_viewcontext(C, &vc);
242 view3d_get_transformation(vc.ar, vc.rv3d, vc.obact, &mats);
243 ED_view3d_calc_clipping(&bb, clip_planes, &mats, rect);
244 mul_m4_fl(clip_planes, -1.0f);
247 /* If mode is inside, get all PBVH nodes that lie at least partially
248 inside the clip_planes volume. If mode is outside, get all nodes
249 that lie at least partially outside the volume. If showing all, get
251 static void get_pbvh_nodes(PBVH *pbvh,
254 float clip_planes[4][4],
257 BLI_pbvh_SearchCallback cb;
259 /* select search callback */
261 case PARTIALVIS_INSIDE:
262 cb = BLI_pbvh_node_planes_contain_AABB;
264 case PARTIALVIS_OUTSIDE:
265 cb = BLI_pbvh_node_planes_exclude_AABB;
271 BLI_pbvh_search_gather(pbvh, cb, clip_planes, nodes, totnode);
274 static int hide_show_exec(bContext *C, wmOperator *op)
276 ARegion *ar = CTX_wm_region(C);
277 Object *ob = CTX_data_active_object(C);
279 PartialVisAction action;
285 float clip_planes[4][4];
289 /* read operator properties */
290 action = RNA_enum_get(op->ptr, "action");
291 area = RNA_enum_get(op->ptr, "area");
292 rect_from_props(&rect, op->ptr);
294 clip_planes_from_rect(C, clip_planes, &rect);
296 dm = mesh_get_derived_final(CTX_data_scene(C), ob, CD_MASK_BAREMESH);
297 pbvh = dm->getPBVH(ob, dm);
298 ob->sculpt->pbvh = pbvh;
300 get_pbvh_nodes(pbvh, &nodes, &totnode, clip_planes, area);
301 pbvh_type = BLI_pbvh_type(pbvh);
305 case PARTIALVIS_HIDE:
306 sculpt_undo_push_begin("Hide area");
308 case PARTIALVIS_SHOW:
309 sculpt_undo_push_begin("Show area");
313 for (i = 0; i < totnode; i++) {
316 partialvis_update_mesh(ob, pbvh, nodes[i], action, area, clip_planes);
319 partialvis_update_grids(ob, pbvh, nodes[i], action, area, clip_planes);
328 sculpt_undo_push_end();
330 /* ensure that edges and faces get hidden as well (not used by
331 sculpt but it looks wrong when entering editmode otherwise) */
332 if (pbvh_type == PBVH_FACES) {
333 mesh_flush_hidden_from_verts(me->mvert, me->mloop,
334 me->medge, me->totedge,
335 me->mpoly, me->totpoly);
338 ED_region_tag_redraw(ar);
340 return OPERATOR_FINISHED;
343 static int hide_show_invoke(bContext *C, wmOperator *op, wmEvent *event)
345 PartialVisArea area = RNA_enum_get(op->ptr, "area");
347 if (area != PARTIALVIS_ALL)
348 return WM_border_select_invoke(C, op, event);
350 return op->type->exec(C, op);
353 void PAINT_OT_hide_show(struct wmOperatorType *ot)
355 static EnumPropertyItem action_items[] = {
356 {PARTIALVIS_HIDE, "HIDE", 0, "Hide", "Hide vertices"},
357 {PARTIALVIS_SHOW, "SHOW", 0, "Show", "Show vertices"},
360 static EnumPropertyItem area_items[] = {
361 {PARTIALVIS_OUTSIDE, "OUTSIDE", 0, "Outside",
362 "Hide or show vertices outside the selection"},
363 {PARTIALVIS_INSIDE, "INSIDE", 0, "Inside",
364 "Hide or show vertices inside the selection"},
365 {PARTIALVIS_ALL, "ALL", 0, "All",
366 "Hide or show all vertices"},
370 ot->name = "Hide/Show";
371 ot->idname = "PAINT_OT_hide_show";
374 ot->invoke = hide_show_invoke;
375 ot->modal = WM_border_select_modal;
376 ot->exec = hide_show_exec;
377 /* sculpt-only for now */
378 ot->poll = sculpt_mode_poll;
380 ot->flag = OPTYPE_REGISTER;
383 RNA_def_enum(ot->srna, "action", action_items, PARTIALVIS_HIDE,
384 "Action", "Whether to hide or show vertices");
385 RNA_def_enum(ot->srna, "area", area_items, PARTIALVIS_INSIDE,
386 "Area", "Which vertices to hide or show");
388 RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
389 RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
390 RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
391 RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);