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