2023-08-16 00:20:26 +10:00
|
|
|
/* SPDX-FileCopyrightText: 2007 Blender Authors
|
2023-05-31 16:19:06 +02:00
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
|
* \ingroup bmesh
|
2012-02-19 18:31:04 +00:00
|
|
|
*
|
|
|
|
|
* BM construction functions.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
2013-07-28 10:38:25 +00:00
|
|
|
#include "BLI_alloca.h"
|
2023-09-01 21:37:11 +02:00
|
|
|
#include "BLI_listbase.h"
|
Cleanup: reduce amount of math-related includes
Using ClangBuildAnalyzer on the whole Blender build, it was pointing
out that BLI_math.h is the heaviest "header hub" (i.e. non tiny file
that is included a lot).
However, there's very little (actually zero) source files in Blender
that need "all the math" (base, colors, vectors, matrices,
quaternions, intersection, interpolation, statistics, solvers and
time). A common use case is source files needing just vectors, or
just vectors & matrices, or just colors etc. Actually, 181 files
were including the whole math thing without needing it at all.
This change removes BLI_math.h completely, and instead in all the
places that need it, includes BLI_math_vector.h or BLI_math_color.h
and so on.
Change from that:
- BLI_math_color.h was included 1399 times -> now 408 (took 114.0sec
to parse -> now 36.3sec)
- BLI_simd.h 1403 -> 418 (109.7sec -> 34.9sec).
Full rebuild of Blender (Apple M1, Xcode, RelWithDebInfo) is not
affected much (342sec -> 334sec). Most of benefit would be when
someone's changing BLI_simd.h or BLI_math_color.h or similar files,
that now there's 3x fewer files result in a recompile.
Pull Request #110944
2023-08-09 11:39:20 +03:00
|
|
|
#include "BLI_math_vector.h"
|
2013-09-05 22:24:12 +00:00
|
|
|
#include "BLI_sort_utils.h"
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2023-11-16 11:41:55 +01:00
|
|
|
#include "BKE_customdata.hh"
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2021-11-09 16:58:45 +11:00
|
|
|
#include "DNA_mesh_types.h"
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2023-12-05 23:01:12 +01:00
|
|
|
#include "bmesh.hh"
|
|
|
|
|
#include "intern/bmesh_private.hh"
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2015-12-24 19:51:41 +11:00
|
|
|
bool BM_verts_from_edges(BMVert **vert_arr, BMEdge **edge_arr, const int len)
|
|
|
|
|
{
|
|
|
|
|
int i, i_prev = len - 1;
|
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
|
vert_arr[i] = BM_edge_share_vert(edge_arr[i_prev], edge_arr[i]);
|
2023-07-26 16:12:55 +02:00
|
|
|
if (vert_arr[i] == nullptr) {
|
2015-12-24 19:51:41 +11:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
i_prev = i;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-28 11:45:53 +10:00
|
|
|
bool BM_edges_from_verts(BMEdge **edge_arr, BMVert **vert_arr, const int len)
|
|
|
|
|
{
|
|
|
|
|
int i, i_prev = len - 1;
|
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
|
edge_arr[i_prev] = BM_edge_exists(vert_arr[i_prev], vert_arr[i]);
|
2023-07-26 16:12:55 +02:00
|
|
|
if (edge_arr[i_prev] == nullptr) {
|
2015-05-28 11:45:53 +10:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
i_prev = i;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BM_edges_from_verts_ensure(BMesh *bm, BMEdge **edge_arr, BMVert **vert_arr, const int len)
|
|
|
|
|
{
|
|
|
|
|
int i, i_prev = len - 1;
|
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
|
edge_arr[i_prev] = BM_edge_create(
|
2023-07-26 16:12:55 +02:00
|
|
|
bm, vert_arr[i_prev], vert_arr[i], nullptr, BM_CREATE_NO_DOUBLE);
|
2015-05-28 11:45:53 +10:00
|
|
|
i_prev = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-25 20:15:20 +10:00
|
|
|
BMFace *BM_face_create_quad_tri(BMesh *bm,
|
|
|
|
|
BMVert *v1,
|
|
|
|
|
BMVert *v2,
|
|
|
|
|
BMVert *v3,
|
|
|
|
|
BMVert *v4,
|
|
|
|
|
const BMFace *f_example,
|
|
|
|
|
const eBMCreateFlag create_flag)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
|
|
|
|
BMVert *vtar[4] = {v1, v2, v3, v4};
|
2013-08-21 07:51:47 +00:00
|
|
|
return BM_face_create_verts(bm, vtar, v4 ? 4 : 3, f_example, create_flag, true);
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
|
|
2015-11-28 13:37:02 +11:00
|
|
|
void BM_face_copy_shared(BMesh *bm, BMFace *f, BMLoopFilterFunc filter_fn, void *user_data)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
2012-04-13 10:37:33 +00:00
|
|
|
BMLoop *l_first;
|
|
|
|
|
BMLoop *l_iter;
|
|
|
|
|
|
2023-12-04 15:13:06 +01:00
|
|
|
#ifndef NDEBUG
|
2013-08-18 11:44:51 +00:00
|
|
|
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
|
|
|
|
do {
|
|
|
|
|
BLI_assert(BM_ELEM_API_FLAG_TEST(l_iter, _FLAG_OVERLAP) == 0);
|
|
|
|
|
} while ((l_iter = l_iter->next) != l_first);
|
|
|
|
|
#endif
|
|
|
|
|
|
2012-04-13 10:37:33 +00:00
|
|
|
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
|
|
|
|
do {
|
|
|
|
|
BMLoop *l_other = l_iter->radial_next;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-04-13 10:37:33 +00:00
|
|
|
if (l_other && l_other != l_iter) {
|
2013-08-18 11:44:51 +00:00
|
|
|
BMLoop *l_src[2];
|
|
|
|
|
BMLoop *l_dst[2] = {l_iter, l_iter->next};
|
2017-05-06 14:18:31 +10:00
|
|
|
uint j;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-04-13 10:37:33 +00:00
|
|
|
if (l_other->v == l_iter->v) {
|
2013-08-18 11:44:51 +00:00
|
|
|
l_src[0] = l_other;
|
|
|
|
|
l_src[1] = l_other->next;
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2013-08-18 11:44:51 +00:00
|
|
|
l_src[0] = l_other->next;
|
|
|
|
|
l_src[1] = l_other;
|
2012-04-13 10:37:33 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-08-18 11:44:51 +00:00
|
|
|
for (j = 0; j < 2; j++) {
|
|
|
|
|
BLI_assert(l_dst[j]->v == l_src[j]->v);
|
|
|
|
|
if (BM_ELEM_API_FLAG_TEST(l_dst[j], _FLAG_OVERLAP) == 0) {
|
2023-07-26 16:12:55 +02:00
|
|
|
if ((filter_fn == nullptr) || filter_fn(l_src[j], user_data)) {
|
2023-12-05 21:38:01 -05:00
|
|
|
CustomData_bmesh_copy_block(bm->ldata, l_src[j]->head.data, &l_dst[j]->head.data);
|
2013-08-18 11:44:51 +00:00
|
|
|
BM_ELEM_API_FLAG_ENABLE(l_dst[j], _FLAG_OVERLAP);
|
|
|
|
|
}
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2012-04-13 10:37:33 +00:00
|
|
|
} while ((l_iter = l_iter->next) != l_first);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-08-18 11:44:51 +00:00
|
|
|
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
|
|
|
|
do {
|
|
|
|
|
BM_ELEM_API_FLAG_DISABLE(l_iter, _FLAG_OVERLAP);
|
|
|
|
|
} while ((l_iter = l_iter->next) != l_first);
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
|
|
2012-02-28 07:42:48 +00:00
|
|
|
/**
|
2015-04-25 17:20:59 +10:00
|
|
|
* Given an array of edges,
|
|
|
|
|
* order them using the winding defined by \a v1 & \a v2
|
|
|
|
|
* into \a edges_sort & \a verts_sort.
|
2012-02-19 18:31:04 +00:00
|
|
|
*
|
2015-04-25 17:20:59 +10:00
|
|
|
* All arrays must be \a len long.
|
2012-02-19 18:31:04 +00:00
|
|
|
*/
|
2015-04-25 17:20:59 +10:00
|
|
|
static bool bm_edges_sort_winding(BMVert *v1,
|
|
|
|
|
BMVert *v2,
|
|
|
|
|
BMEdge **edges,
|
|
|
|
|
const int len,
|
|
|
|
|
BMEdge **edges_sort,
|
|
|
|
|
BMVert **verts_sort)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
2015-04-25 17:20:59 +10:00
|
|
|
BMEdge *e_iter, *e_first;
|
|
|
|
|
BMVert *v_iter;
|
2013-01-03 08:06:12 +00:00
|
|
|
int i;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-04-25 17:20:59 +10:00
|
|
|
/* all flags _must_ be cleared on exit! */
|
2012-02-19 18:31:04 +00:00
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
|
BM_ELEM_API_FLAG_ENABLE(edges[i], _FLAG_MF);
|
2015-04-25 17:20:59 +10:00
|
|
|
BM_ELEM_API_FLAG_ENABLE(edges[i]->v1, _FLAG_MV);
|
|
|
|
|
BM_ELEM_API_FLAG_ENABLE(edges[i]->v2, _FLAG_MV);
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-04-25 17:20:59 +10:00
|
|
|
/* find first edge */
|
2015-04-25 21:14:55 +10:00
|
|
|
i = 0;
|
2015-04-25 17:20:59 +10:00
|
|
|
v_iter = v1;
|
|
|
|
|
e_iter = e_first = v1->e;
|
2012-02-19 18:31:04 +00:00
|
|
|
do {
|
2015-04-25 17:20:59 +10:00
|
|
|
if (BM_ELEM_API_FLAG_TEST(e_iter, _FLAG_MF) && (BM_edge_other_vert(e_iter, v_iter) == v2)) {
|
2015-04-25 21:14:55 +10:00
|
|
|
i = 1;
|
2015-04-25 17:20:59 +10:00
|
|
|
break;
|
2013-01-03 07:53:30 +00:00
|
|
|
}
|
2015-04-25 17:20:59 +10:00
|
|
|
} while ((e_iter = bmesh_disk_edge_next(e_iter, v_iter)) != e_first);
|
2015-04-25 21:14:55 +10:00
|
|
|
if (i == 0) {
|
2015-04-25 17:20:59 +10:00
|
|
|
goto error;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-04-25 17:20:59 +10:00
|
|
|
i = 0;
|
|
|
|
|
do {
|
|
|
|
|
/* entering loop will always succeed */
|
|
|
|
|
if (BM_ELEM_API_FLAG_TEST(e_iter, _FLAG_MF)) {
|
|
|
|
|
if (UNLIKELY(BM_ELEM_API_FLAG_TEST(v_iter, _FLAG_MV) == false)) {
|
|
|
|
|
/* vert is in loop multiple times */
|
|
|
|
|
goto error;
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-04-25 17:20:59 +10:00
|
|
|
BM_ELEM_API_FLAG_DISABLE(e_iter, _FLAG_MF);
|
|
|
|
|
edges_sort[i] = e_iter;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-04-25 17:20:59 +10:00
|
|
|
BM_ELEM_API_FLAG_DISABLE(v_iter, _FLAG_MV);
|
|
|
|
|
verts_sort[i] = v_iter;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-04-25 17:20:59 +10:00
|
|
|
i += 1;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-04-25 17:20:59 +10:00
|
|
|
/* walk onto the next vertex */
|
|
|
|
|
v_iter = BM_edge_other_vert(e_iter, v_iter);
|
|
|
|
|
if (i == len) {
|
|
|
|
|
if (UNLIKELY(v_iter != verts_sort[0])) {
|
|
|
|
|
goto error;
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
2015-04-25 17:20:59 +10:00
|
|
|
break;
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-04-25 17:20:59 +10:00
|
|
|
e_first = e_iter;
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
2015-04-25 17:20:59 +10:00
|
|
|
} while ((e_iter = bmesh_disk_edge_next(e_iter, v_iter)) != e_first);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-04-25 17:20:59 +10:00
|
|
|
if (i == len) {
|
|
|
|
|
return true;
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
|
|
2015-04-25 17:20:59 +10:00
|
|
|
error:
|
2012-02-19 18:31:04 +00:00
|
|
|
for (i = 0; i < len; i++) {
|
2015-04-25 17:20:59 +10:00
|
|
|
BM_ELEM_API_FLAG_DISABLE(edges[i], _FLAG_MF);
|
|
|
|
|
BM_ELEM_API_FLAG_DISABLE(edges[i]->v1, _FLAG_MV);
|
|
|
|
|
BM_ELEM_API_FLAG_DISABLE(edges[i]->v2, _FLAG_MV);
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
|
|
2015-04-25 17:20:59 +10:00
|
|
|
return false;
|
|
|
|
|
}
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2015-04-25 17:20:59 +10:00
|
|
|
BMFace *BM_face_create_ngon(BMesh *bm,
|
|
|
|
|
BMVert *v1,
|
|
|
|
|
BMVert *v2,
|
|
|
|
|
BMEdge **edges,
|
|
|
|
|
const int len,
|
|
|
|
|
const BMFace *f_example,
|
|
|
|
|
const eBMCreateFlag create_flag)
|
|
|
|
|
{
|
|
|
|
|
BMEdge **edges_sort = BLI_array_alloca(edges_sort, len);
|
|
|
|
|
BMVert **verts_sort = BLI_array_alloca(verts_sort, len);
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2015-04-25 17:20:59 +10:00
|
|
|
BLI_assert(len && v1 && v2 && edges && bm);
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2015-04-25 17:20:59 +10:00
|
|
|
if (bm_edges_sort_winding(v1, v2, edges, len, edges_sort, verts_sort)) {
|
|
|
|
|
return BM_face_create(bm, verts_sort, edges_sort, len, f_example, create_flag);
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
|
|
2023-07-26 16:12:55 +02:00
|
|
|
return nullptr;
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
|
|
2015-04-25 20:15:20 +10:00
|
|
|
BMFace *BM_face_create_ngon_verts(BMesh *bm,
|
|
|
|
|
BMVert **vert_arr,
|
|
|
|
|
const int len,
|
|
|
|
|
const BMFace *f_example,
|
|
|
|
|
const eBMCreateFlag create_flag,
|
|
|
|
|
const bool calc_winding,
|
|
|
|
|
const bool create_edges)
|
2013-03-27 05:52:28 +00:00
|
|
|
{
|
|
|
|
|
BMEdge **edge_arr = BLI_array_alloca(edge_arr, len);
|
2017-05-06 14:18:31 +10:00
|
|
|
uint winding[2] = {0, 0};
|
2013-03-27 05:52:28 +00:00
|
|
|
int i, i_prev = len - 1;
|
2013-07-25 18:43:05 +00:00
|
|
|
BMVert *v_winding[2] = {vert_arr[i_prev], vert_arr[0]};
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-03-27 05:52:28 +00:00
|
|
|
BLI_assert(len > 2);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-03-27 05:52:28 +00:00
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
|
if (create_edges) {
|
2023-07-26 16:12:55 +02:00
|
|
|
edge_arr[i] = BM_edge_create(
|
|
|
|
|
bm, vert_arr[i_prev], vert_arr[i], nullptr, BM_CREATE_NO_DOUBLE);
|
2013-03-27 05:52:28 +00:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
edge_arr[i] = BM_edge_exists(vert_arr[i_prev], vert_arr[i]);
|
2023-07-26 16:12:55 +02:00
|
|
|
if (edge_arr[i] == nullptr) {
|
|
|
|
|
return nullptr;
|
2013-03-27 05:52:28 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2013-03-27 05:52:28 +00:00
|
|
|
if (calc_winding) {
|
|
|
|
|
/* the edge may exist already and be attached to a face
|
|
|
|
|
* in this case we can find the best winding to use for the new face */
|
|
|
|
|
if (edge_arr[i]->l) {
|
|
|
|
|
BMVert *test_v1, *test_v2;
|
|
|
|
|
/* we want to use the reverse winding to the existing order */
|
|
|
|
|
BM_edge_ordered_verts(edge_arr[i], &test_v2, &test_v1);
|
|
|
|
|
winding[(vert_arr[i_prev] == test_v2)]++;
|
2020-11-06 12:30:59 +11:00
|
|
|
BLI_assert(ELEM(vert_arr[i_prev], test_v2, test_v1));
|
2013-03-27 05:52:28 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2013-03-27 05:52:28 +00:00
|
|
|
i_prev = i;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-03-27 05:52:28 +00:00
|
|
|
/* --- */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-03-27 05:52:28 +00:00
|
|
|
if (calc_winding) {
|
|
|
|
|
if (winding[0] < winding[1]) {
|
|
|
|
|
winding[0] = 1;
|
|
|
|
|
winding[1] = 0;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
winding[0] = 0;
|
|
|
|
|
winding[1] = 1;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2013-03-27 05:52:28 +00:00
|
|
|
else {
|
|
|
|
|
winding[0] = 0;
|
|
|
|
|
winding[1] = 1;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-03-27 05:52:28 +00:00
|
|
|
/* --- */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-03-27 05:52:28 +00:00
|
|
|
/* create the face */
|
2013-07-25 18:16:55 +00:00
|
|
|
return BM_face_create_ngon(
|
2013-08-21 07:51:47 +00:00
|
|
|
bm, v_winding[winding[0]], v_winding[winding[1]], edge_arr, len, f_example, create_flag);
|
2013-03-27 05:52:28 +00:00
|
|
|
}
|
|
|
|
|
|
2017-01-20 06:06:06 +11:00
|
|
|
void BM_verts_sort_radial_plane(BMVert **vert_arr, int len)
|
2012-03-14 22:57:15 +00:00
|
|
|
{
|
2023-07-27 11:23:35 +10:00
|
|
|
SortIntByFloat *vang = BLI_array_alloca(vang, len);
|
2013-08-21 05:20:57 +00:00
|
|
|
BMVert **vert_arr_map = BLI_array_alloca(vert_arr_map, len);
|
2012-03-14 22:57:15 +00:00
|
|
|
|
2019-08-09 05:27:49 +10:00
|
|
|
float nor[3], cent[3];
|
|
|
|
|
int index_tangent = 0;
|
|
|
|
|
BM_verts_calc_normal_from_cloud_ex(vert_arr, len, nor, cent, &index_tangent);
|
|
|
|
|
const float *far = vert_arr[index_tangent]->co;
|
2012-03-14 22:57:15 +00:00
|
|
|
|
2019-08-09 05:27:49 +10:00
|
|
|
/* Now calculate every points angle around the normal (signed). */
|
|
|
|
|
for (int i = 0; i < len; i++) {
|
2017-01-19 07:59:32 +11:00
|
|
|
vang[i].sort_value = angle_signed_on_axis_v3v3v3_v3(far, cent, vert_arr[i]->co, nor);
|
2013-09-05 22:24:12 +00:00
|
|
|
vang[i].data = i;
|
2017-01-20 06:06:06 +11:00
|
|
|
vert_arr_map[i] = vert_arr[i];
|
2012-03-14 22:57:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* sort by angle and magic! - we have our ngon */
|
2013-09-05 22:24:12 +00:00
|
|
|
qsort(vang, len, sizeof(*vang), BLI_sortutil_cmp_float);
|
2012-03-14 22:57:15 +00:00
|
|
|
|
|
|
|
|
/* --- */
|
|
|
|
|
|
2019-08-09 05:27:49 +10:00
|
|
|
for (int i = 0; i < len; i++) {
|
2017-01-20 06:06:06 +11:00
|
|
|
vert_arr[i] = vert_arr_map[vang[i].data];
|
2012-03-14 22:57:15 +00:00
|
|
|
}
|
|
|
|
|
}
|
2012-02-19 18:31:04 +00:00
|
|
|
|
|
|
|
|
/*************************************************************/
|
|
|
|
|
|
2023-12-09 05:37:37 +01:00
|
|
|
void BM_elem_attrs_copy(BMesh *bm, const BMCustomDataCopyMap &map, const BMVert *src, BMVert *dst)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
2023-12-11 11:42:15 -05:00
|
|
|
BLI_assert(src != dst);
|
2023-12-09 05:37:37 +01:00
|
|
|
CustomData_bmesh_copy_block(bm->vdata, map, src->head.data, &dst->head.data);
|
|
|
|
|
dst->head.hflag = src->head.hflag & ~BM_ELEM_SELECT;
|
|
|
|
|
copy_v3_v3(dst->no, src->no);
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
2023-12-09 05:37:37 +01:00
|
|
|
void BM_elem_attrs_copy(BMesh *bm, const BMCustomDataCopyMap &map, const BMEdge *src, BMEdge *dst)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
2023-12-11 11:42:15 -05:00
|
|
|
BLI_assert(src != dst);
|
|
|
|
|
CustomData_bmesh_copy_block(bm->edata, map, src->head.data, &dst->head.data);
|
2023-12-09 05:37:37 +01:00
|
|
|
dst->head.hflag = src->head.hflag & ~BM_ELEM_SELECT;
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
2023-12-09 05:37:37 +01:00
|
|
|
void BM_elem_attrs_copy(BMesh *bm, const BMCustomDataCopyMap &map, const BMFace *src, BMFace *dst)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
2023-12-11 11:42:15 -05:00
|
|
|
BLI_assert(src != dst);
|
|
|
|
|
CustomData_bmesh_copy_block(bm->pdata, map, src->head.data, &dst->head.data);
|
2023-12-09 05:37:37 +01:00
|
|
|
dst->head.hflag = src->head.hflag & ~BM_ELEM_SELECT;
|
|
|
|
|
copy_v3_v3(dst->no, src->no);
|
|
|
|
|
dst->mat_nr = src->mat_nr;
|
|
|
|
|
}
|
|
|
|
|
void BM_elem_attrs_copy(BMesh *bm, const BMCustomDataCopyMap &map, const BMLoop *src, BMLoop *dst)
|
|
|
|
|
{
|
2023-12-11 11:42:15 -05:00
|
|
|
BLI_assert(src != dst);
|
|
|
|
|
CustomData_bmesh_copy_block(bm->ldata, map, src->head.data, &dst->head.data);
|
2023-12-09 05:37:37 +01:00
|
|
|
dst->head.hflag = src->head.hflag & ~BM_ELEM_SELECT;
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
|
|
2023-12-10 22:06:18 +11:00
|
|
|
void BM_elem_attrs_copy(BMesh *bm, const BMVert *src, BMVert *dst)
|
2023-12-05 17:15:36 -05:00
|
|
|
{
|
BMesh: Improve performance when copying attributes in same mesh
When the BMesh source and result arguments are the same, restore
performance lost by 9175d9b7c27b191ea94a, which made copying layers
have quadratic time complexity. When we know the custom data format
is the same between the source and result, the copying can be much
simpler, so it's worth specializing this case. There is still more
to be done, because often we only know that the two meshes are the
same at runtime. A followup commit will add that check.
The quadratic runtime means performance is fine for low layer counts,
and terrible with higher layer counts. For example, in my testing with
47 boolean attributes, copying 250k vertices went from 2.3 seconds to
316 ms.
The implementation uses a new CustomData function that copies an entire
BMesh custom data block, called by a function in the BMesh module
overloaded for every BMesh element type. That handles the extra data
like flags, normals, and material indices.
Related to #115776
2023-12-05 20:26:28 -05:00
|
|
|
BLI_assert(src != dst);
|
2023-12-10 22:06:18 +11:00
|
|
|
CustomData_bmesh_copy_block(bm->vdata, src->head.data, &dst->head.data);
|
BMesh: Improve performance when copying attributes in same mesh
When the BMesh source and result arguments are the same, restore
performance lost by 9175d9b7c27b191ea94a, which made copying layers
have quadratic time complexity. When we know the custom data format
is the same between the source and result, the copying can be much
simpler, so it's worth specializing this case. There is still more
to be done, because often we only know that the two meshes are the
same at runtime. A followup commit will add that check.
The quadratic runtime means performance is fine for low layer counts,
and terrible with higher layer counts. For example, in my testing with
47 boolean attributes, copying 250k vertices went from 2.3 seconds to
316 ms.
The implementation uses a new CustomData function that copies an entire
BMesh custom data block, called by a function in the BMesh module
overloaded for every BMesh element type. That handles the extra data
like flags, normals, and material indices.
Related to #115776
2023-12-05 20:26:28 -05:00
|
|
|
dst->head.hflag = src->head.hflag & ~BM_ELEM_SELECT;
|
|
|
|
|
copy_v3_v3(dst->no, src->no);
|
|
|
|
|
}
|
2023-12-10 22:06:18 +11:00
|
|
|
void BM_elem_attrs_copy(BMesh *bm, const BMEdge *src, BMEdge *dst)
|
BMesh: Improve performance when copying attributes in same mesh
When the BMesh source and result arguments are the same, restore
performance lost by 9175d9b7c27b191ea94a, which made copying layers
have quadratic time complexity. When we know the custom data format
is the same between the source and result, the copying can be much
simpler, so it's worth specializing this case. There is still more
to be done, because often we only know that the two meshes are the
same at runtime. A followup commit will add that check.
The quadratic runtime means performance is fine for low layer counts,
and terrible with higher layer counts. For example, in my testing with
47 boolean attributes, copying 250k vertices went from 2.3 seconds to
316 ms.
The implementation uses a new CustomData function that copies an entire
BMesh custom data block, called by a function in the BMesh module
overloaded for every BMesh element type. That handles the extra data
like flags, normals, and material indices.
Related to #115776
2023-12-05 20:26:28 -05:00
|
|
|
{
|
|
|
|
|
BLI_assert(src != dst);
|
2023-12-10 22:06:18 +11:00
|
|
|
CustomData_bmesh_copy_block(bm->edata, src->head.data, &dst->head.data);
|
BMesh: Improve performance when copying attributes in same mesh
When the BMesh source and result arguments are the same, restore
performance lost by 9175d9b7c27b191ea94a, which made copying layers
have quadratic time complexity. When we know the custom data format
is the same between the source and result, the copying can be much
simpler, so it's worth specializing this case. There is still more
to be done, because often we only know that the two meshes are the
same at runtime. A followup commit will add that check.
The quadratic runtime means performance is fine for low layer counts,
and terrible with higher layer counts. For example, in my testing with
47 boolean attributes, copying 250k vertices went from 2.3 seconds to
316 ms.
The implementation uses a new CustomData function that copies an entire
BMesh custom data block, called by a function in the BMesh module
overloaded for every BMesh element type. That handles the extra data
like flags, normals, and material indices.
Related to #115776
2023-12-05 20:26:28 -05:00
|
|
|
dst->head.hflag = src->head.hflag & ~BM_ELEM_SELECT;
|
|
|
|
|
}
|
2023-12-10 22:06:18 +11:00
|
|
|
void BM_elem_attrs_copy(BMesh *bm, const BMFace *src, BMFace *dst)
|
BMesh: Improve performance when copying attributes in same mesh
When the BMesh source and result arguments are the same, restore
performance lost by 9175d9b7c27b191ea94a, which made copying layers
have quadratic time complexity. When we know the custom data format
is the same between the source and result, the copying can be much
simpler, so it's worth specializing this case. There is still more
to be done, because often we only know that the two meshes are the
same at runtime. A followup commit will add that check.
The quadratic runtime means performance is fine for low layer counts,
and terrible with higher layer counts. For example, in my testing with
47 boolean attributes, copying 250k vertices went from 2.3 seconds to
316 ms.
The implementation uses a new CustomData function that copies an entire
BMesh custom data block, called by a function in the BMesh module
overloaded for every BMesh element type. That handles the extra data
like flags, normals, and material indices.
Related to #115776
2023-12-05 20:26:28 -05:00
|
|
|
{
|
|
|
|
|
BLI_assert(src != dst);
|
2023-12-10 22:06:18 +11:00
|
|
|
CustomData_bmesh_copy_block(bm->pdata, src->head.data, &dst->head.data);
|
BMesh: Improve performance when copying attributes in same mesh
When the BMesh source and result arguments are the same, restore
performance lost by 9175d9b7c27b191ea94a, which made copying layers
have quadratic time complexity. When we know the custom data format
is the same between the source and result, the copying can be much
simpler, so it's worth specializing this case. There is still more
to be done, because often we only know that the two meshes are the
same at runtime. A followup commit will add that check.
The quadratic runtime means performance is fine for low layer counts,
and terrible with higher layer counts. For example, in my testing with
47 boolean attributes, copying 250k vertices went from 2.3 seconds to
316 ms.
The implementation uses a new CustomData function that copies an entire
BMesh custom data block, called by a function in the BMesh module
overloaded for every BMesh element type. That handles the extra data
like flags, normals, and material indices.
Related to #115776
2023-12-05 20:26:28 -05:00
|
|
|
dst->head.hflag = src->head.hflag & ~BM_ELEM_SELECT;
|
|
|
|
|
copy_v3_v3(dst->no, src->no);
|
|
|
|
|
dst->mat_nr = src->mat_nr;
|
|
|
|
|
}
|
2023-12-10 22:06:18 +11:00
|
|
|
void BM_elem_attrs_copy(BMesh *bm, const BMLoop *src, BMLoop *dst)
|
BMesh: Improve performance when copying attributes in same mesh
When the BMesh source and result arguments are the same, restore
performance lost by 9175d9b7c27b191ea94a, which made copying layers
have quadratic time complexity. When we know the custom data format
is the same between the source and result, the copying can be much
simpler, so it's worth specializing this case. There is still more
to be done, because often we only know that the two meshes are the
same at runtime. A followup commit will add that check.
The quadratic runtime means performance is fine for low layer counts,
and terrible with higher layer counts. For example, in my testing with
47 boolean attributes, copying 250k vertices went from 2.3 seconds to
316 ms.
The implementation uses a new CustomData function that copies an entire
BMesh custom data block, called by a function in the BMesh module
overloaded for every BMesh element type. That handles the extra data
like flags, normals, and material indices.
Related to #115776
2023-12-05 20:26:28 -05:00
|
|
|
{
|
|
|
|
|
BLI_assert(src != dst);
|
2023-12-10 22:06:18 +11:00
|
|
|
CustomData_bmesh_copy_block(bm->ldata, src->head.data, &dst->head.data);
|
BMesh: Improve performance when copying attributes in same mesh
When the BMesh source and result arguments are the same, restore
performance lost by 9175d9b7c27b191ea94a, which made copying layers
have quadratic time complexity. When we know the custom data format
is the same between the source and result, the copying can be much
simpler, so it's worth specializing this case. There is still more
to be done, because often we only know that the two meshes are the
same at runtime. A followup commit will add that check.
The quadratic runtime means performance is fine for low layer counts,
and terrible with higher layer counts. For example, in my testing with
47 boolean attributes, copying 250k vertices went from 2.3 seconds to
316 ms.
The implementation uses a new CustomData function that copies an entire
BMesh custom data block, called by a function in the BMesh module
overloaded for every BMesh element type. That handles the extra data
like flags, normals, and material indices.
Related to #115776
2023-12-05 20:26:28 -05:00
|
|
|
dst->head.hflag = src->head.hflag & ~BM_ELEM_SELECT;
|
2023-12-05 17:15:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-11-14 14:21:15 +11:00
|
|
|
void BM_elem_select_copy(BMesh *bm_dst, void *ele_dst_v, const void *ele_src_v)
|
2013-07-24 19:31:58 +00:00
|
|
|
{
|
2023-07-26 16:12:55 +02:00
|
|
|
BMHeader *ele_dst = static_cast<BMHeader *>(ele_dst_v);
|
|
|
|
|
const BMHeader *ele_src = static_cast<const BMHeader *>(ele_src_v);
|
2013-07-24 19:31:58 +00:00
|
|
|
|
|
|
|
|
BLI_assert(ele_src->htype == ele_dst->htype);
|
|
|
|
|
|
|
|
|
|
if ((ele_src->hflag & BM_ELEM_SELECT) != (ele_dst->hflag & BM_ELEM_SELECT)) {
|
|
|
|
|
BM_elem_select_set(bm_dst, (BMElem *)ele_dst, (ele_src->hflag & BM_ELEM_SELECT) != 0);
|
|
|
|
|
}
|
2013-07-11 12:43:34 +00:00
|
|
|
}
|
|
|
|
|
|
2013-05-26 12:02:29 +00:00
|
|
|
/* helper function for 'BM_mesh_copy' */
|
2023-12-09 05:37:37 +01:00
|
|
|
static BMFace *bm_mesh_copy_new_face(BMesh *bm_new,
|
|
|
|
|
const BMCustomDataCopyMap &face_map,
|
|
|
|
|
const BMCustomDataCopyMap &loop_map,
|
|
|
|
|
BMVert **vtable,
|
|
|
|
|
BMEdge **etable,
|
|
|
|
|
BMFace *f)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
2013-05-25 20:47:06 +00:00
|
|
|
BMLoop **loops = BLI_array_alloca(loops, f->len);
|
|
|
|
|
BMVert **verts = BLI_array_alloca(verts, f->len);
|
|
|
|
|
BMEdge **edges = BLI_array_alloca(edges, f->len);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-05-25 20:47:06 +00:00
|
|
|
BMFace *f_new;
|
|
|
|
|
BMLoop *l_iter, *l_first;
|
|
|
|
|
int j;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-05-25 20:47:06 +00:00
|
|
|
j = 0;
|
|
|
|
|
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
|
|
|
|
do {
|
|
|
|
|
loops[j] = l_iter;
|
|
|
|
|
verts[j] = vtable[BM_elem_index_get(l_iter->v)];
|
|
|
|
|
edges[j] = etable[BM_elem_index_get(l_iter->e)];
|
|
|
|
|
j++;
|
|
|
|
|
} while ((l_iter = l_iter->next) != l_first);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-26 16:12:55 +02:00
|
|
|
f_new = BM_face_create(bm_new, verts, edges, f->len, nullptr, BM_CREATE_SKIP_CD);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-26 16:12:55 +02:00
|
|
|
if (UNLIKELY(f_new == nullptr)) {
|
|
|
|
|
return nullptr;
|
2013-05-25 20:47:06 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-05-25 20:47:06 +00:00
|
|
|
/* use totface in case adding some faces fails */
|
|
|
|
|
BM_elem_index_set(f_new, (bm_new->totface - 1)); /* set_inline */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-12-11 11:42:15 -05:00
|
|
|
CustomData_bmesh_copy_block(bm_new->pdata, face_map, f->head.data, &f_new->head.data);
|
2023-12-09 05:37:37 +01:00
|
|
|
copy_v3_v3(f_new->no, f->no);
|
|
|
|
|
f_new->mat_nr = f->mat_nr;
|
2013-07-24 19:31:58 +00:00
|
|
|
f_new->head.hflag = f->head.hflag; /* low level! don't do this for normal api use */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-05-25 20:47:06 +00:00
|
|
|
j = 0;
|
|
|
|
|
l_iter = l_first = BM_FACE_FIRST_LOOP(f_new);
|
|
|
|
|
do {
|
2023-12-11 11:42:15 -05:00
|
|
|
CustomData_bmesh_copy_block(bm_new->ldata, loop_map, loops[j]->head.data, &l_iter->head.data);
|
2023-12-09 05:37:37 +01:00
|
|
|
l_iter->head.hflag = loops[j]->head.hflag & ~BM_ELEM_SELECT;
|
2013-05-25 20:47:06 +00:00
|
|
|
j++;
|
|
|
|
|
} while ((l_iter = l_iter->next) != l_first);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-05-25 20:47:06 +00:00
|
|
|
return f_new;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-18 21:44:08 +11:00
|
|
|
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)
|
|
|
|
|
|
2021-11-09 16:58:45 +11:00
|
|
|
{
|
2023-07-26 16:12:55 +02:00
|
|
|
if (allocsize == nullptr) {
|
2021-11-09 16:58:45 +11:00
|
|
|
allocsize = &bm_mesh_allocsize_default;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-18 21:44:08 +11:00
|
|
|
for (int i = 0; i < me_src_array_len; i++) {
|
|
|
|
|
const Mesh *me_src = me_src_array[i];
|
2022-10-13 12:42:12 -05:00
|
|
|
CustomData mesh_vdata = CustomData_shallow_copy_remove_non_bmesh_attributes(
|
2023-07-25 21:15:52 +02:00
|
|
|
&me_src->vert_data, CD_MASK_BMESH.vmask);
|
2022-10-13 12:42:12 -05:00
|
|
|
CustomData mesh_edata = CustomData_shallow_copy_remove_non_bmesh_attributes(
|
2023-07-25 21:15:52 +02:00
|
|
|
&me_src->edge_data, CD_MASK_BMESH.emask);
|
2022-10-13 12:42:12 -05:00
|
|
|
CustomData mesh_pdata = CustomData_shallow_copy_remove_non_bmesh_attributes(
|
2023-11-19 10:46:07 -05:00
|
|
|
&me_src->face_data, CD_MASK_BMESH.pmask);
|
2022-10-13 12:42:12 -05:00
|
|
|
CustomData mesh_ldata = CustomData_shallow_copy_remove_non_bmesh_attributes(
|
2023-12-19 20:38:59 -05:00
|
|
|
&me_src->corner_data, CD_MASK_BMESH.lmask);
|
2022-10-13 12:42:12 -05:00
|
|
|
|
2022-01-18 21:44:08 +11:00
|
|
|
if (i == 0) {
|
2023-04-13 14:57:57 +02:00
|
|
|
CustomData_copy_layout(&mesh_vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0);
|
|
|
|
|
CustomData_copy_layout(&mesh_edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0);
|
|
|
|
|
CustomData_copy_layout(&mesh_pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0);
|
|
|
|
|
CustomData_copy_layout(&mesh_ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0);
|
2022-01-18 21:44:08 +11:00
|
|
|
}
|
|
|
|
|
else {
|
2023-04-13 14:57:57 +02:00
|
|
|
CustomData_merge_layout(&mesh_vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0);
|
|
|
|
|
CustomData_merge_layout(&mesh_edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0);
|
|
|
|
|
CustomData_merge_layout(&mesh_pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0);
|
|
|
|
|
CustomData_merge_layout(&mesh_ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0);
|
2022-01-18 21:44:08 +11:00
|
|
|
}
|
2022-10-13 12:42:12 -05:00
|
|
|
|
|
|
|
|
MEM_SAFE_FREE(mesh_vdata.layers);
|
|
|
|
|
MEM_SAFE_FREE(mesh_edata.layers);
|
|
|
|
|
MEM_SAFE_FREE(mesh_pdata.layers);
|
|
|
|
|
MEM_SAFE_FREE(mesh_ldata.layers);
|
2022-01-18 21:44:08 +11:00
|
|
|
}
|
|
|
|
|
|
2021-11-09 16:58:45 +11:00
|
|
|
CustomData_bmesh_init_pool(&bm_dst->vdata, allocsize->totvert, BM_VERT);
|
|
|
|
|
CustomData_bmesh_init_pool(&bm_dst->edata, allocsize->totedge, BM_EDGE);
|
|
|
|
|
CustomData_bmesh_init_pool(&bm_dst->ldata, allocsize->totloop, BM_LOOP);
|
|
|
|
|
CustomData_bmesh_init_pool(&bm_dst->pdata, allocsize->totface, BM_FACE);
|
2022-01-18 21:44:08 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BM_mesh_copy_init_customdata_from_mesh(BMesh *bm_dst,
|
|
|
|
|
const Mesh *me_src,
|
|
|
|
|
const BMAllocTemplate *allocsize)
|
|
|
|
|
{
|
|
|
|
|
BM_mesh_copy_init_customdata_from_mesh_array(bm_dst, &me_src, 1, allocsize);
|
2021-11-09 16:58:45 +11:00
|
|
|
}
|
|
|
|
|
|
2013-07-11 04:24:36 +00:00
|
|
|
void BM_mesh_copy_init_customdata(BMesh *bm_dst, BMesh *bm_src, const BMAllocTemplate *allocsize)
|
|
|
|
|
{
|
2023-07-26 16:12:55 +02:00
|
|
|
if (allocsize == nullptr) {
|
2013-07-11 04:24:36 +00:00
|
|
|
allocsize = &bm_mesh_allocsize_default;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-04-13 14:57:57 +02:00
|
|
|
CustomData_copy_layout(&bm_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0);
|
|
|
|
|
CustomData_copy_layout(&bm_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0);
|
|
|
|
|
CustomData_copy_layout(&bm_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0);
|
|
|
|
|
CustomData_copy_layout(&bm_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-07-11 04:24:36 +00:00
|
|
|
CustomData_bmesh_init_pool(&bm_dst->vdata, allocsize->totvert, BM_VERT);
|
|
|
|
|
CustomData_bmesh_init_pool(&bm_dst->edata, allocsize->totedge, BM_EDGE);
|
|
|
|
|
CustomData_bmesh_init_pool(&bm_dst->ldata, allocsize->totloop, BM_LOOP);
|
|
|
|
|
CustomData_bmesh_init_pool(&bm_dst->pdata, allocsize->totface, BM_FACE);
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-10 11:13:01 -03:00
|
|
|
void BM_mesh_copy_init_customdata_all_layers(BMesh *bm_dst,
|
|
|
|
|
BMesh *bm_src,
|
|
|
|
|
const char htype,
|
|
|
|
|
const BMAllocTemplate *allocsize)
|
|
|
|
|
{
|
2023-07-26 16:12:55 +02:00
|
|
|
if (allocsize == nullptr) {
|
2020-10-10 11:13:01 -03:00
|
|
|
allocsize = &bm_mesh_allocsize_default;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char htypes[4] = {BM_VERT, BM_EDGE, BM_LOOP, BM_FACE};
|
|
|
|
|
BLI_assert(((&bm_dst->vdata + 1) == &bm_dst->edata) &&
|
|
|
|
|
((&bm_dst->vdata + 2) == &bm_dst->ldata) && ((&bm_dst->vdata + 3) == &bm_dst->pdata));
|
|
|
|
|
|
|
|
|
|
BLI_assert(((&allocsize->totvert + 1) == &allocsize->totedge) &&
|
|
|
|
|
((&allocsize->totvert + 2) == &allocsize->totloop) &&
|
|
|
|
|
((&allocsize->totvert + 3) == &allocsize->totface));
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
|
if (!(htypes[i] & htype)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
CustomData *dst = &bm_dst->vdata + i;
|
|
|
|
|
CustomData *src = &bm_src->vdata + i;
|
|
|
|
|
const int size = *(&allocsize->totvert + i);
|
|
|
|
|
|
|
|
|
|
for (int l = 0; l < src->totlayer; l++) {
|
2023-07-26 16:12:55 +02:00
|
|
|
CustomData_add_layer_named(
|
|
|
|
|
dst, eCustomDataType(src->layers[l].type), CD_SET_DEFAULT, 0, src->layers[l].name);
|
2020-10-10 11:13:01 -03:00
|
|
|
}
|
|
|
|
|
CustomData_bmesh_init_pool(dst, size, htypes[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-25 20:47:06 +00:00
|
|
|
BMesh *BM_mesh_copy(BMesh *bm_old)
|
|
|
|
|
{
|
2012-03-01 22:17:04 +00:00
|
|
|
BMesh *bm_new;
|
2023-07-26 16:12:55 +02:00
|
|
|
BMVert *v, *v_new, **vtable = nullptr;
|
|
|
|
|
BMEdge *e, *e_new, **etable = nullptr;
|
|
|
|
|
BMFace *f, *f_new, **ftable = nullptr;
|
2012-04-24 21:19:18 +00:00
|
|
|
BMElem **eletable;
|
2013-05-25 20:47:06 +00:00
|
|
|
BMIter iter;
|
|
|
|
|
int i;
|
2013-09-24 03:31:00 +00:00
|
|
|
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_BM(bm_old);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-19 18:31:04 +00:00
|
|
|
/* allocate a bmesh */
|
2023-07-26 16:12:55 +02:00
|
|
|
BMeshCreateParams params{};
|
|
|
|
|
params.use_toolflags = bm_old->use_toolflags;
|
|
|
|
|
bm_new = BM_mesh_create(&allocsize, ¶ms);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-07-11 04:24:36 +00:00
|
|
|
BM_mesh_copy_init_customdata(bm_new, bm_old, &allocsize);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-12-09 05:37:37 +01:00
|
|
|
const BMCustomDataCopyMap vert_map = CustomData_bmesh_copy_map_calc(bm_old->vdata,
|
|
|
|
|
bm_new->vdata);
|
|
|
|
|
const BMCustomDataCopyMap edge_map = CustomData_bmesh_copy_map_calc(bm_old->edata,
|
|
|
|
|
bm_new->edata);
|
|
|
|
|
const BMCustomDataCopyMap face_map = CustomData_bmesh_copy_map_calc(bm_old->pdata,
|
|
|
|
|
bm_new->pdata);
|
|
|
|
|
const BMCustomDataCopyMap loop_map = CustomData_bmesh_copy_map_calc(bm_old->ldata,
|
|
|
|
|
bm_new->ldata);
|
|
|
|
|
|
2023-07-26 16:12:55 +02:00
|
|
|
vtable = static_cast<BMVert **>(
|
|
|
|
|
MEM_mallocN(sizeof(BMVert *) * bm_old->totvert, "BM_mesh_copy vtable"));
|
|
|
|
|
etable = static_cast<BMEdge **>(
|
|
|
|
|
MEM_mallocN(sizeof(BMEdge *) * bm_old->totedge, "BM_mesh_copy etable"));
|
|
|
|
|
ftable = static_cast<BMFace **>(
|
|
|
|
|
MEM_mallocN(sizeof(BMFace *) * bm_old->totface, "BM_mesh_copy ftable"));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-05-25 20:47:06 +00:00
|
|
|
BM_ITER_MESH_INDEX (v, &iter, bm_old, BM_VERTS_OF_MESH, i) {
|
2021-06-22 10:42:32 -07:00
|
|
|
/* copy between meshes so can't use 'example' argument */
|
2023-07-26 16:12:55 +02:00
|
|
|
v_new = BM_vert_create(bm_new, v->co, nullptr, BM_CREATE_SKIP_CD);
|
2023-12-09 05:37:37 +01:00
|
|
|
CustomData_bmesh_copy_block(bm_new->vdata, vert_map, v->head.data, &v_new->head.data);
|
|
|
|
|
copy_v3_v3(v_new->no, v->no);
|
2013-07-24 19:31:58 +00:00
|
|
|
v_new->head.hflag = v->head.hflag; /* low level! don't do this for normal api use */
|
2013-05-25 20:47:06 +00:00
|
|
|
vtable[i] = v_new;
|
2012-02-19 18:31:04 +00:00
|
|
|
BM_elem_index_set(v, i); /* set_inline */
|
2013-05-25 20:47:06 +00:00
|
|
|
BM_elem_index_set(v_new, i); /* set_inline */
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
2012-03-01 22:17:04 +00:00
|
|
|
bm_old->elem_index_dirty &= ~BM_VERT;
|
|
|
|
|
bm_new->elem_index_dirty &= ~BM_VERT;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-19 18:31:04 +00:00
|
|
|
/* safety check */
|
2012-03-01 22:17:04 +00:00
|
|
|
BLI_assert(i == bm_old->totvert);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-05-25 20:47:06 +00:00
|
|
|
BM_ITER_MESH_INDEX (e, &iter, bm_old, BM_EDGES_OF_MESH, i) {
|
|
|
|
|
e_new = BM_edge_create(bm_new,
|
|
|
|
|
vtable[BM_elem_index_get(e->v1)],
|
|
|
|
|
vtable[BM_elem_index_get(e->v2)],
|
|
|
|
|
e,
|
|
|
|
|
BM_CREATE_SKIP_CD);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-12-10 18:52:18 -05:00
|
|
|
CustomData_bmesh_copy_block(bm_new->edata, edge_map, e->head.data, &e_new->head.data);
|
2013-07-24 19:31:58 +00:00
|
|
|
e_new->head.hflag = e->head.hflag; /* low level! don't do this for normal api use */
|
2013-05-25 20:47:06 +00:00
|
|
|
etable[i] = e_new;
|
2012-02-19 18:31:04 +00:00
|
|
|
BM_elem_index_set(e, i); /* set_inline */
|
2013-05-25 20:47:06 +00:00
|
|
|
BM_elem_index_set(e_new, i); /* set_inline */
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
2012-03-01 22:17:04 +00:00
|
|
|
bm_old->elem_index_dirty &= ~BM_EDGE;
|
|
|
|
|
bm_new->elem_index_dirty &= ~BM_EDGE;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-19 18:31:04 +00:00
|
|
|
/* safety check */
|
2012-03-01 22:17:04 +00:00
|
|
|
BLI_assert(i == bm_old->totedge);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-05-25 20:47:06 +00:00
|
|
|
BM_ITER_MESH_INDEX (f, &iter, bm_old, BM_FACES_OF_MESH, i) {
|
2012-02-19 18:31:04 +00:00
|
|
|
BM_elem_index_set(f, i); /* set_inline */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-12-09 05:37:37 +01:00
|
|
|
f_new = bm_mesh_copy_new_face(bm_new, face_map, loop_map, vtable, etable, f);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-05-25 20:47:06 +00:00
|
|
|
ftable[i] = f_new;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-27 17:14:36 +11:00
|
|
|
if (f == bm_old->act_face) {
|
|
|
|
|
bm_new->act_face = f_new;
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2012-03-01 22:17:04 +00:00
|
|
|
bm_old->elem_index_dirty &= ~BM_FACE;
|
|
|
|
|
bm_new->elem_index_dirty &= ~BM_FACE;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-07-24 19:31:58 +00:00
|
|
|
/* low level! don't do this for normal api use */
|
|
|
|
|
bm_new->totvertsel = bm_old->totvertsel;
|
|
|
|
|
bm_new->totedgesel = bm_old->totedgesel;
|
|
|
|
|
bm_new->totfacesel = bm_old->totfacesel;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-19 18:31:04 +00:00
|
|
|
/* safety check */
|
2012-03-01 22:17:04 +00:00
|
|
|
BLI_assert(i == bm_old->totface);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-19 18:31:04 +00:00
|
|
|
/* copy over edit selection history */
|
2023-08-04 08:51:13 +10:00
|
|
|
LISTBASE_FOREACH (BMEditSelection *, ese, &bm_old->selected) {
|
2023-07-26 16:12:55 +02:00
|
|
|
BMElem *ele = nullptr;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-04-24 21:19:18 +00:00
|
|
|
switch (ese->htype) {
|
|
|
|
|
case BM_VERT:
|
|
|
|
|
eletable = (BMElem **)vtable;
|
|
|
|
|
break;
|
|
|
|
|
case BM_EDGE:
|
|
|
|
|
eletable = (BMElem **)etable;
|
|
|
|
|
break;
|
|
|
|
|
case BM_FACE:
|
|
|
|
|
eletable = (BMElem **)ftable;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2023-07-26 16:12:55 +02:00
|
|
|
eletable = nullptr;
|
2012-04-24 21:19:18 +00:00
|
|
|
break;
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-04-24 21:19:18 +00:00
|
|
|
if (eletable) {
|
|
|
|
|
ele = eletable[BM_elem_index_get(ese->ele)];
|
|
|
|
|
if (ele) {
|
|
|
|
|
BM_select_history_store(bm_new, ele);
|
|
|
|
|
}
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-19 18:31:04 +00:00
|
|
|
MEM_freeN(etable);
|
|
|
|
|
MEM_freeN(vtable);
|
|
|
|
|
MEM_freeN(ftable);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-04-08 16:24:33 +10:00
|
|
|
/* Copy various settings. */
|
|
|
|
|
bm_new->shapenr = bm_old->shapenr;
|
|
|
|
|
bm_new->selectmode = bm_old->selectmode;
|
|
|
|
|
|
2012-03-01 22:17:04 +00:00
|
|
|
return bm_new;
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|