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:
Diffstat (limited to 'source/blender/blenkernel/intern/mesh_normals.cc')
-rw-r--r--source/blender/blenkernel/intern/mesh_normals.cc414
1 files changed, 182 insertions, 232 deletions
diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc
index ebb5a72d137..404357bda8d 100644
--- a/source/blender/blenkernel/intern/mesh_normals.cc
+++ b/source/blender/blenkernel/intern/mesh_normals.cc
@@ -33,18 +33,20 @@
#include "BKE_editmesh_cache.h"
#include "BKE_global.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
#include "atomic_ops.h"
using blender::BitVector;
+using blender::float3;
using blender::MutableSpan;
+using blender::short2;
using blender::Span;
-// #define DEBUG_TIME
+#define DEBUG_TIME
#ifdef DEBUG_TIME
-# include "PIL_time.h"
-# include "PIL_time_utildefines.h"
+# include "BLI_timeit.hh"
#endif
/* -------------------------------------------------------------------- */
@@ -442,7 +444,7 @@ void BKE_mesh_ensure_normals_for_display(Mesh *mesh)
BKE_mesh_poly_normals_ensure(mesh);
break;
case ME_WRAPPER_TYPE_BMESH: {
- struct BMEditMesh *em = mesh->edit_mesh;
+ BMEditMesh *em = mesh->edit_mesh;
EditMeshData *emd = mesh->runtime->edit_data;
if (emd->vertexCos) {
BKE_editmesh_cache_ensure_vert_normals(em, emd);
@@ -456,12 +458,9 @@ void BKE_mesh_ensure_normals_for_display(Mesh *mesh)
void BKE_mesh_calc_normals(Mesh *mesh)
{
#ifdef DEBUG_TIME
- TIMEIT_START_AVERAGED(BKE_mesh_calc_normals);
+ SCOPED_TIMER_AVERAGED(__func__);
#endif
BKE_mesh_vertex_normals_ensure(mesh);
-#ifdef DEBUG_TIME
- TIMEIT_END_AVERAGED(BKE_mesh_calc_normals);
-#endif
}
void BKE_mesh_calc_normals_looptri(const MVert *mverts,
@@ -788,7 +787,7 @@ struct LoopSplitTaskData {
/** We have to create those outside of tasks, since #MemArena is not thread-safe. */
MLoopNorSpace *lnor_space;
- float (*lnor)[3];
+ float3 *lnor;
const MLoop *ml_curr;
const MLoop *ml_prev;
int ml_curr_index;
@@ -809,22 +808,18 @@ struct LoopSplitTaskDataCommon {
* Note we do not need to protect it, though, since two different tasks will *always* affect
* different elements in the arrays. */
MLoopNorSpaceArray *lnors_spacearr;
- float (*loopnors)[3];
- short (*clnors_data)[2];
+ MutableSpan<float3> loopnors;
+ MutableSpan<short2> clnors_data;
/* Read-only. */
- const MVert *mverts;
- const MEdge *medges;
- const MLoop *mloops;
- const MPoly *mpolys;
+ Span<MVert> verts;
+ MutableSpan<MEdge> edges;
+ Span<MLoop> loops;
+ Span<MPoly> polys;
int (*edge_to_loops)[2];
- int *loop_to_poly;
- const float (*polynors)[3];
- const float (*vert_normals)[3];
-
- int numEdges;
- int numLoops;
- int numPolys;
+ Span<int> loop_to_poly;
+ Span<float3> polynors;
+ Span<float3> vert_normals;
};
#define INDEX_UNSET INT_MIN
@@ -837,47 +832,38 @@ static void mesh_edges_sharp_tag(LoopSplitTaskDataCommon *data,
const float split_angle,
const bool do_sharp_edges_tag)
{
- const MEdge *medges = data->medges;
- const MLoop *mloops = data->mloops;
+ MutableSpan<MEdge> edges = data->edges;
+ const Span<MPoly> polys = data->polys;
+ const Span<MLoop> loops = data->loops;
+ const Span<int> loop_to_poly = data->loop_to_poly;
- const MPoly *mpolys = data->mpolys;
-
- const int numEdges = data->numEdges;
- const int numPolys = data->numPolys;
-
- float(*loopnors)[3] = data->loopnors; /* NOTE: loopnors may be nullptr here. */
- const float(*polynors)[3] = data->polynors;
+ MutableSpan<float3> loopnors = data->loopnors; /* NOTE: loopnors may be empty here. */
+ const Span<float3> polynors = data->polynors;
int(*edge_to_loops)[2] = data->edge_to_loops;
- int *loop_to_poly = data->loop_to_poly;
BitVector sharp_edges;
if (do_sharp_edges_tag) {
- sharp_edges.resize(numEdges, false);
+ sharp_edges.resize(edges.size(), false);
}
- const MPoly *mp;
- int mp_index;
-
const float split_angle_cos = check_angle ? cosf(split_angle) : -1.0f;
- for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) {
- const MLoop *ml_curr;
+ for (const int mp_index : polys.index_range()) {
+ const MPoly &poly = polys[mp_index];
int *e2l;
- int ml_curr_index = mp->loopstart;
- const int ml_last_index = (ml_curr_index + mp->totloop) - 1;
+ int ml_curr_index = poly.loopstart;
+ const int ml_last_index = (ml_curr_index + poly.totloop) - 1;
- ml_curr = &mloops[ml_curr_index];
+ const MLoop *ml_curr = &loops[ml_curr_index];
for (; ml_curr_index <= ml_last_index; ml_curr++, ml_curr_index++) {
e2l = edge_to_loops[ml_curr->e];
- loop_to_poly[ml_curr_index] = mp_index;
-
/* Pre-populate all loop normals as if their verts were all-smooth,
* this way we don't have to compute those later!
*/
- if (loopnors) {
+ if (!loopnors.is_empty()) {
copy_v3_v3(loopnors[ml_curr_index], data->vert_normals[ml_curr->v]);
}
@@ -886,7 +872,7 @@ static void mesh_edges_sharp_tag(LoopSplitTaskDataCommon *data,
/* 'Empty' edge until now, set e2l[0] (and e2l[1] to INDEX_UNSET to tag it as unset). */
e2l[0] = ml_curr_index;
/* We have to check this here too, else we might miss some flat faces!!! */
- e2l[1] = (mp->flag & ME_SMOOTH) ? INDEX_UNSET : INDEX_INVALID;
+ e2l[1] = (poly.flag & ME_SMOOTH) ? INDEX_UNSET : INDEX_INVALID;
}
else if (e2l[1] == INDEX_UNSET) {
const bool is_angle_sharp = (check_angle &&
@@ -898,8 +884,8 @@ static void mesh_edges_sharp_tag(LoopSplitTaskDataCommon *data,
* or both poly have opposed (flipped) normals, i.e. both loops on the same edge share the
* same vertex, or angle between both its polys' normals is above split_angle value.
*/
- if (!(mp->flag & ME_SMOOTH) || (medges[ml_curr->e].flag & ME_SHARP) ||
- ml_curr->v == mloops[e2l[0]].v || is_angle_sharp) {
+ if (!(poly.flag & ME_SMOOTH) || (edges[ml_curr->e].flag & ME_SHARP) ||
+ ml_curr->v == loops[e2l[0]].v || is_angle_sharp) {
/* NOTE: we are sure that loop != 0 here ;). */
e2l[1] = INDEX_INVALID;
@@ -929,69 +915,64 @@ static void mesh_edges_sharp_tag(LoopSplitTaskDataCommon *data,
/* If requested, do actual tagging of edges as sharp in another loop. */
if (do_sharp_edges_tag) {
- MEdge *me;
- int me_index;
- for (me = (MEdge *)medges, me_index = 0; me_index < numEdges; me++, me_index++) {
- if (sharp_edges[me_index]) {
- me->flag |= ME_SHARP;
+ for (const int i : edges.index_range()) {
+ if (sharp_edges[i]) {
+ edges[i].flag |= ME_SHARP;
}
}
}
}
-void BKE_edges_sharp_from_angle_set(const struct MVert *mverts,
- const int /*numVerts*/,
- struct MEdge *medges,
+void BKE_edges_sharp_from_angle_set(const MVert *mverts,
+ const int numVerts,
+ MEdge *medges,
const int numEdges,
- const struct MLoop *mloops,
+ const MLoop *mloops,
const int numLoops,
- const struct MPoly *mpolys,
+ const MPoly *mpolys,
const float (*polynors)[3],
const int numPolys,
const float split_angle)
{
+ using namespace blender;
+ using namespace blender::bke;
if (split_angle >= float(M_PI)) {
/* Nothing to do! */
return;
}
- /* Mapping edge -> loops. See BKE_mesh_normals_loop_split() for details. */
+ /* Mapping edge -> loops. See #BKE_mesh_normals_loop_split for details. */
int(*edge_to_loops)[2] = (int(*)[2])MEM_calloc_arrayN(
size_t(numEdges), sizeof(*edge_to_loops), __func__);
/* Simple mapping from a loop to its polygon index. */
- int *loop_to_poly = (int *)MEM_malloc_arrayN(size_t(numLoops), sizeof(*loop_to_poly), __func__);
+ const Array<int> loop_to_poly = mesh_topology::build_loop_to_poly_map({mpolys, numPolys},
+ numLoops);
LoopSplitTaskDataCommon common_data = {};
- common_data.mverts = mverts;
- common_data.medges = medges;
- common_data.mloops = mloops;
- common_data.mpolys = mpolys;
+ common_data.verts = {mverts, numVerts};
+ common_data.edges = {medges, numEdges};
+ common_data.polys = {mpolys, numPolys};
+ common_data.loops = {mloops, numLoops};
common_data.edge_to_loops = edge_to_loops;
common_data.loop_to_poly = loop_to_poly;
- common_data.polynors = polynors;
- common_data.numEdges = numEdges;
- common_data.numPolys = numPolys;
+ common_data.polynors = {reinterpret_cast<const float3 *>(polynors), numPolys};
mesh_edges_sharp_tag(&common_data, true, split_angle, true);
MEM_freeN(edge_to_loops);
- MEM_freeN(loop_to_poly);
}
-void BKE_mesh_loop_manifold_fan_around_vert_next(const MLoop *mloops,
- const MPoly *mpolys,
- const int *loop_to_poly,
- const int *e2lfan_curr,
- const uint mv_pivot_index,
- const MLoop **r_mlfan_curr,
- int *r_mlfan_curr_index,
- int *r_mlfan_vert_index,
- int *r_mpfan_curr_index)
+static void loop_manifold_fan_around_vert_next(const Span<MLoop> loops,
+ const Span<MPoly> polys,
+ const Span<int> loop_to_poly,
+ const int *e2lfan_curr,
+ const uint mv_pivot_index,
+ const MLoop **r_mlfan_curr,
+ int *r_mlfan_curr_index,
+ int *r_mlfan_vert_index,
+ int *r_mpfan_curr_index)
{
- const MLoop *mlfan_next;
- const MPoly *mpfan_next;
-
/* WARNING: This is rather complex!
* We have to find our next edge around the vertex (fan mode).
* First we find the next loop, which is either previous or next to mlfan_curr_index, depending
@@ -1005,38 +986,38 @@ void BKE_mesh_loop_manifold_fan_around_vert_next(const MLoop *mloops,
BLI_assert(*r_mlfan_curr_index >= 0);
BLI_assert(*r_mpfan_curr_index >= 0);
- mlfan_next = &mloops[*r_mlfan_curr_index];
- mpfan_next = &mpolys[*r_mpfan_curr_index];
- if (((*r_mlfan_curr)->v == mlfan_next->v && (*r_mlfan_curr)->v == mv_pivot_index) ||
- ((*r_mlfan_curr)->v != mlfan_next->v && (*r_mlfan_curr)->v != mv_pivot_index)) {
+ const MLoop &mlfan_next = loops[*r_mlfan_curr_index];
+ const MPoly &mpfan_next = polys[*r_mpfan_curr_index];
+ if (((*r_mlfan_curr)->v == mlfan_next.v && (*r_mlfan_curr)->v == mv_pivot_index) ||
+ ((*r_mlfan_curr)->v != mlfan_next.v && (*r_mlfan_curr)->v != mv_pivot_index)) {
/* We need the previous loop, but current one is our vertex's loop. */
*r_mlfan_vert_index = *r_mlfan_curr_index;
- if (--(*r_mlfan_curr_index) < mpfan_next->loopstart) {
- *r_mlfan_curr_index = mpfan_next->loopstart + mpfan_next->totloop - 1;
+ if (--(*r_mlfan_curr_index) < mpfan_next.loopstart) {
+ *r_mlfan_curr_index = mpfan_next.loopstart + mpfan_next.totloop - 1;
}
}
else {
/* We need the next loop, which is also our vertex's loop. */
- if (++(*r_mlfan_curr_index) >= mpfan_next->loopstart + mpfan_next->totloop) {
- *r_mlfan_curr_index = mpfan_next->loopstart;
+ if (++(*r_mlfan_curr_index) >= mpfan_next.loopstart + mpfan_next.totloop) {
+ *r_mlfan_curr_index = mpfan_next.loopstart;
}
*r_mlfan_vert_index = *r_mlfan_curr_index;
}
- *r_mlfan_curr = &mloops[*r_mlfan_curr_index];
+ *r_mlfan_curr = &loops[*r_mlfan_curr_index];
/* And now we are back in sync, mlfan_curr_index is the index of `mlfan_curr`! Pff! */
}
static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopSplitTaskData *data)
{
MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr;
- const short(*clnors_data)[2] = common_data->clnors_data;
+ const Span<short2> clnors_data = common_data->clnors_data;
- const MVert *mverts = common_data->mverts;
- const MEdge *medges = common_data->medges;
- const float(*polynors)[3] = common_data->polynors;
+ const Span<MVert> verts = common_data->verts;
+ const Span<MEdge> edges = common_data->edges;
+ const Span<float3> polynors = common_data->polynors;
MLoopNorSpace *lnor_space = data->lnor_space;
- float(*lnor)[3] = data->lnor;
+ float3 *lnor = data->lnor;
const MLoop *ml_curr = data->ml_curr;
const MLoop *ml_prev = data->ml_prev;
const int ml_curr_index = data->ml_curr_index;
@@ -1064,13 +1045,13 @@ static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopS
float vec_curr[3], vec_prev[3];
const uint mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */
- const MVert *mv_pivot = &mverts[mv_pivot_index];
- const MEdge *me_curr = &medges[ml_curr->e];
- const MVert *mv_2 = (me_curr->v1 == mv_pivot_index) ? &mverts[me_curr->v2] :
- &mverts[me_curr->v1];
- const MEdge *me_prev = &medges[ml_prev->e];
- const MVert *mv_3 = (me_prev->v1 == mv_pivot_index) ? &mverts[me_prev->v2] :
- &mverts[me_prev->v1];
+ const MVert *mv_pivot = &verts[mv_pivot_index];
+ const MEdge *me_curr = &edges[ml_curr->e];
+ const MVert *mv_2 = (me_curr->v1 == mv_pivot_index) ? &verts[me_curr->v2] :
+ &verts[me_curr->v1];
+ const MEdge *me_prev = &edges[ml_prev->e];
+ const MVert *mv_3 = (me_prev->v1 == mv_pivot_index) ? &verts[me_prev->v2] :
+ &verts[me_prev->v1];
sub_v3_v3v3(vec_curr, mv_2->co, mv_pivot->co);
normalize_v3(vec_curr);
@@ -1081,7 +1062,7 @@ static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopS
/* We know there is only one loop in this space, no need to create a link-list in this case. */
BKE_lnor_space_add_loop(lnors_spacearr, lnor_space, ml_curr_index, nullptr, true);
- if (clnors_data) {
+ if (!clnors_data.is_empty()) {
BKE_lnor_space_custom_data_to_normal(lnor_space, clnors_data[ml_curr_index], *lnor);
}
}
@@ -1090,16 +1071,16 @@ static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopS
static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSplitTaskData *data)
{
MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr;
- float(*loopnors)[3] = common_data->loopnors;
- short(*clnors_data)[2] = common_data->clnors_data;
+ MutableSpan<float3> loopnors = common_data->loopnors;
+ MutableSpan<short2> clnors_data = common_data->clnors_data;
- const MVert *mverts = common_data->mverts;
- const MEdge *medges = common_data->medges;
- const MLoop *mloops = common_data->mloops;
- const MPoly *mpolys = common_data->mpolys;
+ const Span<MVert> verts = common_data->verts;
+ const Span<MEdge> edges = common_data->edges;
+ const Span<MPoly> polys = common_data->polys;
+ const Span<MLoop> loops = common_data->loops;
const int(*edge_to_loops)[2] = common_data->edge_to_loops;
- const int *loop_to_poly = common_data->loop_to_poly;
- const float(*polynors)[3] = common_data->polynors;
+ const Span<int> loop_to_poly = common_data->loop_to_poly;
+ const Span<float3> polynors = common_data->polynors;
MLoopNorSpace *lnor_space = data->lnor_space;
#if 0 /* Not needed for 'fan' loops. */
@@ -1121,22 +1102,17 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli
* number of sharp edges per vertex, I doubt the additional memory usage would be worth it,
* especially as it should not be a common case in real-life meshes anyway). */
const uint mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */
- const MVert *mv_pivot = &mverts[mv_pivot_index];
+ const MVert *mv_pivot = &verts[mv_pivot_index];
/* `ml_curr` would be mlfan_prev if we needed that one. */
- const MEdge *me_org = &medges[ml_curr->e];
+ const MEdge *me_org = &edges[ml_curr->e];
- const int *e2lfan_curr;
float vec_curr[3], vec_prev[3], vec_org[3];
- const MLoop *mlfan_curr;
float lnor[3] = {0.0f, 0.0f, 0.0f};
- /* `mlfan_vert_index` the loop of our current edge might not be the loop of our current vertex!
- */
- int mlfan_curr_index, mlfan_vert_index, mpfan_curr_index;
/* We validate clnors data on the fly - cheapest way to do! */
int clnors_avg[2] = {0, 0};
- short(*clnor_ref)[2] = nullptr;
+ short2 *clnor_ref = nullptr;
int clnors_count = 0;
bool clnors_invalid = false;
@@ -1145,11 +1121,13 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli
/* Temp clnors stack. */
BLI_SMALLSTACK_DECLARE(clnors, short *);
- e2lfan_curr = e2l_prev;
- mlfan_curr = ml_prev;
- mlfan_curr_index = ml_prev_index;
- mlfan_vert_index = ml_curr_index;
- mpfan_curr_index = mp_index;
+ const int *e2lfan_curr = e2l_prev;
+ const MLoop *mlfan_curr = ml_prev;
+ /* `mlfan_vert_index` the loop of our current edge might not be the loop of our current vertex!
+ */
+ int mlfan_curr_index = ml_prev_index;
+ int mlfan_vert_index = ml_curr_index;
+ int mpfan_curr_index = mp_index;
BLI_assert(mlfan_curr_index >= 0);
BLI_assert(mlfan_vert_index >= 0);
@@ -1157,7 +1135,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli
/* Only need to compute previous edge's vector once, then we can just reuse old current one! */
{
- const MVert *mv_2 = (me_org->v1 == mv_pivot_index) ? &mverts[me_org->v2] : &mverts[me_org->v1];
+ const MVert *mv_2 = (me_org->v1 == mv_pivot_index) ? &verts[me_org->v2] : &verts[me_org->v1];
sub_v3_v3v3(vec_org, mv_2->co, mv_pivot->co);
normalize_v3(vec_org);
@@ -1171,15 +1149,15 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli
// printf("FAN: vert %d, start edge %d\n", mv_pivot_index, ml_curr->e);
while (true) {
- const MEdge *me_curr = &medges[mlfan_curr->e];
+ const MEdge *me_curr = &edges[mlfan_curr->e];
/* Compute edge vectors.
* NOTE: We could pre-compute those into an array, in the first iteration, instead of computing
* them twice (or more) here. However, time gained is not worth memory and time lost,
* given the fact that this code should not be called that much in real-life meshes.
*/
{
- const MVert *mv_2 = (me_curr->v1 == mv_pivot_index) ? &mverts[me_curr->v2] :
- &mverts[me_curr->v1];
+ const MVert *mv_2 = (me_curr->v1 == mv_pivot_index) ? &verts[me_curr->v2] :
+ &verts[me_curr->v1];
sub_v3_v3v3(vec_curr, mv_2->co, mv_pivot->co);
normalize_v3(vec_curr);
@@ -1194,9 +1172,9 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli
/* Accumulate */
madd_v3_v3fl(lnor, polynors[mpfan_curr_index], fac);
- if (clnors_data) {
+ if (!clnors_data.is_empty()) {
/* Accumulate all clnors, if they are not all equal we have to fix that! */
- short(*clnor)[2] = &clnors_data[mlfan_vert_index];
+ short2 *clnor = &clnors_data[mlfan_vert_index];
if (clnors_count) {
clnors_invalid |= ((*clnor_ref)[0] != (*clnor)[0] || (*clnor_ref)[1] != (*clnor)[1]);
}
@@ -1233,15 +1211,15 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli
copy_v3_v3(vec_prev, vec_curr);
/* Find next loop of the smooth fan. */
- BKE_mesh_loop_manifold_fan_around_vert_next(mloops,
- mpolys,
- loop_to_poly,
- e2lfan_curr,
- mv_pivot_index,
- &mlfan_curr,
- &mlfan_curr_index,
- &mlfan_vert_index,
- &mpfan_curr_index);
+ loop_manifold_fan_around_vert_next(loops,
+ polys,
+ loop_to_poly,
+ e2lfan_curr,
+ mv_pivot_index,
+ &mlfan_curr,
+ &mlfan_curr_index,
+ &mlfan_vert_index,
+ &mpfan_curr_index);
e2lfan_curr = edge_to_loops[mlfan_curr->e];
}
@@ -1261,7 +1239,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli
BKE_lnor_space_define(lnor_space, lnor, vec_org, vec_curr, edge_vectors);
- if (clnors_data) {
+ if (!clnors_data.is_empty()) {
if (clnors_invalid) {
short *clnor;
@@ -1325,10 +1303,6 @@ static void loop_split_worker(TaskPool *__restrict pool, void *taskdata)
BLI_stack_new(sizeof(float[3]), __func__) :
nullptr;
-#ifdef DEBUG_TIME
- TIMEIT_START_AVERAGED(loop_split_worker);
-#endif
-
for (int i = 0; i < LOOP_SPLIT_TASK_BLOCK_SIZE; i++, data++) {
/* A nullptr ml_curr is used to tag ended data! */
if (data->ml_curr == nullptr) {
@@ -1341,10 +1315,6 @@ static void loop_split_worker(TaskPool *__restrict pool, void *taskdata)
if (edge_vectors) {
BLI_stack_free(edge_vectors);
}
-
-#ifdef DEBUG_TIME
- TIMEIT_END_AVERAGED(loop_split_worker);
-#endif
}
/**
@@ -1352,10 +1322,10 @@ static void loop_split_worker(TaskPool *__restrict pool, void *taskdata)
* Needed because cyclic smooth fans have no obvious 'entry point',
* and yet we need to walk them once, and only once.
*/
-static bool loop_split_generator_check_cyclic_smooth_fan(const MLoop *mloops,
- const MPoly *mpolys,
+static bool loop_split_generator_check_cyclic_smooth_fan(const Span<MLoop> mloops,
+ const Span<MPoly> mpolys,
const int (*edge_to_loops)[2],
- const int *loop_to_poly,
+ const Span<int> loop_to_poly,
const int *e2l_prev,
BitVector<> &skip_loops,
const MLoop *ml_curr,
@@ -1365,22 +1335,19 @@ static bool loop_split_generator_check_cyclic_smooth_fan(const MLoop *mloops,
const int mp_curr_index)
{
const uint mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */
- const int *e2lfan_curr;
- const MLoop *mlfan_curr;
- /* `mlfan_vert_index` the loop of our current edge might not be the loop of our current vertex!
- */
- int mlfan_curr_index, mlfan_vert_index, mpfan_curr_index;
- e2lfan_curr = e2l_prev;
+ const int *e2lfan_curr = e2l_prev;
if (IS_EDGE_SHARP(e2lfan_curr)) {
/* Sharp loop, so not a cyclic smooth fan. */
return false;
}
- mlfan_curr = ml_prev;
- mlfan_curr_index = ml_prev_index;
- mlfan_vert_index = ml_curr_index;
- mpfan_curr_index = mp_curr_index;
+ /* `mlfan_vert_index` the loop of our current edge might not be the loop of our current vertex!
+ */
+ const MLoop *mlfan_curr = ml_prev;
+ int mlfan_curr_index = ml_prev_index;
+ int mlfan_vert_index = ml_curr_index;
+ int mpfan_curr_index = mp_curr_index;
BLI_assert(mlfan_curr_index >= 0);
BLI_assert(mlfan_vert_index >= 0);
@@ -1391,15 +1358,15 @@ static bool loop_split_generator_check_cyclic_smooth_fan(const MLoop *mloops,
while (true) {
/* Find next loop of the smooth fan. */
- BKE_mesh_loop_manifold_fan_around_vert_next(mloops,
- mpolys,
- loop_to_poly,
- e2lfan_curr,
- mv_pivot_index,
- &mlfan_curr,
- &mlfan_curr_index,
- &mlfan_vert_index,
- &mpfan_curr_index);
+ loop_manifold_fan_around_vert_next(mloops,
+ mpolys,
+ loop_to_poly,
+ e2lfan_curr,
+ mv_pivot_index,
+ &mlfan_curr,
+ &mlfan_curr_index,
+ &mlfan_vert_index,
+ &mpfan_curr_index);
e2lfan_curr = edge_to_loops[mlfan_curr->e];
@@ -1426,24 +1393,14 @@ static bool loop_split_generator_check_cyclic_smooth_fan(const MLoop *mloops,
static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common_data)
{
MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr;
- float(*loopnors)[3] = common_data->loopnors;
+ MutableSpan<float3> loopnors = common_data->loopnors;
- const MLoop *mloops = common_data->mloops;
- const MPoly *mpolys = common_data->mpolys;
- const int *loop_to_poly = common_data->loop_to_poly;
+ const Span<MLoop> loops = common_data->loops;
+ const Span<MPoly> polys = common_data->polys;
+ const Span<int> loop_to_poly = common_data->loop_to_poly;
const int(*edge_to_loops)[2] = common_data->edge_to_loops;
- const int numLoops = common_data->numLoops;
- const int numPolys = common_data->numPolys;
- const MPoly *mp;
- int mp_index;
-
- const MLoop *ml_curr;
- const MLoop *ml_prev;
- int ml_curr_index;
- int ml_prev_index;
-
- BitVector<> skip_loops(numLoops, false);
+ BitVector<> skip_loops(loops.size(), false);
LoopSplitTaskData *data_buff = nullptr;
int data_idx = 0;
@@ -1453,7 +1410,7 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common
BLI_Stack *edge_vectors = nullptr;
#ifdef DEBUG_TIME
- TIMEIT_START_AVERAGED(loop_split_generator);
+ SCOPED_TIMER_AVERAGED(__func__);
#endif
if (!pool) {
@@ -1465,15 +1422,15 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common
/* We now know edges that can be smoothed (with their vector, and their two loops),
* and edges that will be hard! Now, time to generate the normals.
*/
- for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) {
- float(*lnors)[3];
- const int ml_last_index = (mp->loopstart + mp->totloop) - 1;
- ml_curr_index = mp->loopstart;
- ml_prev_index = ml_last_index;
+ for (const int mp_index : polys.index_range()) {
+ const MPoly &poly = polys[mp_index];
+ const int ml_last_index = (poly.loopstart + poly.totloop) - 1;
+ int ml_curr_index = poly.loopstart;
+ int ml_prev_index = ml_last_index;
- ml_curr = &mloops[ml_curr_index];
- ml_prev = &mloops[ml_prev_index];
- lnors = &loopnors[ml_curr_index];
+ const MLoop *ml_curr = &loops[ml_curr_index];
+ const MLoop *ml_prev = &loops[ml_prev_index];
+ float3 *lnors = &loopnors[ml_curr_index];
for (; ml_curr_index <= ml_last_index; ml_curr++, ml_curr_index++, lnors++) {
const int *e2l_curr = edge_to_loops[ml_curr->e];
@@ -1499,8 +1456,8 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common
* complexity, #loop_manifold_fan_around_vert_next() is quite cheap in term of CPU cycles,
* so really think it's not worth it. */
if (!IS_EDGE_SHARP(e2l_curr) && (skip_loops[ml_curr_index] ||
- !loop_split_generator_check_cyclic_smooth_fan(mloops,
- mpolys,
+ !loop_split_generator_check_cyclic_smooth_fan(loops,
+ polys,
edge_to_loops,
loop_to_poly,
e2l_prev,
@@ -1593,15 +1550,11 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common
if (edge_vectors) {
BLI_stack_free(edge_vectors);
}
-
-#ifdef DEBUG_TIME
- TIMEIT_END_AVERAGED(loop_split_generator);
-#endif
}
void BKE_mesh_normals_loop_split(const MVert *mverts,
const float (*vert_normals)[3],
- const int /*numVerts*/,
+ const int numVerts,
const MEdge *medges,
const int numEdges,
const MLoop *mloops,
@@ -1612,10 +1565,12 @@ void BKE_mesh_normals_loop_split(const MVert *mverts,
const int numPolys,
const bool use_split_normals,
const float split_angle,
+ const int *loop_to_poly_map,
MLoopNorSpaceArray *r_lnors_spacearr,
- short (*clnors_data)[2],
- int *r_loop_to_poly)
+ short (*clnors_data)[2])
{
+ using namespace blender;
+ using namespace blender::bke;
/* For now this is not supported.
* If we do not use split normals, we do not generate anything fancy! */
BLI_assert(use_split_normals || !(r_lnors_spacearr));
@@ -1636,9 +1591,6 @@ void BKE_mesh_normals_loop_split(const MVert *mverts,
const bool is_poly_flat = ((mp->flag & ME_SMOOTH) == 0);
for (; ml_index < ml_index_end; ml_index++) {
- if (r_loop_to_poly) {
- r_loop_to_poly[ml_index] = mp_index;
- }
if (is_poly_flat) {
copy_v3_v3(r_loopnors[ml_index], polynors[mp_index]);
}
@@ -1668,9 +1620,15 @@ void BKE_mesh_normals_loop_split(const MVert *mverts,
size_t(numEdges), sizeof(*edge_to_loops), __func__);
/* Simple mapping from a loop to its polygon index. */
- int *loop_to_poly = r_loop_to_poly ? r_loop_to_poly :
- (int *)MEM_malloc_arrayN(
- size_t(numLoops), sizeof(*loop_to_poly), __func__);
+ Span<int> loop_to_poly;
+ Array<int> local_loop_to_poly_map;
+ if (loop_to_poly_map) {
+ loop_to_poly = {loop_to_poly_map, numLoops};
+ }
+ else {
+ local_loop_to_poly_map = mesh_topology::build_loop_to_poly_map({mpolys, numPolys}, numLoops);
+ loop_to_poly = local_loop_to_poly_map;
+ }
/* When using custom loop normals, disable the angle feature! */
const bool check_angle = (split_angle < float(M_PI)) && (clnors_data == nullptr);
@@ -1678,7 +1636,7 @@ void BKE_mesh_normals_loop_split(const MVert *mverts,
MLoopNorSpaceArray _lnors_spacearr = {nullptr};
#ifdef DEBUG_TIME
- TIMEIT_START_AVERAGED(BKE_mesh_normals_loop_split);
+ SCOPED_TIMER_AVERAGED(__func__);
#endif
if (!r_lnors_spacearr && clnors_data) {
@@ -1692,19 +1650,16 @@ void BKE_mesh_normals_loop_split(const MVert *mverts,
/* Init data common to all tasks. */
LoopSplitTaskDataCommon common_data;
common_data.lnors_spacearr = r_lnors_spacearr;
- common_data.loopnors = r_loopnors;
- common_data.clnors_data = clnors_data;
- common_data.mverts = mverts;
- common_data.medges = medges;
- common_data.mloops = mloops;
- common_data.mpolys = mpolys;
+ common_data.loopnors = {reinterpret_cast<float3 *>(r_loopnors), numLoops};
+ common_data.clnors_data = {reinterpret_cast<short2 *>(clnors_data), clnors_data ? numLoops : 0};
+ common_data.verts = {mverts, numVerts};
+ common_data.edges = {const_cast<MEdge *>(medges), numEdges};
+ common_data.polys = {mpolys, numPolys};
+ common_data.loops = {mloops, numLoops};
common_data.edge_to_loops = edge_to_loops;
common_data.loop_to_poly = loop_to_poly;
- common_data.polynors = polynors;
- common_data.vert_normals = vert_normals;
- common_data.numEdges = numEdges;
- common_data.numLoops = numLoops;
- common_data.numPolys = numPolys;
+ common_data.polynors = {reinterpret_cast<const float3 *>(polynors), numPolys};
+ common_data.vert_normals = {reinterpret_cast<const float3 *>(vert_normals), numVerts};
/* This first loop check which edges are actually smooth, and compute edge vectors. */
mesh_edges_sharp_tag(&common_data, check_angle, split_angle, false);
@@ -1724,19 +1679,12 @@ void BKE_mesh_normals_loop_split(const MVert *mverts,
}
MEM_freeN(edge_to_loops);
- if (!r_loop_to_poly) {
- MEM_freeN(loop_to_poly);
- }
if (r_lnors_spacearr) {
if (r_lnors_spacearr == &_lnors_spacearr) {
BKE_lnor_spacearr_free(r_lnors_spacearr);
}
}
-
-#ifdef DEBUG_TIME
- TIMEIT_END_AVERAGED(BKE_mesh_normals_loop_split);
-#endif
}
#undef INDEX_UNSET
@@ -1766,6 +1714,8 @@ static void mesh_normals_loop_custom_set(const MVert *mverts,
short (*r_clnors_data)[2],
const bool use_vertices)
{
+ using namespace blender;
+ using namespace blender::bke;
/* We *may* make that poor #BKE_mesh_normals_loop_split() even more complex by making it handling
* that feature too, would probably be more efficient in absolute.
* However, this function *is not* performance-critical, since it is mostly expected to be called
@@ -1775,7 +1725,8 @@ static void mesh_normals_loop_custom_set(const MVert *mverts,
MLoopNorSpaceArray lnors_spacearr = {nullptr};
BitVector<> done_loops(numLoops, false);
float(*lnors)[3] = (float(*)[3])MEM_calloc_arrayN(size_t(numLoops), sizeof(*lnors), __func__);
- int *loop_to_poly = (int *)MEM_malloc_arrayN(size_t(numLoops), sizeof(int), __func__);
+ const Array<int> loop_to_poly = mesh_topology::build_loop_to_poly_map({mpolys, numPolys},
+ numLoops);
/* In this case we always consider split nors as ON,
* and do not want to use angle to define smooth fans! */
const bool use_split_normals = true;
@@ -1797,9 +1748,9 @@ static void mesh_normals_loop_custom_set(const MVert *mverts,
numPolys,
use_split_normals,
split_angle,
+ loop_to_poly.data(),
&lnors_spacearr,
- nullptr,
- loop_to_poly);
+ nullptr);
/* Set all given zero vectors to their default value. */
if (use_vertices) {
@@ -1920,9 +1871,9 @@ static void mesh_normals_loop_custom_set(const MVert *mverts,
numPolys,
use_split_normals,
split_angle,
+ loop_to_poly.data(),
&lnors_spacearr,
- nullptr,
- loop_to_poly);
+ nullptr);
}
else {
done_loops.fill(true);
@@ -1984,7 +1935,6 @@ static void mesh_normals_loop_custom_set(const MVert *mverts,
}
MEM_freeN(lnors);
- MEM_freeN(loop_to_poly);
BKE_lnor_spacearr_free(&lnors_spacearr);
}