Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Goudey <h.goudey@me.com>2022-01-24 06:55:39 +0300
committerHans Goudey <h.goudey@me.com>2022-01-24 06:55:39 +0300
commitdf1ef9d32ae96db93367115d3f7c496a22748b97 (patch)
tree9bb39142f77b44b6e7278d4d411f1d81939eafe9 /source/blender
parentae1649e905701420afe7cf1566fdafa438b3472a (diff)
parentc69a581c0b951d219f1501a8ceb7040bdf36e51c (diff)
Merge branch 'master' into temp-geometry-nodes-extrude-mesh
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/bmesh/CMakeLists.txt2
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_convert.cc (renamed from source/blender/bmesh/intern/bmesh_mesh_convert.c)275
-rw-r--r--source/blender/bmesh/intern/bmesh_private.h8
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c12
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c3
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h4
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c58
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c85
-rw-r--r--source/blender/io/alembic/intern/abc_reader_mesh.cc65
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_io.hh3
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc20
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_defaults.h3
-rw-r--r--source/blender/makesdna/DNA_lineart_types.h3
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c20
-rw-r--r--source/blender/modifiers/intern/MOD_triangulate.c16
-rw-r--r--source/blender/modifiers/intern/MOD_weld.cc136
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc80
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_triangulate.cc63
18 files changed, 558 insertions, 298 deletions
diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt
index f57d4da4d26..e2ed005cf9e 100644
--- a/source/blender/bmesh/CMakeLists.txt
+++ b/source/blender/bmesh/CMakeLists.txt
@@ -98,7 +98,7 @@ set(SRC
intern/bmesh_marking.h
intern/bmesh_mesh.c
intern/bmesh_mesh.h
- intern/bmesh_mesh_convert.c
+ intern/bmesh_mesh_convert.cc
intern/bmesh_mesh_convert.h
intern/bmesh_mesh_debug.c
intern/bmesh_mesh_debug.h
diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.c b/source/blender/bmesh/intern/bmesh_mesh_convert.cc
index a7dd5be5cbd..0b2bdb03dd2 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_convert.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_convert.cc
@@ -79,8 +79,11 @@
#include "MEM_guardedalloc.h"
#include "BLI_alloca.h"
+#include "BLI_array.hh"
+#include "BLI_index_range.hh"
#include "BLI_listbase.h"
#include "BLI_math_vector.h"
+#include "BLI_span.hh"
#include "BKE_customdata.h"
#include "BKE_mesh.h"
@@ -95,6 +98,10 @@
#include "bmesh.h"
#include "intern/bmesh_private.h" /* For element checking. */
+using blender::Array;
+using blender::IndexRange;
+using blender::Span;
+
void BM_mesh_cd_flag_ensure(BMesh *bm, Mesh *mesh, const char cd_flag)
{
const char cd_flag_all = BM_mesh_cd_flag_from_bmesh(bm) | cd_flag;
@@ -107,9 +114,9 @@ void BM_mesh_cd_flag_ensure(BMesh *bm, Mesh *mesh, const char cd_flag)
void BM_mesh_cd_flag_apply(BMesh *bm, const char cd_flag)
{
/* CustomData_bmesh_init_pool() must run first */
- BLI_assert(bm->vdata.totlayer == 0 || bm->vdata.pool != NULL);
- BLI_assert(bm->edata.totlayer == 0 || bm->edata.pool != NULL);
- BLI_assert(bm->pdata.totlayer == 0 || bm->pdata.pool != NULL);
+ BLI_assert(bm->vdata.totlayer == 0 || bm->vdata.pool != nullptr);
+ BLI_assert(bm->edata.totlayer == 0 || bm->edata.pool != nullptr);
+ BLI_assert(bm->pdata.totlayer == 0 || bm->pdata.pool != nullptr);
if (cd_flag & ME_CDFLAG_VERT_BWEIGHT) {
if (!CustomData_has_layer(&bm->vdata, CD_BWEIGHT)) {
@@ -175,35 +182,28 @@ char BM_mesh_cd_flag_from_bmesh(BMesh *bm)
}
/* Static function for alloc (duplicate in modifiers_bmesh.c) */
-static BMFace *bm_face_create_from_mpoly(
- MPoly *mp, MLoop *ml, BMesh *bm, BMVert **vtable, BMEdge **etable)
+static BMFace *bm_face_create_from_mpoly(BMesh &bm,
+ Span<MLoop> loops,
+ Span<BMVert *> vtable,
+ Span<BMEdge *> etable)
{
- BMVert **verts = BLI_array_alloca(verts, mp->totloop);
- BMEdge **edges = BLI_array_alloca(edges, mp->totloop);
- int j;
+ Array<BMVert *, BM_DEFAULT_NGON_STACK_SIZE> verts(loops.size());
+ Array<BMEdge *, BM_DEFAULT_NGON_STACK_SIZE> edges(loops.size());
- for (j = 0; j < mp->totloop; j++, ml++) {
- verts[j] = vtable[ml->v];
- edges[j] = etable[ml->e];
+ for (const int i : loops.index_range()) {
+ verts[i] = vtable[loops[i].v];
+ edges[i] = etable[loops[i].e];
}
- return BM_face_create(bm, verts, edges, mp->totloop, NULL, BM_CREATE_SKIP_CD);
+ return BM_face_create(&bm, verts.data(), edges.data(), loops.size(), nullptr, BM_CREATE_SKIP_CD);
}
void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshParams *params)
{
const bool is_new = !(bm->totvert || (bm->vdata.totlayer || bm->edata.totlayer ||
bm->pdata.totlayer || bm->ldata.totlayer));
- MVert *mvert;
- MEdge *medge;
- MLoop *mloop;
- MPoly *mp;
- KeyBlock *actkey, *block;
- BMVert *v, **vtable = NULL;
- BMEdge *e, **etable = NULL;
- BMFace *f, **ftable = NULL;
- float(*keyco)[3] = NULL;
- int totloops, i;
+ KeyBlock *actkey;
+ float(*keyco)[3] = nullptr;
CustomData_MeshMasks mask = CD_MASK_BMESH;
CustomData_MeshMasks_update(&mask, &params->cd_mask_extra);
@@ -225,7 +225,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
/* Only copy normals to the new BMesh if they are not already dirty. This avoids unnecessary
* work, but also accessing normals on an incomplete mesh, for example when restoring undo steps
* in edit mode. */
- const float(*vert_normals)[3] = NULL;
+ const float(*vert_normals)[3] = nullptr;
if (!BKE_mesh_vertex_normals_are_dirty(me)) {
vert_normals = BKE_mesh_vertex_normals_ensure(me);
}
@@ -246,7 +246,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
/* -------------------------------------------------------------------- */
/* Shape Key */
int tot_shape_keys = 0;
- if (me->key != NULL && DEG_is_original_id(&me->id)) {
+ if (me->key != nullptr && DEG_is_original_id(&me->id)) {
/* Evaluated meshes can be topologically inconsistent with their shape keys.
* Shape keys are also already integrated into the state of the evaluated
* mesh, so considering them here would kind of apply them twice. */
@@ -273,20 +273,20 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
if (is_new == false) {
tot_shape_keys = min_ii(tot_shape_keys, CustomData_number_of_layers(&bm->vdata, CD_SHAPEKEY));
}
- const float(**shape_key_table)[3] = tot_shape_keys ?
- BLI_array_alloca(shape_key_table, tot_shape_keys) :
- NULL;
+ const float(**shape_key_table)[3] = tot_shape_keys ? (const float(**)[3])BLI_array_alloca(
+ shape_key_table, tot_shape_keys) :
+ nullptr;
if ((params->active_shapekey != 0) && tot_shape_keys > 0) {
- actkey = BLI_findlink(&me->key->block, params->active_shapekey - 1);
+ actkey = static_cast<KeyBlock *>(BLI_findlink(&me->key->block, params->active_shapekey - 1));
}
else {
- actkey = NULL;
+ actkey = nullptr;
}
if (is_new) {
if (tot_shape_keys || params->add_key_index) {
- CustomData_add_layer(&bm->vdata, CD_SHAPE_KEYINDEX, CD_ASSIGN, NULL, 0);
+ CustomData_add_layer(&bm->vdata, CD_SHAPE_KEYINDEX, CD_ASSIGN, nullptr, 0);
}
}
@@ -301,26 +301,29 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
__func__);
me->key->uidgen = 1;
- for (block = me->key->block.first; block; block = block->next) {
+ LISTBASE_FOREACH (KeyBlock *, block, &me->key->block) {
block->uid = me->key->uidgen++;
}
}
}
if (actkey && actkey->totelem == me->totvert) {
- keyco = params->use_shapekey ? actkey->data : NULL;
+ keyco = params->use_shapekey ? static_cast<float(*)[3]>(actkey->data) : nullptr;
if (is_new) {
bm->shapenr = params->active_shapekey;
}
}
- for (i = 0, block = me->key->block.first; i < tot_shape_keys; block = block->next, i++) {
+ int i;
+ KeyBlock *block;
+ for (i = 0, block = static_cast<KeyBlock *>(me->key->block.first); i < tot_shape_keys;
+ block = block->next, i++) {
if (is_new) {
- CustomData_add_layer_named(&bm->vdata, CD_SHAPEKEY, CD_ASSIGN, NULL, 0, block->name);
+ CustomData_add_layer_named(&bm->vdata, CD_SHAPEKEY, CD_ASSIGN, nullptr, 0, block->name);
int j = CustomData_get_layer_index_n(&bm->vdata, CD_SHAPEKEY, i);
bm->vdata.layers[j].uid = block->uid;
}
- shape_key_table[i] = (const float(*)[3])block->data;
+ shape_key_table[i] = static_cast<const float(*)[3]>(block->data);
}
}
@@ -349,17 +352,18 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX) :
-1;
- vtable = MEM_mallocN(sizeof(BMVert **) * me->totvert, __func__);
-
- for (i = 0, mvert = me->mvert; i < me->totvert; i++, mvert++) {
- v = vtable[i] = BM_vert_create(bm, keyco ? keyco[i] : mvert->co, NULL, BM_CREATE_SKIP_CD);
+ Span<MVert> mvert{me->mvert, me->totvert};
+ Array<BMVert *> vtable(me->totvert);
+ for (const int i : mvert.index_range()) {
+ BMVert *v = vtable[i] = BM_vert_create(
+ bm, keyco ? keyco[i] : mvert[i].co, nullptr, BM_CREATE_SKIP_CD);
BM_elem_index_set(v, i); /* set_ok */
/* Transfer flag. */
- v->head.hflag = BM_vert_flag_from_mflag(mvert->flag & ~SELECT);
+ v->head.hflag = BM_vert_flag_from_mflag(mvert[i].flag & ~SELECT);
/* This is necessary for selection counts to work properly. */
- if (mvert->flag & SELECT) {
+ if (mvert[i].flag & SELECT) {
BM_vert_select_set(bm, v, true);
}
@@ -371,7 +375,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
CustomData_to_bmesh_block(&me->vdata, &bm->vdata, i, &v->head.data, true);
if (cd_vert_bweight_offset != -1) {
- BM_ELEM_CD_SET_FLOAT(v, cd_vert_bweight_offset, (float)mvert->bweight / 255.0f);
+ BM_ELEM_CD_SET_FLOAT(v, cd_vert_bweight_offset, (float)mvert[i].bweight / 255.0f);
}
/* Set shape key original index. */
@@ -381,7 +385,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
/* Set shape-key data. */
if (tot_shape_keys) {
- float(*co_dst)[3] = BM_ELEM_CD_GET_VOID_P(v, cd_shape_key_offset);
+ float(*co_dst)[3] = (float(*)[3])BM_ELEM_CD_GET_VOID_P(v, cd_shape_key_offset);
for (int j = 0; j < tot_shape_keys; j++, co_dst++) {
copy_v3_v3(*co_dst, shape_key_table[j][i]);
}
@@ -391,19 +395,18 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
bm->elem_index_dirty &= ~BM_VERT; /* Added in order, clear dirty flag. */
}
- etable = MEM_mallocN(sizeof(BMEdge **) * me->totedge, __func__);
-
- medge = me->medge;
- for (i = 0; i < me->totedge; i++, medge++) {
- e = etable[i] = BM_edge_create(
- bm, vtable[medge->v1], vtable[medge->v2], NULL, BM_CREATE_SKIP_CD);
+ Span<MEdge> medge{me->medge, me->totedge};
+ Array<BMEdge *> etable(me->totedge);
+ for (const int i : medge.index_range()) {
+ BMEdge *e = etable[i] = BM_edge_create(
+ bm, vtable[medge[i].v1], vtable[medge[i].v2], nullptr, BM_CREATE_SKIP_CD);
BM_elem_index_set(e, i); /* set_ok */
/* Transfer flags. */
- e->head.hflag = BM_edge_flag_from_mflag(medge->flag & ~SELECT);
+ e->head.hflag = BM_edge_flag_from_mflag(medge[i].flag & ~SELECT);
/* This is necessary for selection counts to work properly. */
- if (medge->flag & SELECT) {
+ if (medge[i].flag & SELECT) {
BM_edge_select_set(bm, e, true);
}
@@ -411,33 +414,35 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
CustomData_to_bmesh_block(&me->edata, &bm->edata, i, &e->head.data, true);
if (cd_edge_bweight_offset != -1) {
- BM_ELEM_CD_SET_FLOAT(e, cd_edge_bweight_offset, (float)medge->bweight / 255.0f);
+ BM_ELEM_CD_SET_FLOAT(e, cd_edge_bweight_offset, (float)medge[i].bweight / 255.0f);
}
if (cd_edge_crease_offset != -1) {
- BM_ELEM_CD_SET_FLOAT(e, cd_edge_crease_offset, (float)medge->crease / 255.0f);
+ BM_ELEM_CD_SET_FLOAT(e, cd_edge_crease_offset, (float)medge[i].crease / 255.0f);
}
}
if (is_new) {
bm->elem_index_dirty &= ~BM_EDGE; /* Added in order, clear dirty flag. */
}
+ Span<MPoly> mpoly{me->mpoly, me->totpoly};
+ Span<MLoop> mloop{me->mloop, me->totloop};
+
/* Only needed for selection. */
+
+ Array<BMFace *> ftable;
if (me->mselect && me->totselect != 0) {
- ftable = MEM_mallocN(sizeof(BMFace **) * me->totpoly, __func__);
+ ftable.reinitialize(me->totpoly);
}
- mloop = me->mloop;
- mp = me->mpoly;
- for (i = 0, totloops = 0; i < me->totpoly; i++, mp++) {
- BMLoop *l_iter;
- BMLoop *l_first;
-
- f = bm_face_create_from_mpoly(mp, mloop + mp->loopstart, bm, vtable, etable);
- if (ftable != NULL) {
+ int totloops = 0;
+ for (const int i : mpoly.index_range()) {
+ BMFace *f = bm_face_create_from_mpoly(
+ *bm, mloop.slice(mpoly[i].loopstart, mpoly[i].totloop), vtable, etable);
+ if (!ftable.is_empty()) {
ftable[i] = f;
}
- if (UNLIKELY(f == NULL)) {
+ if (UNLIKELY(f == nullptr)) {
printf(
"%s: Warning! Bad face in mesh"
" \"%s\" at index %d!, skipping\n",
@@ -451,20 +456,21 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
BM_elem_index_set(f, bm->totface - 1); /* set_ok */
/* Transfer flag. */
- f->head.hflag = BM_face_flag_from_mflag(mp->flag & ~ME_FACE_SEL);
+ f->head.hflag = BM_face_flag_from_mflag(mpoly[i].flag & ~ME_FACE_SEL);
/* This is necessary for selection counts to work properly. */
- if (mp->flag & ME_FACE_SEL) {
+ if (mpoly[i].flag & ME_FACE_SEL) {
BM_face_select_set(bm, f, true);
}
- f->mat_nr = mp->mat_nr;
+ f->mat_nr = mpoly[i].mat_nr;
if (i == me->act_face) {
bm->act_face = f;
}
- int j = mp->loopstart;
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ int j = mpoly[i].loopstart;
+ BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l_iter = l_first;
do {
/* Don't use 'j' since we may have skipped some faces, hence some loops. */
BM_elem_index_set(l_iter, totloops++); /* set_ok */
@@ -485,44 +491,39 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
}
/* -------------------------------------------------------------------- */
- /* MSelect clears the array elements (avoid adding multiple times).
+ /* MSelect clears the array elements (to avoid adding multiple times).
*
* Take care to keep this last and not use (v/e/ftable) after this.
*/
if (me->mselect && me->totselect != 0) {
- MSelect *msel;
- for (i = 0, msel = me->mselect; i < me->totselect; i++, msel++) {
+ for (const int i : IndexRange(me->totselect)) {
+ const MSelect &msel = me->mselect[i];
+
BMElem **ele_p;
- switch (msel->type) {
+ switch (msel.type) {
case ME_VSEL:
- ele_p = (BMElem **)&vtable[msel->index];
+ ele_p = (BMElem **)&vtable[msel.index];
break;
case ME_ESEL:
- ele_p = (BMElem **)&etable[msel->index];
+ ele_p = (BMElem **)&etable[msel.index];
break;
case ME_FSEL:
- ele_p = (BMElem **)&ftable[msel->index];
+ ele_p = (BMElem **)&ftable[msel.index];
break;
default:
continue;
}
- if (*ele_p != NULL) {
+ if (*ele_p != nullptr) {
BM_select_history_store_notest(bm, *ele_p);
- *ele_p = NULL;
+ *ele_p = nullptr;
}
}
}
else {
BM_select_history_clear(bm);
}
-
- MEM_freeN(vtable);
- MEM_freeN(etable);
- if (ftable) {
- MEM_freeN(ftable);
- }
}
/**
@@ -531,7 +532,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
static BMVert **bm_to_mesh_vertex_map(BMesh *bm, int ototvert)
{
const int cd_shape_keyindex_offset = CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX);
- BMVert **vertMap = NULL;
+ BMVert **vertMap = nullptr;
BMVert *eve;
int i = 0;
BMIter iter;
@@ -539,7 +540,7 @@ static BMVert **bm_to_mesh_vertex_map(BMesh *bm, int ototvert)
/* Caller needs to ensure this. */
BLI_assert(ototvert > 0);
- vertMap = MEM_callocN(sizeof(*vertMap) * ototvert, "vertMap");
+ vertMap = static_cast<BMVert **>(MEM_callocN(sizeof(*vertMap) * ototvert, "vertMap"));
if (cd_shape_keyindex_offset != -1) {
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
const int keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset);
@@ -547,7 +548,7 @@ static BMVert **bm_to_mesh_vertex_map(BMesh *bm, int ototvert)
/* Not fool-proof, but chances are if we have many verts with the same index,
* we will want to use the first one,
* since the second is more likely to be a duplicate. */
- (vertMap[keyi] == NULL)) {
+ (vertMap[keyi] == nullptr)) {
vertMap[keyi] = eve;
}
}
@@ -617,7 +618,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
const int cd_shape_keyindex_offset = CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX);
- MVert *oldverts = NULL;
+ MVert *oldverts = nullptr;
const int ototvert = me->totvert;
if (me->key && (cd_shape_keyindex_offset != -1)) {
@@ -628,9 +629,9 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
oldverts = MEM_dupallocN(me->mvert);
#else
oldverts = me->mvert;
- me->mvert = NULL;
+ me->mvert = nullptr;
CustomData_update_typemap(&me->vdata);
- CustomData_set_layer(&me->vdata, CD_MVERT, NULL);
+ CustomData_set_layer(&me->vdata, CD_MVERT, nullptr);
#endif
}
@@ -647,7 +648,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
me->totloop = bm->totloop;
me->totpoly = bm->totface;
/* Will be overwritten with a valid value if 'dotess' is set, otherwise we
- * end up with 'me->totface' and me->mface == NULL which can crash T28625. */
+ * end up with 'me->totface' and me->mface == nullptr which can crash T28625. */
me->totface = 0;
me->act_face = -1;
@@ -660,10 +661,14 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
CustomData_copy(&bm->pdata, &me->pdata, mask.pmask, CD_CALLOC, me->totpoly);
}
- MVert *mvert = bm->totvert ? MEM_callocN(sizeof(MVert) * bm->totvert, "bm_to_me.vert") : NULL;
- MEdge *medge = bm->totedge ? MEM_callocN(sizeof(MEdge) * bm->totedge, "bm_to_me.edge") : NULL;
- MLoop *mloop = bm->totloop ? MEM_callocN(sizeof(MLoop) * bm->totloop, "bm_to_me.loop") : NULL;
- MPoly *mpoly = bm->totface ? MEM_callocN(sizeof(MPoly) * bm->totface, "bm_to_me.poly") : NULL;
+ MVert *mvert = bm->totvert ? (MVert *)MEM_callocN(sizeof(MVert) * bm->totvert, "bm_to_me.vert") :
+ nullptr;
+ MEdge *medge = bm->totedge ? (MEdge *)MEM_callocN(sizeof(MEdge) * bm->totedge, "bm_to_me.edge") :
+ nullptr;
+ MLoop *mloop = bm->totloop ? (MLoop *)MEM_callocN(sizeof(MLoop) * bm->totloop, "bm_to_me.loop") :
+ nullptr;
+ MPoly *mpoly = bm->totface ? (MPoly *)MEM_callocN(sizeof(MPoly) * bm->totface, "bm_to_me.poly") :
+ nullptr;
CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, mvert, me->totvert);
CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, medge, me->totedge);
@@ -677,7 +682,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
me->cd_flag = BM_mesh_cd_flag_from_bmesh(bm);
/* This is called again, 'dotess' arg is used there. */
- BKE_mesh_update_customdata_pointers(me, 0);
+ BKE_mesh_update_customdata_pointers(me, false);
i = 0;
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
@@ -767,15 +772,13 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
/* Patch hook indices and vertex parents. */
if (params->calc_object_remap && (ototvert > 0)) {
- BLI_assert(bmain != NULL);
- Object *ob;
- ModifierData *md;
- BMVert **vertMap = NULL;
+ BLI_assert(bmain != nullptr);
+ BMVert **vertMap = nullptr;
- for (ob = bmain->objects.first; ob; ob = ob->id.next) {
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
if ((ob->parent) && (ob->parent->data == me) && ELEM(ob->partype, PARVERT1, PARVERT3)) {
- if (vertMap == NULL) {
+ if (vertMap == nullptr) {
vertMap = bm_to_mesh_vertex_map(bm, ototvert);
}
@@ -799,11 +802,11 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
}
}
if (ob->data == me) {
- for (md = ob->modifiers.first; md; md = md->next) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
if (md->type == eModifierType_Hook) {
HookModifierData *hmd = (HookModifierData *)md;
- if (vertMap == NULL) {
+ if (vertMap == nullptr) {
vertMap = bm_to_mesh_vertex_map(bm, ototvert);
}
@@ -834,15 +837,15 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
BKE_mesh_update_customdata_pointers(me, false);
{
- BMEditSelection *selected;
me->totselect = BLI_listbase_count(&(bm->selected));
MEM_SAFE_FREE(me->mselect);
if (me->totselect != 0) {
- me->mselect = MEM_mallocN(sizeof(MSelect) * me->totselect, "Mesh selection history");
+ me->mselect = static_cast<MSelect *>(
+ MEM_mallocN(sizeof(MSelect) * me->totselect, "Mesh selection history"));
}
- for (i = 0, selected = bm->selected.first; selected; i++, selected = selected->next) {
+ LISTBASE_FOREACH_INDEX (BMEditSelection *, selected, &bm->selected, i) {
if (selected->htype == BM_VERT) {
me->mselect[i].type = ME_VSEL;
}
@@ -861,9 +864,9 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
if (me->key) {
KeyBlock *currkey;
- KeyBlock *actkey = BLI_findlink(&me->key->block, bm->shapenr - 1);
+ KeyBlock *actkey = static_cast<KeyBlock *>(BLI_findlink(&me->key->block, bm->shapenr - 1));
- float(*ofs)[3] = NULL;
+ float(*ofs)[3] = nullptr;
/* Go through and find any shape-key custom-data layers
* that might not have corresponding KeyBlocks, and add them if necessary. */
@@ -872,7 +875,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
continue;
}
- for (currkey = me->key->block.first; currkey; currkey = currkey->next) {
+ for (currkey = (KeyBlock *)me->key->block.first; currkey; currkey = currkey->next) {
if (currkey->uid == bm->vdata.layers[i].uid) {
break;
}
@@ -890,10 +893,10 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
/* Unlikely, but the active key may not be valid if the
* BMesh and the mesh are out of sync. */
- (actkey != NULL) &&
+ (actkey != nullptr) &&
/* Not used here, but 'oldverts' is used later for applying 'ofs'. */
- (oldverts != NULL) &&
+ (oldverts != nullptr) &&
/* Needed for referencing oldverts. */
(cd_shape_keyindex_offset != -1)) {
@@ -902,9 +905,10 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
/* Active key is a base. */
if (act_is_basis) {
- const float(*fp)[3] = actkey->data;
+ const float(*fp)[3] = static_cast<const float(*)[3]>(actkey->data);
- ofs = MEM_callocN(sizeof(float[3]) * bm->totvert, "currkey->data");
+ ofs = static_cast<float(*)[3]>(
+ MEM_callocN(sizeof(float[3]) * bm->totvert, "currkey->data"));
mvert = me->mvert;
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
const int keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset);
@@ -918,7 +922,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
* because it will only work for the existing vertices and not the new
* ones, creating a mess when doing e.g. subdivide + translate. */
MEM_freeN(ofs);
- ofs = NULL;
+ ofs = nullptr;
break;
}
@@ -927,7 +931,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
}
}
- for (currkey = me->key->block.first; currkey; currkey = currkey->next) {
+ LISTBASE_FOREACH (KeyBlock *, currkey, &me->key->block) {
int keyi;
const float(*ofs_pt)[3] = ofs;
float *newkey, (*oldkey)[3], *fp;
@@ -937,11 +941,12 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
CustomData_get_n_offset(&bm->vdata,
CD_SHAPEKEY,
currkey_uuid);
- const bool apply_offset = (cd_shape_offset != -1) && (ofs != NULL) && (currkey != actkey) &&
- (bm->shapenr - 1 == currkey->relative);
+ const bool apply_offset = (cd_shape_offset != -1) && (ofs != nullptr) &&
+ (currkey != actkey) && (bm->shapenr - 1 == currkey->relative);
- fp = newkey = MEM_callocN(me->key->elemsize * bm->totvert, "currkey->data");
- oldkey = currkey->data;
+ fp = newkey = static_cast<float *>(
+ MEM_callocN(me->key->elemsize * bm->totvert, "currkey->data"));
+ oldkey = static_cast<float(*)[3]>(currkey->data);
mvert = me->mvert;
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
@@ -962,9 +967,9 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
}
else if (cd_shape_offset != -1) {
/* In most cases this runs. */
- copy_v3_v3(fp, BM_ELEM_CD_GET_VOID_P(eve, cd_shape_offset));
+ copy_v3_v3(fp, (const float *)BM_ELEM_CD_GET_VOID_P(eve, cd_shape_offset));
}
- else if ((oldkey != NULL) && (cd_shape_keyindex_offset != -1) &&
+ else if ((oldkey != nullptr) && (cd_shape_keyindex_offset != -1) &&
((keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset)) != ORIGINDEX_NONE) &&
(keyi < currkey->totelem)) {
/* Old method of reconstructing keys via vertices original key indices,
@@ -984,7 +989,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
* Otherwise, in case we call again #BM_mesh_bm_to_me on same BMesh,
* we'll apply diff from previous call to #BM_mesh_bm_to_me,
* to shape-key values from *original creation of the BMesh*. See T50524. */
- copy_v3_v3(BM_ELEM_CD_GET_VOID_P(eve, cd_shape_offset), fp);
+ copy_v3_v3((float *)BM_ELEM_CD_GET_VOID_P(eve, cd_shape_offset), fp);
}
fp += 3;
@@ -1014,7 +1019,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
}
}
- if (oldverts != NULL) {
+ if (oldverts != nullptr) {
MEM_freeN(oldverts);
}
@@ -1029,7 +1034,7 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
{
/* Must be an empty mesh. */
BLI_assert(me->totvert == 0);
- BLI_assert(cd_mask_extra == NULL || (cd_mask_extra->vmask & CD_MASK_SHAPEKEY) == 0);
+ BLI_assert(cd_mask_extra == nullptr || (cd_mask_extra->vmask & CD_MASK_SHAPEKEY) == 0);
me->totvert = bm->totvert;
me->totedge = bm->totedge;
@@ -1037,19 +1042,19 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
me->totloop = bm->totloop;
me->totpoly = bm->totface;
- CustomData_add_layer(&me->vdata, CD_ORIGINDEX, CD_CALLOC, NULL, bm->totvert);
- CustomData_add_layer(&me->edata, CD_ORIGINDEX, CD_CALLOC, NULL, bm->totedge);
- CustomData_add_layer(&me->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, bm->totface);
+ CustomData_add_layer(&me->vdata, CD_ORIGINDEX, CD_CALLOC, nullptr, bm->totvert);
+ CustomData_add_layer(&me->edata, CD_ORIGINDEX, CD_CALLOC, nullptr, bm->totedge);
+ CustomData_add_layer(&me->pdata, CD_ORIGINDEX, CD_CALLOC, nullptr, bm->totface);
- CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, bm->totvert);
- CustomData_add_layer(&me->edata, CD_MEDGE, CD_CALLOC, NULL, bm->totedge);
- CustomData_add_layer(&me->ldata, CD_MLOOP, CD_CALLOC, NULL, bm->totloop);
- CustomData_add_layer(&me->pdata, CD_MPOLY, CD_CALLOC, NULL, bm->totface);
+ CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, nullptr, bm->totvert);
+ CustomData_add_layer(&me->edata, CD_MEDGE, CD_CALLOC, nullptr, bm->totedge);
+ CustomData_add_layer(&me->ldata, CD_MLOOP, CD_CALLOC, nullptr, bm->totloop);
+ CustomData_add_layer(&me->pdata, CD_MPOLY, CD_CALLOC, nullptr, bm->totface);
/* Don't process shape-keys, we only feed them through the modifier stack as needed,
* e.g. for applying modifiers or the like. */
CustomData_MeshMasks mask = CD_MASK_DERIVEDMESH;
- if (cd_mask_extra != NULL) {
+ if (cd_mask_extra != nullptr) {
CustomData_MeshMasks_update(&mask, cd_mask_extra);
}
mask.vmask &= ~CD_MASK_SHAPEKEY;
@@ -1082,7 +1087,7 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
/* Don't add origindex layer if one already exists. */
add_orig = !CustomData_has_layer(&bm->pdata, CD_ORIGINDEX);
- index = CustomData_get_layer(&me->vdata, CD_ORIGINDEX);
+ index = (int *)CustomData_get_layer(&me->vdata, CD_ORIGINDEX);
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
MVert *mv = &mvert[i];
@@ -1105,7 +1110,7 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
}
bm->elem_index_dirty &= ~BM_VERT;
- index = CustomData_get_layer(&me->edata, CD_ORIGINDEX);
+ index = (int *)CustomData_get_layer(&me->edata, CD_ORIGINDEX);
BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
MEdge *med = &medge[i];
@@ -1138,7 +1143,7 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
}
bm->elem_index_dirty &= ~BM_EDGE;
- index = CustomData_get_layer(&me->pdata, CD_ORIGINDEX);
+ index = (int *)CustomData_get_layer(&me->pdata, CD_ORIGINDEX);
j = 0;
BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
BMLoop *l_iter;
diff --git a/source/blender/bmesh/intern/bmesh_private.h b/source/blender/bmesh/intern/bmesh_private.h
index 977142578ca..4b3c4cbff82 100644
--- a/source/blender/bmesh/intern/bmesh_private.h
+++ b/source/blender/bmesh/intern/bmesh_private.h
@@ -27,6 +27,10 @@
* parts of the bmesh internals.
*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* returns positive nonzero on error */
#ifdef NDEBUG
@@ -102,3 +106,7 @@ void poly_rotate_plane(const float normal[3], float (*verts)[3], uint nverts);
/* include the rest of our private declarations */
#include "bmesh_structure.h"
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c
index 5d573271ea3..59c357aa416 100644
--- a/source/blender/editors/mesh/editmesh_undo.c
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -687,19 +687,15 @@ static void undomesh_to_editmesh(UndoMesh *um, Object *ob, BMEditMesh *em, Key *
.active_shapekey = um->shapenr,
}));
+ em_tmp = BKE_editmesh_create(bm);
+ *em = *em_tmp;
+
/* Normals should not be stored in the undo mesh, so recalculate them. The edit
* mesh is expected to have valid normals and there is no tracked dirty state. */
BLI_assert(BKE_mesh_vertex_normals_are_dirty(&um->me));
- BM_mesh_normals_update(bm);
-
- em_tmp = BKE_editmesh_create(bm);
- *em = *em_tmp;
/* Calculate face normals and tessellation at once since it's multi-threaded. */
- BKE_editmesh_looptri_calc_ex(em,
- &(const struct BMeshCalcTessellation_Params){
- .face_normals = true,
- });
+ BKE_editmesh_looptri_and_normals_calc(em);
em->selectmode = um->selectmode;
bm->selectmode = um->selectmode;
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
index 59937bb0757..6a3a27a6630 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
@@ -409,6 +409,7 @@ static void options_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(col, ptr, "use_clip_plane_boundaries", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "use_crease_on_smooth", 0, IFACE_("Crease On Smooth"), ICON_NONE);
uiItemR(col, ptr, "use_crease_on_sharp", 0, IFACE_("Crease On Sharp"), ICON_NONE);
+ uiItemR(col, ptr, "use_back_face_culling", 0, NULL, ICON_NONE);
}
static void style_panel_draw(const bContext *UNUSED(C), Panel *panel)
@@ -580,6 +581,7 @@ static void face_mark_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(layout, ptr, "use_face_mark_invert", 0, NULL, ICON_NONE);
uiItemR(layout, ptr, "use_face_mark_boundaries", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_face_mark_keep_contour", 0, NULL, ICON_NONE);
}
static void chaining_panel_draw(const bContext *UNUSED(C), Panel *panel)
@@ -607,6 +609,7 @@ static void chaining_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(col, ptr, "use_fuzzy_all", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "use_loose_edge_chain", 0, IFACE_("Loose Edges"), ICON_NONE);
uiItemR(col, ptr, "use_loose_as_contour", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_detail_preserve", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "use_geometry_space_chain", 0, IFACE_("Geometry Space"), ICON_NONE);
uiItemR(layout,
diff --git a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
index 8c5820c9667..cb17d1d5f1a 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
+++ b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
@@ -300,14 +300,18 @@ typedef struct LineartRenderBuffer {
bool use_loose_edge_chain;
bool use_geometry_space_chain;
bool use_image_boundary_trimming;
+ bool use_back_face_culling;
bool filter_face_mark;
bool filter_face_mark_invert;
bool filter_face_mark_boundaries;
+ bool filter_face_mark_keep_contour;
bool force_crease;
bool sharp_as_crease;
+ bool chain_preserve_details;
+
/* Keep an copy of these data so when line art is running it's self-contained. */
bool cam_is_persp;
float cam_obmat[4][4];
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
index 0deb8b1c335..78ad895c93e 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
@@ -571,6 +571,57 @@ static void lineart_bounding_area_link_chain(LineartRenderBuffer *rb, LineartEdg
}
}
+static bool lineart_chain_fix_ambiguous_segments(LineartEdgeChain *ec,
+ LineartEdgeChainItem *last_matching_eci,
+ float distance_threshold,
+ bool preserve_details,
+ LineartEdgeChainItem **r_next_eci)
+{
+ float dist_accum = 0;
+
+ int fixed_occ = last_matching_eci->occlusion;
+ unsigned char fixed_mask = last_matching_eci->material_mask_bits;
+
+ LineartEdgeChainItem *can_skip_to = NULL;
+ LineartEdgeChainItem *last_eci = last_matching_eci;
+ for (LineartEdgeChainItem *eci = last_matching_eci->next; eci; eci = eci->next) {
+ dist_accum += len_v2v2(last_eci->pos, eci->pos);
+ if (dist_accum > distance_threshold) {
+ break;
+ }
+ last_eci = eci;
+ /* The reason for this is because we don't want visible segments to be "skipped" into
+ * connecting with invisible segments. */
+ if (eci->occlusion < fixed_occ) {
+ break;
+ }
+ if (eci->material_mask_bits == fixed_mask && eci->occlusion == fixed_occ) {
+ can_skip_to = eci;
+ }
+ }
+ if (can_skip_to) {
+ /* Either mark all in-between segments with the same occlusion and mask or delete those
+ * different ones. */
+ LineartEdgeChainItem *next_eci;
+ for (LineartEdgeChainItem *eci = last_matching_eci->next; eci != can_skip_to; eci = next_eci) {
+ next_eci = eci->next;
+ if (eci->material_mask_bits == fixed_mask && eci->occlusion == fixed_occ) {
+ continue;
+ }
+ if (preserve_details) {
+ eci->material_mask_bits = fixed_mask;
+ eci->occlusion = fixed_occ;
+ }
+ else {
+ BLI_remlink(&ec->chain, eci);
+ }
+ }
+ *r_next_eci = can_skip_to;
+ return true;
+ }
+ return false;
+}
+
void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb)
{
LineartEdgeChain *ec, *new_ec;
@@ -597,6 +648,13 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb)
if (lineart_point_overlapping(next_eci, eci->pos[0], eci->pos[1], 1e-5)) {
continue;
}
+ if (lineart_chain_fix_ambiguous_segments(ec,
+ eci->prev,
+ rb->chaining_image_threshold,
+ rb->chain_preserve_details,
+ &next_eci)) {
+ continue;
+ }
}
else {
/* Set the same occlusion level for the end vertex, so when further connection is needed
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
index 5461b80cad1..cb57ce3f940 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
@@ -1346,6 +1346,10 @@ static void lineart_main_cull_triangles(LineartRenderBuffer *rb, bool clip_far)
/* Select the triangle in the array. */
tri = (void *)(((uchar *)eln->pointer) + rb->triangle_size * i);
+ if (tri->flags & LRT_CULL_DISCARD) {
+ continue;
+ }
+
LRT_CULL_DECIDE_INSIDE
LRT_CULL_ENSURE_MEMORY
lineart_triangle_cull_single(rb,
@@ -1489,6 +1493,7 @@ static uint16_t lineart_identify_feature_line(LineartRenderBuffer *rb,
FreestyleEdge *fel, *fer;
bool face_mark_filtered = false;
uint16_t edge_flag_result = 0;
+ bool only_contour = false;
if (use_freestyle_face && rb->filter_face_mark) {
fel = CustomData_bmesh_get(&bm_if_freestyle->pdata, ll->f->head.data, CD_FREESTYLE_FACE);
@@ -1513,7 +1518,12 @@ static uint16_t lineart_identify_feature_line(LineartRenderBuffer *rb,
face_mark_filtered = !face_mark_filtered;
}
if (!face_mark_filtered) {
- return 0;
+ if (rb->filter_face_mark_keep_contour) {
+ only_contour = true;
+ }
+ else {
+ return 0;
+ }
}
}
@@ -1536,8 +1546,31 @@ static uint16_t lineart_identify_feature_line(LineartRenderBuffer *rb,
double dot_1 = 0, dot_2 = 0;
double result;
- if (rb->cam_is_persp) {
- sub_v3_v3v3_db(view_vector, l->gloc, rb->camera_pos);
+ if (rb->use_contour || rb->use_back_face_culling) {
+
+ if (rb->cam_is_persp) {
+ sub_v3_v3v3_db(view_vector, rb->camera_pos, l->gloc);
+ }
+ else {
+ view_vector = rb->view_vector;
+ }
+
+ dot_1 = dot_v3v3_db(view_vector, tri1->gn);
+ dot_2 = dot_v3v3_db(view_vector, tri2->gn);
+
+ if (rb->use_contour && (result = dot_1 * dot_2) <= 0 && (dot_1 + dot_2)) {
+ edge_flag_result |= LRT_EDGE_FLAG_CONTOUR;
+ }
+
+ /* Because the ray points towards the camera, so backface is when dot value being negative.*/
+ if (rb->use_back_face_culling) {
+ if (dot_1 < 0) {
+ tri1->flags |= LRT_CULL_DISCARD;
+ }
+ if (dot_2 < 0) {
+ tri2->flags |= LRT_CULL_DISCARD;
+ }
+ }
}
else {
view_vector = rb->view_vector;
@@ -1550,6 +1583,12 @@ static uint16_t lineart_identify_feature_line(LineartRenderBuffer *rb,
edge_flag_result |= LRT_EDGE_FLAG_CONTOUR;
}
+ /* For when face mark filtering decided that we discard the face but keep_contour option is on.
+ * so we still have correct full contour around the object. */
+ if (only_contour) {
+ return edge_flag_result;
+ }
+
if (rb->use_crease) {
if (rb->sharp_as_crease && !BM_elem_flag_test(e, BM_ELEM_SMOOTH)) {
edge_flag_result |= LRT_EDGE_FLAG_CREASE;
@@ -1875,7 +1914,8 @@ static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBu
bm);
if (eflag) {
/* Only allocate for feature lines (instead of all lines) to save memory.
- * If allow duplicated edges, one edge gets added multiple times if it has multiple types. */
+ * If allow duplicated edges, one edge gets added multiple times if it has multiple types.
+ */
allocate_la_e += rb->allow_duplicated_types ? lineart_edge_type_duplication_count(eflag) : 1;
}
/* Here we just use bm's flag for when loading actual lines, then we don't need to call
@@ -2069,8 +2109,8 @@ static bool lineart_geometry_check_visible(double (*model_view_proj)[4],
}
bool cond[6] = {true, true, true, true, true, true};
- /* Because for a point to be inside clip space, it must satisfy `-Wc <= XYCc <= Wc`, here if all
- * verts falls to the same side of the clip space border, we know it's outside view. */
+ /* Because for a point to be inside clip space, it must satisfy `-Wc <= XYCc <= Wc`, here if
+ * all verts falls to the same side of the clip space border, we know it's outside view. */
for (int i = 0; i < 8; i++) {
cond[0] &= (co[i][0] < -co[i][3]);
cond[1] &= (co[i][0] > co[i][3]);
@@ -2145,7 +2185,8 @@ static void lineart_main_load_geometries(
int thread_count = rb->thread_count;
- /* This memory is in render buffer memory pool. so we don't need to free those after loading. */
+ /* This memory is in render buffer memory pool. so we don't need to free those after loading.
+ */
LineartObjectLoadTaskInfo *olti = lineart_mem_acquire(
&rb->render_data_pool, sizeof(LineartObjectLoadTaskInfo) * thread_count);
@@ -2428,8 +2469,9 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl),
dot_f = dot_v3v3_db(Cv, tri->gn);
/* NOTE(Yiming): When we don't use `dot_f==0` here, it's theoretically possible that _some_
- * faces in perspective mode would get erroneously caught in this condition where they really are
- * legit faces that would produce occlusion, but haven't encountered those yet in my test files.
+ * faces in perspective mode would get erroneously caught in this condition where they really
+ * are legit faces that would produce occlusion, but haven't encountered those yet in my test
+ * files.
*/
if (fabs(dot_f) < FLT_EPSILON) {
return false;
@@ -2496,8 +2538,9 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl),
return false; \
}
- /* Determine the pair of edges that the line has crossed. The "|" symbol in the comment indicates
- * triangle boundary. DBL_TRIANGLE_LIM is needed to for floating point precision tolerance. */
+ /* Determine the pair of edges that the line has crossed. The "|" symbol in the comment
+ * indicates triangle boundary. DBL_TRIANGLE_LIM is needed to for floating point precision
+ * tolerance. */
if (st_l == 2) {
/* Left side is in the triangle. */
@@ -3158,6 +3201,14 @@ static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene,
rb->force_crease = (lmd->calculation_flags & LRT_USE_CREASE_ON_SMOOTH_SURFACES) != 0;
rb->sharp_as_crease = (lmd->calculation_flags & LRT_USE_CREASE_ON_SHARP_EDGES) != 0;
+ rb->chain_preserve_details = (lmd->calculation_flags & LRT_CHAIN_PRESERVE_DETAILS) != 0;
+
+ /* This is used to limit calculation to a certain level to save time, lines who have higher
+ * occlusion levels will get ignored. */
+ rb->max_occlusion_level = lmd->level_end_override;
+
+ rb->use_back_face_culling = (lmd->calculation_flags & LRT_USE_BACK_FACE_CULLING) != 0;
+
int16_t edge_types = lmd->edge_types_override;
rb->use_contour = (edge_types & LRT_EDGE_FLAG_CONTOUR) != 0;
@@ -3171,6 +3222,8 @@ static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene,
rb->filter_face_mark = (lmd->calculation_flags & LRT_FILTER_FACE_MARK) != 0;
rb->filter_face_mark_boundaries = (lmd->calculation_flags & LRT_FILTER_FACE_MARK_BOUNDARIES) !=
0;
+ rb->filter_face_mark_keep_contour = (lmd->calculation_flags &
+ LRT_FILTER_FACE_MARK_KEEP_CONTOUR) != 0;
rb->chain_data_pool = &lc->chain_data_pool;
@@ -4176,12 +4229,6 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
* See definition of LineartTriangleThread for details. */
rb->triangle_size = lineart_triangle_size_get(scene, rb);
- /* This is used to limit calculation to a certain level to save time, lines who have higher
- * occlusion levels will get ignored. */
- rb->max_occlusion_level = (lmd->flags & LRT_GPENCIL_USE_CACHE) ?
- lmd->level_end_override :
- (lmd->use_multiple_levels ? lmd->level_end : lmd->level_start);
-
/* FIXME(Yiming): See definition of int #LineartRenderBuffer::_source_type for detailed. */
rb->_source_type = lmd->source_type;
rb->_source_collection = lmd->source_collection;
@@ -4253,8 +4300,8 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
if (rb->chain_smooth_tolerance > FLT_EPSILON) {
/* Keeping UI range of 0-1 for ease of read while scaling down the actual value for best
- * effective range in image-space (Coordinate only goes from -1 to 1). This value is somewhat
- * arbitrary, but works best for the moment. */
+ * effective range in image-space (Coordinate only goes from -1 to 1). This value is
+ * somewhat arbitrary, but works best for the moment. */
MOD_lineart_smooth_chains(rb, rb->chain_smooth_tolerance / 50);
}
diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc
index bd40eb35123..43581ad48d9 100644
--- a/source/blender/io/alembic/intern/abc_reader_mesh.cc
+++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc
@@ -937,6 +937,40 @@ static void read_vertex_creases(Mesh *mesh,
mesh->cd_flag |= ME_CDFLAG_VERT_CREASE;
}
+static void read_edge_creases(Mesh *mesh,
+ const Int32ArraySamplePtr &indices,
+ const FloatArraySamplePtr &sharpnesses)
+{
+ if (!(indices && sharpnesses)) {
+ return;
+ }
+
+ MEdge *edges = mesh->medge;
+ int totedge = mesh->totedge;
+
+ for (int i = 0, s = 0, e = indices->size(); i < e; i += 2, s++) {
+ int v1 = (*indices)[i];
+ int v2 = (*indices)[i + 1];
+
+ if (v2 < v1) {
+ /* It appears to be common to store edges with the smallest index first, in which case this
+ * prevents us from doing the second search below. */
+ std::swap(v1, v2);
+ }
+
+ MEdge *edge = find_edge(edges, totedge, v1, v2);
+ if (edge == nullptr) {
+ edge = find_edge(edges, totedge, v2, v1);
+ }
+
+ if (edge) {
+ edge->crease = unit_float_to_uchar_clamp((*sharpnesses)[s]);
+ }
+ }
+
+ mesh->cd_flag |= ME_CDFLAG_EDGE_CREASE;
+}
+
/* ************************************************************************** */
AbcSubDReader::AbcSubDReader(const IObject &object, ImportSettings &settings)
@@ -1000,36 +1034,7 @@ void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec
return;
}
- /* Read egde creases. */
- Int32ArraySamplePtr indices = sample.getCreaseIndices();
- Alembic::Abc::FloatArraySamplePtr sharpnesses = sample.getCreaseSharpnesses();
-
- if (indices && sharpnesses) {
- MEdge *edges = mesh->medge;
- int totedge = mesh->totedge;
-
- for (int i = 0, s = 0, e = indices->size(); i < e; i += 2, s++) {
- int v1 = (*indices)[i];
- int v2 = (*indices)[i + 1];
-
- if (v2 < v1) {
- /* It appears to be common to store edges with the smallest index first, in which case this
- * prevents us from doing the second search below. */
- std::swap(v1, v2);
- }
-
- MEdge *edge = find_edge(edges, totedge, v1, v2);
- if (edge == nullptr) {
- edge = find_edge(edges, totedge, v2, v1);
- }
-
- if (edge) {
- edge->crease = unit_float_to_uchar_clamp((*sharpnesses)[s]);
- }
- }
-
- mesh->cd_flag |= ME_CDFLAG_EDGE_CREASE;
- }
+ read_edge_creases(mesh, sample.getCreaseIndices(), sample.getCreaseSharpnesses());
read_vertex_creases(mesh, sample.getCornerIndices(), sample.getCornerSharpnesses());
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_io.hh b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh
index e88a76fc4e8..daae8ae52c8 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_io.hh
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh
@@ -26,6 +26,7 @@
#include <type_traits>
#include "BLI_compiler_attrs.h"
+#include "BLI_fileops.h"
#include "BLI_string_ref.hh"
#include "BLI_utility_mixins.hh"
@@ -276,7 +277,7 @@ template<eFileType filetype> class FormattedFileHandler : NonCopyable, NonMovabl
FormattedFileHandler(std::string outfile_path) noexcept(false)
: outfile_path_(std::move(outfile_path))
{
- outfile_ = std::fopen(outfile_path_.c_str(), "w");
+ outfile_ = BLI_fopen(outfile_path_.c_str(), "w");
if (!outfile_) {
throw std::system_error(errno, std::system_category(), "Cannot open file " + outfile_path_);
}
diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
index 5dac913c902..89e1de49511 100644
--- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
+++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
@@ -1,10 +1,8 @@
/* Apache License, Version 2.0 */
-#include <fstream>
#include <gtest/gtest.h>
#include <ios>
#include <memory>
-#include <sstream>
#include <string>
#include <system_error>
@@ -185,15 +183,21 @@ static std::unique_ptr<OBJWriter> init_writer(const OBJExportParams &params,
}
}
-/* The following is relative to BKE_tempdir_base. */
-const char *const temp_file_path = "output.OBJ";
+/* The following is relative to BKE_tempdir_base.
+ * Use Latin Capital Letter A with Ogonek, Cyrillic Capital Letter Zhe
+ * at the end, to test I/O on non-English file names. */
+const char *const temp_file_path = "output\xc4\x84\xd0\x96.OBJ";
static std::string read_temp_file_in_string(const std::string &file_path)
{
- std::ifstream temp_stream(file_path);
- std::ostringstream input_ss;
- input_ss << temp_stream.rdbuf();
- return input_ss.str();
+ std::string res;
+ size_t buffer_len;
+ void *buffer = BLI_file_read_text_as_mem(file_path.c_str(), 0, &buffer_len);
+ if (buffer != NULL) {
+ res.assign((const char *)buffer, buffer_len);
+ MEM_freeN(buffer);
+ }
+ return res;
}
TEST(obj_exporter_writer, header)
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_defaults.h b/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
index 88eb164c2b4..c51a615bfb6 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
@@ -315,7 +315,8 @@
.opacity = 1.0f, \
.flags = LRT_GPENCIL_MATCH_OUTPUT_VGROUP, \
.crease_threshold = DEG2RAD(140.0f), \
- .calculation_flags = LRT_ALLOW_DUPLI_OBJECTS | LRT_ALLOW_CLIPPING_BOUNDARIES | LRT_USE_CREASE_ON_SHARP_EDGES, \
+ .calculation_flags = LRT_ALLOW_DUPLI_OBJECTS | LRT_ALLOW_CLIPPING_BOUNDARIES | \
+ LRT_USE_CREASE_ON_SHARP_EDGES | LRT_FILTER_FACE_MARK_KEEP_CONTOUR, \
.angle_splitting_threshold = DEG2RAD(60.0f), \
.chaining_image_threshold = 0.001f, \
.chain_smooth_tolerance = 0.2f,\
diff --git a/source/blender/makesdna/DNA_lineart_types.h b/source/blender/makesdna/DNA_lineart_types.h
index d4440592a00..3e77d566d27 100644
--- a/source/blender/makesdna/DNA_lineart_types.h
+++ b/source/blender/makesdna/DNA_lineart_types.h
@@ -50,7 +50,10 @@ typedef enum eLineartMainFlags {
LRT_USE_CREASE_ON_SMOOTH_SURFACES = (1 << 15),
LRT_USE_CREASE_ON_SHARP_EDGES = (1 << 16),
LRT_USE_CUSTOM_CAMERA = (1 << 17),
+ LRT_FILTER_FACE_MARK_KEEP_CONTOUR = (1 << 18),
+ LRT_USE_BACK_FACE_CULLING = (1 << 19),
LRT_USE_IMAGE_BOUNDARY_TRIMMING = (1 << 20),
+ LRT_CHAIN_PRESERVE_DETAILS = (1 << 22),
} eLineartMainFlags;
typedef enum eLineartEdgeFlag {
diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
index 086da4c31ba..e4e594cd8cf 100644
--- a/source/blender/makesrna/intern/rna_gpencil_modifier.c
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -3211,6 +3211,12 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
prop, "Boundaries", "Filter feature lines based on face mark boundaries");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+ prop = RNA_def_property(srna, "use_face_mark_keep_contour", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(
+ prop, NULL, "calculation_flags", LRT_FILTER_FACE_MARK_KEEP_CONTOUR);
+ RNA_def_property_ui_text(prop, "Keep Contour", "Preserve contour lines while filtering");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
prop = RNA_def_property(srna, "chaining_image_threshold", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_ui_text(
prop,
@@ -3231,6 +3237,12 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
prop, "Use Geometry Space", "Use geometry distance for chaining instead of image space");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+ prop = RNA_def_property(srna, "use_detail_preserve", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_CHAIN_PRESERVE_DETAILS);
+ RNA_def_property_ui_text(
+ prop, "Preserve Details", "Keep the zig-zag \"noise\" in initial chaining");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
prop = RNA_def_property(srna, "use_overlap_edge_type_support", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_ALLOW_OVERLAP_EDGE_TYPES);
RNA_def_property_ui_text(prop,
@@ -3444,6 +3456,14 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
prop,
"Image Boundary Trimming",
"Trim all edges right at the boundary of image(including overscan region)");
+
+ prop = RNA_def_property(srna, "use_back_face_culling", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_USE_BACK_FACE_CULLING);
+ RNA_def_property_ui_text(
+ prop,
+ "Back Face Culling",
+ "Remove all back faces to speed up calculation, this will create edges in "
+ "different occlusion levels than when disabled");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "use_invert_collection", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c
index 52d5f3e97ef..b713df05b80 100644
--- a/source/blender/modifiers/intern/MOD_triangulate.c
+++ b/source/blender/modifiers/intern/MOD_triangulate.c
@@ -48,17 +48,11 @@
#include "MOD_modifiertypes.h"
#include "MOD_ui_common.h"
-Mesh *triangulate_mesh(Mesh *mesh,
- const int quad_method,
- const int ngon_method,
- const int min_vertices,
- const int flag);
-
-Mesh *triangulate_mesh(Mesh *mesh,
- const int quad_method,
- const int ngon_method,
- const int min_vertices,
- const int flag)
+static Mesh *triangulate_mesh(Mesh *mesh,
+ const int quad_method,
+ const int ngon_method,
+ const int min_vertices,
+ const int flag)
{
Mesh *result;
BMesh *bm;
diff --git a/source/blender/modifiers/intern/MOD_weld.cc b/source/blender/modifiers/intern/MOD_weld.cc
index 3a06c6a649b..2d4710ca71a 100644
--- a/source/blender/modifiers/intern/MOD_weld.cc
+++ b/source/blender/modifiers/intern/MOD_weld.cc
@@ -331,7 +331,7 @@ static void weld_assert_poly_no_vert_repetition(const WeldPoly &wp,
}
else {
int i = 0;
- while (weld_iter_loop_of_poly_next(&iter)) {
+ while (weld_iter_loop_of_poly_next(iter)) {
verts[i++] = iter.v;
}
}
@@ -386,7 +386,10 @@ static Vector<WeldVert> weld_vert_ctx_alloc_and_setup(Span<int> vert_dest_map,
for (const int i : vert_dest_map.index_range()) {
if (vert_dest_map[i] != OUT_OF_CONTEXT) {
- wvert.append({vert_dest_map[i], i});
+ WeldVert wv{};
+ wv.vert_dest = vert_dest_map[i];
+ wv.vert_orig = i;
+ wvert.append(wv);
}
}
return wvert;
@@ -676,7 +679,7 @@ static void weld_edge_groups_setup(const int medge_len,
/** \name Weld Poly and Loop API
* \{ */
-static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter *iter,
+static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter &iter,
const WeldPoly &wp,
Span<WeldLoop> wloop,
Span<MLoop> mloop,
@@ -687,19 +690,19 @@ static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter *iter,
return false;
}
- iter->loop_start = wp.loop_start;
- iter->loop_end = wp.loop_end;
- iter->wloop = wloop;
- iter->mloop = mloop;
- iter->loop_map = loop_map;
- iter->group = group_buffer;
+ iter.loop_start = wp.loop_start;
+ iter.loop_end = wp.loop_end;
+ iter.wloop = wloop;
+ iter.mloop = mloop;
+ iter.loop_map = loop_map;
+ iter.group = group_buffer;
int group_len = 0;
if (group_buffer) {
/* First loop group needs more attention. */
int loop_start, loop_end, l;
- loop_start = iter->loop_start;
- loop_end = l = iter->loop_end;
+ loop_start = iter.loop_start;
+ loop_end = l = iter.loop_end;
while (l >= loop_start) {
const int loop_ctx = loop_map[l];
if (loop_ctx != OUT_OF_CONTEXT) {
@@ -715,30 +718,30 @@ static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter *iter,
group_len = loop_end - l;
int i = 0;
while (l < loop_end) {
- iter->group[i++] = ++l;
+ iter.group[i++] = ++l;
}
}
}
- iter->group_len = group_len;
+ iter.group_len = group_len;
- iter->l_next = iter->loop_start;
+ iter.l_next = iter.loop_start;
#ifdef USE_WELD_DEBUG
- iter->v = OUT_OF_CONTEXT;
+ iter.v = OUT_OF_CONTEXT;
#endif
return true;
}
-static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter)
+static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter &iter)
{
- int loop_end = iter->loop_end;
- Span<WeldLoop> wloop = iter->wloop;
- Span<int> loop_map = iter->loop_map;
- int l = iter->l_curr = iter->l_next;
- if (l == iter->loop_start) {
+ const int loop_end = iter.loop_end;
+ Span<WeldLoop> wloop = iter.wloop;
+ Span<int> loop_map = iter.loop_map;
+ int l = iter.l_curr = iter.l_next;
+ if (l == iter.loop_start) {
/* `grupo_len` is already calculated in the first loop */
}
else {
- iter->group_len = 0;
+ iter.group_len = 0;
}
while (l <= loop_end) {
int l_next = l + 1;
@@ -749,32 +752,32 @@ static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter)
l_next = wl->loop_skip_to;
}
if (wl->flag == ELEM_COLLAPSED) {
- if (iter->group) {
- iter->group[iter->group_len++] = l;
+ if (iter.group) {
+ iter.group[iter.group_len++] = l;
}
l = l_next;
continue;
}
#ifdef USE_WELD_DEBUG
- BLI_assert(iter->v != wl->vert);
+ BLI_assert(iter.v != wl->vert);
#endif
- iter->v = wl->vert;
- iter->e = wl->edge;
- iter->type = 1;
+ iter.v = wl->vert;
+ iter.e = wl->edge;
+ iter.type = 1;
}
else {
- const MLoop *ml = &iter->mloop[l];
+ const MLoop &ml = iter.mloop[l];
#ifdef USE_WELD_DEBUG
- BLI_assert((uint)iter->v != ml->v);
+ BLI_assert((uint)iter.v != ml.v);
#endif
- iter->v = ml->v;
- iter->e = ml->e;
- iter->type = 0;
+ iter.v = ml.v;
+ iter.e = ml.e;
+ iter.type = 0;
}
- if (iter->group) {
- iter->group[iter->group_len++] = l;
+ if (iter.group) {
+ iter.group[iter.group_len++] = l;
}
- iter->l_next = l_next;
+ iter.l_next = l_next;
return true;
}
@@ -1026,18 +1029,13 @@ static void weld_poly_loop_ctx_setup(Span<MLoop> mloop,
MutableSpan<WeldGroup> r_vlinks,
WeldMesh *r_weld_mesh)
{
- int poly_kill_len, loop_kill_len, wpoly_len, wpoly_new_len;
-
- WeldPoly *wpoly_new;
- WeldLoop *wl;
-
MutableSpan<WeldPoly> wpoly = r_weld_mesh->wpoly;
MutableSpan<WeldLoop> wloop = r_weld_mesh->wloop;
- wpoly_new = r_weld_mesh->wpoly_new;
- wpoly_len = r_weld_mesh->wpoly_len;
- wpoly_new_len = 0;
- poly_kill_len = 0;
- loop_kill_len = 0;
+ WeldPoly *wpoly_new = r_weld_mesh->wpoly_new;
+ int wpoly_len = r_weld_mesh->wpoly_len;
+ int wpoly_new_len = 0;
+ int poly_kill_len = 0;
+ int loop_kill_len = 0;
Span<int> loop_map = r_weld_mesh->loop_map;
@@ -1051,7 +1049,7 @@ static void weld_poly_loop_ctx_setup(Span<MLoop> mloop,
int poly_len = wp.len;
int ctx_verts_len = 0;
- wl = &wloop[ctx_loops_ofs];
+ WeldLoop *wl = &wloop[ctx_loops_ofs];
for (int l = ctx_loops_len; l--; wl++) {
const int edge_dest = wl->edge;
if (edge_dest == ELEM_COLLAPSED) {
@@ -1108,7 +1106,7 @@ static void weld_poly_loop_ctx_setup(Span<MLoop> mloop,
/* Setup Polygon Overlap. */
- int wpoly_and_new_len = wpoly_len + wpoly_new_len;
+ const int wpoly_and_new_len = wpoly_len + wpoly_new_len;
r_vlinks.fill({0, 0});
MutableSpan<WeldGroup> v_links = r_vlinks;
@@ -1116,8 +1114,8 @@ static void weld_poly_loop_ctx_setup(Span<MLoop> mloop,
for (const int i : IndexRange(wpoly_and_new_len)) {
const WeldPoly &wp = wpoly[i];
WeldLoopOfPolyIter iter;
- if (weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, nullptr)) {
- while (weld_iter_loop_of_poly_next(&iter)) {
+ if (weld_iter_loop_of_poly_begin(iter, wp, wloop, mloop, loop_map, nullptr)) {
+ while (weld_iter_loop_of_poly_next(iter)) {
v_links[iter.v].len++;
}
}
@@ -1135,8 +1133,8 @@ static void weld_poly_loop_ctx_setup(Span<MLoop> mloop,
for (const int i : IndexRange(wpoly_and_new_len)) {
const WeldPoly &wp = wpoly[i];
WeldLoopOfPolyIter iter;
- if (weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, nullptr)) {
- while (weld_iter_loop_of_poly_next(&iter)) {
+ if (weld_iter_loop_of_poly_begin(iter, wp, wloop, mloop, loop_map, nullptr)) {
+ while (weld_iter_loop_of_poly_next(iter)) {
link_poly_buffer[v_links[iter.v].ofs++] = i;
}
}
@@ -1159,8 +1157,8 @@ static void weld_poly_loop_ctx_setup(Span<MLoop> mloop,
}
WeldLoopOfPolyIter iter;
- weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, nullptr);
- weld_iter_loop_of_poly_next(&iter);
+ weld_iter_loop_of_poly_begin(iter, wp, wloop, mloop, loop_map, nullptr);
+ weld_iter_loop_of_poly_next(iter);
struct WeldGroup *link_a = &v_links[iter.v];
polys_len_a = link_a->len;
if (polys_len_a == 1) {
@@ -1181,7 +1179,7 @@ static void weld_poly_loop_ctx_setup(Span<MLoop> mloop,
}
WeldLoopOfPolyIter iter_b = iter;
- while (weld_iter_loop_of_poly_next(&iter_b)) {
+ while (weld_iter_loop_of_poly_next(iter_b)) {
struct WeldGroup *link_b = &v_links[iter_b.v];
polys_len_b = link_b->len;
if (polys_len_b == 1) {
@@ -1253,15 +1251,15 @@ static void weld_poly_loop_ctx_setup(Span<MLoop> mloop,
/** \name Weld Mesh API
* \{ */
-static void weld_mesh_context_create(const Mesh *mesh,
+static void weld_mesh_context_create(const Mesh &mesh,
MutableSpan<int> vert_dest_map,
const int vert_kill_len,
WeldMesh *r_weld_mesh)
{
- Span<MEdge> medge{mesh->medge, mesh->totedge};
- Span<MPoly> mpoly{mesh->mpoly, mesh->totpoly};
- Span<MLoop> mloop{mesh->mloop, mesh->totloop};
- const int mvert_len = mesh->totvert;
+ Span<MEdge> medge{mesh.medge, mesh.totedge};
+ Span<MPoly> mpoly{mesh.mpoly, mesh.totpoly};
+ Span<MLoop> mloop{mesh.mloop, mesh.totloop};
+ const int mvert_len = mesh.totvert;
Vector<WeldVert> wvert = weld_vert_ctx_alloc_and_setup(vert_dest_map, vert_kill_len);
r_weld_mesh->vert_kill_len = vert_kill_len;
@@ -1686,7 +1684,7 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
}
WeldMesh weld_mesh;
- weld_mesh_context_create(mesh, vert_dest_map, vert_kill_len, &weld_mesh);
+ weld_mesh_context_create(*mesh, vert_dest_map, vert_kill_len, &weld_mesh);
const int result_nverts = totvert - weld_mesh.vert_kill_len;
const int result_nedges = totedge - weld_mesh.edge_kill_len;
@@ -1740,7 +1738,7 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
dest_index = 0;
for (int i = 0; i < totedge; i++) {
- int source_index = i;
+ const int source_index = i;
int count = 0;
while (i < totedge && weld_mesh.edge_groups_map[i] == OUT_OF_CONTEXT) {
edge_final[i] = dest_index + count;
@@ -1787,8 +1785,8 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
Array<int, 64> group_buffer(weld_mesh.max_poly_len);
for (const int i : mpoly.index_range()) {
const MPoly &mp = mpoly[i];
- int loop_start = loop_cur;
- int poly_ctx = weld_mesh.poly_map[i];
+ const int loop_start = loop_cur;
+ const int poly_ctx = weld_mesh.poly_map[i];
if (poly_ctx == OUT_OF_CONTEXT) {
int mp_loop_len = mp.totloop;
CustomData_copy_data(&mesh->ldata, &result->ldata, mp.loopstart, loop_cur, mp_loop_len);
@@ -1802,14 +1800,14 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
const WeldPoly &wp = weld_mesh.wpoly[poly_ctx];
WeldLoopOfPolyIter iter;
if (!weld_iter_loop_of_poly_begin(
- &iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer.data())) {
+ iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer.data())) {
continue;
}
if (wp.poly_dst != OUT_OF_CONTEXT) {
continue;
}
- while (weld_iter_loop_of_poly_next(&iter)) {
+ while (weld_iter_loop_of_poly_next(iter)) {
customdata_weld(
&mesh->ldata, &result->ldata, group_buffer.data(), iter.group_len, loop_cur);
int v = vert_final[iter.v];
@@ -1834,17 +1832,17 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
for (const int i : IndexRange(weld_mesh.wpoly_new_len)) {
const WeldPoly &wp = weld_mesh.wpoly_new[i];
- int loop_start = loop_cur;
+ const int loop_start = loop_cur;
WeldLoopOfPolyIter iter;
if (!weld_iter_loop_of_poly_begin(
- &iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer.data())) {
+ iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer.data())) {
continue;
}
if (wp.poly_dst != OUT_OF_CONTEXT) {
continue;
}
- while (weld_iter_loop_of_poly_next(&iter)) {
+ while (weld_iter_loop_of_poly_next(iter)) {
customdata_weld(&mesh->ldata, &result->ldata, group_buffer.data(), iter.group_len, loop_cur);
int v = vert_final[iter.v];
int e = edge_final[iter.e];
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc
index c3c26736e88..fbf6b521fd8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc
@@ -14,20 +14,96 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include "BKE_spline.hh"
+
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_input_curve_handles_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
+ b.add_input<decl::Bool>(N_("Relative")).default_value(false).supports_field();
b.add_output<decl::Vector>(N_("Left")).field_source();
b.add_output<decl::Vector>(N_("Right")).field_source();
}
+class HandlePositionFieldInput final : public GeometryFieldInput {
+ Field<bool> relative_;
+ bool left_;
+
+ public:
+ HandlePositionFieldInput(Field<bool> relative, bool left)
+ : GeometryFieldInput(CPPType::get<float3>(), "Handle"), relative_(relative), left_(left)
+ {
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const final
+ {
+ if (component.type() != GEO_COMPONENT_TYPE_CURVE) {
+ return {};
+ }
+
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
+ fn::FieldEvaluator evaluator(field_context, &mask);
+ evaluator.add(relative_);
+ evaluator.evaluate();
+ const VArray<bool> &relative = evaluator.get_evaluated<bool>(0);
+
+ VArray<float3> positions = component.attribute_get_for_read<float3>(
+ "position", ATTR_DOMAIN_POINT, {0, 0, 0});
+
+ StringRef side = left_ ? "handle_left" : "handle_right";
+ VArray<float3> handles = component.attribute_get_for_read<float3>(
+ side, ATTR_DOMAIN_POINT, {0, 0, 0});
+
+ if (relative.is_single()) {
+ if (relative.get_internal_single()) {
+ Array<float3> output(positions.size());
+ for (const int i : positions.index_range()) {
+ output[i] = handles[i] - positions[i];
+ }
+ return component.attribute_try_adapt_domain<float3>(
+ VArray<float3>::ForContainer(std::move(output)), ATTR_DOMAIN_POINT, domain);
+ }
+ return component.attribute_try_adapt_domain<float3>(handles, ATTR_DOMAIN_POINT, domain);
+ }
+
+ Array<float3> output(positions.size());
+ for (const int i : positions.index_range()) {
+ if (relative[i]) {
+ output[i] = handles[i] - positions[i];
+ }
+ else {
+ output[i] = handles[i];
+ }
+ }
+ return component.attribute_try_adapt_domain<float3>(
+ VArray<float3>::ForContainer(std::move(output)), ATTR_DOMAIN_POINT, domain);
+ }
+
+ uint64_t hash() const override
+ {
+ return get_default_hash_2(relative_, left_);
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ if (const HandlePositionFieldInput *other_handle =
+ dynamic_cast<const HandlePositionFieldInput *>(&other)) {
+ return relative_ == other_handle->relative_ && left_ == other_handle->left_;
+ }
+ return false;
+ }
+};
+
static void node_geo_exec(GeoNodeExecParams params)
{
- Field<float3> left_field = AttributeFieldInput::Create<float3>("handle_left");
- Field<float3> right_field = AttributeFieldInput::Create<float3>("handle_right");
+ Field<bool> relative = params.extract_input<Field<bool>>("Relative");
+ Field<float3> left_field{std::make_shared<HandlePositionFieldInput>(relative, true)};
+ Field<float3> right_field{std::make_shared<HandlePositionFieldInput>(relative, false)};
+
params.set_output("Left", std::move(left_field));
params.set_output("Right", std::move(right_field));
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
index 998e4d58bf3..e78c4d7bc35 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
@@ -14,24 +14,25 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include "BKE_customdata.h"
+#include "BKE_mesh.h"
+
+#include "bmesh.h"
+#include "bmesh_tools.h"
+
+#include "DNA_mesh_types.h"
+
#include "UI_interface.h"
#include "UI_resources.h"
#include "node_geometry_util.hh"
-extern "C" {
-Mesh *triangulate_mesh(Mesh *mesh,
- const int quad_method,
- const int ngon_method,
- const int min_vertices,
- const int flag);
-}
-
namespace blender::nodes::node_geo_triangulate_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value();
b.add_input<decl::Int>(N_("Minimum Vertices")).default_value(4).min(4).max(10000);
b.add_output<decl::Geometry>(N_("Mesh"));
}
@@ -48,9 +49,35 @@ static void geo_triangulate_init(bNodeTree *UNUSED(ntree), bNode *node)
node->custom2 = GEO_NODE_TRIANGULATE_NGON_BEAUTY;
}
+static Mesh *triangulate_mesh_selection(const Mesh &mesh,
+ const int quad_method,
+ const int ngon_method,
+ const IndexMask selection,
+ const int min_vertices)
+{
+ CustomData_MeshMasks cd_mask_extra = {
+ CD_MASK_ORIGINDEX, CD_MASK_ORIGINDEX, 0, CD_MASK_ORIGINDEX};
+ BMeshCreateParams create_params{0};
+ BMeshFromMeshParams from_mesh_params{true, 1, 1, 1, cd_mask_extra};
+ BMesh *bm = BKE_mesh_to_bmesh_ex(&mesh, &create_params, &from_mesh_params);
+
+ /* Tag faces to be triangulated from the selection mask. */
+ BM_mesh_elem_table_ensure(bm, BM_FACE);
+ for (int i_face : selection) {
+ BM_elem_flag_set(BM_face_at_index(bm, i_face), BM_ELEM_TAG, true);
+ }
+
+ BM_mesh_triangulate(bm, quad_method, ngon_method, min_vertices, true, NULL, NULL, NULL);
+ Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, &cd_mask_extra, &mesh);
+ BM_mesh_free(bm);
+ BKE_mesh_normals_tag_dirty(result);
+ return result;
+}
+
static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
+ Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
const int min_vertices = std::max(params.extract_input<int>("Minimum Vertices"), 4);
GeometryNodeTriangulateQuads quad_method = static_cast<GeometryNodeTriangulateQuads>(
@@ -59,12 +86,22 @@ static void node_geo_exec(GeoNodeExecParams params)
params.node().custom2);
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- /* #triangulate_mesh might modify the input mesh currently. */
- Mesh *mesh_in = geometry_set.get_mesh_for_write();
- if (mesh_in != nullptr) {
- Mesh *mesh_out = triangulate_mesh(mesh_in, quad_method, ngon_method, min_vertices, 0);
- geometry_set.replace_mesh(mesh_out);
+ if (!geometry_set.has_mesh()) {
+ return;
}
+ GeometryComponent &component = geometry_set.get_component_for_write<MeshComponent>();
+ const Mesh &mesh_in = *geometry_set.get_mesh_for_read();
+
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE);
+ GeometryComponentFieldContext context{component, ATTR_DOMAIN_FACE};
+ FieldEvaluator evaluator{context, domain_size};
+ evaluator.add(selection_field);
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_as_mask(0);
+
+ Mesh *mesh_out = triangulate_mesh_selection(
+ mesh_in, quad_method, ngon_method, selection, min_vertices);
+ geometry_set.replace_mesh(mesh_out);
});
params.set_output("Mesh", std::move(geometry_set));