Cleanup: Remove unecessary C API for direct mesh boolean

The main goal here is to remove the need for a C API to the code in
`mesh_boolean_convert.cc`. This is achieved by moving `MOD_boolean.c`
to C++ and making the necessary changes for it to compile. On top of
that there are some other slight simplifications possible to the
direct mesh boolean code: it doesn't need to copy the material
remaps, and the modifier code can use some other C++ types directly.
This commit is contained in:
Hans Goudey 2021-04-02 00:16:01 -05:00
parent 77f6857740
commit a0e1080428
Notes: blender-bot 2023-02-13 19:04:56 +01:00
Referenced by issue #87138, Memory leak in boolean fast solver collection mode
7 changed files with 166 additions and 287 deletions

View File

@ -23,39 +23,21 @@
* \ingroup bke
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "BLI_array.hh"
#include "BLI_float4x4.hh"
#include "BLI_mesh_boolean.hh"
#include "BLI_span.hh"
Mesh *BKE_mesh_boolean(const Mesh **meshes,
const float (*obmats[])[4][4],
const float (*target_transform)[4][4],
const short **material_remaps,
const int meshes_len,
const bool use_self,
const bool hole_tolerant,
const int boolean_mode);
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
# include "BLI_float4x4.hh"
# include "BLI_mesh_boolean.hh"
# include "BLI_span.hh"
struct Mesh;
namespace blender::meshintersect {
Mesh *direct_mesh_boolean(blender::Span<const Mesh *> meshes,
blender::Span<const float4x4 *> obmats,
const float4x4 &target_transform,
blender::Span<const short *> material_remaps,
blender::Span<blender::Array<short>> material_remaps,
const bool use_self,
const bool hole_tolerant,
const int boolean_mode);
} // namespace blender::meshintersect
#endif

View File

@ -371,7 +371,7 @@ set(SRC
BKE_mball.h
BKE_mball_tessellate.h
BKE_mesh.h
BKE_mesh_boolean_convert.h
BKE_mesh_boolean_convert.hh
BKE_mesh_fair.h
BKE_mesh_iterators.h
BKE_mesh_mapping.h

View File

@ -28,9 +28,10 @@
#include "BKE_customdata.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_mesh_boolean_convert.h"
#include "BKE_mesh_boolean_convert.hh"
#include "BLI_alloca.h"
#include "BLI_array.hh"
#include "BLI_float2.hh"
#include "BLI_float4x4.hh"
#include "BLI_math.h"
@ -97,7 +98,7 @@ class MeshesToIMeshInfo {
Array<float4x4> to_target_transform;
/* For each input mesh, how to remap the material slot numbers to
* the material slots in the first mesh. */
Array<const short *> material_remaps;
Span<Array<short>> material_remaps;
/* Total number of input mesh vertices. */
int tot_meshes_verts;
/* Total number of input mesh edges. */
@ -243,7 +244,7 @@ const MEdge *MeshesToIMeshInfo::input_medge_for_orig_index(int orig_index,
*/
static IMesh meshes_to_imesh(Span<const Mesh *> meshes,
Span<const float4x4 *> obmats,
Span<const short *> material_remaps,
Span<Array<short>> material_remaps,
const float4x4 &target_transform,
IMeshArena &arena,
MeshesToIMeshInfo *r_info)
@ -274,7 +275,7 @@ static IMesh meshes_to_imesh(Span<const Mesh *> meshes,
r_info->mesh_edge_offset = Array<int>(nmeshes);
r_info->mesh_poly_offset = Array<int>(nmeshes);
r_info->to_target_transform = Array<float4x4>(nmeshes);
r_info->material_remaps = Array<const short *>(nmeshes);
r_info->material_remaps = material_remaps;
int v = 0;
int e = 0;
int f = 0;
@ -307,13 +308,6 @@ static IMesh meshes_to_imesh(Span<const Mesh *> meshes,
clean_obmat(*obmats[mi]);
r_info->to_target_transform[mi] = inv_target_mat * objn_mat;
if (mi < material_remaps.size() && mi != 0) {
r_info->material_remaps[mi] = material_remaps[mi];
}
else {
r_info->material_remaps[mi] = nullptr;
}
/* Skip the matrix multiplication for each point when there is no transform for a mesh,
* for example when the first mesh is already in the target space. (Note the logic directly
* above, which uses an identity matrix with a null input transform). */
@ -393,14 +387,14 @@ static void copy_poly_attributes(Mesh *dest_mesh,
const Mesh *orig_me,
int mp_index,
int index_in_orig_me,
const short *material_remap)
Span<short> material_remap)
{
mp->mat_nr = orig_mp->mat_nr;
if (mp->mat_nr >= dest_mesh->totcol) {
mp->mat_nr = 0;
}
else {
if (material_remap) {
if (material_remap.size() > 0) {
short mat_nr = material_remap[orig_mp->mat_nr];
if (mat_nr >= 0 && mat_nr < dest_mesh->totcol) {
mp->mat_nr = mat_nr;
@ -733,8 +727,15 @@ static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim)
++cur_loop_index;
}
copy_poly_attributes(
result, mp, orig_mp, orig_me, fi, index_in_orig_me, mim.material_remaps[orig_me_index]);
copy_poly_attributes(result,
mp,
orig_mp,
orig_me,
fi,
index_in_orig_me,
(mim.material_remaps.size() > 0) ?
mim.material_remaps[orig_me_index].as_span() :
Span<short>());
copy_or_interp_loop_attributes(result, f, mp, orig_mp, orig_me, orig_me_index, mim);
}
@ -771,26 +772,33 @@ static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim)
#endif // WITH_GMP
/**
* Do Exact Boolean directly, without a round trip through #BMesh.
* The Mesh operands are in `meshes`, with corresponding transforms in in `obmats`.
* Do a mesh boolean operation directly on meshes (without going back and forth to BMesh).
* \param meshes: An array of of Mesh pointers.
* \param obmats: An array of pointers to the obmat matrices that transform local
* coordinates to global ones. It is allowed for the pointers to be null, meaning the
* transformation is the identity.
* \param material_remaps: An array of pointers to arrays of maps from material slot numbers in the
* corresponding mesh to the material slot in the first mesh. It is OK for material_remaps or any
* of its constituent arrays to be empty.
*/
Mesh *direct_mesh_boolean(Span<const Mesh *> meshes,
Span<const float4x4 *> obmats,
const float4x4 &target_transform,
Span<const short *> material_remaps,
Span<Array<short>> material_remaps,
const bool use_self,
const bool hole_tolerant,
const int boolean_mode)
{
#ifdef WITH_GMP
const int dbg_level = 0;
BLI_assert(meshes.size() == obmats.size());
const int meshes_len = meshes.size();
if (meshes_len <= 0) {
BLI_assert(material_remaps.size() == 0 || material_remaps.size() == meshes.size());
if (meshes.size() <= 0) {
return nullptr;
}
const int dbg_level = 0;
if (dbg_level > 0) {
std::cout << "\nDIRECT_MESH_INTERSECT, nmeshes = " << meshes_len << "\n";
std::cout << "\nDIRECT_MESH_INTERSECT, nmeshes = " << meshes.size() << "\n";
}
MeshesToIMeshInfo mim;
IMeshArena arena;
@ -805,13 +813,13 @@ Mesh *direct_mesh_boolean(Span<const Mesh *> meshes,
};
IMesh m_out = boolean_mesh(m_in,
static_cast<BoolOpType>(boolean_mode),
meshes_len,
meshes.size(),
shape_fn,
use_self,
hole_tolerant,
nullptr,
&arena);
if (dbg_level > 1) {
if (dbg_level > 0) {
std::cout << m_out;
write_obj_mesh(m_out, "m_out");
}
@ -825,53 +833,3 @@ Mesh *direct_mesh_boolean(Span<const Mesh *> meshes,
}
} // namespace blender::meshintersect
extern "C" {
#ifdef WITH_GMP
/* Do a mesh boolean directly on meshes (without going back and forth to BMesh).
* The \a meshes argument is an array of \a meshes_len of Mesh pointers.
* The \a obmats argument is an array of \a meshes_len of pointers to the obmat
* The \a material_remaps is an array of pointers to arrays of maps from material
* slot numbers in the corresponding mesh to the material slot in the first mesh.
* It is OK for material_remaps or any of its constituent arrays to be NULL.
* matrices that transform local coordinates to global ones. It is allowed
* for the pointers to be nullptr, meaning the transformation is the identity. */
Mesh *BKE_mesh_boolean(const Mesh **meshes,
const float (*obmats[])[4][4],
const float (*target_transform)[4][4],
const short **material_remaps,
const int meshes_len,
const bool use_self,
const bool hole_tolerant,
const int boolean_mode)
{
const blender::float4x4 **transforms = (const blender::float4x4 **)obmats;
const blender::float4x4 &target_float4x4 = *(const blender::float4x4 *)target_transform;
return blender::meshintersect::direct_mesh_boolean(
blender::Span(meshes, meshes_len),
blender::Span(transforms, meshes_len),
target_float4x4,
blender::Span(material_remaps, material_remaps ? meshes_len : 0),
use_self,
hole_tolerant,
boolean_mode);
}
#else
Mesh *BKE_mesh_boolean(const Mesh **UNUSED(meshes),
const float (*obmats[])[4][4],
const float (*target_transform)[4][4],
const short **UNUSED(material_remaps),
const int UNUSED(meshes_len),
const bool UNUSED(use_self),
const bool UNUSED(hole_tolerant),
const int UNUSED(boolean_mode))
{
UNUSED_VARS(obmats, target_transform);
return NULL;
}
#endif
} // extern "C"

View File

@ -20,6 +20,10 @@
* \ingroup bmesh
*/
#ifdef __cplusplus
extern "C" {
#endif
bool BM_mesh_intersect(BMesh *bm,
struct BMLoop *(*looptris)[3],
const int looptris_tot,
@ -41,3 +45,7 @@ enum {
BMESH_ISECT_BOOLEAN_UNION = 1,
BMESH_ISECT_BOOLEAN_DIFFERENCE = 2,
};
#ifdef __cplusplus
}
#endif

View File

@ -50,7 +50,7 @@ set(SRC
intern/MOD_armature.c
intern/MOD_array.c
intern/MOD_bevel.c
intern/MOD_boolean.c
intern/MOD_boolean.cc
intern/MOD_build.c
intern/MOD_cast.c
intern/MOD_cloth.c

View File

@ -21,16 +21,15 @@
* \ingroup modifiers
*/
// #define DEBUG_TIME
#include <stdio.h>
#include <cstdio>
#include "BLI_utildefines.h"
#include "BLI_alloca.h"
#include "BLI_array.h"
#include "BLI_array.hh"
#include "BLI_float4x4.hh"
#include "BLI_math_geom.h"
#include "BLI_math_matrix.h"
#include "BLI_vector.hh"
#include "BLT_translation.h"
@ -49,10 +48,9 @@
#include "BKE_lib_query.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_mesh_boolean_convert.h"
#include "BKE_mesh_boolean_convert.hh"
#include "BKE_mesh_wrapper.h"
#include "BKE_modifier.h"
#include "BKE_screen.h"
#include "UI_interface.h"
#include "UI_resources.h"
@ -71,11 +69,16 @@
#include "tools/bmesh_boolean.h"
#include "tools/bmesh_intersect.h"
// #define DEBUG_TIME
#ifdef DEBUG_TIME
# include "PIL_time.h"
# include "PIL_time_utildefines.h"
# include "BLI_timeit.hh"
#endif
using blender::Array;
using blender::float4x4;
using blender::Vector;
static void initData(ModifierData *md)
{
BooleanModifierData *bmd = (BooleanModifierData *)md;
@ -113,14 +116,14 @@ static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *u
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
BooleanModifierData *bmd = (BooleanModifierData *)md;
if ((bmd->flag & eBooleanModifierFlag_Object) && bmd->object != NULL) {
if ((bmd->flag & eBooleanModifierFlag_Object) && bmd->object != nullptr) {
DEG_add_object_relation(ctx->node, bmd->object, DEG_OB_COMP_TRANSFORM, "Boolean Modifier");
DEG_add_object_relation(ctx->node, bmd->object, DEG_OB_COMP_GEOMETRY, "Boolean Modifier");
}
Collection *col = bmd->collection;
if ((bmd->flag & eBooleanModifierFlag_Collection) && col != NULL) {
if ((bmd->flag & eBooleanModifierFlag_Collection) && col != nullptr) {
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (col, operand_ob) {
if (operand_ob->type == OB_MESH && operand_ob != ctx->object) {
DEG_add_object_relation(ctx->node, operand_ob, DEG_OB_COMP_TRANSFORM, "Boolean Modifier");
@ -136,7 +139,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
static Mesh *get_quick_mesh(
Object *ob_self, Mesh *mesh_self, Object *ob_operand_ob, Mesh *mesh_operand_ob, int operation)
{
Mesh *result = NULL;
Mesh *result = nullptr;
if (mesh_self->totpoly == 0 || mesh_operand_ob->totpoly == 0) {
switch (operation) {
@ -149,11 +152,11 @@ static Mesh *get_quick_mesh(
result = mesh_self;
}
else {
result = (Mesh *)BKE_id_copy_ex(NULL, &mesh_operand_ob->id, NULL, LIB_ID_COPY_LOCALIZE);
result = (Mesh *)BKE_id_copy_ex(
nullptr, &mesh_operand_ob->id, nullptr, LIB_ID_COPY_LOCALIZE);
float imat[4][4];
float omat[4][4];
invert_m4_m4(imat, ob_self->obmat);
mul_m4_m4m4(omat, imat, ob_operand_ob->obmat);
@ -189,9 +192,10 @@ static int bm_face_isect_pair(BMFace *f, void *UNUSED(user_data))
return BM_elem_flag_test(f, BM_FACE_TAG) ? 1 : 0;
}
static bool BMD_error_messages(const Object *ob, ModifierData *md, Collection *col)
static bool BMD_error_messages(const Object *ob, ModifierData *md)
{
BooleanModifierData *bmd = (BooleanModifierData *)md;
Collection *col = bmd->collection;
bool error_returns_result = false;
@ -239,22 +243,20 @@ static bool BMD_error_messages(const Object *ob, ModifierData *md, Collection *c
static BMesh *BMD_mesh_bm_create(
Mesh *mesh, Object *object, Mesh *mesh_operand_ob, Object *operand_ob, bool *r_is_flip)
{
BMesh *bm;
#ifdef DEBUG_TIME
SCOPED_TIMER(__func__)
#endif
*r_is_flip = (is_negative_m4(object->obmat) != is_negative_m4(operand_ob->obmat));
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh, mesh_operand_ob);
bm = BM_mesh_create(&allocsize,
&((struct BMeshCreateParams){
.use_toolflags = false,
}));
BMeshCreateParams bmcp = {false};
BMesh *bm = BM_mesh_create(&allocsize, &bmcp);
BM_mesh_bm_from_me(bm,
mesh_operand_ob,
&((struct BMeshFromMeshParams){
.calc_face_normal = true,
}));
BMeshFromMeshParams params{};
params.calc_face_normal = true;
BM_mesh_bm_from_me(bm, mesh_operand_ob, &params);
if (UNLIKELY(*r_is_flip)) {
const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
@ -265,11 +267,7 @@ static BMesh *BMD_mesh_bm_create(
}
}
BM_mesh_bm_from_me(bm,
mesh,
&((struct BMeshFromMeshParams){
.calc_face_normal = true,
}));
BM_mesh_bm_from_me(bm, mesh, &params);
return bm;
}
@ -282,13 +280,18 @@ static void BMD_mesh_intersection(BMesh *bm,
Object *operand_ob,
bool is_flip)
{
#ifdef DEBUG_TIME
SCOPED_TIMER(__func__)
#endif
BooleanModifierData *bmd = (BooleanModifierData *)md;
/* main bmesh intersection setup */
/* create tessface & intersect */
const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
int tottri;
BMLoop *(*looptris)[3] = MEM_malloc_arrayN(looptris_tot, sizeof(*looptris), __func__);
BMLoop *(*looptris)[3] = (BMLoop * (*)[3])
MEM_malloc_arrayN(looptris_tot, sizeof(*looptris), __func__);
BM_mesh_calc_tessellation_beauty(bm, looptris, &tottri);
@ -324,12 +327,11 @@ static void BMD_mesh_intersection(BMesh *bm,
negate_m3(nmat);
}
const short ob_src_totcol = operand_ob->totcol;
short *material_remap = BLI_array_alloca(material_remap, ob_src_totcol ? ob_src_totcol : 1);
Array<short> material_remap(operand_ob->totcol ? operand_ob->totcol : 1);
/* Using original (not evaluated) object here since we are writing to it. */
/* XXX Pretty sure comment above is fully wrong now with CoW & co ? */
BKE_object_material_remap_calc(ctx->object, operand_ob, material_remap);
BKE_object_material_remap_calc(ctx->object, operand_ob, material_remap.data());
BMFace *efa;
i = 0;
@ -341,7 +343,7 @@ static void BMD_mesh_intersection(BMesh *bm,
BM_elem_flag_enable(efa, BM_FACE_TAG);
/* remap material */
if (LIKELY(efa->mat_nr < ob_src_totcol)) {
if (LIKELY(efa->mat_nr < operand_ob->totcol)) {
efa->mat_nr = material_remap[efa->mat_nr];
}
@ -370,7 +372,7 @@ static void BMD_mesh_intersection(BMesh *bm,
looptris,
tottri,
bm_face_isect_pair,
NULL,
nullptr,
false,
use_separate,
use_dissolve,
@ -388,59 +390,50 @@ static void BMD_mesh_intersection(BMesh *bm,
/* Get a mapping from material slot numbers in the src_ob to slot numbers in the dst_ob.
* If a material doesn't exist in the dst_ob, the mapping just goes to the same slot
* or to zero if there aren't enough slots in the destination.
* Caller must MEM_freeN the returned array. */
static short *get_material_remap(Object *dest_ob, Object *src_ob)
* Caller owns the returned array. */
static Array<short> get_material_remap(Object *dest_ob, Object *src_ob)
{
short *remap;
int n = dest_ob->totcol;
if (n <= 0) {
n = 1;
}
remap = MEM_mallocN(n * sizeof(short), __func__);
BKE_object_material_remap_calc(dest_ob, src_ob, remap);
Array<short> remap(n);
BKE_object_material_remap_calc(dest_ob, src_ob, remap.data());
return remap;
}
/* New method: bypass trip through BMesh. */
static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
const ModifierEvalContext *ctx,
Mesh *mesh)
{
Mesh *result;
Mesh *mesh_operand;
short *remap;
Mesh **meshes = NULL;
const float(**obmats)[4][4] = NULL;
short **material_remaps = NULL;
BLI_array_declare(meshes);
BLI_array_declare(obmats);
BLI_array_declare(material_remaps);
Vector<const Mesh *> meshes;
Vector<float4x4 *> obmats;
Vector<Array<short>> material_remaps;
# ifdef DEBUG_TIME
TIMEIT_START(boolean_bmesh);
SCOPED_TIMER(__func__)
# endif
if ((bmd->flag & eBooleanModifierFlag_Object) && bmd->object == NULL) {
if ((bmd->flag & eBooleanModifierFlag_Object) && bmd->object == nullptr) {
return mesh;
}
BLI_array_append(meshes, mesh);
BLI_array_append(obmats, &ctx->object->obmat);
BLI_array_append(material_remaps, NULL);
meshes.append(mesh);
obmats.append((float4x4 *)&ctx->object->obmat);
material_remaps.append({});
if (bmd->flag & eBooleanModifierFlag_Object) {
mesh_operand = BKE_modifier_get_evaluated_mesh_from_evaluated_object(bmd->object, false);
Mesh *mesh_operand = BKE_modifier_get_evaluated_mesh_from_evaluated_object(bmd->object, false);
if (!mesh_operand) {
return mesh;
}
BKE_mesh_wrapper_ensure_mdata(mesh_operand);
BLI_array_append(meshes, mesh_operand);
BLI_array_append(obmats, &bmd->object->obmat);
remap = get_material_remap(ctx->object, bmd->object);
BLI_array_append(material_remaps, remap);
meshes.append(mesh_operand);
obmats.append((float4x4 *)&bmd->object->obmat);
material_remaps.append(get_material_remap(ctx->object, bmd->object));
}
else if (bmd->flag & eBooleanModifierFlag_Collection) {
Collection *collection = bmd->collection;
/* Allow collection to be empty: then target mesh will just removed self-intersections. */
/* Allow collection to be empty; then target mesh will just removed self-intersections. */
if (collection) {
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection, ob) {
if (ob->type == OB_MESH && ob != ctx->object) {
@ -449,10 +442,9 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
continue;
}
BKE_mesh_wrapper_ensure_mdata(collection_mesh);
BLI_array_append(meshes, collection_mesh);
BLI_array_append(obmats, &ob->obmat);
remap = get_material_remap(ctx->object, ob);
BLI_array_append(material_remaps, remap);
meshes.append(collection_mesh);
obmats.append((float4x4 *)&ob->obmat);
material_remaps.append(get_material_remap(ctx->object, ob));
}
}
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
@ -461,30 +453,13 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
const bool use_self = (bmd->flag & eBooleanModifierFlag_Self) != 0;
const bool hole_tolerant = (bmd->flag & eBooleanModifierFlag_HoleTolerant) != 0;
result = BKE_mesh_boolean((const Mesh **)meshes,
(const float(**)[4][4])obmats,
&ctx->object->obmat,
(const short **)material_remaps,
BLI_array_len(meshes),
use_self,
hole_tolerant,
bmd->operation);
BLI_array_free(meshes);
BLI_array_free(obmats);
for (int i = 0; i < BLI_array_len(material_remaps); i++) {
remap = material_remaps[i];
if (remap) {
MEM_freeN(remap);
}
}
BLI_array_free(material_remaps);
# ifdef DEBUG_TIME
TIMEIT_END(boolean_bmesh);
# endif
return result;
return blender::meshintersect::direct_mesh_boolean(meshes,
obmats,
*(float4x4 *)&ctx->object->obmat,
material_remaps,
use_self,
hole_tolerant,
bmd->operation);
}
#endif
@ -493,12 +468,13 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
BooleanModifierData *bmd = (BooleanModifierData *)md;
Object *object = ctx->object;
Mesh *result = mesh;
Mesh *mesh_operand_ob;
BMesh *bm;
Collection *collection = bmd->collection;
bool is_flip = false;
const bool confirm_return = true;
/* Return result for certain errors. */
if (BMD_error_messages(ctx->object, md)) {
return result;
}
#ifdef WITH_GMP
if (bmd->solver == eBooleanModifierSolver_Exact) {
return exact_boolean_mesh(bmd, ctx, mesh);
@ -506,27 +482,18 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
#endif
#ifdef DEBUG_TIME
TIMEIT_START(boolean_bmesh);
SCOPED_TIMER(__func__)
#endif
if (bmd->flag & eBooleanModifierFlag_Object) {
if (bmd->object == NULL) {
if (bmd->object == nullptr) {
return result;
}
BMD_error_messages(ctx->object, md, NULL);
Object *operand_ob = bmd->object;
#ifdef DEBUG_TIME
TIMEIT_BLOCK_INIT(operand_get_evaluated_mesh);
TIMEIT_BLOCK_START(operand_get_evaluated_mesh);
#endif
mesh_operand_ob = BKE_modifier_get_evaluated_mesh_from_evaluated_object(operand_ob, false);
#ifdef DEBUG_TIME
TIMEIT_BLOCK_END(operand_get_evaluated_mesh);
TIMEIT_BLOCK_STATS(operand_get_evaluated_mesh);
#endif
Mesh *mesh_operand_ob = BKE_modifier_get_evaluated_mesh_from_evaluated_object(operand_ob,
false);
if (mesh_operand_ob) {
/* XXX This is utterly non-optimal, we may go from a bmesh to a mesh back to a bmesh!
@ -537,80 +504,49 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
* Returning mesh is depended on modifiers operation (sergey) */
result = get_quick_mesh(object, mesh, operand_ob, mesh_operand_ob, bmd->operation);
if (result == NULL) {
#ifdef DEBUG_TIME
TIMEIT_BLOCK_INIT(object_BMD_mesh_bm_create);
TIMEIT_BLOCK_START(object_BMD_mesh_bm_create);
#endif
bm = BMD_mesh_bm_create(mesh, object, mesh_operand_ob, operand_ob, &is_flip);
#ifdef DEBUG_TIME
TIMEIT_BLOCK_END(object_BMD_mesh_bm_create);
TIMEIT_BLOCK_STATS(object_BMD_mesh_bm_create);
#endif
if (result == nullptr) {
bool is_flip;
BMesh *bm = BMD_mesh_bm_create(mesh, object, mesh_operand_ob, operand_ob, &is_flip);
#ifdef DEBUG_TIME
TIMEIT_BLOCK_INIT(BMD_mesh_intersection);
TIMEIT_BLOCK_START(BMD_mesh_intersection);
#endif
BMD_mesh_intersection(bm, md, ctx, mesh_operand_ob, object, operand_ob, is_flip);
#ifdef DEBUG_TIME
TIMEIT_BLOCK_END(BMD_mesh_intersection);
TIMEIT_BLOCK_STATS(BMD_mesh_intersection);
#endif
#ifdef DEBUG_TIME
TIMEIT_BLOCK_INIT(BKE_mesh_from_bmesh_for_eval_nomain);
TIMEIT_BLOCK_START(BKE_mesh_from_bmesh_for_eval_nomain);
#endif
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
#ifdef DEBUG_TIME
TIMEIT_BLOCK_END(BKE_mesh_from_bmesh_for_eval_nomain);
TIMEIT_BLOCK_STATS(BKE_mesh_from_bmesh_for_eval_nomain);
#endif
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, mesh);
BM_mesh_free(bm);
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
}
/* if new mesh returned, return it; otherwise there was
* an error, so delete the modifier object */
if (result == NULL) {
if (result == nullptr) {
BKE_modifier_set_error(object, md, "Cannot execute boolean operation");
}
}
}
else {
if (collection == NULL) {
return result;
}
/* Return result for certain errors. */
if (BMD_error_messages(ctx->object, md, collection) == confirm_return) {
if (collection == nullptr) {
return result;
}
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection, operand_ob) {
if (operand_ob->type == OB_MESH && operand_ob != ctx->object) {
mesh_operand_ob = BKE_modifier_get_evaluated_mesh_from_evaluated_object(operand_ob, false);
Mesh *mesh_operand_ob = BKE_modifier_get_evaluated_mesh_from_evaluated_object(operand_ob,
false);
if (mesh_operand_ob) {
/* XXX This is utterly non-optimal, we may go from a bmesh to a mesh back to a bmesh!
* But for 2.90 better not try to be smart here. */
BKE_mesh_wrapper_ensure_mdata(mesh_operand_ob);
bm = BMD_mesh_bm_create(mesh, object, mesh_operand_ob, operand_ob, &is_flip);
bool is_flip;
BMesh *bm = BMD_mesh_bm_create(mesh, object, mesh_operand_ob, operand_ob, &is_flip);
BMD_mesh_intersection(bm, md, ctx, mesh_operand_ob, object, operand_ob, is_flip);
/* Needed for multiple objects to work. */
BM_mesh_bm_to_me(NULL,
bm,
mesh,
(&(struct BMeshToMeshParams){
.calc_object_remap = false,
}));
BMeshToMeshParams params{};
params.calc_object_remap = false;
BM_mesh_bm_to_me(nullptr, bm, mesh, &params);
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, mesh);
BM_mesh_free(bm);
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
}
@ -619,10 +555,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
#ifdef DEBUG_TIME
TIMEIT_END(boolean_bmesh);
#endif
return result;
}
@ -638,22 +570,21 @@ static void requiredDataMask(Object *UNUSED(ob),
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
{
uiLayout *layout = panel->layout;
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr);
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL);
uiItemR(layout, ptr, "operation", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
uiItemR(layout, ptr, "operation", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
uiLayoutSetPropSep(layout, true);
uiItemR(layout, ptr, "operand_type", 0, NULL, ICON_NONE);
uiItemR(layout, ptr, "operand_type", 0, nullptr, ICON_NONE);
if (RNA_enum_get(ptr, "operand_type") == eBooleanModifierFlag_Object) {
uiItemR(layout, ptr, "object", 0, NULL, ICON_NONE);
uiItemR(layout, ptr, "object", 0, nullptr, ICON_NONE);
}
else {
uiItemR(layout, ptr, "collection", 0, NULL, ICON_NONE);
uiItemR(layout, ptr, "collection", 0, nullptr, ICON_NONE);
}
uiItemR(layout, ptr, "solver", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
uiItemR(layout, ptr, "solver", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
modifier_panel_end(layout, ptr);
}
@ -661,8 +592,7 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
static void solver_options_panel_draw(const bContext *UNUSED(C), Panel *panel)
{
uiLayout *layout = panel->layout;
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL);
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr);
const bool use_exact = RNA_enum_get(ptr, "solver") == eBooleanModifierSolver_Exact;
@ -672,16 +602,16 @@ static void solver_options_panel_draw(const bContext *UNUSED(C), Panel *panel)
if (use_exact) {
/* When operand is collection, we always use_self. */
if (RNA_enum_get(ptr, "operand_type") == eBooleanModifierFlag_Object) {
uiItemR(col, ptr, "use_self", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "use_self", 0, nullptr, ICON_NONE);
}
uiItemR(col, ptr, "use_hole_tolerant", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "use_hole_tolerant", 0, nullptr, ICON_NONE);
}
else {
uiItemR(col, ptr, "double_threshold", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "double_threshold", 0, nullptr, ICON_NONE);
}
if (G.debug) {
uiItemR(col, ptr, "debug_options", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "debug_options", 0, nullptr, ICON_NONE);
}
}
@ -689,7 +619,7 @@ static void panelRegister(ARegionType *region_type)
{
PanelType *panel = modifier_panel_register(region_type, eModifierType_Boolean, panel_draw);
modifier_subpanel_register(
region_type, "solver_options", "Solver Options", NULL, solver_options_panel_draw, panel);
region_type, "solver_options", "Solver Options", nullptr, solver_options_panel_draw, panel);
}
ModifierTypeInfo modifierType_Boolean = {
@ -698,31 +628,32 @@ ModifierTypeInfo modifierType_Boolean = {
/* structSize */ sizeof(BooleanModifierData),
/* srna */ &RNA_BooleanModifier,
/* type */ eModifierTypeType_Nonconstructive,
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsEditmode,
/* flags */
(ModifierTypeFlag)(eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsEditmode),
/* icon */ ICON_MOD_BOOLEAN,
/* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* deformVerts */ nullptr,
/* deformMatrices */ nullptr,
/* deformVertsEM */ nullptr,
/* deformMatricesEM */ nullptr,
/* modifyMesh */ modifyMesh,
/* modifyHair */ NULL,
/* modifyGeometrySet */ NULL,
/* modifyVolume */ NULL,
/* modifyHair */ nullptr,
/* modifyGeometrySet */ nullptr,
/* modifyVolume */ nullptr,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
/* freeData */ nullptr,
/* isDisabled */ isDisabled,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* dependsOnTime */ nullptr,
/* dependsOnNormals */ nullptr,
/* foreachIDLink */ foreachIDLink,
/* foreachTexLink */ NULL,
/* freeRuntimeData */ NULL,
/* foreachTexLink */ nullptr,
/* freeRuntimeData */ nullptr,
/* panelRegister */ panelRegister,
/* blendWrite */ NULL,
/* blendRead */ NULL,
/* blendWrite */ nullptr,
/* blendRead */ nullptr,
};

View File

@ -17,7 +17,7 @@
#include "DNA_mesh_types.h"
#include "BKE_mesh.h"
#include "BKE_mesh_boolean_convert.h"
#include "BKE_mesh_boolean_convert.hh"
#include "UI_interface.h"
#include "UI_resources.h"