Blender V4.3
MOD_boolean.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2005 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <cstdio>
10
11#include "BLI_utildefines.h"
12
13#include "BLI_array.hh"
14#include "BLI_math_geom.h"
15#include "BLI_math_matrix.h"
17#include "BLI_vector.hh"
18#include "BLI_vector_set.hh"
19
20#include "BLT_translation.hh"
21
22#include "DNA_defaults.h"
23#include "DNA_mesh_types.h"
24#include "DNA_object_types.h"
25#include "DNA_scene_types.h"
26#include "DNA_screen_types.h"
27
28#include "BKE_collection.hh"
29#include "BKE_global.hh" /* only to check G.debug */
30#include "BKE_lib_id.hh"
31#include "BKE_lib_query.hh"
32#include "BKE_material.h"
33#include "BKE_mesh.hh"
34#include "BKE_mesh_wrapper.hh"
35#include "BKE_modifier.hh"
36
37#include "UI_interface.hh"
38#include "UI_resources.hh"
39
40#include "RNA_access.hh"
41#include "RNA_prototypes.hh"
42
43#include "MOD_ui_common.hh"
44
45#include "MEM_guardedalloc.h"
46
47#include "GEO_mesh_boolean.hh"
48#include "GEO_randomize.hh"
49
50#include "bmesh.hh"
52
53// #define DEBUG_TIME
54
55#ifdef DEBUG_TIME
56# include "BLI_timeit.hh"
57#endif
58
59using blender::Array;
60using blender::float3;
64using blender::Span;
65using blender::Vector;
67
76
77static bool is_disabled(const Scene * /*scene*/, ModifierData *md, bool /*use_render_params*/)
78{
81
83 return !bmd->object || bmd->object->type != OB_MESH;
84 }
86 /* The Exact solver tolerates an empty collection. */
88 }
89 return false;
90}
91
92static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
93{
95
96 walk(user_data, ob, (ID **)&bmd->collection, IDWALK_CB_USER);
97 walk(user_data, ob, (ID **)&bmd->object, IDWALK_CB_NOP);
98}
99
101{
103 if ((bmd->flag & eBooleanModifierFlag_Object) && bmd->object != nullptr) {
104 DEG_add_object_relation(ctx->node, bmd->object, DEG_OB_COMP_TRANSFORM, "Boolean Modifier");
105 DEG_add_object_relation(ctx->node, bmd->object, DEG_OB_COMP_GEOMETRY, "Boolean Modifier");
106 }
107
108 Collection *col = bmd->collection;
109
110 if ((bmd->flag & eBooleanModifierFlag_Collection) && col != nullptr) {
111 DEG_add_collection_geometry_relation(ctx->node, col, "Boolean Modifier");
112 }
113 /* We need own transformation as well. */
114 DEG_add_depends_on_transform_relation(ctx->node, "Boolean Modifier");
115}
116
118 Object *ob_self, Mesh *mesh_self, Object *ob_operand_ob, Mesh *mesh_operand_ob, int operation)
119{
120 Mesh *result = nullptr;
121
122 if (mesh_self->faces_num == 0 || mesh_operand_ob->faces_num == 0) {
123 switch (operation) {
125 result = BKE_mesh_new_nomain(0, 0, 0, 0);
126 break;
127
129 if (mesh_self->faces_num != 0) {
130 result = mesh_self;
131 }
132 else {
133 result = (Mesh *)BKE_id_copy_ex(
134 nullptr, &mesh_operand_ob->id, nullptr, LIB_ID_COPY_LOCALIZE);
135
136 float imat[4][4];
137 float omat[4][4];
138 invert_m4_m4(imat, ob_self->object_to_world().ptr());
139 mul_m4_m4m4(omat, imat, ob_operand_ob->object_to_world().ptr());
140
141 MutableSpan<float3> positions = result->vert_positions_for_write();
142 for (const int i : positions.index_range()) {
143 mul_m4_v3(omat, positions[i]);
144 }
145
146 result->tag_positions_changed();
147 }
148
149 break;
150
152 result = mesh_self;
153 break;
154 }
155 }
156
157 return result;
158}
159
160/* has no meaning for faces, do this so we can tell which face is which */
161#define BM_FACE_TAG BM_ELEM_DRAW
162
166static int bm_face_isect_pair(BMFace *f, void * /*user_data*/)
167{
168 return BM_elem_flag_test(f, BM_FACE_TAG) ? 1 : 0;
169}
170
171static bool BMD_error_messages(const Object *ob, ModifierData *md)
172{
174 Collection *col = bmd->collection;
175
176 bool error_returns_result = false;
177
178 const bool operand_collection = (bmd->flag & eBooleanModifierFlag_Collection) != 0;
179 const bool use_exact = bmd->solver == eBooleanModifierSolver_Mesh_Arr;
180 const bool operation_intersect = bmd->operation == eBooleanModifierOp_Intersect;
181
182#ifndef WITH_GMP
183 /* If compiled without GMP, return a error. */
184 if (use_exact) {
185 BKE_modifier_set_error(ob, md, "Compiled without GMP, using fast solver");
186 error_returns_result = false;
187 }
188#endif
189
190 /* If intersect is selected using fast solver, return a error. */
191 if (operand_collection && operation_intersect && !use_exact) {
192 BKE_modifier_set_error(ob, md, "Cannot execute, intersect only available using exact solver");
193 error_returns_result = true;
194 }
195
196 /* If the selected collection is empty and using fast solver, return a error. */
197 if (operand_collection) {
198 if (!use_exact && BKE_collection_is_empty(col)) {
199 BKE_modifier_set_error(ob, md, "Cannot execute, fast solver and empty collection");
200 error_returns_result = true;
201 }
202
203 /* If the selected collection contain non mesh objects, return a error. */
204 if (col) {
206 if (operand_ob->type != OB_MESH) {
208 ob, md, "Cannot execute, the selected collection contains non mesh objects");
209 error_returns_result = true;
210 }
211 }
213 }
214 }
215
216 return error_returns_result;
217}
218
220 Mesh *mesh, Object *object, Mesh *mesh_operand_ob, Object *operand_ob, bool *r_is_flip)
221{
222#ifdef DEBUG_TIME
223 SCOPED_TIMER(__func__);
224#endif
225
226 *r_is_flip = (is_negative_m4(object->object_to_world().ptr()) !=
227 is_negative_m4(operand_ob->object_to_world().ptr()));
228
229 const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh, mesh_operand_ob);
230
231 BMeshCreateParams bmesh_create_params{};
232 BMesh *bm = BM_mesh_create(&allocsize, &bmesh_create_params);
233
234 /* Keep `mesh` first, needed so active layers are set based on `mesh` not `mesh_operand_ob`,
235 * otherwise the wrong active render layer is used, see #92384.
236 *
237 * NOTE: while initializing customer data layers the is not essential,
238 * it avoids the overhead of having to re-allocate #BMHeader.data when the 2nd mesh is added
239 * (if it contains additional custom-data layers). */
240 const Mesh *mesh_array[2] = {mesh, mesh_operand_ob};
241 BM_mesh_copy_init_customdata_from_mesh_array(bm, mesh_array, ARRAY_SIZE(mesh_array), &allocsize);
242
243 BMeshFromMeshParams bmesh_from_mesh_params{};
244 bmesh_from_mesh_params.calc_face_normal = true;
245 bmesh_from_mesh_params.calc_vert_normal = true;
246 BM_mesh_bm_from_me(bm, mesh_operand_ob, &bmesh_from_mesh_params);
247
248 if (UNLIKELY(*r_is_flip)) {
249 const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
250 BMIter iter;
251 BMFace *efa;
252 BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
253 BM_face_normal_flip_ex(bm, efa, cd_loop_mdisp_offset, true);
254 }
255 }
256
257 BM_mesh_bm_from_me(bm, mesh, &bmesh_from_mesh_params);
258
259 return bm;
260}
261
263 ModifierData *md,
264 const ModifierEvalContext *ctx,
265 Mesh *mesh_operand_ob,
266 Object *object,
267 Object *operand_ob,
268 bool is_flip)
269{
270#ifdef DEBUG_TIME
271 SCOPED_TIMER(__func__);
272#endif
273
275
276 /* Main BMesh intersection setup. */
277 /* Create tessellation & intersect. */
278 const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
279 blender::Array<std::array<BMLoop *, 3>> looptris(looptris_tot);
281
282 /* postpone this until after tessellating
283 * so we can use the original normals before the vertex are moved */
284 {
285 BMIter iter;
286 int i;
287 const int i_verts_end = mesh_operand_ob->verts_num;
288 const int i_faces_end = mesh_operand_ob->faces_num;
289
290 float imat[4][4];
291 float omat[4][4];
292 invert_m4_m4(imat, object->object_to_world().ptr());
293 mul_m4_m4m4(omat, imat, operand_ob->object_to_world().ptr());
294
295 BMVert *eve;
296 i = 0;
297 BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
298 mul_m4_v3(omat, eve->co);
299 if (++i == i_verts_end) {
300 break;
301 }
302 }
303
304 /* we need face normals because of 'BM_face_split_edgenet'
305 * we could calculate on the fly too (before calling split). */
306 float nmat[3][3];
307 copy_m3_m4(nmat, omat);
308 invert_m3(nmat);
309
310 if (UNLIKELY(is_flip)) {
311 negate_m3(nmat);
312 }
313
314 Array<short> material_remap(operand_ob->totcol ? operand_ob->totcol : 1);
315
316 /* Using original (not evaluated) object here since we are writing to it. */
317 /* XXX Pretty sure comment above is fully wrong now with copy-on-eval & co ? */
318 BKE_object_material_remap_calc(ctx->object, operand_ob, material_remap.data());
319
320 BMFace *efa;
321 i = 0;
322 BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
323 mul_transposed_m3_v3(nmat, efa->no);
324 normalize_v3(efa->no);
325
326 /* Temp tag to test which side split faces are from. */
328
329 /* remap material */
330 if (LIKELY(efa->mat_nr < operand_ob->totcol)) {
331 efa->mat_nr = material_remap[efa->mat_nr];
332 }
333 else {
334 efa->mat_nr = 0;
335 }
336
337 if (++i == i_faces_end) {
338 break;
339 }
340 }
341 }
342
343 /* not needed, but normals for 'dm' will be invalid,
344 * currently this is ok for 'BM_mesh_intersect' */
345 // BM_mesh_normals_update(bm);
346
347 bool use_separate = false;
348 bool use_dissolve = true;
349 bool use_island_connect = true;
350
351 /* change for testing */
352 if (G.debug & G_DEBUG) {
353 use_separate = (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_Separate) != 0;
354 use_dissolve = (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_NoDissolve) == 0;
355 use_island_connect = (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_NoConnectRegions) == 0;
356 }
357
359 looptris,
361 nullptr,
362 false,
363 use_separate,
364 use_dissolve,
365 use_island_connect,
366 false,
367 false,
368 bmd->operation,
369 bmd->double_threshold);
370}
371
372#ifdef WITH_GMP
373
374/* Get a mapping from material slot numbers in the src_ob to slot numbers in the dst_ob.
375 * If a material doesn't exist in the dst_ob, the mapping just goes to the same slot
376 * or to zero if there aren't enough slots in the destination. */
377static Array<short> get_material_remap_index_based(Object *dest_ob, Object *src_ob)
378{
379 const int n = src_ob->totcol;
380 if (n <= 0) {
381 return Array<short>(1, 0);
382 }
383 Array<short> remap(n);
384 BKE_object_material_remap_calc(dest_ob, src_ob, remap.data());
385 return remap;
386}
387
388/* Get a mapping from material slot numbers in the source geometry to slot numbers in the result
389 * geometry. The material is added to the result geometry if it doesn't already use it. */
390static Array<short> get_material_remap_transfer(Object &object,
391 const Mesh &mesh,
392 VectorSet<Material *> &materials)
393{
394 const int material_num = mesh.totcol;
395 Array<short> map(material_num);
396 for (const int i : IndexRange(material_num)) {
397 Material *material = BKE_object_material_get_eval(&object, i + 1);
398 map[i] = material ? materials.index_of_or_add(material) : -1;
399 }
400 return map;
401}
402
403static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
404 const ModifierEvalContext *ctx,
405 Mesh *mesh)
406{
408 Vector<float4x4> obmats;
409
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(ctx->object->object_to_world());
422 material_remaps.append({});
423
425 bmd->material_mode);
426 VectorSet<Material *> materials;
427 if (material_mode == eBooleanModifierMaterialMode_Transfer) {
428 if (mesh->totcol == 0) {
429 /* Necessary for faces using the default material when there are no material slots. */
430 materials.add(nullptr);
431 }
432 else {
433 materials.add_multiple({mesh->mat, mesh->totcol});
434 }
435 }
436
439 if (!mesh_operand) {
440 return mesh;
441 }
442 BKE_mesh_wrapper_ensure_mdata(mesh_operand);
443 meshes.append(mesh_operand);
444 obmats.append(bmd->object->object_to_world());
445 if (material_mode == eBooleanModifierMaterialMode_Index) {
446 material_remaps.append(get_material_remap_index_based(ctx->object, bmd->object));
447 }
448 else {
449 material_remaps.append(get_material_remap_transfer(*bmd->object, *mesh_operand, materials));
450 }
451 }
452 else if (bmd->flag & eBooleanModifierFlag_Collection) {
453 Collection *collection = bmd->collection;
454 /* Allow collection to be empty; then target mesh will just removed self-intersections. */
455 if (collection) {
457 if (ob->type == OB_MESH && ob != ctx->object) {
459 if (!collection_mesh) {
460 continue;
461 }
462 BKE_mesh_wrapper_ensure_mdata(collection_mesh);
463 meshes.append(collection_mesh);
464 obmats.append(ob->object_to_world());
465 if (material_mode == eBooleanModifierMaterialMode_Index) {
466 material_remaps.append(get_material_remap_index_based(ctx->object, ob));
467 }
468 else {
469 material_remaps.append(get_material_remap_transfer(*ob, *collection_mesh, materials));
470 }
471 }
472 }
474 }
475 }
476
477 const bool use_self = (bmd->flag & eBooleanModifierFlag_Self) != 0;
478 const bool hole_tolerant = (bmd->flag & eBooleanModifierFlag_HoleTolerant) != 0;
481 op_params.no_self_intersections = !use_self;
482 op_params.watertight = !hole_tolerant;
483 op_params.no_nested_components = false;
485 meshes,
486 obmats,
487 ctx->object->object_to_world(),
488 material_remaps,
489 op_params,
491 nullptr);
492
493 if (material_mode == eBooleanModifierMaterialMode_Transfer) {
494 MEM_SAFE_FREE(result->mat);
495 result->mat = (Material **)MEM_malloc_arrayN(materials.size(), sizeof(Material *), __func__);
496 result->totcol = materials.size();
497 MutableSpan(result->mat, result->totcol).copy_from(materials);
498 }
499
501
502 return result;
503}
504#endif
505
506static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
507{
509 Object *object = ctx->object;
510 Mesh *result = mesh;
511 Collection *collection = bmd->collection;
512
513 /* Return result for certain errors. */
514 if (BMD_error_messages(ctx->object, md)) {
515 return result;
516 }
517
518#ifdef WITH_GMP
520 return exact_boolean_mesh(bmd, ctx, mesh);
521 }
522#endif
523
524#ifdef DEBUG_TIME
525 SCOPED_TIMER(__func__);
526#endif
527
529 if (bmd->object == nullptr) {
530 return result;
531 }
532
533 Object *operand_ob = bmd->object;
534
535 Mesh *mesh_operand_ob = BKE_modifier_get_evaluated_mesh_from_evaluated_object(operand_ob);
536
537 if (mesh_operand_ob) {
538 /* XXX This is utterly non-optimal, we may go from a bmesh to a mesh back to a bmesh!
539 * But for 2.90 better not try to be smart here. */
540 BKE_mesh_wrapper_ensure_mdata(mesh_operand_ob);
541 /* when one of objects is empty (has got no faces) we could speed up
542 * calculation a bit returning one of objects' derived meshes (or empty one)
543 * Returning mesh is dependent on modifiers operation (sergey) */
544 result = get_quick_mesh(object, mesh, operand_ob, mesh_operand_ob, bmd->operation);
545
546 if (result == nullptr) {
547 bool is_flip;
548 BMesh *bm = BMD_mesh_bm_create(mesh, object, mesh_operand_ob, operand_ob, &is_flip);
549
550 BMD_mesh_intersection(bm, md, ctx, mesh_operand_ob, object, operand_ob, is_flip);
551
552 result = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, mesh);
553
555 }
556
557 if (result == nullptr) {
558 BKE_modifier_set_error(object, md, "Cannot execute boolean operation");
559 }
560 }
561 }
562 else {
563 if (collection == nullptr) {
564 return result;
565 }
566
567 FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection, operand_ob) {
568 if (operand_ob->type == OB_MESH && operand_ob != ctx->object) {
569 Mesh *mesh_operand_ob = BKE_modifier_get_evaluated_mesh_from_evaluated_object(operand_ob);
570
571 if (mesh_operand_ob == nullptr) {
572 continue;
573 }
574
575 /* XXX This is utterly non-optimal, we may go from a bmesh to a mesh back to a bmesh!
576 * But for 2.90 better not try to be smart here. */
577 BKE_mesh_wrapper_ensure_mdata(mesh_operand_ob);
578
579 bool is_flip;
580 BMesh *bm = BMD_mesh_bm_create(result, object, mesh_operand_ob, operand_ob, &is_flip);
581
582 BMD_mesh_intersection(bm, md, ctx, mesh_operand_ob, object, operand_ob, is_flip);
583
584 /* Needed for multiple objects to work. */
585 if (result == mesh) {
586 result = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, mesh);
587 }
588 else {
589 BMeshToMeshParams bmesh_to_mesh_params{};
590 bmesh_to_mesh_params.calc_object_remap = false;
591 BM_mesh_bm_to_me(nullptr, bm, result, &bmesh_to_mesh_params);
592 }
594 }
595 }
597 }
598
600
601 return result;
602}
603
604static void required_data_mask(ModifierData * /*md*/, CustomData_MeshMasks *r_cddata_masks)
605{
606 r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
607 r_cddata_masks->fmask |= CD_MASK_MTFACE;
608}
609
610static void panel_draw(const bContext * /*C*/, Panel *panel)
611{
612 uiLayout *layout = panel->layout;
614
615 uiItemR(layout, ptr, "operation", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
616
617 uiLayoutSetPropSep(layout, true);
618
619 uiItemR(layout, ptr, "operand_type", UI_ITEM_NONE, nullptr, ICON_NONE);
620 if (RNA_enum_get(ptr, "operand_type") == eBooleanModifierFlag_Object) {
621 uiItemR(layout, ptr, "object", UI_ITEM_NONE, nullptr, ICON_NONE);
622 }
623 else {
624 uiItemR(layout, ptr, "collection", UI_ITEM_NONE, nullptr, ICON_NONE);
625 }
626
627 uiItemR(layout, ptr, "solver", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
628
629 modifier_panel_end(layout, ptr);
630}
631
632static void solver_options_panel_draw(const bContext * /*C*/, Panel *panel)
633{
634 uiLayout *layout = panel->layout;
636
637 const bool use_exact = RNA_enum_get(ptr, "solver") == eBooleanModifierSolver_Mesh_Arr;
638
639 uiLayoutSetPropSep(layout, true);
640
641 uiLayout *col = uiLayoutColumn(layout, true);
642 if (use_exact) {
643 uiItemR(col, ptr, "material_mode", UI_ITEM_NONE, IFACE_("Materials"), ICON_NONE);
644 /* When operand is collection, we always use_self. */
645 if (RNA_enum_get(ptr, "operand_type") == eBooleanModifierFlag_Object) {
646 uiItemR(col, ptr, "use_self", UI_ITEM_NONE, nullptr, ICON_NONE);
647 }
648 uiItemR(col, ptr, "use_hole_tolerant", UI_ITEM_NONE, nullptr, ICON_NONE);
649 }
650 else {
651 uiItemR(col, ptr, "double_threshold", UI_ITEM_NONE, nullptr, ICON_NONE);
652 }
653
654 if (G.debug) {
655 uiItemR(col, ptr, "debug_options", UI_ITEM_NONE, nullptr, ICON_NONE);
656 }
657}
658
659static void panel_register(ARegionType *region_type)
660{
663 region_type, "solver_options", "Solver Options", nullptr, solver_options_panel_draw, panel);
664}
665
667 /*idname*/ "Boolean",
668 /*name*/ N_("Boolean"),
669 /*struct_name*/ "BooleanModifierData",
670 /*struct_size*/ sizeof(BooleanModifierData),
671 /*srna*/ &RNA_BooleanModifier,
673 /*flags*/
675 /*icon*/ ICON_MOD_BOOLEAN,
676
677 /*copy_data*/ BKE_modifier_copydata_generic,
678
679 /*deform_verts*/ nullptr,
680 /*deform_matrices*/ nullptr,
681 /*deform_verts_EM*/ nullptr,
682 /*deform_matrices_EM*/ nullptr,
683 /*modify_mesh*/ modify_mesh,
684 /*modify_geometry_set*/ nullptr,
685
686 /*init_data*/ init_data,
687 /*required_data_mask*/ required_data_mask,
688 /*free_data*/ nullptr,
689 /*is_disabled*/ is_disabled,
690 /*update_depsgraph*/ update_depsgraph,
691 /*depends_on_time*/ nullptr,
692 /*depends_on_normals*/ nullptr,
693 /*foreach_ID_link*/ foreach_ID_link,
694 /*foreach_tex_link*/ nullptr,
695 /*free_runtime_data*/ nullptr,
696 /*panel_register*/ panel_register,
697 /*blend_write*/ nullptr,
698 /*blend_read*/ nullptr,
699 /*foreach_cache*/ nullptr,
700};
#define FOREACH_COLLECTION_OBJECT_RECURSIVE_END
bool BKE_collection_is_empty(const Collection *collection)
#define FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(_collection, _object)
int CustomData_get_offset(const CustomData *data, eCustomDataType type)
@ G_DEBUG
@ LIB_ID_COPY_LOCALIZE
ID * BKE_id_copy_ex(Main *bmain, const ID *id, ID **new_id_p, int flag)
Definition lib_id.cc:760
@ IDWALK_CB_USER
@ IDWALK_CB_NOP
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)
struct Material * BKE_object_material_get_eval(struct Object *ob, short act)
Mesh * BKE_mesh_new_nomain(int verts_num, int edges_num, int faces_num, int corners_num)
Mesh * BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm, const CustomData_MeshMasks *cd_mask_extra, const Mesh *me_settings)
void BKE_mesh_wrapper_ensure_mdata(Mesh *mesh)
Mesh * BKE_modifier_get_evaluated_mesh_from_evaluated_object(Object *ob_eval)
void BKE_modifier_copydata_generic(const ModifierData *md, ModifierData *md_dst, int flag)
ModifierTypeFlag
@ eModifierTypeFlag_SupportsEditmode
@ eModifierTypeFlag_AcceptsMesh
void(*)(void *user_data, Object *ob, ID **idpoin, int cb_flag) IDWalkFunc
void BKE_modifier_set_error(const Object *ob, ModifierData *md, const char *format,...) ATTR_PRINTF_FORMAT(3
#define BLI_assert(a)
Definition BLI_assert.h:50
MINLINE int poly_to_tri_count(int poly_count, int corner_count)
void negate_m3(float R[3][3])
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void copy_m3_m4(float m1[3][3], const float m2[4][4])
void mul_m4_v3(const float M[4][4], float r[3])
bool is_negative_m4(const float mat[4][4])
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
void mul_transposed_m3_v3(const float M[3][3], float r[3])
bool invert_m3(float mat[3][3])
MINLINE float normalize_v3(float n[3])
#define SCOPED_TIMER(name)
Definition BLI_timeit.hh:61
#define ARRAY_SIZE(arr)
#define UNLIKELY(x)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define LIKELY(x)
#define IFACE_(msgid)
void DEG_add_depends_on_transform_relation(DepsNodeHandle *node_handle, const char *description)
void DEG_add_collection_geometry_relation(DepsNodeHandle *node_handle, Collection *collection, const char *description)
void DEG_add_object_relation(DepsNodeHandle *node_handle, Object *object, eDepsObjectComponentType component, const char *description)
@ DEG_OB_COMP_GEOMETRY
@ DEG_OB_COMP_TRANSFORM
#define CD_MASK_MDEFORMVERT
#define CD_MASK_MTFACE
#define DNA_struct_default_get(struct_name)
@ eBooleanModifierSolver_Mesh_Arr
@ eBooleanModifierBMeshFlag_BMesh_NoDissolve
@ eBooleanModifierBMeshFlag_BMesh_Separate
@ eBooleanModifierBMeshFlag_BMesh_NoConnectRegions
BooleanModifierMaterialMode
@ eBooleanModifierMaterialMode_Index
@ eBooleanModifierMaterialMode_Transfer
@ eModifierType_Boolean
struct BooleanModifierData BooleanModifierData
@ eBooleanModifierOp_Intersect
@ eBooleanModifierOp_Union
@ eBooleanModifierOp_Difference
@ eBooleanModifierFlag_Collection
@ eBooleanModifierFlag_Self
@ eBooleanModifierFlag_HoleTolerant
@ eBooleanModifierFlag_Object
Object is a sort of wrapper for general info.
@ OB_MESH
static bool is_disabled
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
static void init_data(ModifierData *md)
static void solver_options_panel_draw(const bContext *, Panel *panel)
static void panel_register(ARegionType *region_type)
static BMesh * BMD_mesh_bm_create(Mesh *mesh, Object *object, Mesh *mesh_operand_ob, Object *operand_ob, bool *r_is_flip)
static void required_data_mask(ModifierData *, CustomData_MeshMasks *r_cddata_masks)
static void BMD_mesh_intersection(BMesh *bm, ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh_operand_ob, Object *object, Object *operand_ob, bool is_flip)
static Mesh * modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
static Mesh * get_quick_mesh(Object *ob_self, Mesh *mesh_self, Object *ob_operand_ob, Mesh *mesh_operand_ob, int operation)
#define BM_FACE_TAG
static bool BMD_error_messages(const Object *ob, ModifierData *md)
static void panel_draw(const bContext *, Panel *panel)
static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
static void update_depsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
ModifierTypeInfo modifierType_Boolean
static int bm_face_isect_pair(BMFace *f, void *)
PanelType * modifier_subpanel_register(ARegionType *region_type, const char *name, const char *label, PanelDrawFn draw_header, PanelDrawFn draw, PanelType *parent)
void modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
#define UI_ITEM_NONE
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
@ UI_ITEM_R_EXPAND
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)
#define BM_elem_flag_enable(ele, hflag)
bool BM_mesh_intersect(BMesh *bm, const blender::Span< std::array< BMLoop *, 3 > > looptris, 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.
BMesh * BM_mesh_create(const BMAllocTemplate *allocsize, const BMeshCreateParams *params)
BMesh Make Mesh.
#define BMALLOC_TEMPLATE_FROM_ME(...)
void BM_mesh_bm_from_me(BMesh *bm, const Mesh *mesh, const BMeshFromMeshParams *params)
void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *mesh, const BMeshToMeshParams *params)
void BM_mesh_calc_tessellation_beauty(BMesh *bm, MutableSpan< std::array< BMLoop *, 3 > > looptris)
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.
constexpr void copy_from(Span< T > values) const
Definition BLI_span.hh:726
bool add(const Key &key)
void append(const T &value)
uint col
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:45
#define G(x, y, z)
Mesh * mesh_boolean(Span< const Mesh * > meshes, Span< float4x4 > transforms, const float4x4 &target_transform, Span< Array< short > > material_remaps, BooleanOpParameters op_params, Solver solver, Vector< int > *r_intersecting_edges)
void debug_randomize_mesh_order(Mesh *mesh)
Definition randomize.cc:220
int RNA_enum_get(PointerRNA *ptr, const char *name)
short mat_nr
float no[3]
float co[3]
int totloop
CustomData ldata
int totface
struct Collection * collection
Definition DNA_ID.h:413
int faces_num
int verts_num
struct uiLayout * layout
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4126