Files
test/source/blender/bmesh/operators/bmo_fill_edgeloop.cc
Campbell Barton e955c94ed3 License Headers: Set copyright to "Blender Authors", add AUTHORS
Listing the "Blender Foundation" as copyright holder implied the Blender
Foundation holds copyright to files which may include work from many
developers.

While keeping copyright on headers makes sense for isolated libraries,
Blender's own code may be refactored or moved between files in a way
that makes the per file copyright holders less meaningful.

Copyright references to the "Blender Foundation" have been replaced with
"Blender Authors", with the exception of `./extern/` since these this
contains libraries which are more isolated, any changed to license
headers there can be handled on a case-by-case basis.

Some directories in `./intern/` have also been excluded:

- `./intern/cycles/` it's own `AUTHORS` file is planned.
- `./intern/opensubdiv/`.

An "AUTHORS" file has been added, using the chromium projects authors
file as a template.

Design task: #110784

Ref !110783.
2023-08-16 00:20:26 +10:00

141 lines
3.7 KiB
C++

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup bmesh
*
* Fill discrete edge loop(s) with faces.
*/
#include "MEM_guardedalloc.h"
#include "BLI_listbase.h"
#include "bmesh.h"
#include "intern/bmesh_operators_private.h" /* own include */
#define VERT_USED 1
#define EDGE_MARK 2
#define ELE_OUT 4
void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op)
{
/* first collect an array of unique from the edges */
const int tote = BMO_slot_buffer_len(op->slots_in, "edges");
const int totv = tote; /* these should be the same */
BMVert **verts = static_cast<BMVert **>(MEM_mallocN(sizeof(*verts) * totv, __func__));
BMVert *v;
BMEdge *e;
int i;
bool ok = true;
BMOIter oiter;
const short mat_nr = BMO_slot_int_get(op->slots_in, "mat_nr");
const bool use_smooth = BMO_slot_bool_get(op->slots_in, "use_smooth");
/* 'VERT_USED' will be disabled, so enable and fill the array */
i = 0;
BMO_ITER (e, &oiter, op->slots_in, "edges", BM_EDGE) {
BMIter viter;
BMO_edge_flag_enable(bm, e, EDGE_MARK);
BM_ITER_ELEM (v, &viter, e, BM_VERTS_OF_EDGE) {
if (BMO_vert_flag_test(bm, v, VERT_USED) == false) {
if (i == tote) {
goto cleanup;
}
BMO_vert_flag_enable(bm, v, VERT_USED);
verts[i++] = v;
}
}
}
/* we have a different number of verts to edges */
if (i != tote) {
goto cleanup;
}
/* loop over connected flagged edges and fill in faces, this is made slightly more
* complicated because there may be multiple disconnected loops to fill. */
/* sanity check - that each vertex has 2 edge users */
for (i = 0; i < totv; i++) {
v = verts[i];
/* count how many flagged edges this vertex uses */
if (BMO_iter_elem_count_flag(bm, BM_EDGES_OF_VERT, v, EDGE_MARK, true) != 2) {
ok = false;
break;
}
}
if (ok) {
/* NOTE: in the case of multiple loops, this over-allocates (which is fine). */
BMVert **f_verts = static_cast<BMVert **>(MEM_mallocN(sizeof(*verts) * totv, __func__));
BMIter eiter;
/* build array of connected verts and edges */
BMEdge *e_prev = nullptr;
BMEdge *e_next = nullptr;
int totv_used = 0;
while (totv_used < totv) {
for (i = 0; i < totv; i++) {
v = verts[i];
if (BMO_vert_flag_test(bm, v, VERT_USED)) {
break;
}
}
/* this should never fail, as long as (totv_used < totv)
* we should have marked verts available */
BLI_assert(BMO_vert_flag_test(bm, v, VERT_USED));
/* watch it, 'i' is used for final face length */
i = 0;
do {
/* we know that there are 2 edges per vertex so no need to check */
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
if (BMO_edge_flag_test(bm, e, EDGE_MARK)) {
if (e != e_prev) {
e_next = e;
break;
}
}
}
/* fill in the array */
f_verts[i] = v;
BMO_vert_flag_disable(bm, v, VERT_USED);
totv_used++;
/* step over the edges */
v = BM_edge_other_vert(e_next, v);
e_prev = e_next;
i++;
} while (v != f_verts[0]);
if (!BM_face_exists(f_verts, i)) {
BMFace *f;
/* don't use calc_edges option because we already have the edges */
f = BM_face_create_ngon_verts(bm, f_verts, i, nullptr, BM_CREATE_NOP, true, false);
BMO_face_flag_enable(bm, f, ELE_OUT);
f->mat_nr = mat_nr;
if (use_smooth) {
BM_elem_flag_enable(f, BM_ELEM_SMOOTH);
}
}
}
MEM_freeN(f_verts);
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, ELE_OUT);
}
cleanup:
MEM_freeN(verts);
}