39# define BENCHMARK_FILE "/tmp/blender_benchmark.csv"
50constexpr int estimated_max_facelen = 100;
62 const float fuzz = 1e-6f;
63 for (
int i = 0;
i < 4;
i++) {
64 for (
int j = 0; j < 4; j++) {
66 if (
fabsf(f) <= fuzz) {
69 else if (
fabsf(f - 1.0f) <= fuzz) {
72 else if (
fabsf(f + 1.0f) <= fuzz) {
99class MeshesToIMeshInfo {
102 Span<const Mesh *> meshes;
105 Array<int> mesh_vert_offset;
107 Array<int> mesh_edge_offset;
109 Array<int> mesh_face_offset;
112 Array<const meshintersect::Vert *> mesh_to_imesh_vert;
114 Array<meshintersect::Face *> mesh_to_imesh_face;
117 Array<float4x4> to_target_transform;
119 Array<bool> has_negative_transform;
122 Span<Array<short>> material_remaps;
124 int tot_meshes_verts;
126 int tot_meshes_edges;
128 int tot_meshes_polys;
130 int input_mesh_for_imesh_vert(
int imesh_v)
const;
131 int input_mesh_for_imesh_edge(
int imesh_e)
const;
132 int input_mesh_for_imesh_face(
int imesh_f)
const;
133 IndexRange input_face_for_orig_index(
int orig_index,
134 const Mesh **r_orig_mesh,
135 int *r_orig_mesh_index,
136 int *r_index_in_orig_mesh)
const;
137 void input_mvert_for_orig_index(
int orig_index,
138 const Mesh **r_orig_mesh,
139 int *r_index_in_orig_mesh)
const;
140 void input_medge_for_orig_index(
int orig_index,
141 const Mesh **r_orig_mesh,
142 int *r_index_in_orig_mesh)
const;
147int MeshesToIMeshInfo::input_mesh_for_imesh_vert(
int imesh_v)
const
149 int n = int(mesh_vert_offset.size());
150 for (
int i = 0;
i < n - 1; ++
i) {
151 if (imesh_v < mesh_vert_offset[
i + 1]) {
160int MeshesToIMeshInfo::input_mesh_for_imesh_edge(
int imesh_e)
const
162 int n = int(mesh_edge_offset.size());
163 for (
int i = 0;
i < n - 1; ++
i) {
164 if (imesh_e < mesh_edge_offset[
i + 1]) {
173int MeshesToIMeshInfo::input_mesh_for_imesh_face(
int imesh_f)
const
175 int n = int(mesh_face_offset.size());
176 for (
int i = 0;
i < n - 1; ++
i) {
177 if (imesh_f < mesh_face_offset[
i + 1]) {
189IndexRange MeshesToIMeshInfo::input_face_for_orig_index(
int orig_index,
190 const Mesh **r_orig_mesh,
191 int *r_orig_mesh_index,
192 int *r_index_in_orig_mesh)
const
194 int orig_mesh_index = input_mesh_for_imesh_face(orig_index);
195 BLI_assert(0 <= orig_mesh_index && orig_mesh_index < meshes.size());
196 const Mesh *mesh = meshes[orig_mesh_index];
197 const OffsetIndices
faces = mesh->faces();
198 int index_in_mesh = orig_index - mesh_face_offset[orig_mesh_index];
199 BLI_assert(0 <= index_in_mesh && index_in_mesh < mesh->faces_num);
200 const IndexRange face =
faces[index_in_mesh];
204 if (r_orig_mesh_index) {
205 *r_orig_mesh_index = orig_mesh_index;
207 if (r_index_in_orig_mesh) {
208 *r_index_in_orig_mesh = index_in_mesh;
217void MeshesToIMeshInfo::input_mvert_for_orig_index(
int orig_index,
218 const Mesh **r_orig_mesh,
219 int *r_index_in_orig_mesh)
const
221 int orig_mesh_index = input_mesh_for_imesh_vert(orig_index);
222 BLI_assert(0 <= orig_mesh_index && orig_mesh_index < meshes.size());
223 const Mesh *mesh = meshes[orig_mesh_index];
224 int index_in_mesh = orig_index - mesh_vert_offset[orig_mesh_index];
225 BLI_assert(0 <= index_in_mesh && index_in_mesh < mesh->verts_num);
229 if (r_index_in_orig_mesh) {
230 *r_index_in_orig_mesh = index_in_mesh;
235void MeshesToIMeshInfo::input_medge_for_orig_index(
int orig_index,
236 const Mesh **r_orig_mesh,
237 int *r_index_in_orig_mesh)
const
239 int orig_mesh_index = input_mesh_for_imesh_edge(orig_index);
240 BLI_assert(0 <= orig_mesh_index && orig_mesh_index < meshes.size());
241 const Mesh *mesh = meshes[orig_mesh_index];
242 int index_in_mesh = orig_index - mesh_edge_offset[orig_mesh_index];
243 BLI_assert(0 <= index_in_mesh && index_in_mesh < mesh->edges_num);
247 if (r_index_in_orig_mesh) {
248 *r_index_in_orig_mesh = index_in_mesh;
264static meshintersect::IMesh meshes_to_imesh(Span<const Mesh *> meshes,
265 Span<float4x4> transforms,
266 Span<Array<short>> material_remaps,
267 meshintersect::IMeshArena &arena,
268 MeshesToIMeshInfo *r_info)
270 int nmeshes = meshes.
size();
272 r_info->meshes = meshes;
273 r_info->tot_meshes_verts = 0;
274 r_info->tot_meshes_polys = 0;
275 int &totvert = r_info->tot_meshes_verts;
276 int &totedge = r_info->tot_meshes_edges;
277 int &faces_num = r_info->tot_meshes_polys;
278 for (
const Mesh *mesh : meshes) {
287 const int estimate_num_outv = 3 * totvert;
288 const int estimate_num_outf = 4 * faces_num;
289 arena.reserve(estimate_num_outv, estimate_num_outf);
290 r_info->mesh_to_imesh_vert.reinitialize(totvert);
291 r_info->mesh_to_imesh_face.reinitialize(faces_num);
292 r_info->mesh_vert_offset.reinitialize(nmeshes);
293 r_info->mesh_edge_offset.reinitialize(nmeshes);
294 r_info->mesh_face_offset.reinitialize(nmeshes);
295 r_info->to_target_transform.reinitialize(nmeshes);
296 r_info->has_negative_transform.reinitialize(nmeshes);
297 r_info->material_remaps = material_remaps;
305 Vector<const meshintersect::Vert *, estimated_max_facelen> face_vert;
306 Vector<int, estimated_max_facelen> face_edge_orig;
318 for (
int mi : meshes.index_range()) {
319 const Mesh *mesh = meshes[mi];
320 r_info->mesh_vert_offset[mi] =
v;
321 r_info->mesh_edge_offset[mi] =
e;
322 r_info->mesh_face_offset[mi] = f;
326 clean_transform(transforms[mi]);
327 r_info->has_negative_transform[mi] =
math::is_negative(r_info->to_target_transform[mi]);
332 bool need_face_flip = r_info->has_negative_transform[mi] != r_info->has_negative_transform[0];
335 const Span<float3> vert_positions = mesh->vert_positions();
336 const OffsetIndices
faces = mesh->faces();
337 const Span<int> corner_verts = mesh->corner_verts();
338 const Span<int> corner_edges = mesh->corner_edges();
346 for (int i : range) {
347 float3 co = clean_float3(vert_positions[i]);
348 mpq3 mco = mpq3(co.x, co.y, co.z);
349 double3 dco(mco[0].get_d(), mco[1].get_d(), mco[2].get_d());
350 verts[i] = new meshintersect::Vert(mco, dco, meshintersect::NO_INDEX, i);
356 for (int i : range) {
357 float3 co = math::transform_point(r_info->to_target_transform[mi],
358 clean_float3(vert_positions[i]));
359 mpq3 mco = mpq3(co.x, co.y, co.z);
360 double3 dco(mco[0].get_d(), mco[1].get_d(), mco[2].get_d());
361 verts[i] = new meshintersect::Vert(mco, dco, meshintersect::NO_INDEX, i);
365 for (
int i : vert_positions.index_range()) {
366 r_info->mesh_to_imesh_vert[
v] = arena.add_or_find_vert(
verts[
i]);
370 for (
const int face_i :
faces.index_range()) {
371 const IndexRange face =
faces[face_i];
372 int flen = face.
size();
374 face_edge_orig.
resize(flen);
375 for (
int i = 0;
i < flen; ++
i) {
376 const int corner_i = face[
i];
377 int mverti = r_info->mesh_vert_offset[mi] + corner_verts[corner_i];
378 const meshintersect::Vert *fv = r_info->mesh_to_imesh_vert[mverti];
379 if (need_face_flip) {
380 face_vert[flen -
i - 1] = fv;
381 int iedge =
i < flen - 1 ? flen -
i - 2 : flen - 1;
382 face_edge_orig[iedge] =
e + corner_edges[corner_i];
386 face_edge_orig[
i] =
e + corner_edges[corner_i];
389 r_info->mesh_to_imesh_face[f] = arena.add_face(face_vert, f, face_edge_orig);
394 return meshintersect::IMesh(r_info->mesh_to_imesh_face);
400static void copy_vert_attributes(
Mesh *dest_mesh,
403 int index_in_orig_me)
408 for (
int source_layer_i = 0; source_layer_i < source_cd->
totlayer; ++source_layer_i) {
417 if (target_layer_i != -1) {
419 source_cd, target_cd, source_layer_i, target_layer_i, index_in_orig_me, mv_index, 1);
425static void copy_face_attributes(
Mesh *dest_mesh,
428 int index_in_orig_me,
434 for (
int source_layer_i = 0; source_layer_i < source_cd->
totlayer; ++source_layer_i) {
438 if (target_layer_i != -1) {
440 source_cd, target_cd, source_layer_i, target_layer_i, index_in_orig_me, face_index, 1);
446 "material_index", bke::AttrDomain::Face, 0);
447 const int src_index = src_material_indices[index_in_orig_me];
449 const int remapped_index = material_remap[src_index];
450 dst_material_indices[face_index] = remapped_index >= 0 ? remapped_index : src_index;
453 dst_material_indices[face_index] = src_index;
455 BLI_assert(dst_material_indices[face_index] >= 0);
459static void copy_edge_attributes(
Mesh *dest_mesh,
462 int index_in_orig_me)
466 for (
int source_layer_i = 0; source_layer_i < source_cd->
totlayer; ++source_layer_i) {
475 if (target_layer_i != -1) {
477 source_cd, target_cd, source_layer_i, target_layer_i, index_in_orig_me, medge_index, 1);
492static int fill_orig_loops(
const meshintersect::Face *f,
496 MeshesToIMeshInfo &mim,
499 r_orig_loops.
fill(-1);
500 const Span<int> orig_corner_verts = orig_me->corner_verts();
502 int orig_mplen = orig_face.
size();
503 if (f->size() != orig_mplen) {
513 int first_orig_v = f->vert[0]->orig;
514 if (first_orig_v == meshintersect::NO_INDEX) {
518 if (orig_me_index != mim.input_mesh_for_imesh_vert(first_orig_v)) {
521 int orig_me_vert_offset = mim.mesh_vert_offset[orig_me_index];
522 int first_orig_v_in_orig_me = first_orig_v - orig_me_vert_offset;
523 BLI_assert(0 <= first_orig_v_in_orig_me && first_orig_v_in_orig_me < orig_me->verts_num);
526 for (
int i = 0;
i < orig_mplen; ++
i) {
527 int loop_i =
i + orig_face.
start();
528 if (orig_corner_verts[loop_i] == first_orig_v_in_orig_me) {
536 int num_orig_loops_found = 0;
537 for (
int mp_loop_index = 0; mp_loop_index < orig_mplen; ++mp_loop_index) {
538 int orig_mp_loop_index = (mp_loop_index + offset) % orig_mplen;
539 const int vert_i = orig_corner_verts[orig_face.
start() + orig_mp_loop_index];
540 int fv_orig = f->vert[mp_loop_index]->orig;
541 if (fv_orig != meshintersect::NO_INDEX) {
542 fv_orig -= orig_me_vert_offset;
543 if (fv_orig < 0 || fv_orig >= orig_me->
verts_num) {
544 fv_orig = meshintersect::NO_INDEX;
547 if (vert_i == fv_orig) {
548 const int vert_next =
549 orig_corner_verts[orig_face.
start() + ((orig_mp_loop_index + 1) % orig_mplen)];
550 int fvnext_orig = f->vert[(mp_loop_index + 1) % orig_mplen]->orig;
551 if (fvnext_orig != meshintersect::NO_INDEX) {
552 fvnext_orig -= orig_me_vert_offset;
553 if (fvnext_orig < 0 || fvnext_orig >= orig_me->
verts_num) {
554 fvnext_orig = meshintersect::NO_INDEX;
557 if (vert_next == fvnext_orig) {
558 r_orig_loops[mp_loop_index] = orig_face.
start() + orig_mp_loop_index;
559 ++num_orig_loops_found;
563 return num_orig_loops_found;
570static void get_poly2d_cos(
const Mesh *mesh,
574 float r_axis_mat[3][3])
577 const Span<int> corner_verts = mesh->corner_verts();
581 const float3 axis_dominant = bke::mesh::face_normal_calc(positions, face_verts);
584 float3 co = positions[face_verts[
i]];
586 *
reinterpret_cast<float2 *
>(&cos_2d[
i]) = (
float3x3(r_axis_mat) * co).xy();
593static void copy_or_interp_loop_attributes(
Mesh *dest_mesh,
594 const meshintersect::Face *f,
599 MeshesToIMeshInfo &mim)
602 int norig = fill_orig_loops(f, orig_face, orig_me, orig_me_index, mim, orig_loops);
608 float axis_mat[3][3];
609 if (norig != face.
size()) {
618 get_poly2d_cos(orig_me, orig_face, cos_2d, mim.to_target_transform[orig_me_index], axis_mat);
621 const Span<float3> dst_positions = dest_mesh->vert_positions();
622 const Span<int> dst_corner_verts = dest_mesh->corner_verts();
623 for (
int i = 0;
i < face.
size(); ++
i) {
624 int loop_index = face[
i];
625 int orig_loop_index = norig > 0 ? orig_loops[
i] : -1;
627 if (orig_loop_index == -1) {
632 mul_v2_m3v3(co, axis_mat, dst_positions[dst_corner_verts[loop_index]]);
635 for (
int source_layer_i = 0; source_layer_i < source_cd->
totlayer; ++source_layer_i) {
637 if (
STR_ELEM(source_cd->
layers[source_layer_i].
name,
".corner_vert",
".corner_edge")) {
642 if (target_layer_i == -1) {
645 if (orig_loop_index != -1) {
647 source_cd, target_cd, source_layer_i, target_layer_i, orig_loop_index, loop_index, 1);
659 int source_layer_type_index = source_layer_i - source_cd->
typemap[ty];
660 BLI_assert(target_layer_type_index != -1 && source_layer_type_index >= 0);
662 for (
int j = 0; j < orig_face.
size(); ++j) {
667 target_cd, ty, target_layer_type_index, dest_mesh->
corners_num);
670 src_blocks_ofs.
data(),
686static void merge_vertex_loop_face_customdata_layers(
Mesh *target, MeshesToIMeshInfo &mim)
688 for (
int mesh_index = 1; mesh_index < mim.meshes.size(); ++mesh_index) {
689 const Mesh *mesh = mim.meshes[mesh_index];
714static void merge_edge_customdata_layers(
Mesh *target, MeshesToIMeshInfo &mim)
716 for (
int mesh_index = 0; mesh_index < mim.meshes.size(); ++mesh_index) {
717 const Mesh *mesh = mim.meshes[mesh_index];
732static Mesh *imesh_to_mesh(meshintersect::IMesh *im, MeshesToIMeshInfo &mim)
734 constexpr int dbg_level = 0;
737 int out_totvert = im->vert_size();
738 int out_faces_num = im->face_size();
740 for (
const meshintersect::Face *f : im->faces()) {
741 out_totloop += f->size();
745 mim.meshes[0], out_totvert, 0, out_faces_num, out_totloop);
747 merge_vertex_loop_face_customdata_layers(
result, mim);
750 for (
int vi : im->vert_index_range()) {
751 const meshintersect::Vert *
v = im->vert(vi);
752 if (
v->orig != meshintersect::NO_INDEX) {
754 int index_in_orig_me;
755 mim.input_mvert_for_orig_index(
v->orig, &orig_me, &index_in_orig_me);
756 copy_vert_attributes(
result, orig_me, vi, index_in_orig_me);
763 bke::SpanAttributeWriter<int> dst_material_indices =
764 result->attributes_for_write().lookup_or_add_for_write_only_span<
int>(
"material_index",
765 bke::AttrDomain::Face);
766 int cur_loop_index = 0;
769 for (
int fi : im->face_index_range()) {
770 const meshintersect::Face *f = im->face(fi);
772 int index_in_orig_me;
774 const IndexRange orig_face = mim.input_face_for_orig_index(
775 f->orig, &orig_me, &orig_me_index, &index_in_orig_me);
776 dst_face_offsets[fi] = cur_loop_index;
777 for (
int j : f->index_range()) {
778 const meshintersect::Vert *vf = f->vert[j];
779 const int vfi = im->lookup_vert(vf);
780 dst_corner_verts[cur_loop_index] = vfi;
784 copy_face_attributes(
result,
788 (mim.material_remaps.size() > 0) ?
789 mim.material_remaps[orig_me_index].as_span() :
791 dst_material_indices.span);
792 copy_or_interp_loop_attributes(
result,
800 dst_material_indices.finish();
802 bke::mesh_calc_edges(*
result,
false,
false);
803 merge_edge_customdata_layers(
result, mim);
807 const OffsetIndices dst_polys =
result->faces();
809 for (
int fi : im->face_index_range()) {
810 const meshintersect::Face *f = im->face(fi);
812 for (
int j : f->index_range()) {
813 if (f->edge_orig[j] != meshintersect::NO_INDEX) {
815 int index_in_orig_me;
816 mim.input_medge_for_orig_index(f->edge_orig[j], &orig_me, &index_in_orig_me);
817 int e_index = dst_corner_edges[face[j]];
818 copy_edge_attributes(
result, orig_me, e_index, index_in_orig_me);
829static meshintersect::BoolOpType operation_to_mesh_arr_mode(
const Operation operation)
832 case Operation::Intersect:
833 return meshintersect::BoolOpType::Intersect;
834 case Operation::Union:
835 return meshintersect::BoolOpType::Union;
836 case Operation::Difference:
837 return meshintersect::BoolOpType::Difference;
840 return meshintersect::BoolOpType::None;
847 const bool hole_tolerant,
848 const meshintersect::BoolOpType boolean_mode,
852 BLI_assert(material_remaps.is_empty() || material_remaps.size() == meshes.
size());
853 if (meshes.
size() <= 0) {
857 const int dbg_level = 0;
859 std::cout <<
"\nOLD_MESH_INTERSECT, nmeshes = " << meshes.
size() <<
"\n";
861 MeshesToIMeshInfo mim;
862 meshintersect::IMeshArena arena;
863 meshintersect::IMesh m_in = meshes_to_imesh(meshes, transforms, material_remaps, arena, &mim);
864 std::function<int(
int)> shape_fn = [&mim](
int f) {
865 for (
int mi = 0; mi < mim.mesh_face_offset.size() - 1; ++mi) {
866 if (f < mim.mesh_face_offset[mi + 1]) {
870 return int(mim.mesh_face_offset.size()) - 1;
872 meshintersect::IMesh m_out = boolean_mesh(
873 m_in, boolean_mode, meshes.
size(), shape_fn, use_self, hole_tolerant,
nullptr, &arena);
876 write_obj_mesh(m_out,
"m_out");
882 if (r_intersecting_edges !=
nullptr) {
885 for (
int fi : m_out.face_index_range()) {
886 const meshintersect::Face &face = *m_out.face(fi);
888 for (
int i : face.index_range()) {
889 if (face.is_intersect[
i]) {
890 int e_index = corner_edges[mesh_face[
i]];
891 r_intersecting_edges->
append(e_index);
909#define BM_FACE_TAG BM_ELEM_SELECT_UV
939 Array<std::array<BMLoop *, 3>> &r_looptris)
941 const int meshes_num = meshes.
size();
945 const int tsize = transforms.
size();
949 is_flip[
i] = is_negative_transform[
i] != is_negative_transform[0];
952 is_negative_transform[
i] =
false;
964 allocsize.
totvert += meshes[
i]->verts_num;
965 allocsize.
totedge += meshes[
i]->edges_num;
966 allocsize.
totloop += meshes[
i]->corners_num;
967 allocsize.
totface += meshes[
i]->faces_num;
974 bm,
const_cast<const Mesh **
>(meshes.
begin()), meshes_num, &allocsize);
982 verts_end[0] = meshes[0]->verts_num;
983 faces_end[0] = meshes[0]->faces_num;
988 verts_end[
i] = verts_end[
i - 1] + meshes[
i]->verts_num;
989 faces_end[
i] = faces_end[
i - 1] + meshes[
i]->faces_num;
994 for (
int j = faces_end[
i - 1]; j < faces_end[
i]; j++) {
1005 r_looptris.reinitialize(looptris_tot);
1016 if (
i == verts_end[mesh_index]) {
1028 if (is_negative_transform[mesh_index]) {
1034 if (
i < faces_end[0]) {
1039 int cur_mat = efa->
mat_nr;
1040 if (cur_mat < material_remaps[mesh_index].
size()) {
1041 int new_mat = material_remaps[mesh_index][cur_mat];
1043 efa->
mat_nr = material_remaps[mesh_index][cur_mat];
1048 if (
i == faces_end[mesh_index]) {
1058 switch (operation) {
1073 const int boolean_mode,
1077 BLI_assert(material_remaps.size() == 0 || material_remaps.size() == meshes.
size());
1082 if (meshes.
size() == 1) {
1089 if (meshes.
size() == 2) {
1112 Mesh *prev_result_mesh =
nullptr;
1129 if (prev_result_mesh !=
nullptr) {
1134 if (
i < meshes.
size() - 2) {
1135 two_meshes[0] = result_i_mesh;
1136 two_meshes[1] = meshes[
i + 2];
1138 two_transforms[1] = transforms[
i + 2];
1140 two_remaps[1] = material_remaps[
i + 2];
1141 prev_result_mesh = result_i_mesh;
1144 return result_i_mesh;
1152#ifdef BENCHMARK_TIME
1154static void write_boolean_benchmark_time(
1159 const int num_faces_1 = mesh1 ? mesh1->
faces_num : 0;
1160 const int num_faces_2 = mesh2 ? mesh2->
faces_num : 0;
1161 const int num_tris_1 = mesh1 ? mesh1->corner_tris().size() : 0;
1162 const int num_tris_2 = mesh2 ? mesh2->corner_tris().size() : 0;
1166 bool first_time =
false;
1167 if (!std::filesystem::exists(BENCHMARK_FILE)) {
1171 std::ofstream outfile(BENCHMARK_FILE, std::ios_base::app);
1173 if (outfile.is_open()) {
1175 outfile <<
"solver,op,mesh1,mesh2,face1,face2,tris1,tris2,time_in_ms,threads" << std::endl;
1177 outfile << solver <<
"," << op <<
",\"" << mesh1_name <<
"\",\"" << mesh2_name <<
"\","
1178 << num_faces_1 <<
"," << num_faces_2 <<
"," << num_tris_1 <<
"," << num_tris_2 <<
","
1179 << time_ms <<
"," << threads << std::endl;
1183 std::cerr <<
"Unable to open benchmark file: " << BENCHMARK_FILE << std::endl;
1198 Mesh *ans =
nullptr;
1199#ifdef BENCHMARK_TIME
1209 r_intersecting_edges);
1214 ans = mesh_boolean_mesh_arr(meshes,
1220 r_intersecting_edges);
1228 meshes, transforms, material_remaps, op_params, r_intersecting_edges, r_error);
1236#ifdef BENCHMARK_TIME
1239 float time_ms = duration.count() / 1.0e6f;
1244 const Mesh *mesh1 = meshes.
size() > 0 ? meshes[0] :
nullptr;
1245 const Mesh *mesh2 = meshes.
size() > 0 ? meshes[1] :
nullptr;
1249 write_boolean_benchmark_time(solverstr, opstr, mesh1, mesh2, time_ms);
CustomData interface, see also DNA_customdata_types.h.
int CustomData_sizeof(eCustomDataType type)
int CustomData_get_offset(const CustomData *data, eCustomDataType type)
const void * CustomData_get_layer_n(const CustomData *data, eCustomDataType type, int n)
int CustomData_get_named_layer(const CustomData *data, eCustomDataType type, blender::StringRef name)
bool CustomData_layer_has_interp(const CustomData *data, int layer_n)
int CustomData_get_named_layer_index(const CustomData *data, eCustomDataType type, blender::StringRef name)
void CustomData_copy_data_layer(const CustomData *source, CustomData *dest, int src_layer_index, int dst_layer_index, int src_index, int dst_index, int count)
void CustomData_bmesh_interp_n(CustomData *data, const void **src_blocks, const float *weights, int count, void *dst_block_ofs, int n)
bool CustomData_merge_layout(const CustomData *source, CustomData *dest, eCustomDataMask mask, eCDAllocType alloctype, int totelem)
void * CustomData_get_layer_n_for_write(CustomData *data, eCustomDataType type, int n, int totelem)
const CustomData_MeshMasks CD_MASK_MESH
void BKE_id_free(Main *bmain, void *idv)
Mesh * BKE_mesh_new_nomain_from_template(const Mesh *me_src, int verts_num, int edges_num, int faces_num, int corners_num)
bool BKE_mesh_validate(Mesh *mesh, bool do_verbose, bool cddata_check_mask)
Mesh * BKE_mesh_copy_for_eval(const Mesh &source)
Mesh * BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm, const CustomData_MeshMasks *cd_mask_extra, const Mesh *me_settings)
#define BLI_array_alloca(arr, realsize)
#define BLI_assert_unreachable()
void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3])
Normal to x,y matrix.
MINLINE int poly_to_tri_count(int poly_count, int corner_count)
void interp_weights_poly_v2(float w[], float v[][2], int n, const float co[2])
void mul_v2_m3v3(float r[2], const float M[3][3], const float a[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void negate_v3(float r[3])
MINLINE void copy_v3fl_v3db(float r[3], const double a[3])
MINLINE float normalize_v3(float n[3])
int BLI_system_num_threads_override_get(void)
#define POINTER_OFFSET(v, ofs)
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)
@ BMESH_ISECT_BOOLEAN_DIFFERENCE
@ BMESH_ISECT_BOOLEAN_NONE
@ BMESH_ISECT_BOOLEAN_UNION
@ BMESH_ISECT_BOOLEAN_ISECT
#define BM_ITER_MESH(ele, iter, bm, itype)
void BM_mesh_free(BMesh *bm)
BMesh Free Mesh.
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
BMesh * BM_mesh_create(const BMAllocTemplate *allocsize, const BMeshCreateParams *params)
BMesh Make Mesh.
void BM_mesh_bm_from_me(BMesh *bm, const Mesh *mesh, const BMeshFromMeshParams *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.
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
constexpr int64_t size() const
constexpr int64_t start() const
constexpr int64_t size() const
constexpr void fill(const T &value) const
constexpr Span slice(int64_t start, int64_t size) const
constexpr int64_t size() const
constexpr IndexRange index_range() const
constexpr bool is_empty() const
void append(const T &value)
void resize(const int64_t new_size)
constexpr IndexRange drop_back(int64_t n) const
constexpr bool contains(int64_t value) const
constexpr int64_t size() const
constexpr IndexRange index_range() const
constexpr const T * begin() const
constexpr bool is_empty() const
static int operation_to_float_mode(const Operation operation)
Mesh * mesh_boolean_manifold(Span< const Mesh * > meshes, Span< float4x4 > transforms, Span< Array< short > > material_remaps, BooleanOpParameters op_params, Vector< int > *r_intersecting_edges, BooleanError *r_error)
static Mesh * mesh_boolean_float(Span< const Mesh * > meshes, Span< float4x4 > transforms, Span< Array< short > > material_remaps, const int boolean_mode, Vector< int > *)
static BMesh * mesh_bm_concat(Span< const Mesh * > meshes, Span< float4x4 > transforms, Span< Array< short > > material_remaps, Array< std::array< BMLoop *, 3 > > &r_looptris)
Mesh * mesh_boolean(Span< const Mesh * > meshes, Span< float4x4 > transforms, Span< Array< short > > material_remaps, BooleanOpParameters op_params, Solver solver, Vector< int > *r_intersecting_edges, BooleanError *r_error)
static int face_boolean_operand(BMFace *f, void *)
bool is_negative(const MatBase< T, 3, 3 > &mat)
VecBase< T, 3 > transform_direction(const MatBase< T, 3, 3 > &mat, const VecBase< T, 3 > &direction)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
std::chrono::nanoseconds Nanoseconds
Clock::time_point TimePoint
MatBase< float, 4, 4 > float4x4
VecBase< float, 3 > float3
static MatBase identity()
bool no_self_intersections