Blender  V2.93
MOD_boolean.cc
Go to the documentation of this file.
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) 2005 by the Blender Foundation.
17  * All rights reserved.
18  */
19 
24 #include <cstdio>
25 
26 #include "BLI_utildefines.h"
27 
28 #include "BLI_array.hh"
29 #include "BLI_float4x4.hh"
30 #include "BLI_math_geom.h"
31 #include "BLI_math_matrix.h"
32 #include "BLI_vector.hh"
33 
34 #include "BLT_translation.h"
35 
36 #include "DNA_collection_types.h"
37 #include "DNA_defaults.h"
38 #include "DNA_mesh_types.h"
39 #include "DNA_meshdata_types.h"
40 #include "DNA_object_types.h"
41 #include "DNA_scene_types.h"
42 #include "DNA_screen_types.h"
43 
44 #include "BKE_collection.h"
45 #include "BKE_context.h"
46 #include "BKE_global.h" /* only to check G.debug */
47 #include "BKE_lib_id.h"
48 #include "BKE_lib_query.h"
49 #include "BKE_material.h"
50 #include "BKE_mesh.h"
52 #include "BKE_mesh_wrapper.h"
53 #include "BKE_modifier.h"
54 
55 #include "UI_interface.h"
56 #include "UI_resources.h"
57 
58 #include "RNA_access.h"
59 
60 #include "MOD_ui_common.h"
61 #include "MOD_util.h"
62 
63 #include "DEG_depsgraph_query.h"
64 
65 #include "MEM_guardedalloc.h"
66 
67 #include "bmesh.h"
68 #include "bmesh_tools.h"
69 #include "tools/bmesh_boolean.h"
70 #include "tools/bmesh_intersect.h"
71 
72 // #define DEBUG_TIME
73 
74 #ifdef DEBUG_TIME
75 # include "BLI_timeit.hh"
76 #endif
77 
78 using blender::Array;
79 using blender::float4x4;
80 using blender::Vector;
81 
82 static void initData(ModifierData *md)
83 {
85 
87 
89 }
90 
91 static bool isDisabled(const struct Scene *UNUSED(scene),
92  ModifierData *md,
93  bool UNUSED(useRenderParams))
94 {
96  Collection *col = bmd->collection;
97 
98  if (bmd->flag & eBooleanModifierFlag_Object) {
99  return !bmd->object || bmd->object->type != OB_MESH;
100  }
102  /* The Exact solver tolerates an empty collection. */
103  return !col && bmd->solver != eBooleanModifierSolver_Exact;
104  }
105  return false;
106 }
107 
108 static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
109 {
111 
112  walk(userData, ob, (ID **)&bmd->collection, IDWALK_CB_USER);
113  walk(userData, ob, (ID **)&bmd->object, IDWALK_CB_NOP);
114 }
115 
117 {
119  if ((bmd->flag & eBooleanModifierFlag_Object) && bmd->object != nullptr) {
120  DEG_add_object_relation(ctx->node, bmd->object, DEG_OB_COMP_TRANSFORM, "Boolean Modifier");
121  DEG_add_object_relation(ctx->node, bmd->object, DEG_OB_COMP_GEOMETRY, "Boolean Modifier");
122  }
123 
124  Collection *col = bmd->collection;
125 
126  if ((bmd->flag & eBooleanModifierFlag_Collection) && col != nullptr) {
127  DEG_add_collection_geometry_relation(ctx->node, col, "Boolean Modifier");
128  }
129  /* We need own transformation as well. */
130  DEG_add_modifier_to_transform_relation(ctx->node, "Boolean Modifier");
131 }
132 
134  Object *ob_self, Mesh *mesh_self, Object *ob_operand_ob, Mesh *mesh_operand_ob, int operation)
135 {
136  Mesh *result = nullptr;
137 
138  if (mesh_self->totpoly == 0 || mesh_operand_ob->totpoly == 0) {
139  switch (operation) {
141  result = BKE_mesh_new_nomain(0, 0, 0, 0, 0);
142  break;
143 
145  if (mesh_self->totpoly != 0) {
146  result = mesh_self;
147  }
148  else {
150  nullptr, &mesh_operand_ob->id, nullptr, LIB_ID_COPY_LOCALIZE);
151 
152  float imat[4][4];
153  float omat[4][4];
154  invert_m4_m4(imat, ob_self->obmat);
155  mul_m4_m4m4(omat, imat, ob_operand_ob->obmat);
156 
157  const int mverts_len = result->totvert;
158  MVert *mv = result->mvert;
159 
160  for (int i = 0; i < mverts_len; i++, mv++) {
161  mul_m4_v3(omat, mv->co);
162  }
163 
164  result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
165  }
166 
167  break;
168 
170  result = mesh_self;
171  break;
172  }
173  }
174 
175  return result;
176 }
177 
178 /* has no meaning for faces, do this so we can tell which face is which */
179 #define BM_FACE_TAG BM_ELEM_DRAW
180 
185 {
186  return BM_elem_flag_test(f, BM_FACE_TAG) ? 1 : 0;
187 }
188 
189 static bool BMD_error_messages(const Object *ob, ModifierData *md)
190 {
192  Collection *col = bmd->collection;
193 
194  bool error_returns_result = false;
195 
196  const bool operand_collection = (bmd->flag & eBooleanModifierFlag_Collection) != 0;
197  const bool use_exact = bmd->solver == eBooleanModifierSolver_Exact;
198  const bool operation_intersect = bmd->operation == eBooleanModifierOp_Intersect;
199 
200 #ifndef WITH_GMP
201  /* If compiled without GMP, return a error. */
202  if (use_exact) {
203  BKE_modifier_set_error(ob, md, "Compiled without GMP, using fast solver");
204  error_returns_result = false;
205  }
206 #endif
207 
208  /* If intersect is selected using fast solver, return a error. */
209  if (operand_collection && operation_intersect && !use_exact) {
210  BKE_modifier_set_error(ob, md, "Cannot execute, intersect only available using exact solver");
211  error_returns_result = true;
212  }
213 
214  /* If the selected collection is empty and using fast solver, return a error. */
215  if (operand_collection) {
216  if (!use_exact && BKE_collection_is_empty(col)) {
217  BKE_modifier_set_error(ob, md, "Cannot execute, fast solver and empty collection");
218  error_returns_result = true;
219  }
220 
221  /* If the selected collection contain non mesh objects, return a error. */
222  if (col) {
224  if (operand_ob->type != OB_MESH) {
226  ob, md, "Cannot execute, the selected collection contains non mesh objects");
227  error_returns_result = true;
228  }
229  }
231  }
232  }
233 
234  return error_returns_result;
235 }
236 
238  Mesh *mesh, Object *object, Mesh *mesh_operand_ob, Object *operand_ob, bool *r_is_flip)
239 {
240 #ifdef DEBUG_TIME
241  SCOPED_TIMER(__func__)
242 #endif
243 
244  *r_is_flip = (is_negative_m4(object->obmat) != is_negative_m4(operand_ob->obmat));
245 
246  const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh, mesh_operand_ob);
247 
248  BMeshCreateParams bmcp = {false};
249  BMesh *bm = BM_mesh_create(&allocsize, &bmcp);
250 
251  /* Needed so active layers are set based on `mesh` not `mesh_operand_ob`,
252  * otherwise the wrong active render layer is used, see T92384. */
254 
255  /* NOTE(@campbellbarton): Handle in #BM_mesh_bm_from_me, this is a local fix for T94197. */
257  mesh->cd_flag | mesh_operand_ob->cd_flag | BM_mesh_cd_flag_from_bmesh(bm));
258 
259  BMeshFromMeshParams bmesh_from_mesh_params{};
260  bmesh_from_mesh_params.calc_face_normal = true;
261  BM_mesh_bm_from_me(bm, mesh_operand_ob, &bmesh_from_mesh_params);
262 
263  if (UNLIKELY(*r_is_flip)) {
264  const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
265  BMIter iter;
266  BMFace *efa;
267  BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
268  BM_face_normal_flip_ex(bm, efa, cd_loop_mdisp_offset, true);
269  }
270  }
271 
272  BM_mesh_bm_from_me(bm, mesh, &bmesh_from_mesh_params);
273 
274  return bm;
275 }
276 
278  ModifierData *md,
279  const ModifierEvalContext *ctx,
280  Mesh *mesh_operand_ob,
281  Object *object,
282  Object *operand_ob,
283  bool is_flip)
284 {
285 #ifdef DEBUG_TIME
286  SCOPED_TIMER(__func__)
287 #endif
288 
290 
291  /* main bmesh intersection setup */
292  /* create tessface & intersect */
293  const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
294  int tottri;
295  BMLoop *(*looptris)[3] = (BMLoop * (*)[3])
296  MEM_malloc_arrayN(looptris_tot, sizeof(*looptris), __func__);
297 
298  BM_mesh_calc_tessellation_beauty(bm, looptris, &tottri);
299 
300  /* postpone this until after tessellating
301  * so we can use the original normals before the vertex are moved */
302  {
303  BMIter iter;
304  int i;
305  const int i_verts_end = mesh_operand_ob->totvert;
306  const int i_faces_end = mesh_operand_ob->totpoly;
307 
308  float imat[4][4];
309  float omat[4][4];
310  invert_m4_m4(imat, object->obmat);
311  mul_m4_m4m4(omat, imat, operand_ob->obmat);
312 
313  BMVert *eve;
314  i = 0;
315  BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
316  mul_m4_v3(omat, eve->co);
317  if (++i == i_verts_end) {
318  break;
319  }
320  }
321 
322  /* we need face normals because of 'BM_face_split_edgenet'
323  * we could calculate on the fly too (before calling split). */
324  float nmat[3][3];
325  copy_m3_m4(nmat, omat);
326  invert_m3(nmat);
327 
328  if (UNLIKELY(is_flip)) {
329  negate_m3(nmat);
330  }
331 
332  Array<short> material_remap(operand_ob->totcol ? operand_ob->totcol : 1);
333 
334  /* Using original (not evaluated) object here since we are writing to it. */
335  /* XXX Pretty sure comment above is fully wrong now with CoW & co ? */
336  BKE_object_material_remap_calc(ctx->object, operand_ob, material_remap.data());
337 
338  BMFace *efa;
339  i = 0;
340  BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
341  mul_transposed_m3_v3(nmat, efa->no);
342  normalize_v3(efa->no);
343 
344  /* Temp tag to test which side split faces are from. */
346 
347  /* remap material */
348  if (LIKELY(efa->mat_nr < operand_ob->totcol)) {
349  efa->mat_nr = material_remap[efa->mat_nr];
350  }
351 
352  if (++i == i_faces_end) {
353  break;
354  }
355  }
356  }
357 
358  /* not needed, but normals for 'dm' will be invalid,
359  * currently this is ok for 'BM_mesh_intersect' */
360  // BM_mesh_normals_update(bm);
361 
362  bool use_separate = false;
363  bool use_dissolve = true;
364  bool use_island_connect = true;
365 
366  /* change for testing */
367  if (G.debug & G_DEBUG) {
368  use_separate = (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_Separate) != 0;
369  use_dissolve = (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_NoDissolve) == 0;
370  use_island_connect = (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_NoConnectRegions) == 0;
371  }
372 
374  looptris,
375  tottri,
377  nullptr,
378  false,
379  use_separate,
380  use_dissolve,
381  use_island_connect,
382  false,
383  false,
384  bmd->operation,
385  bmd->double_threshold);
386 
387  MEM_freeN(looptris);
388 }
389 
390 #ifdef WITH_GMP
391 
392 /* Get a mapping from material slot numbers in the src_ob to slot numbers in the dst_ob.
393  * If a material doesn't exist in the dst_ob, the mapping just goes to the same slot
394  * or to zero if there aren't enough slots in the destination.
395  * Caller owns the returned array. */
396 static Array<short> get_material_remap(Object *dest_ob, Object *src_ob)
397 {
398  int n = src_ob->totcol;
399  if (n <= 0) {
400  n = 1;
401  }
402  Array<short> remap(n);
403  BKE_object_material_remap_calc(dest_ob, src_ob, remap.data());
404  return remap;
405 }
406 
407 static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
408  const ModifierEvalContext *ctx,
409  Mesh *mesh)
410 {
411  Vector<const Mesh *> meshes;
412  Vector<float4x4 *> obmats;
413  Vector<Array<short>> material_remaps;
414 
415 # ifdef DEBUG_TIME
416  SCOPED_TIMER(__func__)
417 # endif
418 
419  if ((bmd->flag & eBooleanModifierFlag_Object) && bmd->object == nullptr) {
420  return mesh;
421  }
422 
423  meshes.append(mesh);
424  obmats.append((float4x4 *)&ctx->object->obmat);
425  material_remaps.append({});
426  if (bmd->flag & eBooleanModifierFlag_Object) {
428  if (!mesh_operand) {
429  return mesh;
430  }
431  BKE_mesh_wrapper_ensure_mdata(mesh_operand);
432  meshes.append(mesh_operand);
433  obmats.append((float4x4 *)&bmd->object->obmat);
434  material_remaps.append(get_material_remap(ctx->object, bmd->object));
435  }
436  else if (bmd->flag & eBooleanModifierFlag_Collection) {
437  Collection *collection = bmd->collection;
438  /* Allow collection to be empty; then target mesh will just removed self-intersections. */
439  if (collection) {
441  if (ob->type == OB_MESH && ob != ctx->object) {
442  Mesh *collection_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob, false);
443  if (!collection_mesh) {
444  continue;
445  }
446  BKE_mesh_wrapper_ensure_mdata(collection_mesh);
447  meshes.append(collection_mesh);
448  obmats.append((float4x4 *)&ob->obmat);
449  material_remaps.append(get_material_remap(ctx->object, ob));
450  }
451  }
453  }
454  }
455 
456  const bool use_self = (bmd->flag & eBooleanModifierFlag_Self) != 0;
457  const bool hole_tolerant = (bmd->flag & eBooleanModifierFlag_HoleTolerant) != 0;
459  obmats,
460  *(float4x4 *)&ctx->object->obmat,
461  material_remaps,
462  use_self,
463  hole_tolerant,
464  bmd->operation);
465 }
466 #endif
467 
469 {
471  Object *object = ctx->object;
472  Mesh *result = mesh;
473  Collection *collection = bmd->collection;
474 
475  /* Return result for certain errors. */
476  if (BMD_error_messages(ctx->object, md)) {
477  return result;
478  }
479 
480 #ifdef WITH_GMP
481  if (bmd->solver == eBooleanModifierSolver_Exact) {
482  return exact_boolean_mesh(bmd, ctx, mesh);
483  }
484 #endif
485 
486 #ifdef DEBUG_TIME
487  SCOPED_TIMER(__func__)
488 #endif
489 
490  if (bmd->flag & eBooleanModifierFlag_Object) {
491  if (bmd->object == nullptr) {
492  return result;
493  }
494 
495  Object *operand_ob = bmd->object;
496 
497  Mesh *mesh_operand_ob = BKE_modifier_get_evaluated_mesh_from_evaluated_object(operand_ob,
498  false);
499 
500  if (mesh_operand_ob) {
501  /* XXX This is utterly non-optimal, we may go from a bmesh to a mesh back to a bmesh!
502  * But for 2.90 better not try to be smart here. */
503  BKE_mesh_wrapper_ensure_mdata(mesh_operand_ob);
504  /* when one of objects is empty (has got no faces) we could speed up
505  * calculation a bit returning one of objects' derived meshes (or empty one)
506  * Returning mesh is depended on modifiers operation (sergey) */
507  result = get_quick_mesh(object, mesh, operand_ob, mesh_operand_ob, bmd->operation);
508 
509  if (result == nullptr) {
510  bool is_flip;
511  BMesh *bm = BMD_mesh_bm_create(mesh, object, mesh_operand_ob, operand_ob, &is_flip);
512 
513  BMD_mesh_intersection(bm, md, ctx, mesh_operand_ob, object, operand_ob, is_flip);
514 
516 
517  BM_mesh_free(bm);
518  result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
519  }
520 
521  if (result == nullptr) {
522  BKE_modifier_set_error(object, md, "Cannot execute boolean operation");
523  }
524  }
525  }
526  else {
527  if (collection == nullptr) {
528  return result;
529  }
530 
531  FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection, operand_ob) {
532  if (operand_ob->type == OB_MESH && operand_ob != ctx->object) {
533  Mesh *mesh_operand_ob = BKE_modifier_get_evaluated_mesh_from_evaluated_object(operand_ob,
534  false);
535 
536  if (mesh_operand_ob) {
537  /* XXX This is utterly non-optimal, we may go from a bmesh to a mesh back to a bmesh!
538  * But for 2.90 better not try to be smart here. */
539  BKE_mesh_wrapper_ensure_mdata(mesh_operand_ob);
540 
541  bool is_flip;
542  BMesh *bm = BMD_mesh_bm_create(mesh, object, mesh_operand_ob, operand_ob, &is_flip);
543 
544  BMD_mesh_intersection(bm, md, ctx, mesh_operand_ob, object, operand_ob, is_flip);
545 
546  /* Needed for multiple objects to work. */
548  params.calc_object_remap = false;
549  BM_mesh_bm_to_me(nullptr, bm, mesh, &params);
550 
552  BM_mesh_free(bm);
553  result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
554  }
555  }
556  }
558  }
559 
560  return result;
561 }
562 
563 static void requiredDataMask(Object *UNUSED(ob),
564  ModifierData *UNUSED(md),
565  CustomData_MeshMasks *r_cddata_masks)
566 {
567  r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
568  r_cddata_masks->emask |= CD_MASK_MEDGE;
569  r_cddata_masks->fmask |= CD_MASK_MTFACE;
570 }
571 
572 static void panel_draw(const bContext *UNUSED(C), Panel *panel)
573 {
574  uiLayout *layout = panel->layout;
576 
577  uiItemR(layout, ptr, "operation", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
578 
579  uiLayoutSetPropSep(layout, true);
580 
581  uiItemR(layout, ptr, "operand_type", 0, nullptr, ICON_NONE);
582  if (RNA_enum_get(ptr, "operand_type") == eBooleanModifierFlag_Object) {
583  uiItemR(layout, ptr, "object", 0, nullptr, ICON_NONE);
584  }
585  else {
586  uiItemR(layout, ptr, "collection", 0, nullptr, ICON_NONE);
587  }
588 
589  uiItemR(layout, ptr, "solver", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
590 
591  modifier_panel_end(layout, ptr);
592 }
593 
594 static void solver_options_panel_draw(const bContext *UNUSED(C), Panel *panel)
595 {
596  uiLayout *layout = panel->layout;
598 
599  const bool use_exact = RNA_enum_get(ptr, "solver") == eBooleanModifierSolver_Exact;
600 
601  uiLayoutSetPropSep(layout, true);
602 
603  uiLayout *col = uiLayoutColumn(layout, true);
604  if (use_exact) {
605  /* When operand is collection, we always use_self. */
606  if (RNA_enum_get(ptr, "operand_type") == eBooleanModifierFlag_Object) {
607  uiItemR(col, ptr, "use_self", 0, nullptr, ICON_NONE);
608  }
609  uiItemR(col, ptr, "use_hole_tolerant", 0, nullptr, ICON_NONE);
610  }
611  else {
612  uiItemR(col, ptr, "double_threshold", 0, nullptr, ICON_NONE);
613  }
614 
615  if (G.debug) {
616  uiItemR(col, ptr, "debug_options", 0, nullptr, ICON_NONE);
617  }
618 }
619 
620 static void panelRegister(ARegionType *region_type)
621 {
624  region_type, "solver_options", "Solver Options", nullptr, solver_options_panel_draw, panel);
625 }
626 
628  /* name */ "Boolean",
629  /* structName */ "BooleanModifierData",
630  /* structSize */ sizeof(BooleanModifierData),
631  /* srna */ &RNA_BooleanModifier,
633  /* flags */
635  /* icon */ ICON_MOD_BOOLEAN,
636 
637  /* copyData */ BKE_modifier_copydata_generic,
638 
639  /* deformVerts */ nullptr,
640  /* deformMatrices */ nullptr,
641  /* deformVertsEM */ nullptr,
642  /* deformMatricesEM */ nullptr,
643  /* modifyMesh */ modifyMesh,
644  /* modifyHair */ nullptr,
645  /* modifyGeometrySet */ nullptr,
646  /* modifyVolume */ nullptr,
647 
648  /* initData */ initData,
649  /* requiredDataMask */ requiredDataMask,
650  /* freeData */ nullptr,
651  /* isDisabled */ isDisabled,
652  /* updateDepsgraph */ updateDepsgraph,
653  /* dependsOnTime */ nullptr,
654  /* dependsOnNormals */ nullptr,
655  /* foreachIDLink */ foreachIDLink,
656  /* foreachTexLink */ nullptr,
657  /* freeRuntimeData */ nullptr,
658  /* panelRegister */ panelRegister,
659  /* blendWrite */ nullptr,
660  /* blendRead */ nullptr,
661 };
#define FOREACH_COLLECTION_OBJECT_RECURSIVE_END
#define FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(_collection, _object)
bool BKE_collection_is_empty(const struct Collection *collection)
int CustomData_get_offset(const struct CustomData *data, int type)
@ G_DEBUG
Definition: BKE_global.h:133
@ LIB_ID_COPY_LOCALIZE
Definition: BKE_lib_id.h:145
struct ID * BKE_id_copy_ex(struct Main *bmain, const struct ID *id, struct ID **r_newid, const int flag)
@ IDWALK_CB_USER
Definition: BKE_lib_query.h:87
@ IDWALK_CB_NOP
Definition: BKE_lib_query.h:47
General operations, lookup, etc. for materials.
void BKE_object_material_remap_calc(struct Object *ob_dst, struct Object *ob_src, short *remap_src_to_dst)
Definition: material.c:983
struct Mesh * BKE_mesh_new_nomain(int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len)
Definition: mesh.c:877
struct Mesh * BKE_mesh_from_bmesh_for_eval_nomain(struct BMesh *bm, const struct CustomData_MeshMasks *cd_mask_extra, const struct Mesh *me_settings)
void BKE_mesh_wrapper_ensure_mdata(struct Mesh *me)
Definition: mesh_wrapper.c:98
void(* IDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cb_flag)
Definition: BKE_modifier.h:120
ModifierTypeFlag
Definition: BKE_modifier.h:79
@ eModifierTypeFlag_SupportsEditmode
Definition: BKE_modifier.h:83
@ eModifierTypeFlag_AcceptsMesh
Definition: BKE_modifier.h:80
void BKE_modifier_copydata_generic(const struct ModifierData *md, struct ModifierData *md_dst, const int flag)
@ eModifierTypeType_Nonconstructive
Definition: BKE_modifier.h:63
void BKE_modifier_set_error(const struct Object *ob, struct ModifierData *md, const char *format,...) ATTR_PRINTF_FORMAT(3
struct Mesh * BKE_modifier_get_evaluated_mesh_from_evaluated_object(struct Object *ob_eval, const bool get_cage_mesh)
#define BLI_assert(a)
Definition: BLI_assert.h:58
MINLINE int poly_to_tri_count(const int poly_count, const int corner_count)
void negate_m3(float R[3][3])
Definition: math_matrix.c:993
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:262
void copy_m3_m4(float m1[3][3], const float m2[4][4])
Definition: math_matrix.c:105
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1278
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:732
bool is_negative_m4(const float mat[4][4])
Definition: math_matrix.c:2590
bool invert_m3(float R[3][3])
Definition: math_matrix.c:1152
void mul_transposed_m3_v3(const float M[3][3], float r[3])
Definition: math_matrix.c:940
MINLINE float normalize_v3(float r[3])
#define SCOPED_TIMER(name)
Definition: BLI_timeit.hh:57
#define UNUSED(x)
#define UNLIKELY(x)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define LIKELY(x)
void DEG_add_object_relation(struct DepsNodeHandle *node_handle, struct Object *object, eDepsObjectComponentType component, const char *description)
void DEG_add_modifier_to_transform_relation(struct DepsNodeHandle *node_handle, const char *description)
void DEG_add_collection_geometry_relation(struct DepsNodeHandle *node_handle, struct Collection *collection, const char *description)
@ DEG_OB_COMP_GEOMETRY
@ DEG_OB_COMP_TRANSFORM
Object groups, one object can be in many groups at once.
#define CD_MASK_NORMAL
#define CD_MASK_MDEFORMVERT
#define CD_MASK_MEDGE
#define CD_MASK_MTFACE
#define DNA_struct_default_get(struct_name)
Definition: DNA_defaults.h:44
@ eBooleanModifierSolver_Exact
@ eBooleanModifierBMeshFlag_BMesh_NoDissolve
@ eBooleanModifierBMeshFlag_BMesh_Separate
@ eBooleanModifierBMeshFlag_BMesh_NoConnectRegions
@ eBooleanModifierFlag_Collection
@ eBooleanModifierFlag_Self
@ eBooleanModifierFlag_HoleTolerant
@ eBooleanModifierFlag_Object
@ eModifierType_Boolean
struct BooleanModifierData BooleanModifierData
@ eBooleanModifierOp_Intersect
@ eBooleanModifierOp_Union
@ eBooleanModifierOp_Difference
Object is a sort of wrapper for general info.
@ OB_MESH
Read Guarded memory(de)allocation.
static Mesh * modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
Definition: MOD_boolean.cc:468
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
Definition: MOD_boolean.cc:116
static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams))
Definition: MOD_boolean.cc:91
static void BMD_mesh_intersection(BMesh *bm, ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh_operand_ob, Object *object, Object *operand_ob, bool is_flip)
Definition: MOD_boolean.cc:277
static void requiredDataMask(Object *UNUSED(ob), ModifierData *UNUSED(md), CustomData_MeshMasks *r_cddata_masks)
Definition: MOD_boolean.cc:563
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
Definition: MOD_boolean.cc:108
#define BM_FACE_TAG
Definition: MOD_boolean.cc:179
static bool BMD_error_messages(const Object *ob, ModifierData *md)
Definition: MOD_boolean.cc:189
static BMesh * BMD_mesh_bm_create(Mesh *mesh, Object *object, Mesh *mesh_operand_ob, Object *operand_ob, bool *r_is_flip)
Definition: MOD_boolean.cc:237
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
Definition: MOD_boolean.cc:572
static Mesh * get_quick_mesh(Object *ob_self, Mesh *mesh_self, Object *ob_operand_ob, Mesh *mesh_operand_ob, int operation)
Definition: MOD_boolean.cc:133
static void initData(ModifierData *md)
Definition: MOD_boolean.cc:82
static void panelRegister(ARegionType *region_type)
Definition: MOD_boolean.cc:620
static void solver_options_panel_draw(const bContext *UNUSED(C), Panel *panel)
Definition: MOD_boolean.cc:594
ModifierTypeInfo modifierType_Boolean
Definition: MOD_boolean.cc:627
static int bm_face_isect_pair(BMFace *f, void *UNUSED(user_data))
Definition: MOD_boolean.cc:184
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
PanelType * modifier_subpanel_register(ARegionType *region_type, const char *name, const char *label, PanelDrawFn draw_header, PanelDrawFn draw, PanelType *parent)
StructRNA RNA_BooleanModifier
#define C
Definition: RandGen.cpp:39
@ UI_ITEM_R_EXPAND
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
void BM_mesh_copy_init_customdata_from_mesh(BMesh *bm_dst, const Mesh *me_src, const BMAllocTemplate *allocsize)
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:26
#define BM_elem_flag_enable(ele, hflag)
Definition: bmesh_inline.h:28
bool BM_mesh_intersect(BMesh *bm, struct BMLoop *(*looptris)[3], const int looptris_tot, int(*test_fn)(BMFace *f, void *user_data), void *user_data, const bool use_self, const bool use_separate, const bool use_dissolve, const bool use_island_connect, const bool use_partial_connect, const bool use_edge_tag, const int boolean_mode, const float eps)
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_VERTS_OF_MESH
@ BM_FACES_OF_MESH
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_free(BMesh *bm)
BMesh Free Mesh.
Definition: bmesh_mesh.c:307
BMesh * BM_mesh_create(const BMAllocTemplate *allocsize, const struct BMeshCreateParams *params)
BMesh Make Mesh.
Definition: bmesh_mesh.c:157
#define BMALLOC_TEMPLATE_FROM_ME(...)
Definition: bmesh_mesh.h:163
char BM_mesh_cd_flag_from_bmesh(BMesh *bm)
void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshParams *params)
Mesh -> BMesh.
void BM_mesh_cd_flag_apply(BMesh *bm, const char cd_flag)
void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMeshParams *params)
void BM_mesh_calc_tessellation_beauty(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptris_tot)
void BM_face_normal_flip_ex(BMesh *bm, BMFace *f, const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip)
Face Flip Normal.
const T * data() const
Definition: BLI_array.hh:297
void append(const T &value)
Definition: BLI_vector.hh:438
Scene scene
void * user_data
uint col
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:48
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
Mesh * direct_mesh_boolean(blender::Span< const Mesh * > meshes, blender::Span< const float4x4 * > obmats, const float4x4 &target_transform, blender::Span< blender::Array< short >> material_remaps, const bool use_self, const bool hole_tolerant, const int boolean_mode)
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6402
short mat_nr
Definition: bmesh_class.h:281
float no[3]
Definition: bmesh_class.h:280
float co[3]
Definition: bmesh_class.h:99
int totloop
Definition: bmesh_class.h:297
CustomData ldata
Definition: bmesh_class.h:337
int totface
Definition: bmesh_class.h:297
struct Object * object
struct Collection * collection
Definition: DNA_ID.h:273
char cd_flag
int totvert
int totpoly
struct Object * object
Definition: BKE_modifier.h:154
struct DepsNodeHandle * node
Definition: BKE_modifier.h:147
float obmat[4][4]
struct uiLayout * layout
#define G(x, y, z)
PointerRNA * ptr
Definition: wm_files.c:3157