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_evaluate.c')
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c6275
1 files changed, 3263 insertions, 3012 deletions
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index 1e4c9a6950a..2ef1a009321 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -74,14 +74,14 @@ static CLG_LogRef LOG = {"bke.mesh_evaluate"};
*/
static void mesh_calc_normals_vert_fallback(MVert *mverts, int numVerts)
{
- int i;
- for (i = 0; i < numVerts; i++) {
- MVert *mv = &mverts[i];
- float no[3];
+ int i;
+ for (i = 0; i < numVerts; i++) {
+ MVert *mv = &mverts[i];
+ float no[3];
- normalize_v3_v3(no, mv->co);
- normal_float_to_short_v3(mv->no, no);
- }
+ normalize_v3_v3(no, mv->co);
+ normal_float_to_short_v3(mv->no, no);
+ }
}
/* TODO(Sybren): we can probably rename this to BKE_mesh_calc_normals_mapping(),
@@ -89,265 +89,302 @@ static void mesh_calc_normals_vert_fallback(MVert *mverts, int numVerts)
* called anywhere. */
void BKE_mesh_calc_normals_mapping_simple(struct Mesh *mesh)
{
- const bool only_face_normals = CustomData_is_referenced_layer(&mesh->vdata, CD_MVERT);
+ const bool only_face_normals = CustomData_is_referenced_layer(&mesh->vdata, CD_MVERT);
- BKE_mesh_calc_normals_mapping_ex(
- mesh->mvert, mesh->totvert,
- mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, NULL,
- mesh->mface, mesh->totface, NULL, NULL,
- only_face_normals);
+ BKE_mesh_calc_normals_mapping_ex(mesh->mvert,
+ mesh->totvert,
+ mesh->mloop,
+ mesh->mpoly,
+ mesh->totloop,
+ mesh->totpoly,
+ NULL,
+ mesh->mface,
+ mesh->totface,
+ NULL,
+ NULL,
+ only_face_normals);
}
/* Calculate vertex and face normals, face normals are returned in *r_faceNors if non-NULL
* and vertex normals are stored in actual mverts.
*/
-void BKE_mesh_calc_normals_mapping(
- MVert *mverts, int numVerts,
- const MLoop *mloop, const MPoly *mpolys, int numLoops, int numPolys, float (*r_polyNors)[3],
- const MFace *mfaces, int numFaces, const int *origIndexFace, float (*r_faceNors)[3])
-{
- BKE_mesh_calc_normals_mapping_ex(
- mverts, numVerts, mloop, mpolys,
- numLoops, numPolys, r_polyNors, mfaces, numFaces,
- origIndexFace, r_faceNors, false);
+void BKE_mesh_calc_normals_mapping(MVert *mverts,
+ int numVerts,
+ const MLoop *mloop,
+ const MPoly *mpolys,
+ int numLoops,
+ int numPolys,
+ float (*r_polyNors)[3],
+ const MFace *mfaces,
+ int numFaces,
+ const int *origIndexFace,
+ float (*r_faceNors)[3])
+{
+ BKE_mesh_calc_normals_mapping_ex(mverts,
+ numVerts,
+ mloop,
+ mpolys,
+ numLoops,
+ numPolys,
+ r_polyNors,
+ mfaces,
+ numFaces,
+ origIndexFace,
+ r_faceNors,
+ false);
}
/* extended version of 'BKE_mesh_calc_normals_poly' with option not to calc vertex normals */
-void BKE_mesh_calc_normals_mapping_ex(
- MVert *mverts, int numVerts,
- const MLoop *mloop, const MPoly *mpolys,
- int numLoops, int numPolys, float (*r_polyNors)[3],
- const MFace *mfaces, int numFaces, const int *origIndexFace, float (*r_faceNors)[3],
- const bool only_face_normals)
-{
- float (*pnors)[3] = r_polyNors, (*fnors)[3] = r_faceNors;
- int i;
- const MFace *mf;
- const MPoly *mp;
-
- if (numPolys == 0) {
- if (only_face_normals == false) {
- mesh_calc_normals_vert_fallback(mverts, numVerts);
- }
- return;
- }
-
- /* if we are not calculating verts and no verts were passes then we have nothing to do */
- if ((only_face_normals == true) && (r_polyNors == NULL) && (r_faceNors == NULL)) {
- CLOG_WARN(&LOG, "called with nothing to do");
- return;
- }
-
- if (!pnors) pnors = MEM_calloc_arrayN((size_t)numPolys, sizeof(float[3]), __func__);
- /* if (!fnors) fnors = MEM_calloc_arrayN(numFaces, sizeof(float[3]), "face nors mesh.c"); */ /* NO NEED TO ALLOC YET */
-
-
- if (only_face_normals == false) {
- /* vertex normals are optional, they require some extra calculations,
- * so make them optional */
- BKE_mesh_calc_normals_poly(mverts, NULL, numVerts, mloop, mpolys, numLoops, numPolys, pnors, false);
- }
- else {
- /* only calc poly normals */
- mp = mpolys;
- for (i = 0; i < numPolys; i++, mp++) {
- BKE_mesh_calc_poly_normal(mp, mloop + mp->loopstart, mverts, pnors[i]);
- }
- }
-
- if (origIndexFace &&
- /* fnors == r_faceNors */ /* NO NEED TO ALLOC YET */
- fnors != NULL &&
- numFaces)
- {
- mf = mfaces;
- for (i = 0; i < numFaces; i++, mf++, origIndexFace++) {
- if (*origIndexFace < numPolys) {
- copy_v3_v3(fnors[i], pnors[*origIndexFace]);
- }
- else {
- /* eek, we're not corresponding to polys */
- CLOG_ERROR(&LOG, "tessellation face indices are incorrect. normals may look bad.");
- }
- }
- }
-
- if (pnors != r_polyNors) MEM_freeN(pnors);
- /* if (fnors != r_faceNors) MEM_freeN(fnors); */ /* NO NEED TO ALLOC YET */
-
- fnors = pnors = NULL;
-
+void BKE_mesh_calc_normals_mapping_ex(MVert *mverts,
+ int numVerts,
+ const MLoop *mloop,
+ const MPoly *mpolys,
+ int numLoops,
+ int numPolys,
+ float (*r_polyNors)[3],
+ const MFace *mfaces,
+ int numFaces,
+ const int *origIndexFace,
+ float (*r_faceNors)[3],
+ const bool only_face_normals)
+{
+ float(*pnors)[3] = r_polyNors, (*fnors)[3] = r_faceNors;
+ int i;
+ const MFace *mf;
+ const MPoly *mp;
+
+ if (numPolys == 0) {
+ if (only_face_normals == false) {
+ mesh_calc_normals_vert_fallback(mverts, numVerts);
+ }
+ return;
+ }
+
+ /* if we are not calculating verts and no verts were passes then we have nothing to do */
+ if ((only_face_normals == true) && (r_polyNors == NULL) && (r_faceNors == NULL)) {
+ CLOG_WARN(&LOG, "called with nothing to do");
+ return;
+ }
+
+ if (!pnors)
+ pnors = MEM_calloc_arrayN((size_t)numPolys, sizeof(float[3]), __func__);
+ /* if (!fnors) fnors = MEM_calloc_arrayN(numFaces, sizeof(float[3]), "face nors mesh.c"); */ /* NO NEED TO ALLOC YET */
+
+ if (only_face_normals == false) {
+ /* vertex normals are optional, they require some extra calculations,
+ * so make them optional */
+ BKE_mesh_calc_normals_poly(
+ mverts, NULL, numVerts, mloop, mpolys, numLoops, numPolys, pnors, false);
+ }
+ else {
+ /* only calc poly normals */
+ mp = mpolys;
+ for (i = 0; i < numPolys; i++, mp++) {
+ BKE_mesh_calc_poly_normal(mp, mloop + mp->loopstart, mverts, pnors[i]);
+ }
+ }
+
+ if (origIndexFace &&
+ /* fnors == r_faceNors */ /* NO NEED TO ALLOC YET */
+ fnors != NULL &&
+ numFaces) {
+ mf = mfaces;
+ for (i = 0; i < numFaces; i++, mf++, origIndexFace++) {
+ if (*origIndexFace < numPolys) {
+ copy_v3_v3(fnors[i], pnors[*origIndexFace]);
+ }
+ else {
+ /* eek, we're not corresponding to polys */
+ CLOG_ERROR(&LOG, "tessellation face indices are incorrect. normals may look bad.");
+ }
+ }
+ }
+
+ if (pnors != r_polyNors)
+ MEM_freeN(pnors);
+ /* if (fnors != r_faceNors) MEM_freeN(fnors); */ /* NO NEED TO ALLOC YET */
+
+ fnors = pnors = NULL;
}
typedef struct MeshCalcNormalsData {
- const MPoly *mpolys;
- const MLoop *mloop;
- MVert *mverts;
- float (*pnors)[3];
- float (*lnors_weighted)[3];
- float (*vnors)[3];
+ const MPoly *mpolys;
+ const MLoop *mloop;
+ MVert *mverts;
+ float (*pnors)[3];
+ float (*lnors_weighted)[3];
+ float (*vnors)[3];
} MeshCalcNormalsData;
-static void mesh_calc_normals_poly_cb(
- void *__restrict userdata,
- const int pidx,
- const ParallelRangeTLS *__restrict UNUSED(tls))
-{
- MeshCalcNormalsData *data = userdata;
- const MPoly *mp = &data->mpolys[pidx];
-
- BKE_mesh_calc_poly_normal(mp, data->mloop + mp->loopstart, data->mverts, data->pnors[pidx]);
-}
-
-static void mesh_calc_normals_poly_prepare_cb(
- void *__restrict userdata,
- const int pidx,
- const ParallelRangeTLS *__restrict UNUSED(tls))
-{
- MeshCalcNormalsData *data = userdata;
- const MPoly *mp = &data->mpolys[pidx];
- const MLoop *ml = &data->mloop[mp->loopstart];
- const MVert *mverts = data->mverts;
-
- float pnor_temp[3];
- float *pnor = data->pnors ? data->pnors[pidx] : pnor_temp;
- float (*lnors_weighted)[3] = data->lnors_weighted;
-
- const int nverts = mp->totloop;
- float (*edgevecbuf)[3] = BLI_array_alloca(edgevecbuf, (size_t)nverts);
- int i;
-
- /* Polygon Normal and edge-vector */
- /* inline version of #BKE_mesh_calc_poly_normal, also does edge-vectors */
- {
- int i_prev = nverts - 1;
- const float *v_prev = mverts[ml[i_prev].v].co;
- const float *v_curr;
-
- zero_v3(pnor);
- /* Newell's Method */
- for (i = 0; i < nverts; i++) {
- v_curr = mverts[ml[i].v].co;
- add_newell_cross_v3_v3v3(pnor, v_prev, v_curr);
-
- /* Unrelated to normalize, calculate edge-vector */
- sub_v3_v3v3(edgevecbuf[i_prev], v_prev, v_curr);
- normalize_v3(edgevecbuf[i_prev]);
- i_prev = i;
-
- v_prev = v_curr;
- }
- if (UNLIKELY(normalize_v3(pnor) == 0.0f)) {
- pnor[2] = 1.0f; /* other axes set to 0.0 */
- }
- }
-
- /* accumulate angle weighted face normal */
- /* inline version of #accumulate_vertex_normals_poly_v3,
- * split between this threaded callback and #mesh_calc_normals_poly_accum_cb. */
- {
- const float *prev_edge = edgevecbuf[nverts - 1];
-
- for (i = 0; i < nverts; i++) {
- const int lidx = mp->loopstart + i;
- const float *cur_edge = edgevecbuf[i];
-
- /* calculate angle between the two poly edges incident on
- * this vertex */
- const float fac = saacos(-dot_v3v3(cur_edge, prev_edge));
-
- /* Store for later accumulation */
- mul_v3_v3fl(lnors_weighted[lidx], pnor, fac);
-
- prev_edge = cur_edge;
- }
- }
-}
-
-static void mesh_calc_normals_poly_finalize_cb(
- void *__restrict userdata,
- const int vidx,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void mesh_calc_normals_poly_cb(void *__restrict userdata,
+ const int pidx,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- MeshCalcNormalsData *data = userdata;
-
- MVert *mv = &data->mverts[vidx];
- float *no = data->vnors[vidx];
-
- if (UNLIKELY(normalize_v3(no) == 0.0f)) {
- /* following Mesh convention; we use vertex coordinate itself for normal in this case */
- normalize_v3_v3(no, mv->co);
- }
+ MeshCalcNormalsData *data = userdata;
+ const MPoly *mp = &data->mpolys[pidx];
- normal_float_to_short_v3(mv->no, no);
+ BKE_mesh_calc_poly_normal(mp, data->mloop + mp->loopstart, data->mverts, data->pnors[pidx]);
}
-void BKE_mesh_calc_normals_poly(
- MVert *mverts, float (*r_vertnors)[3], int numVerts,
- const MLoop *mloop, const MPoly *mpolys,
- int numLoops, int numPolys, float (*r_polynors)[3],
- const bool only_face_normals)
+static void mesh_calc_normals_poly_prepare_cb(void *__restrict userdata,
+ const int pidx,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- float (*pnors)[3] = r_polynors;
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.min_iter_per_thread = 1024;
-
- if (only_face_normals) {
- BLI_assert((pnors != NULL) || (numPolys == 0));
- BLI_assert(r_vertnors == NULL);
+ MeshCalcNormalsData *data = userdata;
+ const MPoly *mp = &data->mpolys[pidx];
+ const MLoop *ml = &data->mloop[mp->loopstart];
+ const MVert *mverts = data->mverts;
- MeshCalcNormalsData data = {
- .mpolys = mpolys, .mloop = mloop, .mverts = mverts, .pnors = pnors,
- };
-
- BLI_task_parallel_range(0, numPolys, &data, mesh_calc_normals_poly_cb, &settings);
- return;
- }
-
- float (*vnors)[3] = r_vertnors;
- float (*lnors_weighted)[3] = MEM_malloc_arrayN((size_t)numLoops, sizeof(*lnors_weighted), __func__);
- bool free_vnors = false;
-
- /* first go through and calculate normals for all the polys */
- if (vnors == NULL) {
- vnors = MEM_calloc_arrayN((size_t)numVerts, sizeof(*vnors), __func__);
- free_vnors = true;
- }
- else {
- memset(vnors, 0, sizeof(*vnors) * (size_t)numVerts);
- }
-
- MeshCalcNormalsData data = {
- .mpolys = mpolys, .mloop = mloop, .mverts = mverts,
- .pnors = pnors, .lnors_weighted = lnors_weighted, .vnors = vnors,
- };
+ float pnor_temp[3];
+ float *pnor = data->pnors ? data->pnors[pidx] : pnor_temp;
+ float(*lnors_weighted)[3] = data->lnors_weighted;
- /* Compute poly normals, and prepare weighted loop normals. */
- BLI_task_parallel_range(0, numPolys, &data, mesh_calc_normals_poly_prepare_cb, &settings);
+ const int nverts = mp->totloop;
+ float(*edgevecbuf)[3] = BLI_array_alloca(edgevecbuf, (size_t)nverts);
+ int i;
- /* Actually accumulate weighted loop normals into vertex ones. */
- /* Unfortunately, not possible to thread that (not in a reasonable, totally lock- and barrier-free fashion),
- * since several loops will point to the same vertex... */
- for (int lidx = 0; lidx < numLoops; lidx++) {
- add_v3_v3(vnors[mloop[lidx].v], data.lnors_weighted[lidx]);
- }
+ /* Polygon Normal and edge-vector */
+ /* inline version of #BKE_mesh_calc_poly_normal, also does edge-vectors */
+ {
+ int i_prev = nverts - 1;
+ const float *v_prev = mverts[ml[i_prev].v].co;
+ const float *v_curr;
+
+ zero_v3(pnor);
+ /* Newell's Method */
+ for (i = 0; i < nverts; i++) {
+ v_curr = mverts[ml[i].v].co;
+ add_newell_cross_v3_v3v3(pnor, v_prev, v_curr);
+
+ /* Unrelated to normalize, calculate edge-vector */
+ sub_v3_v3v3(edgevecbuf[i_prev], v_prev, v_curr);
+ normalize_v3(edgevecbuf[i_prev]);
+ i_prev = i;
+
+ v_prev = v_curr;
+ }
+ if (UNLIKELY(normalize_v3(pnor) == 0.0f)) {
+ pnor[2] = 1.0f; /* other axes set to 0.0 */
+ }
+ }
+
+ /* accumulate angle weighted face normal */
+ /* inline version of #accumulate_vertex_normals_poly_v3,
+ * split between this threaded callback and #mesh_calc_normals_poly_accum_cb. */
+ {
+ const float *prev_edge = edgevecbuf[nverts - 1];
+
+ for (i = 0; i < nverts; i++) {
+ const int lidx = mp->loopstart + i;
+ const float *cur_edge = edgevecbuf[i];
+
+ /* calculate angle between the two poly edges incident on
+ * this vertex */
+ const float fac = saacos(-dot_v3v3(cur_edge, prev_edge));
+
+ /* Store for later accumulation */
+ mul_v3_v3fl(lnors_weighted[lidx], pnor, fac);
+
+ prev_edge = cur_edge;
+ }
+ }
+}
+
+static void mesh_calc_normals_poly_finalize_cb(void *__restrict userdata,
+ const int vidx,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ MeshCalcNormalsData *data = userdata;
+
+ MVert *mv = &data->mverts[vidx];
+ float *no = data->vnors[vidx];
+
+ if (UNLIKELY(normalize_v3(no) == 0.0f)) {
+ /* following Mesh convention; we use vertex coordinate itself for normal in this case */
+ normalize_v3_v3(no, mv->co);
+ }
+
+ normal_float_to_short_v3(mv->no, no);
+}
+
+void BKE_mesh_calc_normals_poly(MVert *mverts,
+ float (*r_vertnors)[3],
+ int numVerts,
+ const MLoop *mloop,
+ const MPoly *mpolys,
+ int numLoops,
+ int numPolys,
+ float (*r_polynors)[3],
+ const bool only_face_normals)
+{
+ float(*pnors)[3] = r_polynors;
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = 1024;
+
+ if (only_face_normals) {
+ BLI_assert((pnors != NULL) || (numPolys == 0));
+ BLI_assert(r_vertnors == NULL);
+
+ MeshCalcNormalsData data = {
+ .mpolys = mpolys,
+ .mloop = mloop,
+ .mverts = mverts,
+ .pnors = pnors,
+ };
+
+ BLI_task_parallel_range(0, numPolys, &data, mesh_calc_normals_poly_cb, &settings);
+ return;
+ }
+
+ float(*vnors)[3] = r_vertnors;
+ float(*lnors_weighted)[3] = MEM_malloc_arrayN(
+ (size_t)numLoops, sizeof(*lnors_weighted), __func__);
+ bool free_vnors = false;
+
+ /* first go through and calculate normals for all the polys */
+ if (vnors == NULL) {
+ vnors = MEM_calloc_arrayN((size_t)numVerts, sizeof(*vnors), __func__);
+ free_vnors = true;
+ }
+ else {
+ memset(vnors, 0, sizeof(*vnors) * (size_t)numVerts);
+ }
+
+ MeshCalcNormalsData data = {
+ .mpolys = mpolys,
+ .mloop = mloop,
+ .mverts = mverts,
+ .pnors = pnors,
+ .lnors_weighted = lnors_weighted,
+ .vnors = vnors,
+ };
+
+ /* Compute poly normals, and prepare weighted loop normals. */
+ BLI_task_parallel_range(0, numPolys, &data, mesh_calc_normals_poly_prepare_cb, &settings);
+
+ /* Actually accumulate weighted loop normals into vertex ones. */
+ /* Unfortunately, not possible to thread that (not in a reasonable, totally lock- and barrier-free fashion),
+ * since several loops will point to the same vertex... */
+ for (int lidx = 0; lidx < numLoops; lidx++) {
+ add_v3_v3(vnors[mloop[lidx].v], data.lnors_weighted[lidx]);
+ }
+
+ /* Normalize and validate computed vertex normals. */
+ BLI_task_parallel_range(0, numVerts, &data, mesh_calc_normals_poly_finalize_cb, &settings);
- /* Normalize and validate computed vertex normals. */
- BLI_task_parallel_range(0, numVerts, &data, mesh_calc_normals_poly_finalize_cb, &settings);
-
- if (free_vnors) {
- MEM_freeN(vnors);
- }
- MEM_freeN(lnors_weighted);
+ if (free_vnors) {
+ MEM_freeN(vnors);
+ }
+ MEM_freeN(lnors_weighted);
}
void BKE_mesh_ensure_normals(Mesh *mesh)
{
- if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) {
- BKE_mesh_calc_normals(mesh);
- }
- BLI_assert((mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) == 0);
+ if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) {
+ BKE_mesh_calc_normals(mesh);
+ }
+ BLI_assert((mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) == 0);
}
/**
@@ -355,185 +392,210 @@ void BKE_mesh_ensure_normals(Mesh *mesh)
*/
void BKE_mesh_ensure_normals_for_display(Mesh *mesh)
{
- float (*poly_nors)[3] = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
- const bool do_vert_normals = (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) != 0;
- const bool do_poly_normals = (mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL || poly_nors == NULL);
+ float(*poly_nors)[3] = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
+ const bool do_vert_normals = (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) != 0;
+ const bool do_poly_normals = (mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL || poly_nors == NULL);
- if (do_vert_normals || do_poly_normals) {
- const bool do_add_poly_nors_cddata = (poly_nors == NULL);
- if (do_add_poly_nors_cddata) {
- poly_nors = MEM_malloc_arrayN((size_t)mesh->totpoly, sizeof(*poly_nors), __func__);
- }
+ if (do_vert_normals || do_poly_normals) {
+ const bool do_add_poly_nors_cddata = (poly_nors == NULL);
+ if (do_add_poly_nors_cddata) {
+ poly_nors = MEM_malloc_arrayN((size_t)mesh->totpoly, sizeof(*poly_nors), __func__);
+ }
- /* calculate poly/vert normals */
- BKE_mesh_calc_normals_poly(
- mesh->mvert, NULL, mesh->totvert, mesh->mloop, mesh->mpoly,
- mesh->totloop, mesh->totpoly, poly_nors,
- !do_vert_normals);
+ /* calculate poly/vert normals */
+ BKE_mesh_calc_normals_poly(mesh->mvert,
+ NULL,
+ mesh->totvert,
+ mesh->mloop,
+ mesh->mpoly,
+ mesh->totloop,
+ mesh->totpoly,
+ poly_nors,
+ !do_vert_normals);
- if (do_add_poly_nors_cddata) {
- CustomData_add_layer(&mesh->pdata, CD_NORMAL, CD_ASSIGN, poly_nors, mesh->totpoly);
- }
+ if (do_add_poly_nors_cddata) {
+ CustomData_add_layer(&mesh->pdata, CD_NORMAL, CD_ASSIGN, poly_nors, mesh->totpoly);
+ }
- mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
- mesh->runtime.cd_dirty_poly &= ~CD_MASK_NORMAL;
- }
+ mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
+ mesh->runtime.cd_dirty_poly &= ~CD_MASK_NORMAL;
+ }
}
/* Note that this does not update the CD_NORMAL layer, but does update the normals in the CD_MVERT layer. */
void BKE_mesh_calc_normals(Mesh *mesh)
{
#ifdef DEBUG_TIME
- TIMEIT_START_AVERAGED(BKE_mesh_calc_normals);
+ TIMEIT_START_AVERAGED(BKE_mesh_calc_normals);
#endif
- BKE_mesh_calc_normals_poly(
- mesh->mvert, NULL, mesh->totvert,
- mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly,
- NULL, false);
+ BKE_mesh_calc_normals_poly(mesh->mvert,
+ NULL,
+ mesh->totvert,
+ mesh->mloop,
+ mesh->mpoly,
+ mesh->totloop,
+ mesh->totpoly,
+ NULL,
+ false);
#ifdef DEBUG_TIME
- TIMEIT_END_AVERAGED(BKE_mesh_calc_normals);
+ TIMEIT_END_AVERAGED(BKE_mesh_calc_normals);
#endif
- mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
+ mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
}
void BKE_mesh_calc_normals_tessface(
- MVert *mverts, int numVerts,
- const MFace *mfaces, int numFaces,
- float (*r_faceNors)[3])
-{
- float (*tnorms)[3] = MEM_calloc_arrayN((size_t)numVerts, sizeof(*tnorms), "tnorms");
- float (*fnors)[3] = (r_faceNors) ? r_faceNors : MEM_calloc_arrayN((size_t)numFaces, sizeof(*fnors), "meshnormals");
- int i;
-
- if (!tnorms || !fnors) {
- goto cleanup;
- }
-
- for (i = 0; i < numFaces; i++) {
- const MFace *mf = &mfaces[i];
- float *f_no = fnors[i];
- float *n4 = (mf->v4) ? tnorms[mf->v4] : NULL;
- const float *c4 = (mf->v4) ? mverts[mf->v4].co : NULL;
-
- if (mf->v4)
- normal_quad_v3(f_no, mverts[mf->v1].co, mverts[mf->v2].co, mverts[mf->v3].co, mverts[mf->v4].co);
- else
- normal_tri_v3(f_no, mverts[mf->v1].co, mverts[mf->v2].co, mverts[mf->v3].co);
-
- accumulate_vertex_normals_v3(
- tnorms[mf->v1], tnorms[mf->v2], tnorms[mf->v3], n4,
- f_no, mverts[mf->v1].co, mverts[mf->v2].co, mverts[mf->v3].co, c4);
- }
-
- /* following Mesh convention; we use vertex coordinate itself for normal in this case */
- for (i = 0; i < numVerts; i++) {
- MVert *mv = &mverts[i];
- float *no = tnorms[i];
-
- if (UNLIKELY(normalize_v3(no) == 0.0f)) {
- normalize_v3_v3(no, mv->co);
- }
-
- normal_float_to_short_v3(mv->no, no);
- }
+ MVert *mverts, int numVerts, const MFace *mfaces, int numFaces, float (*r_faceNors)[3])
+{
+ float(*tnorms)[3] = MEM_calloc_arrayN((size_t)numVerts, sizeof(*tnorms), "tnorms");
+ float(*fnors)[3] = (r_faceNors) ?
+ r_faceNors :
+ MEM_calloc_arrayN((size_t)numFaces, sizeof(*fnors), "meshnormals");
+ int i;
+
+ if (!tnorms || !fnors) {
+ goto cleanup;
+ }
+
+ for (i = 0; i < numFaces; i++) {
+ const MFace *mf = &mfaces[i];
+ float *f_no = fnors[i];
+ float *n4 = (mf->v4) ? tnorms[mf->v4] : NULL;
+ const float *c4 = (mf->v4) ? mverts[mf->v4].co : NULL;
+
+ if (mf->v4)
+ normal_quad_v3(
+ f_no, mverts[mf->v1].co, mverts[mf->v2].co, mverts[mf->v3].co, mverts[mf->v4].co);
+ else
+ normal_tri_v3(f_no, mverts[mf->v1].co, mverts[mf->v2].co, mverts[mf->v3].co);
+
+ accumulate_vertex_normals_v3(tnorms[mf->v1],
+ tnorms[mf->v2],
+ tnorms[mf->v3],
+ n4,
+ f_no,
+ mverts[mf->v1].co,
+ mverts[mf->v2].co,
+ mverts[mf->v3].co,
+ c4);
+ }
+
+ /* following Mesh convention; we use vertex coordinate itself for normal in this case */
+ for (i = 0; i < numVerts; i++) {
+ MVert *mv = &mverts[i];
+ float *no = tnorms[i];
+
+ if (UNLIKELY(normalize_v3(no) == 0.0f)) {
+ normalize_v3_v3(no, mv->co);
+ }
+
+ normal_float_to_short_v3(mv->no, no);
+ }
cleanup:
- MEM_freeN(tnorms);
-
- if (fnors != r_faceNors)
- MEM_freeN(fnors);
-}
-
-void BKE_mesh_calc_normals_looptri(
- MVert *mverts, int numVerts,
- const MLoop *mloop,
- const MLoopTri *looptri, int looptri_num,
- float (*r_tri_nors)[3])
-{
- float (*tnorms)[3] = MEM_calloc_arrayN((size_t)numVerts, sizeof(*tnorms), "tnorms");
- float (*fnors)[3] = (r_tri_nors) ? r_tri_nors : MEM_calloc_arrayN((size_t)looptri_num, sizeof(*fnors), "meshnormals");
- int i;
-
- if (!tnorms || !fnors) {
- goto cleanup;
- }
-
- for (i = 0; i < looptri_num; i++) {
- const MLoopTri *lt = &looptri[i];
- float *f_no = fnors[i];
- const unsigned int vtri[3] = {
- mloop[lt->tri[0]].v,
- mloop[lt->tri[1]].v,
- mloop[lt->tri[2]].v,
- };
-
- normal_tri_v3(
- f_no,
- mverts[vtri[0]].co, mverts[vtri[1]].co, mverts[vtri[2]].co);
-
- accumulate_vertex_normals_tri_v3(
- tnorms[vtri[0]], tnorms[vtri[1]], tnorms[vtri[2]],
- f_no, mverts[vtri[0]].co, mverts[vtri[1]].co, mverts[vtri[2]].co);
- }
-
- /* following Mesh convention; we use vertex coordinate itself for normal in this case */
- for (i = 0; i < numVerts; i++) {
- MVert *mv = &mverts[i];
- float *no = tnorms[i];
-
- if (UNLIKELY(normalize_v3(no) == 0.0f)) {
- normalize_v3_v3(no, mv->co);
- }
-
- normal_float_to_short_v3(mv->no, no);
- }
+ MEM_freeN(tnorms);
+
+ if (fnors != r_faceNors)
+ MEM_freeN(fnors);
+}
+
+void BKE_mesh_calc_normals_looptri(MVert *mverts,
+ int numVerts,
+ const MLoop *mloop,
+ const MLoopTri *looptri,
+ int looptri_num,
+ float (*r_tri_nors)[3])
+{
+ float(*tnorms)[3] = MEM_calloc_arrayN((size_t)numVerts, sizeof(*tnorms), "tnorms");
+ float(*fnors)[3] = (r_tri_nors) ?
+ r_tri_nors :
+ MEM_calloc_arrayN((size_t)looptri_num, sizeof(*fnors), "meshnormals");
+ int i;
+
+ if (!tnorms || !fnors) {
+ goto cleanup;
+ }
+
+ for (i = 0; i < looptri_num; i++) {
+ const MLoopTri *lt = &looptri[i];
+ float *f_no = fnors[i];
+ const unsigned int vtri[3] = {
+ mloop[lt->tri[0]].v,
+ mloop[lt->tri[1]].v,
+ mloop[lt->tri[2]].v,
+ };
+
+ normal_tri_v3(f_no, mverts[vtri[0]].co, mverts[vtri[1]].co, mverts[vtri[2]].co);
+
+ accumulate_vertex_normals_tri_v3(tnorms[vtri[0]],
+ tnorms[vtri[1]],
+ tnorms[vtri[2]],
+ f_no,
+ mverts[vtri[0]].co,
+ mverts[vtri[1]].co,
+ mverts[vtri[2]].co);
+ }
+
+ /* following Mesh convention; we use vertex coordinate itself for normal in this case */
+ for (i = 0; i < numVerts; i++) {
+ MVert *mv = &mverts[i];
+ float *no = tnorms[i];
+
+ if (UNLIKELY(normalize_v3(no) == 0.0f)) {
+ normalize_v3_v3(no, mv->co);
+ }
+
+ normal_float_to_short_v3(mv->no, no);
+ }
cleanup:
- MEM_freeN(tnorms);
+ MEM_freeN(tnorms);
- if (fnors != r_tri_nors)
- MEM_freeN(fnors);
+ if (fnors != r_tri_nors)
+ MEM_freeN(fnors);
}
-void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr, const int numLoops, const char data_type)
+void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr,
+ const int numLoops,
+ const char data_type)
{
- if (!(lnors_spacearr->lspacearr && lnors_spacearr->loops_pool)) {
- MemArena *mem;
+ if (!(lnors_spacearr->lspacearr && lnors_spacearr->loops_pool)) {
+ MemArena *mem;
- if (!lnors_spacearr->mem) {
- lnors_spacearr->mem = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
- }
- mem = lnors_spacearr->mem;
- lnors_spacearr->lspacearr = BLI_memarena_calloc(mem, sizeof(MLoopNorSpace *) * (size_t)numLoops);
- lnors_spacearr->loops_pool = BLI_memarena_alloc(mem, sizeof(LinkNode) * (size_t)numLoops);
+ if (!lnors_spacearr->mem) {
+ lnors_spacearr->mem = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+ }
+ mem = lnors_spacearr->mem;
+ lnors_spacearr->lspacearr = BLI_memarena_calloc(mem,
+ sizeof(MLoopNorSpace *) * (size_t)numLoops);
+ lnors_spacearr->loops_pool = BLI_memarena_alloc(mem, sizeof(LinkNode) * (size_t)numLoops);
- lnors_spacearr->num_spaces = 0;
- }
- BLI_assert(ELEM(data_type, MLNOR_SPACEARR_BMLOOP_PTR, MLNOR_SPACEARR_LOOP_INDEX));
- lnors_spacearr->data_type = data_type;
+ lnors_spacearr->num_spaces = 0;
+ }
+ BLI_assert(ELEM(data_type, MLNOR_SPACEARR_BMLOOP_PTR, MLNOR_SPACEARR_LOOP_INDEX));
+ lnors_spacearr->data_type = data_type;
}
void BKE_lnor_spacearr_clear(MLoopNorSpaceArray *lnors_spacearr)
{
- lnors_spacearr->num_spaces = 0;
- lnors_spacearr->lspacearr = NULL;
- lnors_spacearr->loops_pool = NULL;
- BLI_memarena_clear(lnors_spacearr->mem);
+ lnors_spacearr->num_spaces = 0;
+ lnors_spacearr->lspacearr = NULL;
+ lnors_spacearr->loops_pool = NULL;
+ BLI_memarena_clear(lnors_spacearr->mem);
}
void BKE_lnor_spacearr_free(MLoopNorSpaceArray *lnors_spacearr)
{
- lnors_spacearr->num_spaces = 0;
- lnors_spacearr->lspacearr = NULL;
- lnors_spacearr->loops_pool = NULL;
- BLI_memarena_free(lnors_spacearr->mem);
- lnors_spacearr->mem = NULL;
+ lnors_spacearr->num_spaces = 0;
+ lnors_spacearr->lspacearr = NULL;
+ lnors_spacearr->loops_pool = NULL;
+ BLI_memarena_free(lnors_spacearr->mem);
+ lnors_spacearr->mem = NULL;
}
MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr)
{
- lnors_spacearr->num_spaces++;
- return BLI_memarena_calloc(lnors_spacearr->mem, sizeof(MLoopNorSpace));
+ lnors_spacearr->num_spaces++;
+ return BLI_memarena_calloc(lnors_spacearr->mem, sizeof(MLoopNorSpace));
}
/* This threshold is a bit touchy (usual float precision issue), this value seems OK. */
@@ -543,69 +605,74 @@ MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr)
* Beware, this modifies ref_vec and other_vec in place!
* In case no valid space can be generated, ref_alpha and ref_beta are set to zero (which means 'use auto lnors').
*/
-void BKE_lnor_space_define(
- MLoopNorSpace *lnor_space, const float lnor[3],
- float vec_ref[3], float vec_other[3], BLI_Stack *edge_vectors)
-{
- const float pi2 = (float)M_PI * 2.0f;
- float tvec[3], dtp;
- const float dtp_ref = dot_v3v3(vec_ref, lnor);
- const float dtp_other = dot_v3v3(vec_other, lnor);
-
- if (UNLIKELY(fabsf(dtp_ref) >= LNOR_SPACE_TRIGO_THRESHOLD || fabsf(dtp_other) >= LNOR_SPACE_TRIGO_THRESHOLD)) {
- /* If vec_ref or vec_other are too much aligned with lnor, we can't build lnor space,
- * tag it as invalid and abort. */
- lnor_space->ref_alpha = lnor_space->ref_beta = 0.0f;
-
- if (edge_vectors) {
- BLI_stack_clear(edge_vectors);
- }
- return;
- }
-
- copy_v3_v3(lnor_space->vec_lnor, lnor);
-
- /* Compute ref alpha, average angle of all available edge vectors to lnor. */
- if (edge_vectors) {
- float alpha = 0.0f;
- int nbr = 0;
- while (!BLI_stack_is_empty(edge_vectors)) {
- const float *vec = BLI_stack_peek(edge_vectors);
- alpha += saacosf(dot_v3v3(vec, lnor));
- BLI_stack_discard(edge_vectors);
- nbr++;
- }
- /* Note: In theory, this could be 'nbr > 2', but there is one case where we only have two edges for
- * two loops: a smooth vertex with only two edges and two faces (our Monkey's nose has that, e.g.). */
- BLI_assert(nbr >= 2); /* This piece of code shall only be called for more than one loop... */
- lnor_space->ref_alpha = alpha / (float)nbr;
- }
- else {
- lnor_space->ref_alpha = (saacosf(dot_v3v3(vec_ref, lnor)) + saacosf(dot_v3v3(vec_other, lnor))) / 2.0f;
- }
-
- /* Project vec_ref on lnor's ortho plane. */
- mul_v3_v3fl(tvec, lnor, dtp_ref);
- sub_v3_v3(vec_ref, tvec);
- normalize_v3_v3(lnor_space->vec_ref, vec_ref);
-
- cross_v3_v3v3(tvec, lnor, lnor_space->vec_ref);
- normalize_v3_v3(lnor_space->vec_ortho, tvec);
-
- /* Project vec_other on lnor's ortho plane. */
- mul_v3_v3fl(tvec, lnor, dtp_other);
- sub_v3_v3(vec_other, tvec);
- normalize_v3(vec_other);
-
- /* Beta is angle between ref_vec and other_vec, around lnor. */
- dtp = dot_v3v3(lnor_space->vec_ref, vec_other);
- if (LIKELY(dtp < LNOR_SPACE_TRIGO_THRESHOLD)) {
- const float beta = saacos(dtp);
- lnor_space->ref_beta = (dot_v3v3(lnor_space->vec_ortho, vec_other) < 0.0f) ? pi2 - beta : beta;
- }
- else {
- lnor_space->ref_beta = pi2;
- }
+void BKE_lnor_space_define(MLoopNorSpace *lnor_space,
+ const float lnor[3],
+ float vec_ref[3],
+ float vec_other[3],
+ BLI_Stack *edge_vectors)
+{
+ const float pi2 = (float)M_PI * 2.0f;
+ float tvec[3], dtp;
+ const float dtp_ref = dot_v3v3(vec_ref, lnor);
+ const float dtp_other = dot_v3v3(vec_other, lnor);
+
+ if (UNLIKELY(fabsf(dtp_ref) >= LNOR_SPACE_TRIGO_THRESHOLD ||
+ fabsf(dtp_other) >= LNOR_SPACE_TRIGO_THRESHOLD)) {
+ /* If vec_ref or vec_other are too much aligned with lnor, we can't build lnor space,
+ * tag it as invalid and abort. */
+ lnor_space->ref_alpha = lnor_space->ref_beta = 0.0f;
+
+ if (edge_vectors) {
+ BLI_stack_clear(edge_vectors);
+ }
+ return;
+ }
+
+ copy_v3_v3(lnor_space->vec_lnor, lnor);
+
+ /* Compute ref alpha, average angle of all available edge vectors to lnor. */
+ if (edge_vectors) {
+ float alpha = 0.0f;
+ int nbr = 0;
+ while (!BLI_stack_is_empty(edge_vectors)) {
+ const float *vec = BLI_stack_peek(edge_vectors);
+ alpha += saacosf(dot_v3v3(vec, lnor));
+ BLI_stack_discard(edge_vectors);
+ nbr++;
+ }
+ /* Note: In theory, this could be 'nbr > 2', but there is one case where we only have two edges for
+ * two loops: a smooth vertex with only two edges and two faces (our Monkey's nose has that, e.g.). */
+ BLI_assert(nbr >= 2); /* This piece of code shall only be called for more than one loop... */
+ lnor_space->ref_alpha = alpha / (float)nbr;
+ }
+ else {
+ lnor_space->ref_alpha = (saacosf(dot_v3v3(vec_ref, lnor)) +
+ saacosf(dot_v3v3(vec_other, lnor))) /
+ 2.0f;
+ }
+
+ /* Project vec_ref on lnor's ortho plane. */
+ mul_v3_v3fl(tvec, lnor, dtp_ref);
+ sub_v3_v3(vec_ref, tvec);
+ normalize_v3_v3(lnor_space->vec_ref, vec_ref);
+
+ cross_v3_v3v3(tvec, lnor, lnor_space->vec_ref);
+ normalize_v3_v3(lnor_space->vec_ortho, tvec);
+
+ /* Project vec_other on lnor's ortho plane. */
+ mul_v3_v3fl(tvec, lnor, dtp_other);
+ sub_v3_v3(vec_other, tvec);
+ normalize_v3(vec_other);
+
+ /* Beta is angle between ref_vec and other_vec, around lnor. */
+ dtp = dot_v3v3(lnor_space->vec_ref, vec_other);
+ if (LIKELY(dtp < LNOR_SPACE_TRIGO_THRESHOLD)) {
+ const float beta = saacos(dtp);
+ lnor_space->ref_beta = (dot_v3v3(lnor_space->vec_ortho, vec_other) < 0.0f) ? pi2 - beta : beta;
+ }
+ else {
+ lnor_space->ref_beta = pi2;
+ }
}
/**
@@ -615,157 +682,166 @@ void BKE_lnor_space_define(
* If \a is_single is set, the BMLoop or loop index is directly stored in \a lnor_space->loops pointer (since there
* is only one loop in this fan), else it is added to the linked list of loops in the fan.
*/
-void BKE_lnor_space_add_loop(
- MLoopNorSpaceArray *lnors_spacearr, MLoopNorSpace *lnor_space,
- const int ml_index, void *bm_loop, const bool is_single)
-{
- BLI_assert((lnors_spacearr->data_type == MLNOR_SPACEARR_LOOP_INDEX && bm_loop == NULL) ||
- (lnors_spacearr->data_type == MLNOR_SPACEARR_BMLOOP_PTR && bm_loop != NULL));
-
- lnors_spacearr->lspacearr[ml_index] = lnor_space;
- if (bm_loop == NULL) {
- bm_loop = POINTER_FROM_INT(ml_index);
- }
- if (is_single) {
- BLI_assert(lnor_space->loops == NULL);
- lnor_space->flags |= MLNOR_SPACE_IS_SINGLE;
- lnor_space->loops = bm_loop;
- }
- else {
- BLI_assert((lnor_space->flags & MLNOR_SPACE_IS_SINGLE) == 0);
- BLI_linklist_prepend_nlink(&lnor_space->loops, bm_loop, &lnors_spacearr->loops_pool[ml_index]);
- }
+void BKE_lnor_space_add_loop(MLoopNorSpaceArray *lnors_spacearr,
+ MLoopNorSpace *lnor_space,
+ const int ml_index,
+ void *bm_loop,
+ const bool is_single)
+{
+ BLI_assert((lnors_spacearr->data_type == MLNOR_SPACEARR_LOOP_INDEX && bm_loop == NULL) ||
+ (lnors_spacearr->data_type == MLNOR_SPACEARR_BMLOOP_PTR && bm_loop != NULL));
+
+ lnors_spacearr->lspacearr[ml_index] = lnor_space;
+ if (bm_loop == NULL) {
+ bm_loop = POINTER_FROM_INT(ml_index);
+ }
+ if (is_single) {
+ BLI_assert(lnor_space->loops == NULL);
+ lnor_space->flags |= MLNOR_SPACE_IS_SINGLE;
+ lnor_space->loops = bm_loop;
+ }
+ else {
+ BLI_assert((lnor_space->flags & MLNOR_SPACE_IS_SINGLE) == 0);
+ BLI_linklist_prepend_nlink(&lnor_space->loops, bm_loop, &lnors_spacearr->loops_pool[ml_index]);
+ }
}
MINLINE float unit_short_to_float(const short val)
{
- return (float)val / (float)SHRT_MAX;
+ return (float)val / (float)SHRT_MAX;
}
MINLINE short unit_float_to_short(const float val)
{
- /* Rounding... */
- return (short)floorf(val * (float)SHRT_MAX + 0.5f);
-}
-
-void BKE_lnor_space_custom_data_to_normal(MLoopNorSpace *lnor_space, const short clnor_data[2], float r_custom_lnor[3])
-{
- /* NOP custom normal data or invalid lnor space, return. */
- if (clnor_data[0] == 0 || lnor_space->ref_alpha == 0.0f || lnor_space->ref_beta == 0.0f) {
- copy_v3_v3(r_custom_lnor, lnor_space->vec_lnor);
- return;
- }
-
- {
- /* TODO Check whether using sincosf() gives any noticeable benefit
- * (could not even get it working under linux though)! */
- const float pi2 = (float)(M_PI * 2.0);
- const float alphafac = unit_short_to_float(clnor_data[0]);
- const float alpha = (alphafac > 0.0f ? lnor_space->ref_alpha : pi2 - lnor_space->ref_alpha) * alphafac;
- const float betafac = unit_short_to_float(clnor_data[1]);
-
- mul_v3_v3fl(r_custom_lnor, lnor_space->vec_lnor, cosf(alpha));
-
- if (betafac == 0.0f) {
- madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ref, sinf(alpha));
- }
- else {
- const float sinalpha = sinf(alpha);
- const float beta = (betafac > 0.0f ? lnor_space->ref_beta : pi2 - lnor_space->ref_beta) * betafac;
- madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ref, sinalpha * cosf(beta));
- madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ortho, sinalpha * sinf(beta));
- }
- }
-}
-
-void BKE_lnor_space_custom_normal_to_data(MLoopNorSpace *lnor_space, const float custom_lnor[3], short r_clnor_data[2])
-{
- /* We use null vector as NOP custom normal (can be simpler than giving autocomputed lnor...). */
- if (is_zero_v3(custom_lnor) || compare_v3v3(lnor_space->vec_lnor, custom_lnor, 1e-4f)) {
- r_clnor_data[0] = r_clnor_data[1] = 0;
- return;
- }
-
- {
- const float pi2 = (float)(M_PI * 2.0);
- const float cos_alpha = dot_v3v3(lnor_space->vec_lnor, custom_lnor);
- float vec[3], cos_beta;
- float alpha;
-
- alpha = saacosf(cos_alpha);
- if (alpha > lnor_space->ref_alpha) {
- /* Note we could stick to [0, pi] range here, but makes decoding more complex, not worth it. */
- r_clnor_data[0] = unit_float_to_short(-(pi2 - alpha) / (pi2 - lnor_space->ref_alpha));
- }
- else {
- r_clnor_data[0] = unit_float_to_short(alpha / lnor_space->ref_alpha);
- }
-
- /* Project custom lnor on (vec_ref, vec_ortho) plane. */
- mul_v3_v3fl(vec, lnor_space->vec_lnor, -cos_alpha);
- add_v3_v3(vec, custom_lnor);
- normalize_v3(vec);
-
- cos_beta = dot_v3v3(lnor_space->vec_ref, vec);
-
- if (cos_beta < LNOR_SPACE_TRIGO_THRESHOLD) {
- float beta = saacosf(cos_beta);
- if (dot_v3v3(lnor_space->vec_ortho, vec) < 0.0f) {
- beta = pi2 - beta;
- }
-
- if (beta > lnor_space->ref_beta) {
- r_clnor_data[1] = unit_float_to_short(-(pi2 - beta) / (pi2 - lnor_space->ref_beta));
- }
- else {
- r_clnor_data[1] = unit_float_to_short(beta / lnor_space->ref_beta);
- }
- }
- else {
- r_clnor_data[1] = 0;
- }
- }
+ /* Rounding... */
+ return (short)floorf(val * (float)SHRT_MAX + 0.5f);
+}
+
+void BKE_lnor_space_custom_data_to_normal(MLoopNorSpace *lnor_space,
+ const short clnor_data[2],
+ float r_custom_lnor[3])
+{
+ /* NOP custom normal data or invalid lnor space, return. */
+ if (clnor_data[0] == 0 || lnor_space->ref_alpha == 0.0f || lnor_space->ref_beta == 0.0f) {
+ copy_v3_v3(r_custom_lnor, lnor_space->vec_lnor);
+ return;
+ }
+
+ {
+ /* TODO Check whether using sincosf() gives any noticeable benefit
+ * (could not even get it working under linux though)! */
+ const float pi2 = (float)(M_PI * 2.0);
+ const float alphafac = unit_short_to_float(clnor_data[0]);
+ const float alpha = (alphafac > 0.0f ? lnor_space->ref_alpha : pi2 - lnor_space->ref_alpha) *
+ alphafac;
+ const float betafac = unit_short_to_float(clnor_data[1]);
+
+ mul_v3_v3fl(r_custom_lnor, lnor_space->vec_lnor, cosf(alpha));
+
+ if (betafac == 0.0f) {
+ madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ref, sinf(alpha));
+ }
+ else {
+ const float sinalpha = sinf(alpha);
+ const float beta = (betafac > 0.0f ? lnor_space->ref_beta : pi2 - lnor_space->ref_beta) *
+ betafac;
+ madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ref, sinalpha * cosf(beta));
+ madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ortho, sinalpha * sinf(beta));
+ }
+ }
+}
+
+void BKE_lnor_space_custom_normal_to_data(MLoopNorSpace *lnor_space,
+ const float custom_lnor[3],
+ short r_clnor_data[2])
+{
+ /* We use null vector as NOP custom normal (can be simpler than giving autocomputed lnor...). */
+ if (is_zero_v3(custom_lnor) || compare_v3v3(lnor_space->vec_lnor, custom_lnor, 1e-4f)) {
+ r_clnor_data[0] = r_clnor_data[1] = 0;
+ return;
+ }
+
+ {
+ const float pi2 = (float)(M_PI * 2.0);
+ const float cos_alpha = dot_v3v3(lnor_space->vec_lnor, custom_lnor);
+ float vec[3], cos_beta;
+ float alpha;
+
+ alpha = saacosf(cos_alpha);
+ if (alpha > lnor_space->ref_alpha) {
+ /* Note we could stick to [0, pi] range here, but makes decoding more complex, not worth it. */
+ r_clnor_data[0] = unit_float_to_short(-(pi2 - alpha) / (pi2 - lnor_space->ref_alpha));
+ }
+ else {
+ r_clnor_data[0] = unit_float_to_short(alpha / lnor_space->ref_alpha);
+ }
+
+ /* Project custom lnor on (vec_ref, vec_ortho) plane. */
+ mul_v3_v3fl(vec, lnor_space->vec_lnor, -cos_alpha);
+ add_v3_v3(vec, custom_lnor);
+ normalize_v3(vec);
+
+ cos_beta = dot_v3v3(lnor_space->vec_ref, vec);
+
+ if (cos_beta < LNOR_SPACE_TRIGO_THRESHOLD) {
+ float beta = saacosf(cos_beta);
+ if (dot_v3v3(lnor_space->vec_ortho, vec) < 0.0f) {
+ beta = pi2 - beta;
+ }
+
+ if (beta > lnor_space->ref_beta) {
+ r_clnor_data[1] = unit_float_to_short(-(pi2 - beta) / (pi2 - lnor_space->ref_beta));
+ }
+ else {
+ r_clnor_data[1] = unit_float_to_short(beta / lnor_space->ref_beta);
+ }
+ }
+ else {
+ r_clnor_data[1] = 0;
+ }
+ }
}
#define LOOP_SPLIT_TASK_BLOCK_SIZE 1024
typedef struct LoopSplitTaskData {
- /* Specific to each instance (each task). */
- MLoopNorSpace *lnor_space; /* We have to create those outside of tasks, since afaik memarena is not threadsafe. */
- float (*lnor)[3];
- const MLoop *ml_curr;
- const MLoop *ml_prev;
- int ml_curr_index;
- int ml_prev_index;
- const int *e2l_prev; /* Also used a flag to switch between single or fan process! */
- int mp_index;
-
- /* This one is special, it's owned and managed by worker tasks, avoid to have to create it for each fan! */
- BLI_Stack *edge_vectors;
-
- char pad_c;
+ /* Specific to each instance (each task). */
+ MLoopNorSpace *
+ lnor_space; /* We have to create those outside of tasks, since afaik memarena is not threadsafe. */
+ float (*lnor)[3];
+ const MLoop *ml_curr;
+ const MLoop *ml_prev;
+ int ml_curr_index;
+ int ml_prev_index;
+ const int *e2l_prev; /* Also used a flag to switch between single or fan process! */
+ int mp_index;
+
+ /* This one is special, it's owned and managed by worker tasks, avoid to have to create it for each fan! */
+ BLI_Stack *edge_vectors;
+
+ char pad_c;
} LoopSplitTaskData;
typedef struct LoopSplitTaskDataCommon {
- /* Read/write.
- * 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];
-
- /* Read-only. */
- const MVert *mverts;
- const MEdge *medges;
- const MLoop *mloops;
- const MPoly *mpolys;
- int (*edge_to_loops)[2];
- int *loop_to_poly;
- const float (*polynors)[3];
-
- int numEdges;
- int numLoops;
- int numPolys;
+ /* Read/write.
+ * 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];
+
+ /* Read-only. */
+ const MVert *mverts;
+ const MEdge *medges;
+ const MLoop *mloops;
+ const MPoly *mpolys;
+ int (*edge_to_loops)[2];
+ int *loop_to_poly;
+ const float (*polynors)[3];
+
+ int numEdges;
+ int numLoops;
+ int numPolys;
} LoopSplitTaskDataCommon;
#define INDEX_UNSET INT_MIN
@@ -773,714 +849,753 @@ typedef struct LoopSplitTaskDataCommon {
/* See comment about edge_to_loops below. */
#define IS_EDGE_SHARP(_e2l) (ELEM((_e2l)[1], INDEX_UNSET, INDEX_INVALID))
-static void mesh_edges_sharp_tag(
- LoopSplitTaskDataCommon *data,
- const bool check_angle, const float split_angle, const bool do_sharp_edges_tag)
-{
- const MVert *mverts = data->mverts;
- const MEdge *medges = data->medges;
- const MLoop *mloops = data->mloops;
-
- const MPoly *mpolys = data->mpolys;
-
- const int numEdges = data->numEdges;
- const int numPolys = data->numPolys;
-
- float (*loopnors)[3] = data->loopnors; /* Note: loopnors may be NULL here. */
- const float (*polynors)[3] = data->polynors;
-
- int (*edge_to_loops)[2] = data->edge_to_loops;
- int *loop_to_poly = data->loop_to_poly;
-
- BLI_bitmap *sharp_edges = do_sharp_edges_tag ? BLI_BITMAP_NEW(numEdges, __func__) : NULL;
-
- 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;
- int *e2l;
- int ml_curr_index = mp->loopstart;
- const int ml_last_index = (ml_curr_index + mp->totloop) - 1;
-
- ml_curr = &mloops[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) {
- normal_short_to_float_v3(loopnors[ml_curr_index], mverts[ml_curr->v].no);
- }
-
- /* Check whether current edge might be smooth or sharp */
- if ((e2l[0] | e2l[1]) == 0) {
- /* '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;
- }
- else if (e2l[1] == INDEX_UNSET) {
- const bool is_angle_sharp = (
- check_angle &&
- dot_v3v3(polynors[loop_to_poly[e2l[0]]], polynors[mp_index]) < split_angle_cos);
-
- /* Second loop using this edge, time to test its sharpness.
- * An edge is sharp if it is tagged as such, or its face is not smooth,
- * 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)
- {
- /* Note: we are sure that loop != 0 here ;) */
- e2l[1] = INDEX_INVALID;
-
- /* We want to avoid tagging edges as sharp when it is already defined as such by
- * other causes than angle threshold... */
- if (do_sharp_edges_tag && is_angle_sharp) {
- BLI_BITMAP_SET(sharp_edges, ml_curr->e, true);
- }
- }
- else {
- e2l[1] = ml_curr_index;
- }
- }
- else if (!IS_EDGE_SHARP(e2l)) {
- /* More than two loops using this edge, tag as sharp if not yet done. */
- e2l[1] = INDEX_INVALID;
-
- /* We want to avoid tagging edges as sharp when it is already defined as such by
- * other causes than angle threshold... */
- if (do_sharp_edges_tag) {
- BLI_BITMAP_SET(sharp_edges, ml_curr->e, false);
- }
- }
- /* Else, edge is already 'disqualified' (i.e. sharp)! */
- }
- }
-
- /* 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 (BLI_BITMAP_TEST(sharp_edges, me_index)) {
- me->flag |= ME_SHARP;
- }
- }
-
- MEM_freeN(sharp_edges);
- }
+static void mesh_edges_sharp_tag(LoopSplitTaskDataCommon *data,
+ const bool check_angle,
+ const float split_angle,
+ const bool do_sharp_edges_tag)
+{
+ const MVert *mverts = data->mverts;
+ const MEdge *medges = data->medges;
+ const MLoop *mloops = data->mloops;
+
+ const MPoly *mpolys = data->mpolys;
+
+ const int numEdges = data->numEdges;
+ const int numPolys = data->numPolys;
+
+ float(*loopnors)[3] = data->loopnors; /* Note: loopnors may be NULL here. */
+ const float(*polynors)[3] = data->polynors;
+
+ int(*edge_to_loops)[2] = data->edge_to_loops;
+ int *loop_to_poly = data->loop_to_poly;
+
+ BLI_bitmap *sharp_edges = do_sharp_edges_tag ? BLI_BITMAP_NEW(numEdges, __func__) : NULL;
+
+ 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;
+ int *e2l;
+ int ml_curr_index = mp->loopstart;
+ const int ml_last_index = (ml_curr_index + mp->totloop) - 1;
+
+ ml_curr = &mloops[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) {
+ normal_short_to_float_v3(loopnors[ml_curr_index], mverts[ml_curr->v].no);
+ }
+
+ /* Check whether current edge might be smooth or sharp */
+ if ((e2l[0] | e2l[1]) == 0) {
+ /* '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;
+ }
+ else if (e2l[1] == INDEX_UNSET) {
+ const bool is_angle_sharp = (check_angle &&
+ dot_v3v3(polynors[loop_to_poly[e2l[0]]], polynors[mp_index]) <
+ split_angle_cos);
+
+ /* Second loop using this edge, time to test its sharpness.
+ * An edge is sharp if it is tagged as such, or its face is not smooth,
+ * 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) {
+ /* Note: we are sure that loop != 0 here ;) */
+ e2l[1] = INDEX_INVALID;
+
+ /* We want to avoid tagging edges as sharp when it is already defined as such by
+ * other causes than angle threshold... */
+ if (do_sharp_edges_tag && is_angle_sharp) {
+ BLI_BITMAP_SET(sharp_edges, ml_curr->e, true);
+ }
+ }
+ else {
+ e2l[1] = ml_curr_index;
+ }
+ }
+ else if (!IS_EDGE_SHARP(e2l)) {
+ /* More than two loops using this edge, tag as sharp if not yet done. */
+ e2l[1] = INDEX_INVALID;
+
+ /* We want to avoid tagging edges as sharp when it is already defined as such by
+ * other causes than angle threshold... */
+ if (do_sharp_edges_tag) {
+ BLI_BITMAP_SET(sharp_edges, ml_curr->e, false);
+ }
+ }
+ /* Else, edge is already 'disqualified' (i.e. sharp)! */
+ }
+ }
+
+ /* 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 (BLI_BITMAP_TEST(sharp_edges, me_index)) {
+ me->flag |= ME_SHARP;
+ }
+ }
+
+ MEM_freeN(sharp_edges);
+ }
}
/** Define sharp edges as needed to mimic 'autosmooth' from angle threshold.
*
* Used when defining an empty custom loop normals data layer, to keep same shading as with autosmooth!
*/
-void BKE_edges_sharp_from_angle_set(
- const struct MVert *mverts, const int UNUSED(numVerts),
- struct MEdge *medges, const int numEdges,
- struct MLoop *mloops, const int numLoops,
- struct MPoly *mpolys, const float (*polynors)[3], const int numPolys,
- const float split_angle)
-{
- if (split_angle >= (float)M_PI) {
- /* Nothing to do! */
- return;
- }
-
- /* Mapping edge -> loops. See BKE_mesh_normals_loop_split() for details. */
- int (*edge_to_loops)[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 = MEM_malloc_arrayN((size_t)numLoops, sizeof(*loop_to_poly), __func__);
-
- LoopSplitTaskDataCommon common_data = {
- .mverts = mverts,
- .medges = medges,
- .mloops = mloops,
- .mpolys = mpolys,
- .edge_to_loops = edge_to_loops,
- .loop_to_poly = loop_to_poly,
- .polynors = polynors,
- .numEdges = numEdges,
- .numPolys = 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)
-{
- 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
- * whether both loops using current edge are in the same direction or not, and whether
- * mlfan_curr_index actually uses the vertex we are fanning around!
- * mlfan_curr_index is the index of mlfan_next here, and mlfan_next is not the real next one
- * (i.e. not the future mlfan_curr)...
- */
- *r_mlfan_curr_index = (e2lfan_curr[0] == *r_mlfan_curr_index) ? e2lfan_curr[1] : e2lfan_curr[0];
- *r_mpfan_curr_index = loop_to_poly[*r_mlfan_curr_index];
-
- 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))
- {
- /* 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;
- }
- }
- 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;
- }
- *r_mlfan_vert_index = *r_mlfan_curr_index;
- }
- *r_mlfan_curr = &mloops[*r_mlfan_curr_index];
- /* And now we are back in sync, mlfan_curr_index is the index of mlfan_curr! Pff! */
+void BKE_edges_sharp_from_angle_set(const struct MVert *mverts,
+ const int UNUSED(numVerts),
+ struct MEdge *medges,
+ const int numEdges,
+ struct MLoop *mloops,
+ const int numLoops,
+ struct MPoly *mpolys,
+ const float (*polynors)[3],
+ const int numPolys,
+ const float split_angle)
+{
+ if (split_angle >= (float)M_PI) {
+ /* Nothing to do! */
+ return;
+ }
+
+ /* Mapping edge -> loops. See BKE_mesh_normals_loop_split() for details. */
+ int(*edge_to_loops)[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 = MEM_malloc_arrayN((size_t)numLoops, sizeof(*loop_to_poly), __func__);
+
+ LoopSplitTaskDataCommon common_data = {
+ .mverts = mverts,
+ .medges = medges,
+ .mloops = mloops,
+ .mpolys = mpolys,
+ .edge_to_loops = edge_to_loops,
+ .loop_to_poly = loop_to_poly,
+ .polynors = polynors,
+ .numEdges = numEdges,
+ .numPolys = 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)
+{
+ 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
+ * whether both loops using current edge are in the same direction or not, and whether
+ * mlfan_curr_index actually uses the vertex we are fanning around!
+ * mlfan_curr_index is the index of mlfan_next here, and mlfan_next is not the real next one
+ * (i.e. not the future mlfan_curr)...
+ */
+ *r_mlfan_curr_index = (e2lfan_curr[0] == *r_mlfan_curr_index) ? e2lfan_curr[1] : e2lfan_curr[0];
+ *r_mpfan_curr_index = loop_to_poly[*r_mlfan_curr_index];
+
+ 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)) {
+ /* 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;
+ }
+ }
+ 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;
+ }
+ *r_mlfan_vert_index = *r_mlfan_curr_index;
+ }
+ *r_mlfan_curr = &mloops[*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;
- short (*clnors_data)[2] = common_data->clnors_data;
-
- const MVert *mverts = common_data->mverts;
- const MEdge *medges = common_data->medges;
- const float (*polynors)[3] = common_data->polynors;
-
- MLoopNorSpace *lnor_space = data->lnor_space;
- float (*lnor)[3] = 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;
-#if 0 /* Not needed for 'single' loop. */
- const int ml_prev_index = data->ml_prev_index;
- const int *e2l_prev = data->e2l_prev;
+ MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr;
+ short(*clnors_data)[2] = common_data->clnors_data;
+
+ const MVert *mverts = common_data->mverts;
+ const MEdge *medges = common_data->medges;
+ const float(*polynors)[3] = common_data->polynors;
+
+ MLoopNorSpace *lnor_space = data->lnor_space;
+ float(*lnor)[3] = 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;
+#if 0 /* Not needed for 'single' loop. */
+ const int ml_prev_index = data->ml_prev_index;
+ const int *e2l_prev = data->e2l_prev;
#endif
- const int mp_index = data->mp_index;
+ const int mp_index = data->mp_index;
- /* Simple case (both edges around that vertex are sharp in current polygon),
- * this loop just takes its poly normal.
- */
- copy_v3_v3(*lnor, polynors[mp_index]);
+ /* Simple case (both edges around that vertex are sharp in current polygon),
+ * this loop just takes its poly normal.
+ */
+ copy_v3_v3(*lnor, polynors[mp_index]);
-// printf("BASIC: handling loop %d / edge %d / vert %d / poly %d\n", ml_curr_index, ml_curr->e, ml_curr->v, mp_index);
+ // printf("BASIC: handling loop %d / edge %d / vert %d / poly %d\n", ml_curr_index, ml_curr->e, ml_curr->v, mp_index);
- /* If needed, generate this (simple!) lnor space. */
- if (lnors_spacearr) {
- float vec_curr[3], vec_prev[3];
+ /* If needed, generate this (simple!) lnor space. */
+ if (lnors_spacearr) {
+ float vec_curr[3], vec_prev[3];
- const unsigned int 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 unsigned int 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];
- sub_v3_v3v3(vec_curr, mv_2->co, mv_pivot->co);
- normalize_v3(vec_curr);
- sub_v3_v3v3(vec_prev, mv_3->co, mv_pivot->co);
- normalize_v3(vec_prev);
+ sub_v3_v3v3(vec_curr, mv_2->co, mv_pivot->co);
+ normalize_v3(vec_curr);
+ sub_v3_v3v3(vec_prev, mv_3->co, mv_pivot->co);
+ normalize_v3(vec_prev);
- BKE_lnor_space_define(lnor_space, *lnor, vec_curr, vec_prev, NULL);
- /* We know there is only one loop in this space, no need to create a linklist in this case... */
- BKE_lnor_space_add_loop(lnors_spacearr, lnor_space, ml_curr_index, NULL, true);
+ BKE_lnor_space_define(lnor_space, *lnor, vec_curr, vec_prev, NULL);
+ /* We know there is only one loop in this space, no need to create a linklist in this case... */
+ BKE_lnor_space_add_loop(lnors_spacearr, lnor_space, ml_curr_index, NULL, true);
- if (clnors_data) {
- BKE_lnor_space_custom_data_to_normal(lnor_space, clnors_data[ml_curr_index], *lnor);
- }
- }
+ if (clnors_data) {
+ BKE_lnor_space_custom_data_to_normal(lnor_space, clnors_data[ml_curr_index], *lnor);
+ }
+ }
}
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;
-
- 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 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;
-
- MLoopNorSpace *lnor_space = data->lnor_space;
-#if 0 /* Not needed for 'fan' loops. */
- float (*lnor)[3] = data->lnor;
+ MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr;
+ float(*loopnors)[3] = common_data->loopnors;
+ short(*clnors_data)[2] = 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 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;
+
+ MLoopNorSpace *lnor_space = data->lnor_space;
+#if 0 /* Not needed for 'fan' loops. */
+ float (*lnor)[3] = data->lnor;
#endif
- const MLoop *ml_curr = data->ml_curr;
- const MLoop *ml_prev = data->ml_prev;
- const int ml_curr_index = data->ml_curr_index;
- const int ml_prev_index = data->ml_prev_index;
- const int mp_index = data->mp_index;
- const int *e2l_prev = data->e2l_prev;
-
- BLI_Stack *edge_vectors = data->edge_vectors;
-
- /* Gah... We have to fan around current vertex, until we find the other non-smooth edge,
- * and accumulate face normals into the vertex!
- * Note in case this vertex has only one sharp edges, this is a waste because the normal is the same as
- * the vertex normal, but I do not see any easy way to detect that (would need to count 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 unsigned int mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */
- const MVert *mv_pivot = &mverts[mv_pivot_index];
- const MEdge *me_org = &medges[ml_curr->e]; /* ml_curr would be mlfan_prev if we needed that one */
- 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] = NULL;
- int clnors_nbr = 0;
- bool clnors_invalid = false;
-
- /* Temp loop normal stack. */
- BLI_SMALLSTACK_DECLARE(normal, float *);
- /* 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;
-
- BLI_assert(mlfan_curr_index >= 0);
- BLI_assert(mlfan_vert_index >= 0);
- BLI_assert(mpfan_curr_index >= 0);
-
- /* 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];
-
- sub_v3_v3v3(vec_org, mv_2->co, mv_pivot->co);
- normalize_v3(vec_org);
- copy_v3_v3(vec_prev, vec_org);
-
- if (lnors_spacearr) {
- BLI_stack_push(edge_vectors, vec_org);
- }
- }
-
-// printf("FAN: vert %d, start edge %d\n", mv_pivot_index, ml_curr->e);
-
- while (true) {
- const MEdge *me_curr = &medges[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];
-
- sub_v3_v3v3(vec_curr, mv_2->co, mv_pivot->co);
- normalize_v3(vec_curr);
- }
-
-// printf("\thandling edge %d / loop %d\n", mlfan_curr->e, mlfan_curr_index);
-
- {
- /* Code similar to accumulate_vertex_normals_poly_v3. */
- /* Calculate angle between the two poly edges incident on this vertex. */
- const float fac = saacos(dot_v3v3(vec_curr, vec_prev));
- /* Accumulate */
- madd_v3_v3fl(lnor, polynors[mpfan_curr_index], fac);
-
- if (clnors_data) {
- /* Accumulate all clnors, if they are not all equal we have to fix that! */
- short (*clnor)[2] = &clnors_data[mlfan_vert_index];
- if (clnors_nbr) {
- clnors_invalid |= ((*clnor_ref)[0] != (*clnor)[0] || (*clnor_ref)[1] != (*clnor)[1]);
- }
- else {
- clnor_ref = clnor;
- }
- clnors_avg[0] += (*clnor)[0];
- clnors_avg[1] += (*clnor)[1];
- clnors_nbr++;
- /* We store here a pointer to all custom lnors processed. */
- BLI_SMALLSTACK_PUSH(clnors, (short *)*clnor);
- }
- }
-
- /* We store here a pointer to all loop-normals processed. */
- BLI_SMALLSTACK_PUSH(normal, (float *)(loopnors[mlfan_vert_index]));
-
- if (lnors_spacearr) {
- /* Assign current lnor space to current 'vertex' loop. */
- BKE_lnor_space_add_loop(lnors_spacearr, lnor_space, mlfan_vert_index, NULL, false);
- if (me_curr != me_org) {
- /* We store here all edges-normalized vectors processed. */
- BLI_stack_push(edge_vectors, vec_curr);
- }
- }
-
- if (IS_EDGE_SHARP(e2lfan_curr) || (me_curr == me_org)) {
- /* Current edge is sharp and we have finished with this fan of faces around this vert,
- * or this vert is smooth, and we have completed a full turn around it.
- */
-// printf("FAN: Finished!\n");
- break;
- }
-
- 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);
-
- e2lfan_curr = edge_to_loops[mlfan_curr->e];
- }
-
- {
- float lnor_len = normalize_v3(lnor);
-
- /* If we are generating lnor spacearr, we can now define the one for this fan,
- * and optionally compute final lnor from custom data too!
- */
- if (lnors_spacearr) {
- if (UNLIKELY(lnor_len == 0.0f)) {
- /* Use vertex normal as fallback! */
- copy_v3_v3(lnor, loopnors[mlfan_vert_index]);
- lnor_len = 1.0f;
- }
-
- BKE_lnor_space_define(lnor_space, lnor, vec_org, vec_curr, edge_vectors);
-
- if (clnors_data) {
- if (clnors_invalid) {
- short *clnor;
-
- clnors_avg[0] /= clnors_nbr;
- clnors_avg[1] /= clnors_nbr;
- /* Fix/update all clnors of this fan with computed average value. */
- if (G.debug & G_DEBUG) {
- printf("Invalid clnors in this fan!\n");
- }
- while ((clnor = BLI_SMALLSTACK_POP(clnors))) {
- //print_v2("org clnor", clnor);
- clnor[0] = (short)clnors_avg[0];
- clnor[1] = (short)clnors_avg[1];
- }
- //print_v2("new clnors", clnors_avg);
- }
- /* Extra bonus: since smallstack is local to this func, no more need to empty it at all cost! */
-
- BKE_lnor_space_custom_data_to_normal(lnor_space, *clnor_ref, lnor);
- }
- }
-
- /* In case we get a zero normal here, just use vertex normal already set! */
- if (LIKELY(lnor_len != 0.0f)) {
- /* Copy back the final computed normal into all related loop-normals. */
- float *nor;
-
- while ((nor = BLI_SMALLSTACK_POP(normal))) {
- copy_v3_v3(nor, lnor);
- }
- }
- /* Extra bonus: since smallstack is local to this func, no more need to empty it at all cost! */
- }
-}
-
-static void loop_split_worker_do(
- LoopSplitTaskDataCommon *common_data, LoopSplitTaskData *data, BLI_Stack *edge_vectors)
-{
- BLI_assert(data->ml_curr);
- if (data->e2l_prev) {
- BLI_assert((edge_vectors == NULL) || BLI_stack_is_empty(edge_vectors));
- data->edge_vectors = edge_vectors;
- split_loop_nor_fan_do(common_data, data);
- }
- else {
- /* No need for edge_vectors for 'single' case! */
- split_loop_nor_single_do(common_data, data);
- }
-}
-
-static void loop_split_worker(TaskPool * __restrict pool, void *taskdata, int UNUSED(threadid))
-{
- LoopSplitTaskDataCommon *common_data = BLI_task_pool_userdata(pool);
- LoopSplitTaskData *data = taskdata;
-
- /* Temp edge vectors stack, only used when computing lnor spacearr. */
- BLI_Stack *edge_vectors = common_data->lnors_spacearr ? BLI_stack_new(sizeof(float[3]), __func__) : NULL;
+ const MLoop *ml_curr = data->ml_curr;
+ const MLoop *ml_prev = data->ml_prev;
+ const int ml_curr_index = data->ml_curr_index;
+ const int ml_prev_index = data->ml_prev_index;
+ const int mp_index = data->mp_index;
+ const int *e2l_prev = data->e2l_prev;
+
+ BLI_Stack *edge_vectors = data->edge_vectors;
+
+ /* Gah... We have to fan around current vertex, until we find the other non-smooth edge,
+ * and accumulate face normals into the vertex!
+ * Note in case this vertex has only one sharp edges, this is a waste because the normal is the same as
+ * the vertex normal, but I do not see any easy way to detect that (would need to count 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 unsigned int mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */
+ const MVert *mv_pivot = &mverts[mv_pivot_index];
+ const MEdge *me_org =
+ &medges[ml_curr->e]; /* ml_curr would be mlfan_prev if we needed that one */
+ 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] = NULL;
+ int clnors_nbr = 0;
+ bool clnors_invalid = false;
+
+ /* Temp loop normal stack. */
+ BLI_SMALLSTACK_DECLARE(normal, float *);
+ /* 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;
+
+ BLI_assert(mlfan_curr_index >= 0);
+ BLI_assert(mlfan_vert_index >= 0);
+ BLI_assert(mpfan_curr_index >= 0);
+
+ /* 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];
+
+ sub_v3_v3v3(vec_org, mv_2->co, mv_pivot->co);
+ normalize_v3(vec_org);
+ copy_v3_v3(vec_prev, vec_org);
+
+ if (lnors_spacearr) {
+ BLI_stack_push(edge_vectors, vec_org);
+ }
+ }
+
+ // printf("FAN: vert %d, start edge %d\n", mv_pivot_index, ml_curr->e);
+
+ while (true) {
+ const MEdge *me_curr = &medges[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];
+
+ sub_v3_v3v3(vec_curr, mv_2->co, mv_pivot->co);
+ normalize_v3(vec_curr);
+ }
+
+ // printf("\thandling edge %d / loop %d\n", mlfan_curr->e, mlfan_curr_index);
+
+ {
+ /* Code similar to accumulate_vertex_normals_poly_v3. */
+ /* Calculate angle between the two poly edges incident on this vertex. */
+ const float fac = saacos(dot_v3v3(vec_curr, vec_prev));
+ /* Accumulate */
+ madd_v3_v3fl(lnor, polynors[mpfan_curr_index], fac);
+
+ if (clnors_data) {
+ /* Accumulate all clnors, if they are not all equal we have to fix that! */
+ short(*clnor)[2] = &clnors_data[mlfan_vert_index];
+ if (clnors_nbr) {
+ clnors_invalid |= ((*clnor_ref)[0] != (*clnor)[0] || (*clnor_ref)[1] != (*clnor)[1]);
+ }
+ else {
+ clnor_ref = clnor;
+ }
+ clnors_avg[0] += (*clnor)[0];
+ clnors_avg[1] += (*clnor)[1];
+ clnors_nbr++;
+ /* We store here a pointer to all custom lnors processed. */
+ BLI_SMALLSTACK_PUSH(clnors, (short *)*clnor);
+ }
+ }
+
+ /* We store here a pointer to all loop-normals processed. */
+ BLI_SMALLSTACK_PUSH(normal, (float *)(loopnors[mlfan_vert_index]));
+
+ if (lnors_spacearr) {
+ /* Assign current lnor space to current 'vertex' loop. */
+ BKE_lnor_space_add_loop(lnors_spacearr, lnor_space, mlfan_vert_index, NULL, false);
+ if (me_curr != me_org) {
+ /* We store here all edges-normalized vectors processed. */
+ BLI_stack_push(edge_vectors, vec_curr);
+ }
+ }
+
+ if (IS_EDGE_SHARP(e2lfan_curr) || (me_curr == me_org)) {
+ /* Current edge is sharp and we have finished with this fan of faces around this vert,
+ * or this vert is smooth, and we have completed a full turn around it.
+ */
+ // printf("FAN: Finished!\n");
+ break;
+ }
+
+ 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);
+
+ e2lfan_curr = edge_to_loops[mlfan_curr->e];
+ }
+
+ {
+ float lnor_len = normalize_v3(lnor);
+
+ /* If we are generating lnor spacearr, we can now define the one for this fan,
+ * and optionally compute final lnor from custom data too!
+ */
+ if (lnors_spacearr) {
+ if (UNLIKELY(lnor_len == 0.0f)) {
+ /* Use vertex normal as fallback! */
+ copy_v3_v3(lnor, loopnors[mlfan_vert_index]);
+ lnor_len = 1.0f;
+ }
+
+ BKE_lnor_space_define(lnor_space, lnor, vec_org, vec_curr, edge_vectors);
+
+ if (clnors_data) {
+ if (clnors_invalid) {
+ short *clnor;
+
+ clnors_avg[0] /= clnors_nbr;
+ clnors_avg[1] /= clnors_nbr;
+ /* Fix/update all clnors of this fan with computed average value. */
+ if (G.debug & G_DEBUG) {
+ printf("Invalid clnors in this fan!\n");
+ }
+ while ((clnor = BLI_SMALLSTACK_POP(clnors))) {
+ //print_v2("org clnor", clnor);
+ clnor[0] = (short)clnors_avg[0];
+ clnor[1] = (short)clnors_avg[1];
+ }
+ //print_v2("new clnors", clnors_avg);
+ }
+ /* Extra bonus: since smallstack is local to this func, no more need to empty it at all cost! */
+
+ BKE_lnor_space_custom_data_to_normal(lnor_space, *clnor_ref, lnor);
+ }
+ }
+
+ /* In case we get a zero normal here, just use vertex normal already set! */
+ if (LIKELY(lnor_len != 0.0f)) {
+ /* Copy back the final computed normal into all related loop-normals. */
+ float *nor;
+
+ while ((nor = BLI_SMALLSTACK_POP(normal))) {
+ copy_v3_v3(nor, lnor);
+ }
+ }
+ /* Extra bonus: since smallstack is local to this func, no more need to empty it at all cost! */
+ }
+}
+
+static void loop_split_worker_do(LoopSplitTaskDataCommon *common_data,
+ LoopSplitTaskData *data,
+ BLI_Stack *edge_vectors)
+{
+ BLI_assert(data->ml_curr);
+ if (data->e2l_prev) {
+ BLI_assert((edge_vectors == NULL) || BLI_stack_is_empty(edge_vectors));
+ data->edge_vectors = edge_vectors;
+ split_loop_nor_fan_do(common_data, data);
+ }
+ else {
+ /* No need for edge_vectors for 'single' case! */
+ split_loop_nor_single_do(common_data, data);
+ }
+}
+
+static void loop_split_worker(TaskPool *__restrict pool, void *taskdata, int UNUSED(threadid))
+{
+ LoopSplitTaskDataCommon *common_data = BLI_task_pool_userdata(pool);
+ LoopSplitTaskData *data = taskdata;
+
+ /* Temp edge vectors stack, only used when computing lnor spacearr. */
+ BLI_Stack *edge_vectors = common_data->lnors_spacearr ?
+ BLI_stack_new(sizeof(float[3]), __func__) :
+ NULL;
#ifdef DEBUG_TIME
- TIMEIT_START_AVERAGED(loop_split_worker);
+ TIMEIT_START_AVERAGED(loop_split_worker);
#endif
- for (int i = 0; i < LOOP_SPLIT_TASK_BLOCK_SIZE; i++, data++) {
- /* A NULL ml_curr is used to tag ended data! */
- if (data->ml_curr == NULL) {
- break;
- }
+ for (int i = 0; i < LOOP_SPLIT_TASK_BLOCK_SIZE; i++, data++) {
+ /* A NULL ml_curr is used to tag ended data! */
+ if (data->ml_curr == NULL) {
+ break;
+ }
- loop_split_worker_do(common_data, data, edge_vectors);
- }
+ loop_split_worker_do(common_data, data, edge_vectors);
+ }
- if (edge_vectors) {
- BLI_stack_free(edge_vectors);
- }
+ if (edge_vectors) {
+ BLI_stack_free(edge_vectors);
+ }
#ifdef DEBUG_TIME
- TIMEIT_END_AVERAGED(loop_split_worker);
+ TIMEIT_END_AVERAGED(loop_split_worker);
#endif
}
/* Check whether gievn loop is part of an unknown-so-far cyclic smooth fan, or not.
* 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,
- const int (*edge_to_loops)[2], const int *loop_to_poly, const int *e2l_prev, BLI_bitmap *skip_loops,
- const MLoop *ml_curr, const MLoop *ml_prev, const int ml_curr_index, const int ml_prev_index,
- const int mp_curr_index)
-{
- const unsigned int 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;
- 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;
-
- BLI_assert(mlfan_curr_index >= 0);
- BLI_assert(mlfan_vert_index >= 0);
- BLI_assert(mpfan_curr_index >= 0);
-
- BLI_assert(!BLI_BITMAP_TEST(skip_loops, mlfan_vert_index));
- BLI_BITMAP_ENABLE(skip_loops, mlfan_vert_index);
-
- 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);
-
- e2lfan_curr = edge_to_loops[mlfan_curr->e];
-
- if (IS_EDGE_SHARP(e2lfan_curr)) {
- /* Sharp loop/edge, so not a cyclic smooth fan... */
- return false;
- }
- /* Smooth loop/edge... */
- else if (BLI_BITMAP_TEST(skip_loops, mlfan_vert_index)) {
- if (mlfan_vert_index == ml_curr_index) {
- /* We walked around a whole cyclic smooth fan without finding any already-processed loop, means we can
- * use initial ml_curr/ml_prev edge as start for this smooth fan. */
- return true;
- }
- /* ... already checked in some previous looping, we can abort. */
- return false;
- }
- else {
- /* ... we can skip it in future, and keep checking the smooth fan. */
- BLI_BITMAP_ENABLE(skip_loops, mlfan_vert_index);
- }
- }
+static bool loop_split_generator_check_cyclic_smooth_fan(const MLoop *mloops,
+ const MPoly *mpolys,
+ const int (*edge_to_loops)[2],
+ const int *loop_to_poly,
+ const int *e2l_prev,
+ BLI_bitmap *skip_loops,
+ const MLoop *ml_curr,
+ const MLoop *ml_prev,
+ const int ml_curr_index,
+ const int ml_prev_index,
+ const int mp_curr_index)
+{
+ const unsigned int 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;
+ 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;
+
+ BLI_assert(mlfan_curr_index >= 0);
+ BLI_assert(mlfan_vert_index >= 0);
+ BLI_assert(mpfan_curr_index >= 0);
+
+ BLI_assert(!BLI_BITMAP_TEST(skip_loops, mlfan_vert_index));
+ BLI_BITMAP_ENABLE(skip_loops, mlfan_vert_index);
+
+ 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);
+
+ e2lfan_curr = edge_to_loops[mlfan_curr->e];
+
+ if (IS_EDGE_SHARP(e2lfan_curr)) {
+ /* Sharp loop/edge, so not a cyclic smooth fan... */
+ return false;
+ }
+ /* Smooth loop/edge... */
+ else if (BLI_BITMAP_TEST(skip_loops, mlfan_vert_index)) {
+ if (mlfan_vert_index == ml_curr_index) {
+ /* We walked around a whole cyclic smooth fan without finding any already-processed loop, means we can
+ * use initial ml_curr/ml_prev edge as start for this smooth fan. */
+ return true;
+ }
+ /* ... already checked in some previous looping, we can abort. */
+ return false;
+ }
+ else {
+ /* ... we can skip it in future, and keep checking the smooth fan. */
+ BLI_BITMAP_ENABLE(skip_loops, mlfan_vert_index);
+ }
+ }
}
static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common_data)
{
- MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr;
- float (*loopnors)[3] = common_data->loopnors;
+ MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr;
+ float(*loopnors)[3] = 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 int (*edge_to_loops)[2] = common_data->edge_to_loops;
- const int numLoops = common_data->numLoops;
- const int numPolys = common_data->numPolys;
+ const MLoop *mloops = common_data->mloops;
+ const MPoly *mpolys = common_data->mpolys;
+ const 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 MPoly *mp;
+ int mp_index;
- const MLoop *ml_curr;
- const MLoop *ml_prev;
- int ml_curr_index;
- int ml_prev_index;
+ const MLoop *ml_curr;
+ const MLoop *ml_prev;
+ int ml_curr_index;
+ int ml_prev_index;
- BLI_bitmap *skip_loops = BLI_BITMAP_NEW(numLoops, __func__);
+ BLI_bitmap *skip_loops = BLI_BITMAP_NEW(numLoops, __func__);
- LoopSplitTaskData *data_buff = NULL;
- int data_idx = 0;
+ LoopSplitTaskData *data_buff = NULL;
+ int data_idx = 0;
- /* Temp edge vectors stack, only used when computing lnor spacearr (and we are not multi-threading). */
- BLI_Stack *edge_vectors = NULL;
+ /* Temp edge vectors stack, only used when computing lnor spacearr (and we are not multi-threading). */
+ BLI_Stack *edge_vectors = NULL;
#ifdef DEBUG_TIME
- TIMEIT_START_AVERAGED(loop_split_generator);
+ TIMEIT_START_AVERAGED(loop_split_generator);
#endif
- if (!pool) {
- if (lnors_spacearr) {
- edge_vectors = BLI_stack_new(sizeof(float[3]), __func__);
- }
- }
-
- /* 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;
-
- ml_curr = &mloops[ml_curr_index];
- ml_prev = &mloops[ml_prev_index];
- 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];
- const int *e2l_prev = edge_to_loops[ml_prev->e];
-
-// printf("Checking loop %d / edge %u / vert %u (sharp edge: %d, skiploop: %d)...",
-// ml_curr_index, ml_curr->e, ml_curr->v, IS_EDGE_SHARP(e2l_curr), BLI_BITMAP_TEST_BOOL(skip_loops, ml_curr_index));
-
- /* A smooth edge, we have to check for cyclic smooth fan case.
- * If we find a new, never-processed cyclic smooth fan, we can do it now using that loop/edge as
- * 'entry point', otherwise we can skip it. */
- /* Note: In theory, we could make loop_split_generator_check_cyclic_smooth_fan() store
- * mlfan_vert_index'es and edge indexes in two stacks, to avoid having to fan again around the vert during
- * actual computation of clnor & clnorspace. However, this would complicate the code, add more memory usage,
- * and despite its logical 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) &&
- (BLI_BITMAP_TEST(skip_loops, ml_curr_index) ||
- !loop_split_generator_check_cyclic_smooth_fan(
- mloops, mpolys, edge_to_loops, loop_to_poly, e2l_prev, skip_loops,
- ml_curr, ml_prev, ml_curr_index, ml_prev_index, mp_index)))
- {
-// printf("SKIPPING!\n");
- }
- else {
- LoopSplitTaskData *data, data_local;
-
-// printf("PROCESSING!\n");
-
- if (pool) {
- if (data_idx == 0) {
- data_buff = MEM_calloc_arrayN(LOOP_SPLIT_TASK_BLOCK_SIZE, sizeof(*data_buff), __func__);
- }
- data = &data_buff[data_idx];
- }
- else {
- data = &data_local;
- memset(data, 0, sizeof(*data));
- }
-
- if (IS_EDGE_SHARP(e2l_curr) && IS_EDGE_SHARP(e2l_prev)) {
- data->lnor = lnors;
- data->ml_curr = ml_curr;
- data->ml_prev = ml_prev;
- data->ml_curr_index = ml_curr_index;
-#if 0 /* Not needed for 'single' loop. */
- data->ml_prev_index = ml_prev_index;
- data->e2l_prev = NULL; /* Tag as 'single' task. */
+ if (!pool) {
+ if (lnors_spacearr) {
+ edge_vectors = BLI_stack_new(sizeof(float[3]), __func__);
+ }
+ }
+
+ /* 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;
+
+ ml_curr = &mloops[ml_curr_index];
+ ml_prev = &mloops[ml_prev_index];
+ 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];
+ const int *e2l_prev = edge_to_loops[ml_prev->e];
+
+ // printf("Checking loop %d / edge %u / vert %u (sharp edge: %d, skiploop: %d)...",
+ // ml_curr_index, ml_curr->e, ml_curr->v, IS_EDGE_SHARP(e2l_curr), BLI_BITMAP_TEST_BOOL(skip_loops, ml_curr_index));
+
+ /* A smooth edge, we have to check for cyclic smooth fan case.
+ * If we find a new, never-processed cyclic smooth fan, we can do it now using that loop/edge as
+ * 'entry point', otherwise we can skip it. */
+ /* Note: In theory, we could make loop_split_generator_check_cyclic_smooth_fan() store
+ * mlfan_vert_index'es and edge indexes in two stacks, to avoid having to fan again around the vert during
+ * actual computation of clnor & clnorspace. However, this would complicate the code, add more memory usage,
+ * and despite its logical 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) && (BLI_BITMAP_TEST(skip_loops, ml_curr_index) ||
+ !loop_split_generator_check_cyclic_smooth_fan(mloops,
+ mpolys,
+ edge_to_loops,
+ loop_to_poly,
+ e2l_prev,
+ skip_loops,
+ ml_curr,
+ ml_prev,
+ ml_curr_index,
+ ml_prev_index,
+ mp_index))) {
+ // printf("SKIPPING!\n");
+ }
+ else {
+ LoopSplitTaskData *data, data_local;
+
+ // printf("PROCESSING!\n");
+
+ if (pool) {
+ if (data_idx == 0) {
+ data_buff = MEM_calloc_arrayN(
+ LOOP_SPLIT_TASK_BLOCK_SIZE, sizeof(*data_buff), __func__);
+ }
+ data = &data_buff[data_idx];
+ }
+ else {
+ data = &data_local;
+ memset(data, 0, sizeof(*data));
+ }
+
+ if (IS_EDGE_SHARP(e2l_curr) && IS_EDGE_SHARP(e2l_prev)) {
+ data->lnor = lnors;
+ data->ml_curr = ml_curr;
+ data->ml_prev = ml_prev;
+ data->ml_curr_index = ml_curr_index;
+#if 0 /* Not needed for 'single' loop. */
+ data->ml_prev_index = ml_prev_index;
+ data->e2l_prev = NULL; /* Tag as 'single' task. */
#endif
- data->mp_index = mp_index;
- if (lnors_spacearr) {
- data->lnor_space = BKE_lnor_space_create(lnors_spacearr);
- }
- }
- /* We *do not need* to check/tag loops as already computed!
- * Due to the fact a loop only links to one of its two edges, a same fan *will never be walked
- * more than once!*
- * Since we consider edges having neighbor polys with inverted (flipped) normals as sharp, we are sure
- * that no fan will be skipped, even only considering the case (sharp curr_edge, smooth prev_edge),
- * and not the alternative (smooth curr_edge, sharp prev_edge).
- * All this due/thanks to link between normals and loop ordering (i.e. winding).
- */
- else {
-#if 0 /* Not needed for 'fan' loops. */
- data->lnor = lnors;
+ data->mp_index = mp_index;
+ if (lnors_spacearr) {
+ data->lnor_space = BKE_lnor_space_create(lnors_spacearr);
+ }
+ }
+ /* We *do not need* to check/tag loops as already computed!
+ * Due to the fact a loop only links to one of its two edges, a same fan *will never be walked
+ * more than once!*
+ * Since we consider edges having neighbor polys with inverted (flipped) normals as sharp, we are sure
+ * that no fan will be skipped, even only considering the case (sharp curr_edge, smooth prev_edge),
+ * and not the alternative (smooth curr_edge, sharp prev_edge).
+ * All this due/thanks to link between normals and loop ordering (i.e. winding).
+ */
+ else {
+#if 0 /* Not needed for 'fan' loops. */
+ data->lnor = lnors;
#endif
- data->ml_curr = ml_curr;
- data->ml_prev = ml_prev;
- data->ml_curr_index = ml_curr_index;
- data->ml_prev_index = ml_prev_index;
- data->e2l_prev = e2l_prev; /* Also tag as 'fan' task. */
- data->mp_index = mp_index;
- if (lnors_spacearr) {
- data->lnor_space = BKE_lnor_space_create(lnors_spacearr);
- }
- }
-
- if (pool) {
- data_idx++;
- if (data_idx == LOOP_SPLIT_TASK_BLOCK_SIZE) {
- BLI_task_pool_push(pool, loop_split_worker, data_buff, true, TASK_PRIORITY_LOW);
- data_idx = 0;
- }
- }
- else {
- loop_split_worker_do(common_data, data, edge_vectors);
- }
- }
-
- ml_prev = ml_curr;
- ml_prev_index = ml_curr_index;
- }
- }
-
- /* Last block of data... Since it is calloc'ed and we use first NULL item as stopper, everything is fine. */
- if (pool && data_idx) {
- BLI_task_pool_push(pool, loop_split_worker, data_buff, true, TASK_PRIORITY_LOW);
- }
-
- if (edge_vectors) {
- BLI_stack_free(edge_vectors);
- }
- MEM_freeN(skip_loops);
+ data->ml_curr = ml_curr;
+ data->ml_prev = ml_prev;
+ data->ml_curr_index = ml_curr_index;
+ data->ml_prev_index = ml_prev_index;
+ data->e2l_prev = e2l_prev; /* Also tag as 'fan' task. */
+ data->mp_index = mp_index;
+ if (lnors_spacearr) {
+ data->lnor_space = BKE_lnor_space_create(lnors_spacearr);
+ }
+ }
+
+ if (pool) {
+ data_idx++;
+ if (data_idx == LOOP_SPLIT_TASK_BLOCK_SIZE) {
+ BLI_task_pool_push(pool, loop_split_worker, data_buff, true, TASK_PRIORITY_LOW);
+ data_idx = 0;
+ }
+ }
+ else {
+ loop_split_worker_do(common_data, data, edge_vectors);
+ }
+ }
+
+ ml_prev = ml_curr;
+ ml_prev_index = ml_curr_index;
+ }
+ }
+
+ /* Last block of data... Since it is calloc'ed and we use first NULL item as stopper, everything is fine. */
+ if (pool && data_idx) {
+ BLI_task_pool_push(pool, loop_split_worker, data_buff, true, TASK_PRIORITY_LOW);
+ }
+
+ if (edge_vectors) {
+ BLI_stack_free(edge_vectors);
+ }
+ MEM_freeN(skip_loops);
#ifdef DEBUG_TIME
- TIMEIT_END_AVERAGED(loop_split_generator);
+ TIMEIT_END_AVERAGED(loop_split_generator);
#endif
}
@@ -1488,127 +1603,138 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common
* Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals').
* Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry (splitting edges).
*/
-void BKE_mesh_normals_loop_split(
- const MVert *mverts, const int UNUSED(numVerts), MEdge *medges, const int numEdges,
- MLoop *mloops, float (*r_loopnors)[3], const int numLoops,
- MPoly *mpolys, const float (*polynors)[3], const int numPolys,
- const bool use_split_normals, const float split_angle,
- MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2], int *r_loop_to_poly)
-{
- /* 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));
-
- if (!use_split_normals) {
- /* In this case, we simply fill lnors with vnors (or fnors for flat faces), quite simple!
- * Note this is done here to keep some logic and consistency in this quite complex code,
- * since we may want to use lnors even when mesh's 'autosmooth' is disabled (see e.g. mesh mapping code).
- * As usual, we could handle that on case-by-case basis, but simpler to keep it well confined here.
- */
- int mp_index;
-
- for (mp_index = 0; mp_index < numPolys; mp_index++) {
- MPoly *mp = &mpolys[mp_index];
- int ml_index = mp->loopstart;
- const int ml_index_end = ml_index + mp->totloop;
- 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]);
- }
- else {
- normal_short_to_float_v3(r_loopnors[ml_index], mverts[mloops[ml_index].v].no);
- }
- }
- }
- return;
- }
-
- /* Mapping edge -> loops.
- * If that edge is used by more than two loops (polys), it is always sharp (and tagged as such, see below).
- * We also use the second loop index as a kind of flag: smooth edge: > 0,
- * sharp edge: < 0 (INDEX_INVALID || INDEX_UNSET),
- * unset: INDEX_UNSET
- * Note that currently we only have two values for second loop of sharp edges. However, if needed, we can
- * store the negated value of loop index instead of INDEX_INVALID to retrieve the real value later in code).
- * Note also that lose edges always have both values set to 0!
- */
- int (*edge_to_loops)[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 = r_loop_to_poly ? r_loop_to_poly : MEM_malloc_arrayN((size_t)numLoops, sizeof(*loop_to_poly), __func__);
-
- /* When using custom loop normals, disable the angle feature! */
- const bool check_angle = (split_angle < (float)M_PI) && (clnors_data == NULL);
-
- MLoopNorSpaceArray _lnors_spacearr = {NULL};
+void BKE_mesh_normals_loop_split(const MVert *mverts,
+ const int UNUSED(numVerts),
+ MEdge *medges,
+ const int numEdges,
+ MLoop *mloops,
+ float (*r_loopnors)[3],
+ const int numLoops,
+ MPoly *mpolys,
+ const float (*polynors)[3],
+ const int numPolys,
+ const bool use_split_normals,
+ const float split_angle,
+ MLoopNorSpaceArray *r_lnors_spacearr,
+ short (*clnors_data)[2],
+ int *r_loop_to_poly)
+{
+ /* 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));
+
+ if (!use_split_normals) {
+ /* In this case, we simply fill lnors with vnors (or fnors for flat faces), quite simple!
+ * Note this is done here to keep some logic and consistency in this quite complex code,
+ * since we may want to use lnors even when mesh's 'autosmooth' is disabled (see e.g. mesh mapping code).
+ * As usual, we could handle that on case-by-case basis, but simpler to keep it well confined here.
+ */
+ int mp_index;
+
+ for (mp_index = 0; mp_index < numPolys; mp_index++) {
+ MPoly *mp = &mpolys[mp_index];
+ int ml_index = mp->loopstart;
+ const int ml_index_end = ml_index + mp->totloop;
+ 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]);
+ }
+ else {
+ normal_short_to_float_v3(r_loopnors[ml_index], mverts[mloops[ml_index].v].no);
+ }
+ }
+ }
+ return;
+ }
+
+ /* Mapping edge -> loops.
+ * If that edge is used by more than two loops (polys), it is always sharp (and tagged as such, see below).
+ * We also use the second loop index as a kind of flag: smooth edge: > 0,
+ * sharp edge: < 0 (INDEX_INVALID || INDEX_UNSET),
+ * unset: INDEX_UNSET
+ * Note that currently we only have two values for second loop of sharp edges. However, if needed, we can
+ * store the negated value of loop index instead of INDEX_INVALID to retrieve the real value later in code).
+ * Note also that lose edges always have both values set to 0!
+ */
+ int(*edge_to_loops)[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 = r_loop_to_poly ?
+ r_loop_to_poly :
+ MEM_malloc_arrayN((size_t)numLoops, sizeof(*loop_to_poly), __func__);
+
+ /* When using custom loop normals, disable the angle feature! */
+ const bool check_angle = (split_angle < (float)M_PI) && (clnors_data == NULL);
+
+ MLoopNorSpaceArray _lnors_spacearr = {NULL};
#ifdef DEBUG_TIME
- TIMEIT_START_AVERAGED(BKE_mesh_normals_loop_split);
+ TIMEIT_START_AVERAGED(BKE_mesh_normals_loop_split);
#endif
- if (!r_lnors_spacearr && clnors_data) {
- /* We need to compute lnor spacearr if some custom lnor data are given to us! */
- r_lnors_spacearr = &_lnors_spacearr;
- }
- if (r_lnors_spacearr) {
- BKE_lnor_spacearr_init(r_lnors_spacearr, numLoops, MLNOR_SPACEARR_LOOP_INDEX);
- }
-
- /* Init data common to all tasks. */
- LoopSplitTaskDataCommon common_data = {
- .lnors_spacearr = r_lnors_spacearr,
- .loopnors = r_loopnors,
- .clnors_data = clnors_data,
- .mverts = mverts,
- .medges = medges,
- .mloops = mloops,
- .mpolys = mpolys,
- .edge_to_loops = edge_to_loops,
- .loop_to_poly = loop_to_poly,
- .polynors = polynors,
- .numEdges = numEdges,
- .numLoops = numLoops,
- .numPolys = numPolys,
- };
-
- /* This first loop check which edges are actually smooth, and compute edge vectors. */
- mesh_edges_sharp_tag(&common_data, check_angle, split_angle, false);
-
- if (numLoops < LOOP_SPLIT_TASK_BLOCK_SIZE * 8) {
- /* Not enough loops to be worth the whole threading overhead... */
- loop_split_generator(NULL, &common_data);
- }
- else {
- TaskScheduler *task_scheduler;
- TaskPool *task_pool;
-
- task_scheduler = BLI_task_scheduler_get();
- task_pool = BLI_task_pool_create(task_scheduler, &common_data);
-
- loop_split_generator(task_pool, &common_data);
-
- BLI_task_pool_work_and_wait(task_pool);
-
- BLI_task_pool_free(task_pool);
- }
-
- 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);
- }
- }
+ if (!r_lnors_spacearr && clnors_data) {
+ /* We need to compute lnor spacearr if some custom lnor data are given to us! */
+ r_lnors_spacearr = &_lnors_spacearr;
+ }
+ if (r_lnors_spacearr) {
+ BKE_lnor_spacearr_init(r_lnors_spacearr, numLoops, MLNOR_SPACEARR_LOOP_INDEX);
+ }
+
+ /* Init data common to all tasks. */
+ LoopSplitTaskDataCommon common_data = {
+ .lnors_spacearr = r_lnors_spacearr,
+ .loopnors = r_loopnors,
+ .clnors_data = clnors_data,
+ .mverts = mverts,
+ .medges = medges,
+ .mloops = mloops,
+ .mpolys = mpolys,
+ .edge_to_loops = edge_to_loops,
+ .loop_to_poly = loop_to_poly,
+ .polynors = polynors,
+ .numEdges = numEdges,
+ .numLoops = numLoops,
+ .numPolys = numPolys,
+ };
+
+ /* This first loop check which edges are actually smooth, and compute edge vectors. */
+ mesh_edges_sharp_tag(&common_data, check_angle, split_angle, false);
+
+ if (numLoops < LOOP_SPLIT_TASK_BLOCK_SIZE * 8) {
+ /* Not enough loops to be worth the whole threading overhead... */
+ loop_split_generator(NULL, &common_data);
+ }
+ else {
+ TaskScheduler *task_scheduler;
+ TaskPool *task_pool;
+
+ task_scheduler = BLI_task_scheduler_get();
+ task_pool = BLI_task_pool_create(task_scheduler, &common_data);
+
+ loop_split_generator(task_pool, &common_data);
+
+ BLI_task_pool_work_and_wait(task_pool);
+
+ BLI_task_pool_free(task_pool);
+ }
+
+ 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);
+ TIMEIT_END_AVERAGED(BKE_mesh_normals_loop_split);
#endif
}
@@ -1625,262 +1751,338 @@ void BKE_mesh_normals_loop_split(
* r_custom_loopnors is expected to have normalized normals, or zero ones, in which case they will be replaced
* by default loop/vertex normal.
*/
-static void mesh_normals_loop_custom_set(
- const MVert *mverts, const int numVerts, MEdge *medges, const int numEdges,
- MLoop *mloops, float (*r_custom_loopnors)[3], const int numLoops,
- MPoly *mpolys, const float (*polynors)[3], const int numPolys,
- short (*r_clnors_data)[2], const bool use_vertices)
-{
- /* 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
- * by io addons when importing custom normals, and modifier (and perhaps from some editing tools later?).
- * So better to keep some simplicity here, and just call BKE_mesh_normals_loop_split() twice!
- */
- MLoopNorSpaceArray lnors_spacearr = {NULL};
- BLI_bitmap *done_loops = BLI_BITMAP_NEW((size_t)numLoops, __func__);
- float (*lnors)[3] = MEM_calloc_arrayN((size_t)numLoops, sizeof(*lnors), __func__);
- int *loop_to_poly = MEM_malloc_arrayN((size_t)numLoops, sizeof(int), __func__);
- /* 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;
- const float split_angle = (float)M_PI;
- int i;
-
- BLI_SMALLSTACK_DECLARE(clnors_data, short *);
-
- /* Compute current lnor spacearr. */
- BKE_mesh_normals_loop_split(
- mverts, numVerts, medges, numEdges, mloops, lnors, numLoops,
- mpolys, polynors, numPolys, use_split_normals, split_angle,
- &lnors_spacearr, NULL, loop_to_poly);
-
- /* Set all given zero vectors to their default value. */
- if (use_vertices) {
- for (i = 0; i < numVerts; i++) {
- if (is_zero_v3(r_custom_loopnors[i])) {
- normal_short_to_float_v3(r_custom_loopnors[i], mverts[i].no);
- }
- }
- }
- else {
- for (i = 0; i < numLoops; i++) {
- if (is_zero_v3(r_custom_loopnors[i])) {
- copy_v3_v3(r_custom_loopnors[i], lnors[i]);
- }
- }
- }
-
- BLI_assert(lnors_spacearr.data_type == MLNOR_SPACEARR_LOOP_INDEX);
-
- /* Now, check each current smooth fan (one lnor space per smooth fan!), and if all its matching custom lnors
- * are not (enough) equal, add sharp edges as needed.
- * This way, next time we run BKE_mesh_normals_loop_split(), we'll get lnor spacearr/smooth fans matching
- * given custom lnors.
- * Note this code *will never* unsharp edges!
- * And quite obviously, when we set custom normals per vertices, running this is absolutely useless.
- */
- if (!use_vertices) {
- for (i = 0; i < numLoops; i++) {
- if (!lnors_spacearr.lspacearr[i]) {
- /* This should not happen in theory, but in some rare case (probably ugly geometry)
- * we can get some NULL loopspacearr at this point. :/
- * Maybe we should set those loops' edges as sharp?
- */
- BLI_BITMAP_ENABLE(done_loops, i);
- if (G.debug & G_DEBUG) {
- printf("WARNING! Getting invalid NULL loop space for loop %d!\n", i);
- }
- continue;
- }
-
- if (!BLI_BITMAP_TEST(done_loops, i)) {
- /* Notes:
- * * In case of mono-loop smooth fan, we have nothing to do.
- * * Loops in this linklist are ordered (in reversed order compared to how they were discovered by
- * BKE_mesh_normals_loop_split(), but this is not a problem). Which means if we find a
- * mismatching clnor, we know all remaining loops will have to be in a new, different smooth fan/
- * lnor space.
- * * In smooth fan case, we compare each clnor against a ref one, to avoid small differences adding
- * up into a real big one in the end!
- */
- if (lnors_spacearr.lspacearr[i]->flags & MLNOR_SPACE_IS_SINGLE) {
- BLI_BITMAP_ENABLE(done_loops, i);
- continue;
- }
-
- LinkNode *loops = lnors_spacearr.lspacearr[i]->loops;
- MLoop *prev_ml = NULL;
- const float *org_nor = NULL;
-
- while (loops) {
- const int lidx = POINTER_AS_INT(loops->link);
- MLoop *ml = &mloops[lidx];
- const int nidx = lidx;
- float *nor = r_custom_loopnors[nidx];
-
- if (!org_nor) {
- org_nor = nor;
- }
- else if (dot_v3v3(org_nor, nor) < LNOR_SPACE_TRIGO_THRESHOLD) {
- /* Current normal differs too much from org one, we have to tag the edge between
- * previous loop's face and current's one as sharp.
- * We know those two loops do not point to the same edge, since we do not allow reversed winding
- * in a same smooth fan.
- */
- const MPoly *mp = &mpolys[loop_to_poly[lidx]];
- const MLoop *mlp = &mloops[(lidx == mp->loopstart) ? mp->loopstart + mp->totloop - 1 : lidx - 1];
- medges[(prev_ml->e == mlp->e) ? prev_ml->e : ml->e].flag |= ME_SHARP;
-
- org_nor = nor;
- }
-
- prev_ml = ml;
- loops = loops->next;
- BLI_BITMAP_ENABLE(done_loops, lidx);
- }
-
- /* We also have to check between last and first loops, otherwise we may miss some sharp edges here!
- * This is just a simplified version of above while loop.
- * See T45984. */
- loops = lnors_spacearr.lspacearr[i]->loops;
- if (loops && org_nor) {
- const int lidx = POINTER_AS_INT(loops->link);
- MLoop *ml = &mloops[lidx];
- const int nidx = lidx;
- float *nor = r_custom_loopnors[nidx];
-
- if (dot_v3v3(org_nor, nor) < LNOR_SPACE_TRIGO_THRESHOLD) {
- const MPoly *mp = &mpolys[loop_to_poly[lidx]];
- const MLoop *mlp = &mloops[(lidx == mp->loopstart) ? mp->loopstart + mp->totloop - 1 : lidx - 1];
- medges[(prev_ml->e == mlp->e) ? prev_ml->e : ml->e].flag |= ME_SHARP;
- }
- }
- }
- }
-
- /* And now, recompute our new auto lnors and lnor spacearr! */
- BKE_lnor_spacearr_clear(&lnors_spacearr);
- BKE_mesh_normals_loop_split(
- mverts, numVerts, medges, numEdges, mloops, lnors, numLoops,
- mpolys, polynors, numPolys, use_split_normals, split_angle,
- &lnors_spacearr, NULL, loop_to_poly);
- }
- else {
- BLI_bitmap_set_all(done_loops, true, (size_t)numLoops);
- }
-
- /* And we just have to convert plain object-space custom normals to our lnor space-encoded ones. */
- for (i = 0; i < numLoops; i++) {
- if (!lnors_spacearr.lspacearr[i]) {
- BLI_BITMAP_DISABLE(done_loops, i);
- if (G.debug & G_DEBUG) {
- printf("WARNING! Still getting invalid NULL loop space in second loop for loop %d!\n", i);
- }
- continue;
- }
-
- if (BLI_BITMAP_TEST_BOOL(done_loops, i)) {
- /* Note we accumulate and average all custom normals in current smooth fan, to avoid getting different
- * clnors data (tiny differences in plain custom normals can give rather huge differences in
- * computed 2D factors).
- */
- LinkNode *loops = lnors_spacearr.lspacearr[i]->loops;
- if (lnors_spacearr.lspacearr[i]->flags & MLNOR_SPACE_IS_SINGLE) {
- BLI_assert(POINTER_AS_INT(loops) == i);
- const int nidx = use_vertices ? (int)mloops[i].v : i;
- float *nor = r_custom_loopnors[nidx];
-
- BKE_lnor_space_custom_normal_to_data(lnors_spacearr.lspacearr[i], nor, r_clnors_data[i]);
- BLI_BITMAP_DISABLE(done_loops, i);
- }
- else {
- int nbr_nors = 0;
- float avg_nor[3];
- short clnor_data_tmp[2], *clnor_data;
-
- zero_v3(avg_nor);
- while (loops) {
- const int lidx = POINTER_AS_INT(loops->link);
- const int nidx = use_vertices ? (int)mloops[lidx].v : lidx;
- float *nor = r_custom_loopnors[nidx];
-
- nbr_nors++;
- add_v3_v3(avg_nor, nor);
- BLI_SMALLSTACK_PUSH(clnors_data, (short *)r_clnors_data[lidx]);
-
- loops = loops->next;
- BLI_BITMAP_DISABLE(done_loops, lidx);
- }
-
- mul_v3_fl(avg_nor, 1.0f / (float)nbr_nors);
- BKE_lnor_space_custom_normal_to_data(lnors_spacearr.lspacearr[i], avg_nor, clnor_data_tmp);
-
- while ((clnor_data = BLI_SMALLSTACK_POP(clnors_data))) {
- clnor_data[0] = clnor_data_tmp[0];
- clnor_data[1] = clnor_data_tmp[1];
- }
- }
- }
- }
-
- MEM_freeN(lnors);
- MEM_freeN(loop_to_poly);
- MEM_freeN(done_loops);
- BKE_lnor_spacearr_free(&lnors_spacearr);
-}
-
-void BKE_mesh_normals_loop_custom_set(
- const MVert *mverts, const int numVerts, MEdge *medges, const int numEdges,
- MLoop *mloops, float (*r_custom_loopnors)[3], const int numLoops,
- MPoly *mpolys, const float (*polynors)[3], const int numPolys,
- short (*r_clnors_data)[2])
-{
- mesh_normals_loop_custom_set(
- mverts, numVerts, medges, numEdges, mloops, r_custom_loopnors, numLoops,
- mpolys, polynors, numPolys, r_clnors_data, false);
-}
-
-void BKE_mesh_normals_loop_custom_from_vertices_set(
- const MVert *mverts, float (*r_custom_vertnors)[3], const int numVerts,
- MEdge *medges, const int numEdges, MLoop *mloops, const int numLoops,
- MPoly *mpolys, const float (*polynors)[3], const int numPolys,
- short (*r_clnors_data)[2])
-{
- mesh_normals_loop_custom_set(
- mverts, numVerts, medges, numEdges, mloops, r_custom_vertnors, numLoops,
- mpolys, polynors, numPolys, r_clnors_data, true);
+static void mesh_normals_loop_custom_set(const MVert *mverts,
+ const int numVerts,
+ MEdge *medges,
+ const int numEdges,
+ MLoop *mloops,
+ float (*r_custom_loopnors)[3],
+ const int numLoops,
+ MPoly *mpolys,
+ const float (*polynors)[3],
+ const int numPolys,
+ short (*r_clnors_data)[2],
+ const bool use_vertices)
+{
+ /* 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
+ * by io addons when importing custom normals, and modifier (and perhaps from some editing tools later?).
+ * So better to keep some simplicity here, and just call BKE_mesh_normals_loop_split() twice!
+ */
+ MLoopNorSpaceArray lnors_spacearr = {NULL};
+ BLI_bitmap *done_loops = BLI_BITMAP_NEW((size_t)numLoops, __func__);
+ float(*lnors)[3] = MEM_calloc_arrayN((size_t)numLoops, sizeof(*lnors), __func__);
+ int *loop_to_poly = MEM_malloc_arrayN((size_t)numLoops, sizeof(int), __func__);
+ /* 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;
+ const float split_angle = (float)M_PI;
+ int i;
+
+ BLI_SMALLSTACK_DECLARE(clnors_data, short *);
+
+ /* Compute current lnor spacearr. */
+ BKE_mesh_normals_loop_split(mverts,
+ numVerts,
+ medges,
+ numEdges,
+ mloops,
+ lnors,
+ numLoops,
+ mpolys,
+ polynors,
+ numPolys,
+ use_split_normals,
+ split_angle,
+ &lnors_spacearr,
+ NULL,
+ loop_to_poly);
+
+ /* Set all given zero vectors to their default value. */
+ if (use_vertices) {
+ for (i = 0; i < numVerts; i++) {
+ if (is_zero_v3(r_custom_loopnors[i])) {
+ normal_short_to_float_v3(r_custom_loopnors[i], mverts[i].no);
+ }
+ }
+ }
+ else {
+ for (i = 0; i < numLoops; i++) {
+ if (is_zero_v3(r_custom_loopnors[i])) {
+ copy_v3_v3(r_custom_loopnors[i], lnors[i]);
+ }
+ }
+ }
+
+ BLI_assert(lnors_spacearr.data_type == MLNOR_SPACEARR_LOOP_INDEX);
+
+ /* Now, check each current smooth fan (one lnor space per smooth fan!), and if all its matching custom lnors
+ * are not (enough) equal, add sharp edges as needed.
+ * This way, next time we run BKE_mesh_normals_loop_split(), we'll get lnor spacearr/smooth fans matching
+ * given custom lnors.
+ * Note this code *will never* unsharp edges!
+ * And quite obviously, when we set custom normals per vertices, running this is absolutely useless.
+ */
+ if (!use_vertices) {
+ for (i = 0; i < numLoops; i++) {
+ if (!lnors_spacearr.lspacearr[i]) {
+ /* This should not happen in theory, but in some rare case (probably ugly geometry)
+ * we can get some NULL loopspacearr at this point. :/
+ * Maybe we should set those loops' edges as sharp?
+ */
+ BLI_BITMAP_ENABLE(done_loops, i);
+ if (G.debug & G_DEBUG) {
+ printf("WARNING! Getting invalid NULL loop space for loop %d!\n", i);
+ }
+ continue;
+ }
+
+ if (!BLI_BITMAP_TEST(done_loops, i)) {
+ /* Notes:
+ * * In case of mono-loop smooth fan, we have nothing to do.
+ * * Loops in this linklist are ordered (in reversed order compared to how they were discovered by
+ * BKE_mesh_normals_loop_split(), but this is not a problem). Which means if we find a
+ * mismatching clnor, we know all remaining loops will have to be in a new, different smooth fan/
+ * lnor space.
+ * * In smooth fan case, we compare each clnor against a ref one, to avoid small differences adding
+ * up into a real big one in the end!
+ */
+ if (lnors_spacearr.lspacearr[i]->flags & MLNOR_SPACE_IS_SINGLE) {
+ BLI_BITMAP_ENABLE(done_loops, i);
+ continue;
+ }
+
+ LinkNode *loops = lnors_spacearr.lspacearr[i]->loops;
+ MLoop *prev_ml = NULL;
+ const float *org_nor = NULL;
+
+ while (loops) {
+ const int lidx = POINTER_AS_INT(loops->link);
+ MLoop *ml = &mloops[lidx];
+ const int nidx = lidx;
+ float *nor = r_custom_loopnors[nidx];
+
+ if (!org_nor) {
+ org_nor = nor;
+ }
+ else if (dot_v3v3(org_nor, nor) < LNOR_SPACE_TRIGO_THRESHOLD) {
+ /* Current normal differs too much from org one, we have to tag the edge between
+ * previous loop's face and current's one as sharp.
+ * We know those two loops do not point to the same edge, since we do not allow reversed winding
+ * in a same smooth fan.
+ */
+ const MPoly *mp = &mpolys[loop_to_poly[lidx]];
+ const MLoop *mlp =
+ &mloops[(lidx == mp->loopstart) ? mp->loopstart + mp->totloop - 1 : lidx - 1];
+ medges[(prev_ml->e == mlp->e) ? prev_ml->e : ml->e].flag |= ME_SHARP;
+
+ org_nor = nor;
+ }
+
+ prev_ml = ml;
+ loops = loops->next;
+ BLI_BITMAP_ENABLE(done_loops, lidx);
+ }
+
+ /* We also have to check between last and first loops, otherwise we may miss some sharp edges here!
+ * This is just a simplified version of above while loop.
+ * See T45984. */
+ loops = lnors_spacearr.lspacearr[i]->loops;
+ if (loops && org_nor) {
+ const int lidx = POINTER_AS_INT(loops->link);
+ MLoop *ml = &mloops[lidx];
+ const int nidx = lidx;
+ float *nor = r_custom_loopnors[nidx];
+
+ if (dot_v3v3(org_nor, nor) < LNOR_SPACE_TRIGO_THRESHOLD) {
+ const MPoly *mp = &mpolys[loop_to_poly[lidx]];
+ const MLoop *mlp =
+ &mloops[(lidx == mp->loopstart) ? mp->loopstart + mp->totloop - 1 : lidx - 1];
+ medges[(prev_ml->e == mlp->e) ? prev_ml->e : ml->e].flag |= ME_SHARP;
+ }
+ }
+ }
+ }
+
+ /* And now, recompute our new auto lnors and lnor spacearr! */
+ BKE_lnor_spacearr_clear(&lnors_spacearr);
+ BKE_mesh_normals_loop_split(mverts,
+ numVerts,
+ medges,
+ numEdges,
+ mloops,
+ lnors,
+ numLoops,
+ mpolys,
+ polynors,
+ numPolys,
+ use_split_normals,
+ split_angle,
+ &lnors_spacearr,
+ NULL,
+ loop_to_poly);
+ }
+ else {
+ BLI_bitmap_set_all(done_loops, true, (size_t)numLoops);
+ }
+
+ /* And we just have to convert plain object-space custom normals to our lnor space-encoded ones. */
+ for (i = 0; i < numLoops; i++) {
+ if (!lnors_spacearr.lspacearr[i]) {
+ BLI_BITMAP_DISABLE(done_loops, i);
+ if (G.debug & G_DEBUG) {
+ printf("WARNING! Still getting invalid NULL loop space in second loop for loop %d!\n", i);
+ }
+ continue;
+ }
+
+ if (BLI_BITMAP_TEST_BOOL(done_loops, i)) {
+ /* Note we accumulate and average all custom normals in current smooth fan, to avoid getting different
+ * clnors data (tiny differences in plain custom normals can give rather huge differences in
+ * computed 2D factors).
+ */
+ LinkNode *loops = lnors_spacearr.lspacearr[i]->loops;
+ if (lnors_spacearr.lspacearr[i]->flags & MLNOR_SPACE_IS_SINGLE) {
+ BLI_assert(POINTER_AS_INT(loops) == i);
+ const int nidx = use_vertices ? (int)mloops[i].v : i;
+ float *nor = r_custom_loopnors[nidx];
+
+ BKE_lnor_space_custom_normal_to_data(lnors_spacearr.lspacearr[i], nor, r_clnors_data[i]);
+ BLI_BITMAP_DISABLE(done_loops, i);
+ }
+ else {
+ int nbr_nors = 0;
+ float avg_nor[3];
+ short clnor_data_tmp[2], *clnor_data;
+
+ zero_v3(avg_nor);
+ while (loops) {
+ const int lidx = POINTER_AS_INT(loops->link);
+ const int nidx = use_vertices ? (int)mloops[lidx].v : lidx;
+ float *nor = r_custom_loopnors[nidx];
+
+ nbr_nors++;
+ add_v3_v3(avg_nor, nor);
+ BLI_SMALLSTACK_PUSH(clnors_data, (short *)r_clnors_data[lidx]);
+
+ loops = loops->next;
+ BLI_BITMAP_DISABLE(done_loops, lidx);
+ }
+
+ mul_v3_fl(avg_nor, 1.0f / (float)nbr_nors);
+ BKE_lnor_space_custom_normal_to_data(lnors_spacearr.lspacearr[i], avg_nor, clnor_data_tmp);
+
+ while ((clnor_data = BLI_SMALLSTACK_POP(clnors_data))) {
+ clnor_data[0] = clnor_data_tmp[0];
+ clnor_data[1] = clnor_data_tmp[1];
+ }
+ }
+ }
+ }
+
+ MEM_freeN(lnors);
+ MEM_freeN(loop_to_poly);
+ MEM_freeN(done_loops);
+ BKE_lnor_spacearr_free(&lnors_spacearr);
+}
+
+void BKE_mesh_normals_loop_custom_set(const MVert *mverts,
+ const int numVerts,
+ MEdge *medges,
+ const int numEdges,
+ MLoop *mloops,
+ float (*r_custom_loopnors)[3],
+ const int numLoops,
+ MPoly *mpolys,
+ const float (*polynors)[3],
+ const int numPolys,
+ short (*r_clnors_data)[2])
+{
+ mesh_normals_loop_custom_set(mverts,
+ numVerts,
+ medges,
+ numEdges,
+ mloops,
+ r_custom_loopnors,
+ numLoops,
+ mpolys,
+ polynors,
+ numPolys,
+ r_clnors_data,
+ false);
+}
+
+void BKE_mesh_normals_loop_custom_from_vertices_set(const MVert *mverts,
+ float (*r_custom_vertnors)[3],
+ const int numVerts,
+ MEdge *medges,
+ const int numEdges,
+ MLoop *mloops,
+ const int numLoops,
+ MPoly *mpolys,
+ const float (*polynors)[3],
+ const int numPolys,
+ short (*r_clnors_data)[2])
+{
+ mesh_normals_loop_custom_set(mverts,
+ numVerts,
+ medges,
+ numEdges,
+ mloops,
+ r_custom_vertnors,
+ numLoops,
+ mpolys,
+ polynors,
+ numPolys,
+ r_clnors_data,
+ true);
}
static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const bool use_vertices)
{
- short (*clnors)[2];
- const int numloops = mesh->totloop;
-
- clnors = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL);
- if (clnors != NULL) {
- memset(clnors, 0, sizeof(*clnors) * (size_t)numloops);
- }
- else {
- clnors = CustomData_add_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL, numloops);
- }
-
- float (*polynors)[3] = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
- bool free_polynors = false;
- if (polynors == NULL) {
- polynors = MEM_mallocN(sizeof(float[3]) * (size_t)mesh->totpoly, __func__);
- BKE_mesh_calc_normals_poly(
- mesh->mvert, NULL, mesh->totvert,
- mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, polynors, false);
- free_polynors = true;
- }
-
- mesh_normals_loop_custom_set(
- mesh->mvert, mesh->totvert, mesh->medge, mesh->totedge, mesh->mloop, r_custom_nors, mesh->totloop,
- mesh->mpoly, polynors, mesh->totpoly, clnors, use_vertices);
-
- if (free_polynors) {
- MEM_freeN(polynors);
- }
+ short(*clnors)[2];
+ const int numloops = mesh->totloop;
+
+ clnors = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL);
+ if (clnors != NULL) {
+ memset(clnors, 0, sizeof(*clnors) * (size_t)numloops);
+ }
+ else {
+ clnors = CustomData_add_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL, numloops);
+ }
+
+ float(*polynors)[3] = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
+ bool free_polynors = false;
+ if (polynors == NULL) {
+ polynors = MEM_mallocN(sizeof(float[3]) * (size_t)mesh->totpoly, __func__);
+ BKE_mesh_calc_normals_poly(mesh->mvert,
+ NULL,
+ mesh->totvert,
+ mesh->mloop,
+ mesh->mpoly,
+ mesh->totloop,
+ mesh->totpoly,
+ polynors,
+ false);
+ free_polynors = true;
+ }
+
+ mesh_normals_loop_custom_set(mesh->mvert,
+ mesh->totvert,
+ mesh->medge,
+ mesh->totedge,
+ mesh->mloop,
+ r_custom_nors,
+ mesh->totloop,
+ mesh->mpoly,
+ polynors,
+ mesh->totpoly,
+ clnors,
+ use_vertices);
+
+ if (free_polynors) {
+ MEM_freeN(polynors);
+ }
}
/**
@@ -1891,7 +2093,7 @@ static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const
*/
void BKE_mesh_set_custom_normals(Mesh *mesh, float (*r_custom_loopnors)[3])
{
- mesh_set_custom_normals(mesh, r_custom_loopnors, false);
+ mesh_set_custom_normals(mesh, r_custom_loopnors, false);
}
/**
@@ -1902,47 +2104,46 @@ void BKE_mesh_set_custom_normals(Mesh *mesh, float (*r_custom_loopnors)[3])
*/
void BKE_mesh_set_custom_normals_from_vertices(Mesh *mesh, float (*r_custom_vertnors)[3])
{
- mesh_set_custom_normals(mesh, r_custom_vertnors, true);
+ mesh_set_custom_normals(mesh, r_custom_vertnors, true);
}
-
/**
* Computes average per-vertex normals from given custom loop normals.
*
* \param clnors: The computed custom loop normals.
* \param r_vert_clnors: The (already allocated) array where to store averaged per-vertex normals.
*/
-void BKE_mesh_normals_loop_to_vertex(
- const int numVerts, const MLoop *mloops, const int numLoops,
- const float (*clnors)[3], float (*r_vert_clnors)[3])
+void BKE_mesh_normals_loop_to_vertex(const int numVerts,
+ const MLoop *mloops,
+ const int numLoops,
+ const float (*clnors)[3],
+ float (*r_vert_clnors)[3])
{
- const MLoop *ml;
- int i;
+ const MLoop *ml;
+ int i;
- int *vert_loops_nbr = MEM_calloc_arrayN((size_t)numVerts, sizeof(*vert_loops_nbr), __func__);
+ int *vert_loops_nbr = MEM_calloc_arrayN((size_t)numVerts, sizeof(*vert_loops_nbr), __func__);
- copy_vn_fl((float *)r_vert_clnors, 3 * numVerts, 0.0f);
+ copy_vn_fl((float *)r_vert_clnors, 3 * numVerts, 0.0f);
- for (i = 0, ml = mloops; i < numLoops; i++, ml++) {
- const unsigned int v = ml->v;
+ for (i = 0, ml = mloops; i < numLoops; i++, ml++) {
+ const unsigned int v = ml->v;
- add_v3_v3(r_vert_clnors[v], clnors[i]);
- vert_loops_nbr[v]++;
- }
+ add_v3_v3(r_vert_clnors[v], clnors[i]);
+ vert_loops_nbr[v]++;
+ }
- for (i = 0; i < numVerts; i++) {
- mul_v3_fl(r_vert_clnors[i], 1.0f / (float)vert_loops_nbr[i]);
- }
+ for (i = 0; i < numVerts; i++) {
+ mul_v3_fl(r_vert_clnors[i], 1.0f / (float)vert_loops_nbr[i]);
+ }
- MEM_freeN(vert_loops_nbr);
+ MEM_freeN(vert_loops_nbr);
}
-
#undef LNOR_SPACE_TRIGO_THRESHOLD
/** \} */
-
/* -------------------------------------------------------------------- */
/** \name Polygon Calculations
* \{ */
@@ -1954,175 +2155,169 @@ void BKE_mesh_normals_loop_to_vertex(
* polygon See Graphics Gems for
* computing newell normal.
*/
-static void mesh_calc_ngon_normal(
- const MPoly *mpoly, const MLoop *loopstart,
- const MVert *mvert, float normal[3])
-{
- const int nverts = mpoly->totloop;
- const float *v_prev = mvert[loopstart[nverts - 1].v].co;
- const float *v_curr;
- int i;
-
- zero_v3(normal);
-
- /* Newell's Method */
- for (i = 0; i < nverts; i++) {
- v_curr = mvert[loopstart[i].v].co;
- add_newell_cross_v3_v3v3(normal, v_prev, v_curr);
- v_prev = v_curr;
- }
-
- if (UNLIKELY(normalize_v3(normal) == 0.0f)) {
- normal[2] = 1.0f; /* other axis set to 0.0 */
- }
-}
-
-void BKE_mesh_calc_poly_normal(
- const MPoly *mpoly, const MLoop *loopstart,
- const MVert *mvarray, float r_no[3])
-{
- if (mpoly->totloop > 4) {
- mesh_calc_ngon_normal(mpoly, loopstart, mvarray, r_no);
- }
- else if (mpoly->totloop == 3) {
- normal_tri_v3(
- r_no,
- mvarray[loopstart[0].v].co,
- mvarray[loopstart[1].v].co,
- mvarray[loopstart[2].v].co);
- }
- else if (mpoly->totloop == 4) {
- normal_quad_v3(
- r_no,
- mvarray[loopstart[0].v].co,
- mvarray[loopstart[1].v].co,
- mvarray[loopstart[2].v].co,
- mvarray[loopstart[3].v].co);
- }
- else { /* horrible, two sided face! */
- r_no[0] = 0.0;
- r_no[1] = 0.0;
- r_no[2] = 1.0;
- }
+static void mesh_calc_ngon_normal(const MPoly *mpoly,
+ const MLoop *loopstart,
+ const MVert *mvert,
+ float normal[3])
+{
+ const int nverts = mpoly->totloop;
+ const float *v_prev = mvert[loopstart[nverts - 1].v].co;
+ const float *v_curr;
+ int i;
+
+ zero_v3(normal);
+
+ /* Newell's Method */
+ for (i = 0; i < nverts; i++) {
+ v_curr = mvert[loopstart[i].v].co;
+ add_newell_cross_v3_v3v3(normal, v_prev, v_curr);
+ v_prev = v_curr;
+ }
+
+ if (UNLIKELY(normalize_v3(normal) == 0.0f)) {
+ normal[2] = 1.0f; /* other axis set to 0.0 */
+ }
+}
+
+void BKE_mesh_calc_poly_normal(const MPoly *mpoly,
+ const MLoop *loopstart,
+ const MVert *mvarray,
+ float r_no[3])
+{
+ if (mpoly->totloop > 4) {
+ mesh_calc_ngon_normal(mpoly, loopstart, mvarray, r_no);
+ }
+ else if (mpoly->totloop == 3) {
+ normal_tri_v3(
+ r_no, mvarray[loopstart[0].v].co, mvarray[loopstart[1].v].co, mvarray[loopstart[2].v].co);
+ }
+ else if (mpoly->totloop == 4) {
+ normal_quad_v3(r_no,
+ mvarray[loopstart[0].v].co,
+ mvarray[loopstart[1].v].co,
+ mvarray[loopstart[2].v].co,
+ mvarray[loopstart[3].v].co);
+ }
+ else { /* horrible, two sided face! */
+ r_no[0] = 0.0;
+ r_no[1] = 0.0;
+ r_no[2] = 1.0;
+ }
}
/* duplicate of function above _but_ takes coords rather then mverts */
-static void mesh_calc_ngon_normal_coords(
- const MPoly *mpoly, const MLoop *loopstart,
- const float (*vertex_coords)[3], float r_normal[3])
-{
- const int nverts = mpoly->totloop;
- const float *v_prev = vertex_coords[loopstart[nverts - 1].v];
- const float *v_curr;
- int i;
-
- zero_v3(r_normal);
-
- /* Newell's Method */
- for (i = 0; i < nverts; i++) {
- v_curr = vertex_coords[loopstart[i].v];
- add_newell_cross_v3_v3v3(r_normal, v_prev, v_curr);
- v_prev = v_curr;
- }
-
- if (UNLIKELY(normalize_v3(r_normal) == 0.0f)) {
- r_normal[2] = 1.0f; /* other axis set to 0.0 */
- }
-}
-
-void BKE_mesh_calc_poly_normal_coords(
- const MPoly *mpoly, const MLoop *loopstart,
- const float (*vertex_coords)[3], float r_no[3])
-{
- if (mpoly->totloop > 4) {
- mesh_calc_ngon_normal_coords(mpoly, loopstart, vertex_coords, r_no);
- }
- else if (mpoly->totloop == 3) {
- normal_tri_v3(
- r_no,
- vertex_coords[loopstart[0].v],
- vertex_coords[loopstart[1].v],
- vertex_coords[loopstart[2].v]);
- }
- else if (mpoly->totloop == 4) {
- normal_quad_v3(
- r_no,
- vertex_coords[loopstart[0].v],
- vertex_coords[loopstart[1].v],
- vertex_coords[loopstart[2].v],
- vertex_coords[loopstart[3].v]);
- }
- else { /* horrible, two sided face! */
- r_no[0] = 0.0;
- r_no[1] = 0.0;
- r_no[2] = 1.0;
- }
-}
-
-static void mesh_calc_ngon_center(
- const MPoly *mpoly, const MLoop *loopstart,
- const MVert *mvert, float cent[3])
-{
- const float w = 1.0f / (float)mpoly->totloop;
- int i;
-
- zero_v3(cent);
-
- for (i = 0; i < mpoly->totloop; i++) {
- madd_v3_v3fl(cent, mvert[(loopstart++)->v].co, w);
- }
-}
-
-void BKE_mesh_calc_poly_center(
- const MPoly *mpoly, const MLoop *loopstart,
- const MVert *mvarray, float r_cent[3])
-{
- if (mpoly->totloop == 3) {
- mid_v3_v3v3v3(
- r_cent,
- mvarray[loopstart[0].v].co,
- mvarray[loopstart[1].v].co,
- mvarray[loopstart[2].v].co);
- }
- else if (mpoly->totloop == 4) {
- mid_v3_v3v3v3v3(
- r_cent,
- mvarray[loopstart[0].v].co,
- mvarray[loopstart[1].v].co,
- mvarray[loopstart[2].v].co,
- mvarray[loopstart[3].v].co);
- }
- else {
- mesh_calc_ngon_center(mpoly, loopstart, mvarray, r_cent);
- }
+static void mesh_calc_ngon_normal_coords(const MPoly *mpoly,
+ const MLoop *loopstart,
+ const float (*vertex_coords)[3],
+ float r_normal[3])
+{
+ const int nverts = mpoly->totloop;
+ const float *v_prev = vertex_coords[loopstart[nverts - 1].v];
+ const float *v_curr;
+ int i;
+
+ zero_v3(r_normal);
+
+ /* Newell's Method */
+ for (i = 0; i < nverts; i++) {
+ v_curr = vertex_coords[loopstart[i].v];
+ add_newell_cross_v3_v3v3(r_normal, v_prev, v_curr);
+ v_prev = v_curr;
+ }
+
+ if (UNLIKELY(normalize_v3(r_normal) == 0.0f)) {
+ r_normal[2] = 1.0f; /* other axis set to 0.0 */
+ }
+}
+
+void BKE_mesh_calc_poly_normal_coords(const MPoly *mpoly,
+ const MLoop *loopstart,
+ const float (*vertex_coords)[3],
+ float r_no[3])
+{
+ if (mpoly->totloop > 4) {
+ mesh_calc_ngon_normal_coords(mpoly, loopstart, vertex_coords, r_no);
+ }
+ else if (mpoly->totloop == 3) {
+ normal_tri_v3(r_no,
+ vertex_coords[loopstart[0].v],
+ vertex_coords[loopstart[1].v],
+ vertex_coords[loopstart[2].v]);
+ }
+ else if (mpoly->totloop == 4) {
+ normal_quad_v3(r_no,
+ vertex_coords[loopstart[0].v],
+ vertex_coords[loopstart[1].v],
+ vertex_coords[loopstart[2].v],
+ vertex_coords[loopstart[3].v]);
+ }
+ else { /* horrible, two sided face! */
+ r_no[0] = 0.0;
+ r_no[1] = 0.0;
+ r_no[2] = 1.0;
+ }
+}
+
+static void mesh_calc_ngon_center(const MPoly *mpoly,
+ const MLoop *loopstart,
+ const MVert *mvert,
+ float cent[3])
+{
+ const float w = 1.0f / (float)mpoly->totloop;
+ int i;
+
+ zero_v3(cent);
+
+ for (i = 0; i < mpoly->totloop; i++) {
+ madd_v3_v3fl(cent, mvert[(loopstart++)->v].co, w);
+ }
+}
+
+void BKE_mesh_calc_poly_center(const MPoly *mpoly,
+ const MLoop *loopstart,
+ const MVert *mvarray,
+ float r_cent[3])
+{
+ if (mpoly->totloop == 3) {
+ mid_v3_v3v3v3(r_cent,
+ mvarray[loopstart[0].v].co,
+ mvarray[loopstart[1].v].co,
+ mvarray[loopstart[2].v].co);
+ }
+ else if (mpoly->totloop == 4) {
+ mid_v3_v3v3v3v3(r_cent,
+ mvarray[loopstart[0].v].co,
+ mvarray[loopstart[1].v].co,
+ mvarray[loopstart[2].v].co,
+ mvarray[loopstart[3].v].co);
+ }
+ else {
+ mesh_calc_ngon_center(mpoly, loopstart, mvarray, r_cent);
+ }
}
/* note, passing polynormal is only a speedup so we can skip calculating it */
-float BKE_mesh_calc_poly_area(
- const MPoly *mpoly, const MLoop *loopstart,
- const MVert *mvarray)
-{
- if (mpoly->totloop == 3) {
- return area_tri_v3(
- mvarray[loopstart[0].v].co,
- mvarray[loopstart[1].v].co,
- mvarray[loopstart[2].v].co);
- }
- else {
- int i;
- const MLoop *l_iter = loopstart;
- float area;
- float (*vertexcos)[3] = BLI_array_alloca(vertexcos, (size_t)mpoly->totloop);
-
- /* pack vertex cos into an array for area_poly_v3 */
- for (i = 0; i < mpoly->totloop; i++, l_iter++) {
- copy_v3_v3(vertexcos[i], mvarray[l_iter->v].co);
- }
-
- /* finally calculate the area */
- area = area_poly_v3((const float (*)[3])vertexcos, (unsigned int)mpoly->totloop);
-
- return area;
- }
+float BKE_mesh_calc_poly_area(const MPoly *mpoly, const MLoop *loopstart, const MVert *mvarray)
+{
+ if (mpoly->totloop == 3) {
+ return area_tri_v3(
+ mvarray[loopstart[0].v].co, mvarray[loopstart[1].v].co, mvarray[loopstart[2].v].co);
+ }
+ else {
+ int i;
+ const MLoop *l_iter = loopstart;
+ float area;
+ float(*vertexcos)[3] = BLI_array_alloca(vertexcos, (size_t)mpoly->totloop);
+
+ /* pack vertex cos into an array for area_poly_v3 */
+ for (i = 0; i < mpoly->totloop; i++, l_iter++) {
+ copy_v3_v3(vertexcos[i], mvarray[l_iter->v].co);
+ }
+
+ /* finally calculate the area */
+ area = area_poly_v3((const float(*)[3])vertexcos, (unsigned int)mpoly->totloop);
+
+ return area;
+ }
}
/**
@@ -2141,41 +2336,42 @@ float BKE_mesh_calc_poly_area(
* - The resulting volume will only be correct if the mesh is manifold and has consistent face winding
* (non-contiguous face normals or holes in the mesh surface).
*/
-static float mesh_calc_poly_volume_centroid(
- const MPoly *mpoly, const MLoop *loopstart, const MVert *mvarray,
- float r_cent[3])
+static float mesh_calc_poly_volume_centroid(const MPoly *mpoly,
+ const MLoop *loopstart,
+ const MVert *mvarray,
+ float r_cent[3])
{
- const float *v_pivot, *v_step1;
- float total_volume = 0.0f;
+ const float *v_pivot, *v_step1;
+ float total_volume = 0.0f;
- zero_v3(r_cent);
+ zero_v3(r_cent);
- v_pivot = mvarray[loopstart[0].v].co;
- v_step1 = mvarray[loopstart[1].v].co;
+ v_pivot = mvarray[loopstart[0].v].co;
+ v_step1 = mvarray[loopstart[1].v].co;
- for (int i = 2; i < mpoly->totloop; i++) {
- const float *v_step2 = mvarray[loopstart[i].v].co;
+ for (int i = 2; i < mpoly->totloop; i++) {
+ const float *v_step2 = mvarray[loopstart[i].v].co;
- /* Calculate the 6x volume of the tetrahedron formed by the 3 vertices
- * of the triangle and the origin as the fourth vertex */
- float v_cross[3];
- cross_v3_v3v3(v_cross, v_pivot, v_step1);
- const float tetra_volume = dot_v3v3 (v_cross, v_step2);
- total_volume += tetra_volume;
+ /* Calculate the 6x volume of the tetrahedron formed by the 3 vertices
+ * of the triangle and the origin as the fourth vertex */
+ float v_cross[3];
+ cross_v3_v3v3(v_cross, v_pivot, v_step1);
+ const float tetra_volume = dot_v3v3(v_cross, v_step2);
+ total_volume += tetra_volume;
- /* Calculate the centroid of the tetrahedron formed by the 3 vertices
- * of the triangle and the origin as the fourth vertex.
- * The centroid is simply the average of the 4 vertices.
- *
- * Note that the vector is 4x the actual centroid so the division can be done once at the end. */
- for (uint j = 0; j < 3; j++) {
- r_cent[j] += tetra_volume * (v_pivot[j] + v_step1[j] + v_step2[j]);
- }
+ /* Calculate the centroid of the tetrahedron formed by the 3 vertices
+ * of the triangle and the origin as the fourth vertex.
+ * The centroid is simply the average of the 4 vertices.
+ *
+ * Note that the vector is 4x the actual centroid so the division can be done once at the end. */
+ for (uint j = 0; j < 3; j++) {
+ r_cent[j] += tetra_volume * (v_pivot[j] + v_step1[j] + v_step2[j]);
+ }
- v_step1 = v_step2;
- }
+ v_step1 = v_step2;
+ }
- return total_volume;
+ return total_volume;
}
/**
@@ -2184,154 +2380,158 @@ static float mesh_calc_poly_volume_centroid(
* - This has the advantage over #mesh_calc_poly_volume_centroid
* that it doesn't depend on solid geometry, instead it weights the surface by volume.
*/
-static float mesh_calc_poly_area_centroid(
- const MPoly *mpoly, const MLoop *loopstart, const MVert *mvarray,
- float r_cent[3])
+static float mesh_calc_poly_area_centroid(const MPoly *mpoly,
+ const MLoop *loopstart,
+ const MVert *mvarray,
+ float r_cent[3])
{
- int i;
- float tri_area;
- float total_area = 0.0f;
- float v1[3], v2[3], v3[3], normal[3], tri_cent[3];
+ int i;
+ float tri_area;
+ float total_area = 0.0f;
+ float v1[3], v2[3], v3[3], normal[3], tri_cent[3];
- BKE_mesh_calc_poly_normal(mpoly, loopstart, mvarray, normal);
- copy_v3_v3(v1, mvarray[loopstart[0].v].co);
- copy_v3_v3(v2, mvarray[loopstart[1].v].co);
- zero_v3(r_cent);
+ BKE_mesh_calc_poly_normal(mpoly, loopstart, mvarray, normal);
+ copy_v3_v3(v1, mvarray[loopstart[0].v].co);
+ copy_v3_v3(v2, mvarray[loopstart[1].v].co);
+ zero_v3(r_cent);
- for (i = 2; i < mpoly->totloop; i++) {
- copy_v3_v3(v3, mvarray[loopstart[i].v].co);
+ for (i = 2; i < mpoly->totloop; i++) {
+ copy_v3_v3(v3, mvarray[loopstart[i].v].co);
- tri_area = area_tri_signed_v3(v1, v2, v3, normal);
- total_area += tri_area;
+ tri_area = area_tri_signed_v3(v1, v2, v3, normal);
+ total_area += tri_area;
- mid_v3_v3v3v3(tri_cent, v1, v2, v3);
- madd_v3_v3fl(r_cent, tri_cent, tri_area);
+ mid_v3_v3v3v3(tri_cent, v1, v2, v3);
+ madd_v3_v3fl(r_cent, tri_cent, tri_area);
- copy_v3_v3(v2, v3);
- }
+ copy_v3_v3(v2, v3);
+ }
- mul_v3_fl(r_cent, 1.0f / total_area);
+ mul_v3_fl(r_cent, 1.0f / total_area);
- return total_area;
+ return total_area;
}
-void BKE_mesh_calc_poly_angles(
- const MPoly *mpoly, const MLoop *loopstart,
- const MVert *mvarray, float angles[])
+void BKE_mesh_calc_poly_angles(const MPoly *mpoly,
+ const MLoop *loopstart,
+ const MVert *mvarray,
+ float angles[])
{
- float nor_prev[3];
- float nor_next[3];
+ float nor_prev[3];
+ float nor_next[3];
- int i_this = mpoly->totloop - 1;
- int i_next = 0;
+ int i_this = mpoly->totloop - 1;
+ int i_next = 0;
- sub_v3_v3v3(nor_prev, mvarray[loopstart[i_this - 1].v].co, mvarray[loopstart[i_this].v].co);
- normalize_v3(nor_prev);
+ sub_v3_v3v3(nor_prev, mvarray[loopstart[i_this - 1].v].co, mvarray[loopstart[i_this].v].co);
+ normalize_v3(nor_prev);
- while (i_next < mpoly->totloop) {
- sub_v3_v3v3(nor_next, mvarray[loopstart[i_this].v].co, mvarray[loopstart[i_next].v].co);
- normalize_v3(nor_next);
- angles[i_this] = angle_normalized_v3v3(nor_prev, nor_next);
+ while (i_next < mpoly->totloop) {
+ sub_v3_v3v3(nor_next, mvarray[loopstart[i_this].v].co, mvarray[loopstart[i_next].v].co);
+ normalize_v3(nor_next);
+ angles[i_this] = angle_normalized_v3v3(nor_prev, nor_next);
- /* step */
- copy_v3_v3(nor_prev, nor_next);
- i_this = i_next;
- i_next++;
- }
+ /* step */
+ copy_v3_v3(nor_prev, nor_next);
+ i_this = i_next;
+ i_next++;
+ }
}
void BKE_mesh_poly_edgehash_insert(EdgeHash *ehash, const MPoly *mp, const MLoop *mloop)
{
- const MLoop *ml, *ml_next;
- int i = mp->totloop;
+ const MLoop *ml, *ml_next;
+ int i = mp->totloop;
- ml_next = mloop; /* first loop */
- ml = &ml_next[i - 1]; /* last loop */
+ ml_next = mloop; /* first loop */
+ ml = &ml_next[i - 1]; /* last loop */
- while (i-- != 0) {
- BLI_edgehash_reinsert(ehash, ml->v, ml_next->v, NULL);
+ while (i-- != 0) {
+ BLI_edgehash_reinsert(ehash, ml->v, ml_next->v, NULL);
- ml = ml_next;
- ml_next++;
- }
+ ml = ml_next;
+ ml_next++;
+ }
}
-void BKE_mesh_poly_edgebitmap_insert(unsigned int *edge_bitmap, const MPoly *mp, const MLoop *mloop)
+void BKE_mesh_poly_edgebitmap_insert(unsigned int *edge_bitmap,
+ const MPoly *mp,
+ const MLoop *mloop)
{
- const MLoop *ml;
- int i = mp->totloop;
+ const MLoop *ml;
+ int i = mp->totloop;
- ml = mloop;
+ ml = mloop;
- while (i-- != 0) {
- BLI_BITMAP_ENABLE(edge_bitmap, ml->e);
- ml++;
- }
+ while (i-- != 0) {
+ BLI_BITMAP_ENABLE(edge_bitmap, ml->e);
+ ml++;
+ }
}
/** \} */
-
/* -------------------------------------------------------------------- */
/** \name Mesh Center Calculation
* \{ */
bool BKE_mesh_center_median(const Mesh *me, float r_cent[3])
{
- int i = me->totvert;
- const MVert *mvert;
- zero_v3(r_cent);
- for (mvert = me->mvert; i--; mvert++) {
- add_v3_v3(r_cent, mvert->co);
- }
- /* otherwise we get NAN for 0 verts */
- if (me->totvert) {
- mul_v3_fl(r_cent, 1.0f / (float)me->totvert);
- }
+ int i = me->totvert;
+ const MVert *mvert;
+ zero_v3(r_cent);
+ for (mvert = me->mvert; i--; mvert++) {
+ add_v3_v3(r_cent, mvert->co);
+ }
+ /* otherwise we get NAN for 0 verts */
+ if (me->totvert) {
+ mul_v3_fl(r_cent, 1.0f / (float)me->totvert);
+ }
- return (me->totvert != 0);
+ return (me->totvert != 0);
}
bool BKE_mesh_center_bounds(const Mesh *me, float r_cent[3])
{
- float min[3], max[3];
- INIT_MINMAX(min, max);
- if (BKE_mesh_minmax(me, min, max)) {
- mid_v3_v3v3(r_cent, min, max);
- return true;
- }
+ float min[3], max[3];
+ INIT_MINMAX(min, max);
+ if (BKE_mesh_minmax(me, min, max)) {
+ mid_v3_v3v3(r_cent, min, max);
+ return true;
+ }
- return false;
+ return false;
}
bool BKE_mesh_center_of_surface(const Mesh *me, float r_cent[3])
{
- int i = me->totpoly;
- MPoly *mpoly;
- float poly_area;
- float total_area = 0.0f;
- float poly_cent[3];
+ int i = me->totpoly;
+ MPoly *mpoly;
+ float poly_area;
+ float total_area = 0.0f;
+ float poly_cent[3];
- zero_v3(r_cent);
+ zero_v3(r_cent);
- /* calculate a weighted average of polygon centroids */
- for (mpoly = me->mpoly; i--; mpoly++) {
- poly_area = mesh_calc_poly_area_centroid(mpoly, me->mloop + mpoly->loopstart, me->mvert, poly_cent);
+ /* calculate a weighted average of polygon centroids */
+ for (mpoly = me->mpoly; i--; mpoly++) {
+ poly_area = mesh_calc_poly_area_centroid(
+ mpoly, me->mloop + mpoly->loopstart, me->mvert, poly_cent);
- madd_v3_v3fl(r_cent, poly_cent, poly_area);
- total_area += poly_area;
- }
- /* otherwise we get NAN for 0 polys */
- if (me->totpoly) {
- mul_v3_fl(r_cent, 1.0f / total_area);
- }
+ madd_v3_v3fl(r_cent, poly_cent, poly_area);
+ total_area += poly_area;
+ }
+ /* otherwise we get NAN for 0 polys */
+ if (me->totpoly) {
+ mul_v3_fl(r_cent, 1.0f / total_area);
+ }
- /* zero area faces cause this, fallback to median */
- if (UNLIKELY(!is_finite_v3(r_cent))) {
- return BKE_mesh_center_median(me, r_cent);
- }
+ /* zero area faces cause this, fallback to median */
+ if (UNLIKELY(!is_finite_v3(r_cent))) {
+ return BKE_mesh_center_median(me, r_cent);
+ }
- return (me->totpoly != 0);
+ return (me->totpoly != 0);
}
/**
@@ -2339,77 +2539,79 @@ bool BKE_mesh_center_of_surface(const Mesh *me, float r_cent[3])
*/
bool BKE_mesh_center_of_volume(const Mesh *me, float r_cent[3])
{
- int i = me->totpoly;
- MPoly *mpoly;
- float poly_volume;
- float total_volume = 0.0f;
- float poly_cent[3];
+ int i = me->totpoly;
+ MPoly *mpoly;
+ float poly_volume;
+ float total_volume = 0.0f;
+ float poly_cent[3];
- zero_v3(r_cent);
+ zero_v3(r_cent);
- /* calculate a weighted average of polyhedron centroids */
- for (mpoly = me->mpoly; i--; mpoly++) {
- poly_volume = mesh_calc_poly_volume_centroid(mpoly, me->mloop + mpoly->loopstart, me->mvert, poly_cent);
+ /* calculate a weighted average of polyhedron centroids */
+ for (mpoly = me->mpoly; i--; mpoly++) {
+ poly_volume = mesh_calc_poly_volume_centroid(
+ mpoly, me->mloop + mpoly->loopstart, me->mvert, poly_cent);
- /* poly_cent is already volume-weighted, so no need to multiply by the volume */
- add_v3_v3(r_cent, poly_cent);
- total_volume += poly_volume;
- }
- /* otherwise we get NAN for 0 polys */
- if (total_volume != 0.0f) {
- /* multiply by 0.25 to get the correct centroid */
- /* no need to divide volume by 6 as the centroid is weighted by 6x the volume, so it all cancels out */
- mul_v3_fl(r_cent, 0.25f / total_volume);
- }
+ /* poly_cent is already volume-weighted, so no need to multiply by the volume */
+ add_v3_v3(r_cent, poly_cent);
+ total_volume += poly_volume;
+ }
+ /* otherwise we get NAN for 0 polys */
+ if (total_volume != 0.0f) {
+ /* multiply by 0.25 to get the correct centroid */
+ /* no need to divide volume by 6 as the centroid is weighted by 6x the volume, so it all cancels out */
+ mul_v3_fl(r_cent, 0.25f / total_volume);
+ }
- /* this can happen for non-manifold objects, fallback to median */
- if (UNLIKELY(!is_finite_v3(r_cent))) {
- return BKE_mesh_center_median(me, r_cent);
- }
+ /* this can happen for non-manifold objects, fallback to median */
+ if (UNLIKELY(!is_finite_v3(r_cent))) {
+ return BKE_mesh_center_median(me, r_cent);
+ }
- return (me->totpoly != 0);
+ return (me->totpoly != 0);
}
/** \} */
-
/* -------------------------------------------------------------------- */
/** \name Mesh Volume Calculation
* \{ */
-static bool mesh_calc_center_centroid_ex(
- const MVert *mverts, int UNUSED(mverts_num),
- const MLoopTri *looptri, int looptri_num,
- const MLoop *mloop, float r_center[3])
+static bool mesh_calc_center_centroid_ex(const MVert *mverts,
+ int UNUSED(mverts_num),
+ const MLoopTri *looptri,
+ int looptri_num,
+ const MLoop *mloop,
+ float r_center[3])
{
- const MLoopTri *lt;
- float totweight;
- int i;
+ const MLoopTri *lt;
+ float totweight;
+ int i;
- zero_v3(r_center);
+ zero_v3(r_center);
- if (looptri_num == 0)
- return false;
+ if (looptri_num == 0)
+ return false;
- totweight = 0.0f;
- for (i = 0, lt = looptri; i < looptri_num; i++, lt++) {
- const MVert *v1 = &mverts[mloop[lt->tri[0]].v];
- const MVert *v2 = &mverts[mloop[lt->tri[1]].v];
- const MVert *v3 = &mverts[mloop[lt->tri[2]].v];
- float area;
+ totweight = 0.0f;
+ for (i = 0, lt = looptri; i < looptri_num; i++, lt++) {
+ const MVert *v1 = &mverts[mloop[lt->tri[0]].v];
+ const MVert *v2 = &mverts[mloop[lt->tri[1]].v];
+ const MVert *v3 = &mverts[mloop[lt->tri[2]].v];
+ float area;
- area = area_tri_v3(v1->co, v2->co, v3->co);
- madd_v3_v3fl(r_center, v1->co, area);
- madd_v3_v3fl(r_center, v2->co, area);
- madd_v3_v3fl(r_center, v3->co, area);
- totweight += area;
- }
- if (totweight == 0.0f)
- return false;
+ area = area_tri_v3(v1->co, v2->co, v3->co);
+ madd_v3_v3fl(r_center, v1->co, area);
+ madd_v3_v3fl(r_center, v2->co, area);
+ madd_v3_v3fl(r_center, v3->co, area);
+ totweight += area;
+ }
+ if (totweight == 0.0f)
+ return false;
- mul_v3_fl(r_center, 1.0f / (3.0f * totweight));
+ mul_v3_fl(r_center, 1.0f / (3.0f * totweight));
- return true;
+ return true;
}
/**
@@ -2418,62 +2620,64 @@ static bool mesh_calc_center_centroid_ex(
* \param r_volume: Volume (unsigned).
* \param r_center: Center of mass.
*/
-void BKE_mesh_calc_volume(
- const MVert *mverts, const int mverts_num,
- const MLoopTri *looptri, const int looptri_num,
- const MLoop *mloop,
- float *r_volume, float r_center[3])
-{
- const MLoopTri *lt;
- float center[3];
- float totvol;
- int i;
-
- if (r_volume)
- *r_volume = 0.0f;
- if (r_center)
- zero_v3(r_center);
-
- if (looptri_num == 0)
- return;
-
- if (!mesh_calc_center_centroid_ex(mverts, mverts_num, looptri, looptri_num, mloop, center))
- return;
-
- totvol = 0.0f;
-
- for (i = 0, lt = looptri; i < looptri_num; i++, lt++) {
- const MVert *v1 = &mverts[mloop[lt->tri[0]].v];
- const MVert *v2 = &mverts[mloop[lt->tri[1]].v];
- const MVert *v3 = &mverts[mloop[lt->tri[2]].v];
- float vol;
-
- vol = volume_tetrahedron_signed_v3(center, v1->co, v2->co, v3->co);
- if (r_volume) {
- totvol += vol;
- }
- if (r_center) {
- /* averaging factor 1/3 is applied in the end */
- madd_v3_v3fl(r_center, v1->co, vol);
- madd_v3_v3fl(r_center, v2->co, vol);
- madd_v3_v3fl(r_center, v3->co, vol);
- }
- }
-
- /* Note: Depending on arbitrary centroid position,
- * totvol can become negative even for a valid mesh.
- * The true value is always the positive value.
- */
- if (r_volume) {
- *r_volume = fabsf(totvol);
- }
- if (r_center) {
- /* Note: Factor 1/3 is applied once for all vertices here.
- * This also automatically negates the vector if totvol is negative.
- */
- if (totvol != 0.0f)
- mul_v3_fl(r_center, (1.0f / 3.0f) / totvol);
- }
+void BKE_mesh_calc_volume(const MVert *mverts,
+ const int mverts_num,
+ const MLoopTri *looptri,
+ const int looptri_num,
+ const MLoop *mloop,
+ float *r_volume,
+ float r_center[3])
+{
+ const MLoopTri *lt;
+ float center[3];
+ float totvol;
+ int i;
+
+ if (r_volume)
+ *r_volume = 0.0f;
+ if (r_center)
+ zero_v3(r_center);
+
+ if (looptri_num == 0)
+ return;
+
+ if (!mesh_calc_center_centroid_ex(mverts, mverts_num, looptri, looptri_num, mloop, center))
+ return;
+
+ totvol = 0.0f;
+
+ for (i = 0, lt = looptri; i < looptri_num; i++, lt++) {
+ const MVert *v1 = &mverts[mloop[lt->tri[0]].v];
+ const MVert *v2 = &mverts[mloop[lt->tri[1]].v];
+ const MVert *v3 = &mverts[mloop[lt->tri[2]].v];
+ float vol;
+
+ vol = volume_tetrahedron_signed_v3(center, v1->co, v2->co, v3->co);
+ if (r_volume) {
+ totvol += vol;
+ }
+ if (r_center) {
+ /* averaging factor 1/3 is applied in the end */
+ madd_v3_v3fl(r_center, v1->co, vol);
+ madd_v3_v3fl(r_center, v2->co, vol);
+ madd_v3_v3fl(r_center, v3->co, vol);
+ }
+ }
+
+ /* Note: Depending on arbitrary centroid position,
+ * totvol can become negative even for a valid mesh.
+ * The true value is always the positive value.
+ */
+ if (r_volume) {
+ *r_volume = fabsf(totvol);
+ }
+ if (r_center) {
+ /* Note: Factor 1/3 is applied once for all vertices here.
+ * This also automatically negates the vector if totvol is negative.
+ */
+ if (totvol != 0.0f)
+ mul_v3_fl(r_center, (1.0f / 3.0f) / totvol);
+ }
}
/** \} */
@@ -2486,69 +2690,72 @@ void BKE_mesh_calc_volume(
* Convert a triangle or quadrangle of loop/poly data to tessface data
*/
void BKE_mesh_loops_to_mface_corners(
- CustomData *fdata, CustomData *ldata,
- CustomData *UNUSED(pdata), unsigned int lindex[4], int findex,
- const int UNUSED(polyindex),
- const int mf_len, /* 3 or 4 */
-
- /* cache values to avoid lookups every time */
- const int numUV, /* CustomData_number_of_layers(ldata, CD_MLOOPUV) */
- const int numCol, /* CustomData_number_of_layers(ldata, CD_MLOOPCOL) */
- const bool hasPCol, /* CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL) */
- const bool hasOrigSpace, /* CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP) */
- const bool hasLNor /* CustomData_has_layer(ldata, CD_NORMAL) */
+ CustomData *fdata,
+ CustomData *ldata,
+ CustomData *UNUSED(pdata),
+ unsigned int lindex[4],
+ int findex,
+ const int UNUSED(polyindex),
+ const int mf_len, /* 3 or 4 */
+
+ /* cache values to avoid lookups every time */
+ const int numUV, /* CustomData_number_of_layers(ldata, CD_MLOOPUV) */
+ const int numCol, /* CustomData_number_of_layers(ldata, CD_MLOOPCOL) */
+ const bool hasPCol, /* CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL) */
+ const bool hasOrigSpace, /* CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP) */
+ const bool hasLNor /* CustomData_has_layer(ldata, CD_NORMAL) */
)
{
- MTFace *texface;
- MCol *mcol;
- MLoopCol *mloopcol;
- MLoopUV *mloopuv;
- int i, j;
+ MTFace *texface;
+ MCol *mcol;
+ MLoopCol *mloopcol;
+ MLoopUV *mloopuv;
+ int i, j;
- for (i = 0; i < numUV; i++) {
- texface = CustomData_get_n(fdata, CD_MTFACE, findex, i);
+ for (i = 0; i < numUV; i++) {
+ texface = CustomData_get_n(fdata, CD_MTFACE, findex, i);
- for (j = 0; j < mf_len; j++) {
- mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, (int)lindex[j], i);
- copy_v2_v2(texface->uv[j], mloopuv->uv);
- }
- }
+ for (j = 0; j < mf_len; j++) {
+ mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, (int)lindex[j], i);
+ copy_v2_v2(texface->uv[j], mloopuv->uv);
+ }
+ }
- for (i = 0; i < numCol; i++) {
- mcol = CustomData_get_n(fdata, CD_MCOL, findex, i);
+ for (i = 0; i < numCol; i++) {
+ mcol = CustomData_get_n(fdata, CD_MCOL, findex, i);
- for (j = 0; j < mf_len; j++) {
- mloopcol = CustomData_get_n(ldata, CD_MLOOPCOL, (int)lindex[j], i);
- MESH_MLOOPCOL_TO_MCOL(mloopcol, &mcol[j]);
- }
- }
+ for (j = 0; j < mf_len; j++) {
+ mloopcol = CustomData_get_n(ldata, CD_MLOOPCOL, (int)lindex[j], i);
+ MESH_MLOOPCOL_TO_MCOL(mloopcol, &mcol[j]);
+ }
+ }
- if (hasPCol) {
- mcol = CustomData_get(fdata, findex, CD_PREVIEW_MCOL);
+ if (hasPCol) {
+ mcol = CustomData_get(fdata, findex, CD_PREVIEW_MCOL);
- for (j = 0; j < mf_len; j++) {
- mloopcol = CustomData_get(ldata, (int)lindex[j], CD_PREVIEW_MLOOPCOL);
- MESH_MLOOPCOL_TO_MCOL(mloopcol, &mcol[j]);
- }
- }
+ for (j = 0; j < mf_len; j++) {
+ mloopcol = CustomData_get(ldata, (int)lindex[j], CD_PREVIEW_MLOOPCOL);
+ MESH_MLOOPCOL_TO_MCOL(mloopcol, &mcol[j]);
+ }
+ }
- if (hasOrigSpace) {
- OrigSpaceFace *of = CustomData_get(fdata, findex, CD_ORIGSPACE);
- OrigSpaceLoop *lof;
+ if (hasOrigSpace) {
+ OrigSpaceFace *of = CustomData_get(fdata, findex, CD_ORIGSPACE);
+ OrigSpaceLoop *lof;
- for (j = 0; j < mf_len; j++) {
- lof = CustomData_get(ldata, (int)lindex[j], CD_ORIGSPACE_MLOOP);
- copy_v2_v2(of->uv[j], lof->uv);
- }
- }
+ for (j = 0; j < mf_len; j++) {
+ lof = CustomData_get(ldata, (int)lindex[j], CD_ORIGSPACE_MLOOP);
+ copy_v2_v2(of->uv[j], lof->uv);
+ }
+ }
- if (hasLNor) {
- short (*tlnors)[3] = CustomData_get(fdata, findex, CD_TESSLOOPNORMAL);
+ if (hasLNor) {
+ short(*tlnors)[3] = CustomData_get(fdata, findex, CD_TESSLOOPNORMAL);
- for (j = 0; j < mf_len; j++) {
- normal_float_to_short_v3(tlnors[j], CustomData_get(ldata, (int)lindex[j], CD_NORMAL));
- }
- }
+ for (j = 0; j < mf_len; j++) {
+ normal_float_to_short_v3(tlnors[j], CustomData_get(ldata, (int)lindex[j], CD_NORMAL));
+ }
+ }
}
/**
@@ -2558,138 +2765,139 @@ void BKE_mesh_loops_to_mface_corners(
*
* \note when mface is not NULL, mface[face_index].v4 is used to test quads, else, loopindices[face_index][3] is used.
*/
-void BKE_mesh_loops_to_tessdata(
- CustomData *fdata, CustomData *ldata, MFace *mface,
- int *polyindices, unsigned int (*loopindices)[4], const int num_faces)
-{
- /* Note: performances are sub-optimal when we get a NULL mface, we could be ~25% quicker with dedicated code...
- * Issue is, unless having two different functions with nearly the same code, there's not much ways to solve
- * this. Better imho to live with it for now. :/ --mont29
- */
- const int numUV = CustomData_number_of_layers(ldata, CD_MLOOPUV);
- const int numCol = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
- const bool hasPCol = CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL);
- const bool hasOrigSpace = CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP);
- const bool hasLoopNormal = CustomData_has_layer(ldata, CD_NORMAL);
- const bool hasLoopTangent = CustomData_has_layer(ldata, CD_TANGENT);
- int findex, i, j;
- const int *pidx;
- unsigned int (*lidx)[4];
-
- for (i = 0; i < numUV; i++) {
- MTFace *texface = CustomData_get_layer_n(fdata, CD_MTFACE, i);
- MLoopUV *mloopuv = CustomData_get_layer_n(ldata, CD_MLOOPUV, i);
-
- for (findex = 0, pidx = polyindices, lidx = loopindices;
- findex < num_faces;
- pidx++, lidx++, findex++, texface++)
- {
- for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
- copy_v2_v2(texface->uv[j], mloopuv[(*lidx)[j]].uv);
- }
- }
- }
-
- for (i = 0; i < numCol; i++) {
- MCol (*mcol)[4] = CustomData_get_layer_n(fdata, CD_MCOL, i);
- MLoopCol *mloopcol = CustomData_get_layer_n(ldata, CD_MLOOPCOL, i);
-
- for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, mcol++) {
- for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
- MESH_MLOOPCOL_TO_MCOL(&mloopcol[(*lidx)[j]], &(*mcol)[j]);
- }
- }
- }
-
- if (hasPCol) {
- MCol (*mcol)[4] = CustomData_get_layer(fdata, CD_PREVIEW_MCOL);
- MLoopCol *mloopcol = CustomData_get_layer(ldata, CD_PREVIEW_MLOOPCOL);
-
- for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, mcol++) {
- for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
- MESH_MLOOPCOL_TO_MCOL(&mloopcol[(*lidx)[j]], &(*mcol)[j]);
- }
- }
- }
-
- if (hasOrigSpace) {
- OrigSpaceFace *of = CustomData_get_layer(fdata, CD_ORIGSPACE);
- OrigSpaceLoop *lof = CustomData_get_layer(ldata, CD_ORIGSPACE_MLOOP);
-
- for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, of++) {
- for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
- copy_v2_v2(of->uv[j], lof[(*lidx)[j]].uv);
- }
- }
- }
-
- if (hasLoopNormal) {
- short (*fnors)[4][3] = CustomData_get_layer(fdata, CD_TESSLOOPNORMAL);
- float (*lnors)[3] = CustomData_get_layer(ldata, CD_NORMAL);
-
- for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, fnors++) {
- for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
- normal_float_to_short_v3((*fnors)[j], lnors[(*lidx)[j]]);
- }
- }
- }
-
- if (hasLoopTangent) {
- /* need to do for all uv maps at some point */
- float (*ftangents)[4] = CustomData_get_layer(fdata, CD_TANGENT);
- float (*ltangents)[4] = CustomData_get_layer(ldata, CD_TANGENT);
-
- for (findex = 0, pidx = polyindices, lidx = loopindices;
- findex < num_faces;
- pidx++, lidx++, findex++)
- {
- int nverts = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3;
- for (j = nverts; j--;) {
- copy_v4_v4(ftangents[findex * 4 + j], ltangents[(*lidx)[j]]);
- }
- }
- }
-}
-
-void BKE_mesh_tangent_loops_to_tessdata(
- CustomData *fdata, CustomData *ldata, MFace *mface,
- int *polyindices, unsigned int (*loopindices)[4], const int num_faces, const char *layer_name)
-{
- /* Note: performances are sub-optimal when we get a NULL mface, we could be ~25% quicker with dedicated code...
- * Issue is, unless having two different functions with nearly the same code, there's not much ways to solve
- * this. Better imho to live with it for now. :/ --mont29
- */
-
- float (*ftangents)[4] = NULL;
- float (*ltangents)[4] = NULL;
-
- int findex, j;
- const int *pidx;
- unsigned int (*lidx)[4];
-
- if (layer_name)
- ltangents = CustomData_get_layer_named(ldata, CD_TANGENT, layer_name);
- else
- ltangents = CustomData_get_layer(ldata, CD_TANGENT);
-
- if (ltangents) {
- /* need to do for all uv maps at some point */
- if (layer_name)
- ftangents = CustomData_get_layer_named(fdata, CD_TANGENT, layer_name);
- else
- ftangents = CustomData_get_layer(fdata, CD_TANGENT);
- if (ftangents) {
- for (findex = 0, pidx = polyindices, lidx = loopindices;
- findex < num_faces;
- pidx++, lidx++, findex++)
- {
- int nverts = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3;
- for (j = nverts; j--;) {
- copy_v4_v4(ftangents[findex * 4 + j], ltangents[(*lidx)[j]]);
- }
- }
- }
- }
+void BKE_mesh_loops_to_tessdata(CustomData *fdata,
+ CustomData *ldata,
+ MFace *mface,
+ int *polyindices,
+ unsigned int (*loopindices)[4],
+ const int num_faces)
+{
+ /* Note: performances are sub-optimal when we get a NULL mface, we could be ~25% quicker with dedicated code...
+ * Issue is, unless having two different functions with nearly the same code, there's not much ways to solve
+ * this. Better imho to live with it for now. :/ --mont29
+ */
+ const int numUV = CustomData_number_of_layers(ldata, CD_MLOOPUV);
+ const int numCol = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
+ const bool hasPCol = CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL);
+ const bool hasOrigSpace = CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP);
+ const bool hasLoopNormal = CustomData_has_layer(ldata, CD_NORMAL);
+ const bool hasLoopTangent = CustomData_has_layer(ldata, CD_TANGENT);
+ int findex, i, j;
+ const int *pidx;
+ unsigned int(*lidx)[4];
+
+ for (i = 0; i < numUV; i++) {
+ MTFace *texface = CustomData_get_layer_n(fdata, CD_MTFACE, i);
+ MLoopUV *mloopuv = CustomData_get_layer_n(ldata, CD_MLOOPUV, i);
+
+ for (findex = 0, pidx = polyindices, lidx = loopindices; findex < num_faces;
+ pidx++, lidx++, findex++, texface++) {
+ for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
+ copy_v2_v2(texface->uv[j], mloopuv[(*lidx)[j]].uv);
+ }
+ }
+ }
+
+ for (i = 0; i < numCol; i++) {
+ MCol(*mcol)[4] = CustomData_get_layer_n(fdata, CD_MCOL, i);
+ MLoopCol *mloopcol = CustomData_get_layer_n(ldata, CD_MLOOPCOL, i);
+
+ for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, mcol++) {
+ for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
+ MESH_MLOOPCOL_TO_MCOL(&mloopcol[(*lidx)[j]], &(*mcol)[j]);
+ }
+ }
+ }
+
+ if (hasPCol) {
+ MCol(*mcol)[4] = CustomData_get_layer(fdata, CD_PREVIEW_MCOL);
+ MLoopCol *mloopcol = CustomData_get_layer(ldata, CD_PREVIEW_MLOOPCOL);
+
+ for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, mcol++) {
+ for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
+ MESH_MLOOPCOL_TO_MCOL(&mloopcol[(*lidx)[j]], &(*mcol)[j]);
+ }
+ }
+ }
+
+ if (hasOrigSpace) {
+ OrigSpaceFace *of = CustomData_get_layer(fdata, CD_ORIGSPACE);
+ OrigSpaceLoop *lof = CustomData_get_layer(ldata, CD_ORIGSPACE_MLOOP);
+
+ for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, of++) {
+ for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
+ copy_v2_v2(of->uv[j], lof[(*lidx)[j]].uv);
+ }
+ }
+ }
+
+ if (hasLoopNormal) {
+ short(*fnors)[4][3] = CustomData_get_layer(fdata, CD_TESSLOOPNORMAL);
+ float(*lnors)[3] = CustomData_get_layer(ldata, CD_NORMAL);
+
+ for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, fnors++) {
+ for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
+ normal_float_to_short_v3((*fnors)[j], lnors[(*lidx)[j]]);
+ }
+ }
+ }
+
+ if (hasLoopTangent) {
+ /* need to do for all uv maps at some point */
+ float(*ftangents)[4] = CustomData_get_layer(fdata, CD_TANGENT);
+ float(*ltangents)[4] = CustomData_get_layer(ldata, CD_TANGENT);
+
+ for (findex = 0, pidx = polyindices, lidx = loopindices; findex < num_faces;
+ pidx++, lidx++, findex++) {
+ int nverts = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3;
+ for (j = nverts; j--;) {
+ copy_v4_v4(ftangents[findex * 4 + j], ltangents[(*lidx)[j]]);
+ }
+ }
+ }
+}
+
+void BKE_mesh_tangent_loops_to_tessdata(CustomData *fdata,
+ CustomData *ldata,
+ MFace *mface,
+ int *polyindices,
+ unsigned int (*loopindices)[4],
+ const int num_faces,
+ const char *layer_name)
+{
+ /* Note: performances are sub-optimal when we get a NULL mface, we could be ~25% quicker with dedicated code...
+ * Issue is, unless having two different functions with nearly the same code, there's not much ways to solve
+ * this. Better imho to live with it for now. :/ --mont29
+ */
+
+ float(*ftangents)[4] = NULL;
+ float(*ltangents)[4] = NULL;
+
+ int findex, j;
+ const int *pidx;
+ unsigned int(*lidx)[4];
+
+ if (layer_name)
+ ltangents = CustomData_get_layer_named(ldata, CD_TANGENT, layer_name);
+ else
+ ltangents = CustomData_get_layer(ldata, CD_TANGENT);
+
+ if (ltangents) {
+ /* need to do for all uv maps at some point */
+ if (layer_name)
+ ftangents = CustomData_get_layer_named(fdata, CD_TANGENT, layer_name);
+ else
+ ftangents = CustomData_get_layer(fdata, CD_TANGENT);
+ if (ftangents) {
+ for (findex = 0, pidx = polyindices, lidx = loopindices; findex < num_faces;
+ pidx++, lidx++, findex++) {
+ int nverts = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3;
+ for (j = nverts; j--;) {
+ copy_v4_v4(ftangents[findex * 4 + j], ltangents[(*lidx)[j]]);
+ }
+ }
+ }
+ }
}
/**
@@ -2699,507 +2907,530 @@ void BKE_mesh_tangent_loops_to_tessdata(
*
* \return number of tessellation faces.
*/
-int BKE_mesh_recalc_tessellation(
- CustomData *fdata, CustomData *ldata, CustomData *pdata,
- MVert *mvert,
- int totface, int totloop, int totpoly,
- const bool do_face_nor_copy)
-{
- /* use this to avoid locking pthread for _every_ polygon
- * and calling the fill function */
+int BKE_mesh_recalc_tessellation(CustomData *fdata,
+ CustomData *ldata,
+ CustomData *pdata,
+ MVert *mvert,
+ int totface,
+ int totloop,
+ int totpoly,
+ const bool do_face_nor_copy)
+{
+ /* use this to avoid locking pthread for _every_ polygon
+ * and calling the fill function */
#define USE_TESSFACE_SPEEDUP
-#define USE_TESSFACE_QUADS /* NEEDS FURTHER TESTING */
+#define USE_TESSFACE_QUADS /* NEEDS FURTHER TESTING */
/* We abuse MFace->edcode to tag quad faces. See below for details. */
#define TESSFACE_IS_QUAD 1
- const int looptri_num = poly_to_tri_count(totpoly, totloop);
-
- MPoly *mp, *mpoly;
- MLoop *ml, *mloop;
- MFace *mface, *mf;
- MemArena *arena = NULL;
- int *mface_to_poly_map;
- unsigned int (*lindices)[4];
- int poly_index, mface_index;
- unsigned int j;
-
- mpoly = CustomData_get_layer(pdata, CD_MPOLY);
- mloop = CustomData_get_layer(ldata, CD_MLOOP);
-
- /* allocate the length of totfaces, avoid many small reallocs,
- * if all faces are tri's it will be correct, quads == 2x allocs */
- /* take care. we are _not_ calloc'ing so be sure to initialize each field */
- mface_to_poly_map = MEM_malloc_arrayN((size_t)looptri_num, sizeof(*mface_to_poly_map), __func__);
- mface = MEM_malloc_arrayN((size_t)looptri_num, sizeof(*mface), __func__);
- lindices = MEM_malloc_arrayN((size_t)looptri_num, sizeof(*lindices), __func__);
-
- mface_index = 0;
- mp = mpoly;
- for (poly_index = 0; poly_index < totpoly; poly_index++, mp++) {
- const unsigned int mp_loopstart = (unsigned int)mp->loopstart;
- const unsigned int mp_totloop = (unsigned int)mp->totloop;
- unsigned int l1, l2, l3, l4;
- unsigned int *lidx;
- if (mp_totloop < 3) {
- /* do nothing */
- }
+ const int looptri_num = poly_to_tri_count(totpoly, totloop);
+
+ MPoly *mp, *mpoly;
+ MLoop *ml, *mloop;
+ MFace *mface, *mf;
+ MemArena *arena = NULL;
+ int *mface_to_poly_map;
+ unsigned int(*lindices)[4];
+ int poly_index, mface_index;
+ unsigned int j;
+
+ mpoly = CustomData_get_layer(pdata, CD_MPOLY);
+ mloop = CustomData_get_layer(ldata, CD_MLOOP);
+
+ /* allocate the length of totfaces, avoid many small reallocs,
+ * if all faces are tri's it will be correct, quads == 2x allocs */
+ /* take care. we are _not_ calloc'ing so be sure to initialize each field */
+ mface_to_poly_map = MEM_malloc_arrayN((size_t)looptri_num, sizeof(*mface_to_poly_map), __func__);
+ mface = MEM_malloc_arrayN((size_t)looptri_num, sizeof(*mface), __func__);
+ lindices = MEM_malloc_arrayN((size_t)looptri_num, sizeof(*lindices), __func__);
+
+ mface_index = 0;
+ mp = mpoly;
+ for (poly_index = 0; poly_index < totpoly; poly_index++, mp++) {
+ const unsigned int mp_loopstart = (unsigned int)mp->loopstart;
+ const unsigned int mp_totloop = (unsigned int)mp->totloop;
+ unsigned int l1, l2, l3, l4;
+ unsigned int *lidx;
+ if (mp_totloop < 3) {
+ /* do nothing */
+ }
#ifdef USE_TESSFACE_SPEEDUP
-#define ML_TO_MF(i1, i2, i3) \
- mface_to_poly_map[mface_index] = poly_index; \
- mf = &mface[mface_index]; \
- lidx = lindices[mface_index]; \
- /* set loop indices, transformed to vert indices later */ \
- l1 = mp_loopstart + i1; \
- l2 = mp_loopstart + i2; \
- l3 = mp_loopstart + i3; \
- mf->v1 = mloop[l1].v; \
- mf->v2 = mloop[l2].v; \
- mf->v3 = mloop[l3].v; \
- mf->v4 = 0; \
- lidx[0] = l1; \
- lidx[1] = l2; \
- lidx[2] = l3; \
- lidx[3] = 0; \
- mf->mat_nr = mp->mat_nr; \
- mf->flag = mp->flag; \
- mf->edcode = 0; \
- (void)0
+# define ML_TO_MF(i1, i2, i3) \
+ mface_to_poly_map[mface_index] = poly_index; \
+ mf = &mface[mface_index]; \
+ lidx = lindices[mface_index]; \
+ /* set loop indices, transformed to vert indices later */ \
+ l1 = mp_loopstart + i1; \
+ l2 = mp_loopstart + i2; \
+ l3 = mp_loopstart + i3; \
+ mf->v1 = mloop[l1].v; \
+ mf->v2 = mloop[l2].v; \
+ mf->v3 = mloop[l3].v; \
+ mf->v4 = 0; \
+ lidx[0] = l1; \
+ lidx[1] = l2; \
+ lidx[2] = l3; \
+ lidx[3] = 0; \
+ mf->mat_nr = mp->mat_nr; \
+ mf->flag = mp->flag; \
+ mf->edcode = 0; \
+ (void)0
/* ALMOST IDENTICAL TO DEFINE ABOVE (see EXCEPTION) */
-#define ML_TO_MF_QUAD() \
- mface_to_poly_map[mface_index] = poly_index; \
- mf = &mface[mface_index]; \
- lidx = lindices[mface_index]; \
- /* set loop indices, transformed to vert indices later */ \
- l1 = mp_loopstart + 0; /* EXCEPTION */ \
- l2 = mp_loopstart + 1; /* EXCEPTION */ \
- l3 = mp_loopstart + 2; /* EXCEPTION */ \
- l4 = mp_loopstart + 3; /* EXCEPTION */ \
- mf->v1 = mloop[l1].v; \
- mf->v2 = mloop[l2].v; \
- mf->v3 = mloop[l3].v; \
- mf->v4 = mloop[l4].v; \
- lidx[0] = l1; \
- lidx[1] = l2; \
- lidx[2] = l3; \
- lidx[3] = l4; \
- mf->mat_nr = mp->mat_nr; \
- mf->flag = mp->flag; \
- mf->edcode = TESSFACE_IS_QUAD; \
- (void)0
-
-
- else if (mp_totloop == 3) {
- ML_TO_MF(0, 1, 2);
- mface_index++;
- }
- else if (mp_totloop == 4) {
-#ifdef USE_TESSFACE_QUADS
- ML_TO_MF_QUAD();
- mface_index++;
-#else
- ML_TO_MF(0, 1, 2);
- mface_index++;
- ML_TO_MF(0, 2, 3);
- mface_index++;
-#endif
- }
+# define ML_TO_MF_QUAD() \
+ mface_to_poly_map[mface_index] = poly_index; \
+ mf = &mface[mface_index]; \
+ lidx = lindices[mface_index]; \
+ /* set loop indices, transformed to vert indices later */ \
+ l1 = mp_loopstart + 0; /* EXCEPTION */ \
+ l2 = mp_loopstart + 1; /* EXCEPTION */ \
+ l3 = mp_loopstart + 2; /* EXCEPTION */ \
+ l4 = mp_loopstart + 3; /* EXCEPTION */ \
+ mf->v1 = mloop[l1].v; \
+ mf->v2 = mloop[l2].v; \
+ mf->v3 = mloop[l3].v; \
+ mf->v4 = mloop[l4].v; \
+ lidx[0] = l1; \
+ lidx[1] = l2; \
+ lidx[2] = l3; \
+ lidx[3] = l4; \
+ mf->mat_nr = mp->mat_nr; \
+ mf->flag = mp->flag; \
+ mf->edcode = TESSFACE_IS_QUAD; \
+ (void)0
+
+ else if (mp_totloop == 3) {
+ ML_TO_MF(0, 1, 2);
+ mface_index++;
+ }
+ else if (mp_totloop == 4) {
+# ifdef USE_TESSFACE_QUADS
+ ML_TO_MF_QUAD();
+ mface_index++;
+# else
+ ML_TO_MF(0, 1, 2);
+ mface_index++;
+ ML_TO_MF(0, 2, 3);
+ mface_index++;
+# endif
+ }
#endif /* USE_TESSFACE_SPEEDUP */
- else {
- const float *co_curr, *co_prev;
+ else {
+ const float *co_curr, *co_prev;
- float normal[3];
-
- float axis_mat[3][3];
- float (*projverts)[2];
- unsigned int (*tris)[3];
-
- const unsigned int totfilltri = mp_totloop - 2;
-
- if (UNLIKELY(arena == NULL)) {
- arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
- }
-
- tris = BLI_memarena_alloc(arena, sizeof(*tris) * (size_t)totfilltri);
- projverts = BLI_memarena_alloc(arena, sizeof(*projverts) * (size_t)mp_totloop);
-
- zero_v3(normal);
-
- /* calc normal, flipped: to get a positive 2d cross product */
- ml = mloop + mp_loopstart;
- co_prev = mvert[ml[mp_totloop - 1].v].co;
- for (j = 0; j < mp_totloop; j++, ml++) {
- co_curr = mvert[ml->v].co;
- add_newell_cross_v3_v3v3(normal, co_prev, co_curr);
- co_prev = co_curr;
- }
- if (UNLIKELY(normalize_v3(normal) == 0.0f)) {
- normal[2] = 1.0f;
- }
-
- /* project verts to 2d */
- axis_dominant_v3_to_m3_negate(axis_mat, normal);
-
- ml = mloop + mp_loopstart;
- for (j = 0; j < mp_totloop; j++, ml++) {
- mul_v2_m3v3(projverts[j], axis_mat, mvert[ml->v].co);
- }
-
- BLI_polyfill_calc_arena(projverts, mp_totloop, 1, tris, arena);
-
- /* apply fill */
- for (j = 0; j < totfilltri; j++) {
- unsigned int *tri = tris[j];
- lidx = lindices[mface_index];
-
- mface_to_poly_map[mface_index] = poly_index;
- mf = &mface[mface_index];
-
- /* set loop indices, transformed to vert indices later */
- l1 = mp_loopstart + tri[0];
- l2 = mp_loopstart + tri[1];
- l3 = mp_loopstart + tri[2];
-
- mf->v1 = mloop[l1].v;
- mf->v2 = mloop[l2].v;
- mf->v3 = mloop[l3].v;
- mf->v4 = 0;
-
- lidx[0] = l1;
- lidx[1] = l2;
- lidx[2] = l3;
- lidx[3] = 0;
-
- mf->mat_nr = mp->mat_nr;
- mf->flag = mp->flag;
- mf->edcode = 0;
-
- mface_index++;
- }
-
- BLI_memarena_clear(arena);
- }
- }
-
- if (arena) {
- BLI_memarena_free(arena);
- arena = NULL;
- }
-
- CustomData_free(fdata, totface);
- totface = mface_index;
-
- BLI_assert(totface <= looptri_num);
-
- /* not essential but without this we store over-alloc'd memory in the CustomData layers */
- if (LIKELY(looptri_num != totface)) {
- mface = MEM_reallocN(mface, sizeof(*mface) * (size_t)totface);
- mface_to_poly_map = MEM_reallocN(mface_to_poly_map, sizeof(*mface_to_poly_map) * (size_t)totface);
- }
-
- CustomData_add_layer(fdata, CD_MFACE, CD_ASSIGN, mface, totface);
-
- /* CD_ORIGINDEX will contain an array of indices from tessfaces to the polygons
- * they are directly tessellated from */
- CustomData_add_layer(fdata, CD_ORIGINDEX, CD_ASSIGN, mface_to_poly_map, totface);
- CustomData_from_bmeshpoly(fdata, ldata, totface);
-
- if (do_face_nor_copy) {
- /* If polys have a normals layer, copying that to faces can help
- * avoid the need to recalculate normals later */
- if (CustomData_has_layer(pdata, CD_NORMAL)) {
- float (*pnors)[3] = CustomData_get_layer(pdata, CD_NORMAL);
- float (*fnors)[3] = CustomData_add_layer(fdata, CD_NORMAL, CD_CALLOC, NULL, totface);
- for (mface_index = 0; mface_index < totface; mface_index++) {
- copy_v3_v3(fnors[mface_index], pnors[mface_to_poly_map[mface_index]]);
- }
- }
- }
-
- /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
- * Polygons take care of their loops ordering, hence not of their vertices ordering.
- * Currently, our tfaces' fourth vertex index might be 0 even for a quad. However, we know our fourth loop index is
- * never 0 for quads (because they are sorted for polygons, and our quads are still mere copies of their polygons).
- * So we pass NULL as MFace pointer, and BKE_mesh_loops_to_tessdata will use the fourth loop index as quad test.
- * ...
- */
- BKE_mesh_loops_to_tessdata(fdata, ldata, NULL, mface_to_poly_map, lindices, totface);
-
- /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
- * ...However, most TFace code uses 'MFace->v4 == 0' test to check whether it is a tri or quad.
- * test_index_face() will check this and rotate the tessellated face if needed.
- */
+ float normal[3];
+
+ float axis_mat[3][3];
+ float(*projverts)[2];
+ unsigned int(*tris)[3];
+
+ const unsigned int totfilltri = mp_totloop - 2;
+
+ if (UNLIKELY(arena == NULL)) {
+ arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+ }
+
+ tris = BLI_memarena_alloc(arena, sizeof(*tris) * (size_t)totfilltri);
+ projverts = BLI_memarena_alloc(arena, sizeof(*projverts) * (size_t)mp_totloop);
+
+ zero_v3(normal);
+
+ /* calc normal, flipped: to get a positive 2d cross product */
+ ml = mloop + mp_loopstart;
+ co_prev = mvert[ml[mp_totloop - 1].v].co;
+ for (j = 0; j < mp_totloop; j++, ml++) {
+ co_curr = mvert[ml->v].co;
+ add_newell_cross_v3_v3v3(normal, co_prev, co_curr);
+ co_prev = co_curr;
+ }
+ if (UNLIKELY(normalize_v3(normal) == 0.0f)) {
+ normal[2] = 1.0f;
+ }
+
+ /* project verts to 2d */
+ axis_dominant_v3_to_m3_negate(axis_mat, normal);
+
+ ml = mloop + mp_loopstart;
+ for (j = 0; j < mp_totloop; j++, ml++) {
+ mul_v2_m3v3(projverts[j], axis_mat, mvert[ml->v].co);
+ }
+
+ BLI_polyfill_calc_arena(projverts, mp_totloop, 1, tris, arena);
+
+ /* apply fill */
+ for (j = 0; j < totfilltri; j++) {
+ unsigned int *tri = tris[j];
+ lidx = lindices[mface_index];
+
+ mface_to_poly_map[mface_index] = poly_index;
+ mf = &mface[mface_index];
+
+ /* set loop indices, transformed to vert indices later */
+ l1 = mp_loopstart + tri[0];
+ l2 = mp_loopstart + tri[1];
+ l3 = mp_loopstart + tri[2];
+
+ mf->v1 = mloop[l1].v;
+ mf->v2 = mloop[l2].v;
+ mf->v3 = mloop[l3].v;
+ mf->v4 = 0;
+
+ lidx[0] = l1;
+ lidx[1] = l2;
+ lidx[2] = l3;
+ lidx[3] = 0;
+
+ mf->mat_nr = mp->mat_nr;
+ mf->flag = mp->flag;
+ mf->edcode = 0;
+
+ mface_index++;
+ }
+
+ BLI_memarena_clear(arena);
+ }
+ }
+
+ if (arena) {
+ BLI_memarena_free(arena);
+ arena = NULL;
+ }
+
+ CustomData_free(fdata, totface);
+ totface = mface_index;
+
+ BLI_assert(totface <= looptri_num);
+
+ /* not essential but without this we store over-alloc'd memory in the CustomData layers */
+ if (LIKELY(looptri_num != totface)) {
+ mface = MEM_reallocN(mface, sizeof(*mface) * (size_t)totface);
+ mface_to_poly_map = MEM_reallocN(mface_to_poly_map,
+ sizeof(*mface_to_poly_map) * (size_t)totface);
+ }
+
+ CustomData_add_layer(fdata, CD_MFACE, CD_ASSIGN, mface, totface);
+
+ /* CD_ORIGINDEX will contain an array of indices from tessfaces to the polygons
+ * they are directly tessellated from */
+ CustomData_add_layer(fdata, CD_ORIGINDEX, CD_ASSIGN, mface_to_poly_map, totface);
+ CustomData_from_bmeshpoly(fdata, ldata, totface);
+
+ if (do_face_nor_copy) {
+ /* If polys have a normals layer, copying that to faces can help
+ * avoid the need to recalculate normals later */
+ if (CustomData_has_layer(pdata, CD_NORMAL)) {
+ float(*pnors)[3] = CustomData_get_layer(pdata, CD_NORMAL);
+ float(*fnors)[3] = CustomData_add_layer(fdata, CD_NORMAL, CD_CALLOC, NULL, totface);
+ for (mface_index = 0; mface_index < totface; mface_index++) {
+ copy_v3_v3(fnors[mface_index], pnors[mface_to_poly_map[mface_index]]);
+ }
+ }
+ }
+
+ /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
+ * Polygons take care of their loops ordering, hence not of their vertices ordering.
+ * Currently, our tfaces' fourth vertex index might be 0 even for a quad. However, we know our fourth loop index is
+ * never 0 for quads (because they are sorted for polygons, and our quads are still mere copies of their polygons).
+ * So we pass NULL as MFace pointer, and BKE_mesh_loops_to_tessdata will use the fourth loop index as quad test.
+ * ...
+ */
+ BKE_mesh_loops_to_tessdata(fdata, ldata, NULL, mface_to_poly_map, lindices, totface);
+
+ /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
+ * ...However, most TFace code uses 'MFace->v4 == 0' test to check whether it is a tri or quad.
+ * test_index_face() will check this and rotate the tessellated face if needed.
+ */
#ifdef USE_TESSFACE_QUADS
- mf = mface;
- for (mface_index = 0; mface_index < totface; mface_index++, mf++) {
- if (mf->edcode == TESSFACE_IS_QUAD) {
- test_index_face(mf, fdata, mface_index, 4);
- mf->edcode = 0;
- }
- }
+ mf = mface;
+ for (mface_index = 0; mface_index < totface; mface_index++, mf++) {
+ if (mf->edcode == TESSFACE_IS_QUAD) {
+ test_index_face(mf, fdata, mface_index, 4);
+ mf->edcode = 0;
+ }
+ }
#endif
- MEM_freeN(lindices);
+ MEM_freeN(lindices);
- return totface;
+ return totface;
#undef USE_TESSFACE_SPEEDUP
#undef USE_TESSFACE_QUADS
#undef ML_TO_MF
#undef ML_TO_MF_QUAD
-
}
/**
* Calculate tessellation into #MLoopTri which exist only for this purpose.
*/
-void BKE_mesh_recalc_looptri(
- const MLoop *mloop, const MPoly *mpoly,
- const MVert *mvert,
- int totloop, int totpoly,
- MLoopTri *mlooptri)
+void BKE_mesh_recalc_looptri(const MLoop *mloop,
+ const MPoly *mpoly,
+ const MVert *mvert,
+ int totloop,
+ int totpoly,
+ MLoopTri *mlooptri)
{
- /* use this to avoid locking pthread for _every_ polygon
- * and calling the fill function */
+ /* use this to avoid locking pthread for _every_ polygon
+ * and calling the fill function */
#define USE_TESSFACE_SPEEDUP
- const MPoly *mp;
- const MLoop *ml;
- MLoopTri *mlt;
- MemArena *arena = NULL;
- int poly_index, mlooptri_index;
- unsigned int j;
-
- mlooptri_index = 0;
- mp = mpoly;
- for (poly_index = 0; poly_index < totpoly; poly_index++, mp++) {
- const unsigned int mp_loopstart = (unsigned int)mp->loopstart;
- const unsigned int mp_totloop = (unsigned int)mp->totloop;
- unsigned int l1, l2, l3;
- if (mp_totloop < 3) {
- /* do nothing */
- }
+ const MPoly *mp;
+ const MLoop *ml;
+ MLoopTri *mlt;
+ MemArena *arena = NULL;
+ int poly_index, mlooptri_index;
+ unsigned int j;
+
+ mlooptri_index = 0;
+ mp = mpoly;
+ for (poly_index = 0; poly_index < totpoly; poly_index++, mp++) {
+ const unsigned int mp_loopstart = (unsigned int)mp->loopstart;
+ const unsigned int mp_totloop = (unsigned int)mp->totloop;
+ unsigned int l1, l2, l3;
+ if (mp_totloop < 3) {
+ /* do nothing */
+ }
#ifdef USE_TESSFACE_SPEEDUP
-#define ML_TO_MLT(i1, i2, i3) { \
- mlt = &mlooptri[mlooptri_index]; \
- l1 = mp_loopstart + i1; \
- l2 = mp_loopstart + i2; \
- l3 = mp_loopstart + i3; \
- ARRAY_SET_ITEMS(mlt->tri, l1, l2, l3); \
- mlt->poly = (unsigned int)poly_index; \
- } ((void)0)
-
- else if (mp_totloop == 3) {
- ML_TO_MLT(0, 1, 2);
- mlooptri_index++;
- }
- else if (mp_totloop == 4) {
- ML_TO_MLT(0, 1, 2);
- MLoopTri *mlt_a = mlt;
- mlooptri_index++;
- ML_TO_MLT(0, 2, 3);
- MLoopTri *mlt_b = mlt;
- mlooptri_index++;
-
- if (UNLIKELY(is_quad_flip_v3_first_third_fast(
- mvert[mloop[mlt_a->tri[0]].v].co,
- mvert[mloop[mlt_a->tri[1]].v].co,
- mvert[mloop[mlt_a->tri[2]].v].co,
- mvert[mloop[mlt_b->tri[2]].v].co)))
- {
- /* flip out of degenerate 0-2 state. */
- mlt_a->tri[2] = mlt_b->tri[2];
- mlt_b->tri[0] = mlt_a->tri[1];
- }
- }
+# define ML_TO_MLT(i1, i2, i3) \
+ { \
+ mlt = &mlooptri[mlooptri_index]; \
+ l1 = mp_loopstart + i1; \
+ l2 = mp_loopstart + i2; \
+ l3 = mp_loopstart + i3; \
+ ARRAY_SET_ITEMS(mlt->tri, l1, l2, l3); \
+ mlt->poly = (unsigned int)poly_index; \
+ } \
+ ((void)0)
+
+ else if (mp_totloop == 3) {
+ ML_TO_MLT(0, 1, 2);
+ mlooptri_index++;
+ }
+ else if (mp_totloop == 4) {
+ ML_TO_MLT(0, 1, 2);
+ MLoopTri *mlt_a = mlt;
+ mlooptri_index++;
+ ML_TO_MLT(0, 2, 3);
+ MLoopTri *mlt_b = mlt;
+ mlooptri_index++;
+
+ if (UNLIKELY(is_quad_flip_v3_first_third_fast(mvert[mloop[mlt_a->tri[0]].v].co,
+ mvert[mloop[mlt_a->tri[1]].v].co,
+ mvert[mloop[mlt_a->tri[2]].v].co,
+ mvert[mloop[mlt_b->tri[2]].v].co))) {
+ /* flip out of degenerate 0-2 state. */
+ mlt_a->tri[2] = mlt_b->tri[2];
+ mlt_b->tri[0] = mlt_a->tri[1];
+ }
+ }
#endif /* USE_TESSFACE_SPEEDUP */
- else {
- const float *co_curr, *co_prev;
+ else {
+ const float *co_curr, *co_prev;
- float normal[3];
+ float normal[3];
- float axis_mat[3][3];
- float (*projverts)[2];
- unsigned int (*tris)[3];
+ float axis_mat[3][3];
+ float(*projverts)[2];
+ unsigned int(*tris)[3];
- const unsigned int totfilltri = mp_totloop - 2;
+ const unsigned int totfilltri = mp_totloop - 2;
- if (UNLIKELY(arena == NULL)) {
- arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
- }
+ if (UNLIKELY(arena == NULL)) {
+ arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+ }
- tris = BLI_memarena_alloc(arena, sizeof(*tris) * (size_t)totfilltri);
- projverts = BLI_memarena_alloc(arena, sizeof(*projverts) * (size_t)mp_totloop);
+ tris = BLI_memarena_alloc(arena, sizeof(*tris) * (size_t)totfilltri);
+ projverts = BLI_memarena_alloc(arena, sizeof(*projverts) * (size_t)mp_totloop);
- zero_v3(normal);
+ zero_v3(normal);
- /* calc normal, flipped: to get a positive 2d cross product */
- ml = mloop + mp_loopstart;
- co_prev = mvert[ml[mp_totloop - 1].v].co;
- for (j = 0; j < mp_totloop; j++, ml++) {
- co_curr = mvert[ml->v].co;
- add_newell_cross_v3_v3v3(normal, co_prev, co_curr);
- co_prev = co_curr;
- }
- if (UNLIKELY(normalize_v3(normal) == 0.0f)) {
- normal[2] = 1.0f;
- }
+ /* calc normal, flipped: to get a positive 2d cross product */
+ ml = mloop + mp_loopstart;
+ co_prev = mvert[ml[mp_totloop - 1].v].co;
+ for (j = 0; j < mp_totloop; j++, ml++) {
+ co_curr = mvert[ml->v].co;
+ add_newell_cross_v3_v3v3(normal, co_prev, co_curr);
+ co_prev = co_curr;
+ }
+ if (UNLIKELY(normalize_v3(normal) == 0.0f)) {
+ normal[2] = 1.0f;
+ }
- /* project verts to 2d */
- axis_dominant_v3_to_m3_negate(axis_mat, normal);
+ /* project verts to 2d */
+ axis_dominant_v3_to_m3_negate(axis_mat, normal);
- ml = mloop + mp_loopstart;
- for (j = 0; j < mp_totloop; j++, ml++) {
- mul_v2_m3v3(projverts[j], axis_mat, mvert[ml->v].co);
- }
+ ml = mloop + mp_loopstart;
+ for (j = 0; j < mp_totloop; j++, ml++) {
+ mul_v2_m3v3(projverts[j], axis_mat, mvert[ml->v].co);
+ }
- BLI_polyfill_calc_arena(projverts, mp_totloop, 1, tris, arena);
+ BLI_polyfill_calc_arena(projverts, mp_totloop, 1, tris, arena);
- /* apply fill */
- for (j = 0; j < totfilltri; j++) {
- unsigned int *tri = tris[j];
+ /* apply fill */
+ for (j = 0; j < totfilltri; j++) {
+ unsigned int *tri = tris[j];
- mlt = &mlooptri[mlooptri_index];
+ mlt = &mlooptri[mlooptri_index];
- /* set loop indices, transformed to vert indices later */
- l1 = mp_loopstart + tri[0];
- l2 = mp_loopstart + tri[1];
- l3 = mp_loopstart + tri[2];
+ /* set loop indices, transformed to vert indices later */
+ l1 = mp_loopstart + tri[0];
+ l2 = mp_loopstart + tri[1];
+ l3 = mp_loopstart + tri[2];
- ARRAY_SET_ITEMS(mlt->tri, l1, l2, l3);
- mlt->poly = (unsigned int)poly_index;
+ ARRAY_SET_ITEMS(mlt->tri, l1, l2, l3);
+ mlt->poly = (unsigned int)poly_index;
- mlooptri_index++;
- }
+ mlooptri_index++;
+ }
- BLI_memarena_clear(arena);
- }
- }
+ BLI_memarena_clear(arena);
+ }
+ }
- if (arena) {
- BLI_memarena_free(arena);
- arena = NULL;
- }
+ if (arena) {
+ BLI_memarena_free(arena);
+ arena = NULL;
+ }
- BLI_assert(mlooptri_index == poly_to_tri_count(totpoly, totloop));
- UNUSED_VARS_NDEBUG(totloop);
+ BLI_assert(mlooptri_index == poly_to_tri_count(totpoly, totloop));
+ UNUSED_VARS_NDEBUG(totloop);
#undef USE_TESSFACE_SPEEDUP
#undef ML_TO_MLT
}
-static void bm_corners_to_loops_ex(
- ID *id, CustomData *fdata, CustomData *ldata,
- MFace *mface, int totloop, int findex, int loopstart, int numTex, int numCol)
-{
- MTFace *texface;
- MCol *mcol;
- MLoopCol *mloopcol;
- MLoopUV *mloopuv;
- MFace *mf;
- int i;
-
- mf = mface + findex;
-
- for (i = 0; i < numTex; i++) {
- texface = CustomData_get_n(fdata, CD_MTFACE, findex, i);
-
- mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, loopstart, i);
- copy_v2_v2(mloopuv->uv, texface->uv[0]); mloopuv++;
- copy_v2_v2(mloopuv->uv, texface->uv[1]); mloopuv++;
- copy_v2_v2(mloopuv->uv, texface->uv[2]); mloopuv++;
-
- if (mf->v4) {
- copy_v2_v2(mloopuv->uv, texface->uv[3]); mloopuv++;
- }
- }
-
- for (i = 0; i < numCol; i++) {
- mloopcol = CustomData_get_n(ldata, CD_MLOOPCOL, loopstart, i);
- mcol = CustomData_get_n(fdata, CD_MCOL, findex, i);
-
- MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[0]); mloopcol++;
- MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[1]); mloopcol++;
- MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[2]); mloopcol++;
- if (mf->v4) {
- MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[3]); mloopcol++;
- }
- }
-
- if (CustomData_has_layer(fdata, CD_TESSLOOPNORMAL)) {
- float (*lnors)[3] = CustomData_get(ldata, loopstart, CD_NORMAL);
- short (*tlnors)[3] = CustomData_get(fdata, findex, CD_TESSLOOPNORMAL);
- const int max = mf->v4 ? 4 : 3;
-
- for (i = 0; i < max; i++, lnors++, tlnors++) {
- normal_short_to_float_v3(*lnors, *tlnors);
- }
- }
-
- if (CustomData_has_layer(fdata, CD_MDISPS)) {
- MDisps *ld = CustomData_get(ldata, loopstart, CD_MDISPS);
- MDisps *fd = CustomData_get(fdata, findex, CD_MDISPS);
- float (*disps)[3] = fd->disps;
- int tot = mf->v4 ? 4 : 3;
- int corners;
-
- if (CustomData_external_test(fdata, CD_MDISPS)) {
- if (id && fdata->external) {
- CustomData_external_add(
- ldata, id, CD_MDISPS,
- totloop, fdata->external->filename);
- }
- }
-
- corners = multires_mdisp_corners(fd);
-
- if (corners == 0) {
- /* Empty MDisp layers appear in at least one of the sintel.blend files.
- * Not sure why this happens, but it seems fine to just ignore them here.
- * If (corners == 0) for a non-empty layer though, something went wrong. */
- BLI_assert(fd->totdisp == 0);
- }
- else {
- const int side = (int)sqrtf((float)(fd->totdisp / corners));
- const int side_sq = side * side;
-
- for (i = 0; i < tot; i++, disps += side_sq, ld++) {
- ld->totdisp = side_sq;
- ld->level = (int)(logf((float)side - 1.0f) / (float)M_LN2) + 1;
-
- if (ld->disps)
- MEM_freeN(ld->disps);
-
- ld->disps = MEM_malloc_arrayN((size_t)side_sq, sizeof(float[3]), "converted loop mdisps");
- if (fd->disps) {
- memcpy(ld->disps, disps, (size_t)side_sq * sizeof(float[3]));
- }
- else {
- memset(ld->disps, 0, (size_t)side_sq * sizeof(float[3]));
- }
- }
- }
- }
+static void bm_corners_to_loops_ex(ID *id,
+ CustomData *fdata,
+ CustomData *ldata,
+ MFace *mface,
+ int totloop,
+ int findex,
+ int loopstart,
+ int numTex,
+ int numCol)
+{
+ MTFace *texface;
+ MCol *mcol;
+ MLoopCol *mloopcol;
+ MLoopUV *mloopuv;
+ MFace *mf;
+ int i;
+
+ mf = mface + findex;
+
+ for (i = 0; i < numTex; i++) {
+ texface = CustomData_get_n(fdata, CD_MTFACE, findex, i);
+
+ mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, loopstart, i);
+ copy_v2_v2(mloopuv->uv, texface->uv[0]);
+ mloopuv++;
+ copy_v2_v2(mloopuv->uv, texface->uv[1]);
+ mloopuv++;
+ copy_v2_v2(mloopuv->uv, texface->uv[2]);
+ mloopuv++;
+
+ if (mf->v4) {
+ copy_v2_v2(mloopuv->uv, texface->uv[3]);
+ mloopuv++;
+ }
+ }
+
+ for (i = 0; i < numCol; i++) {
+ mloopcol = CustomData_get_n(ldata, CD_MLOOPCOL, loopstart, i);
+ mcol = CustomData_get_n(fdata, CD_MCOL, findex, i);
+
+ MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[0]);
+ mloopcol++;
+ MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[1]);
+ mloopcol++;
+ MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[2]);
+ mloopcol++;
+ if (mf->v4) {
+ MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[3]);
+ mloopcol++;
+ }
+ }
+
+ if (CustomData_has_layer(fdata, CD_TESSLOOPNORMAL)) {
+ float(*lnors)[3] = CustomData_get(ldata, loopstart, CD_NORMAL);
+ short(*tlnors)[3] = CustomData_get(fdata, findex, CD_TESSLOOPNORMAL);
+ const int max = mf->v4 ? 4 : 3;
+
+ for (i = 0; i < max; i++, lnors++, tlnors++) {
+ normal_short_to_float_v3(*lnors, *tlnors);
+ }
+ }
+
+ if (CustomData_has_layer(fdata, CD_MDISPS)) {
+ MDisps *ld = CustomData_get(ldata, loopstart, CD_MDISPS);
+ MDisps *fd = CustomData_get(fdata, findex, CD_MDISPS);
+ float(*disps)[3] = fd->disps;
+ int tot = mf->v4 ? 4 : 3;
+ int corners;
+
+ if (CustomData_external_test(fdata, CD_MDISPS)) {
+ if (id && fdata->external) {
+ CustomData_external_add(ldata, id, CD_MDISPS, totloop, fdata->external->filename);
+ }
+ }
+
+ corners = multires_mdisp_corners(fd);
+
+ if (corners == 0) {
+ /* Empty MDisp layers appear in at least one of the sintel.blend files.
+ * Not sure why this happens, but it seems fine to just ignore them here.
+ * If (corners == 0) for a non-empty layer though, something went wrong. */
+ BLI_assert(fd->totdisp == 0);
+ }
+ else {
+ const int side = (int)sqrtf((float)(fd->totdisp / corners));
+ const int side_sq = side * side;
+
+ for (i = 0; i < tot; i++, disps += side_sq, ld++) {
+ ld->totdisp = side_sq;
+ ld->level = (int)(logf((float)side - 1.0f) / (float)M_LN2) + 1;
+
+ if (ld->disps)
+ MEM_freeN(ld->disps);
+
+ ld->disps = MEM_malloc_arrayN((size_t)side_sq, sizeof(float[3]), "converted loop mdisps");
+ if (fd->disps) {
+ memcpy(ld->disps, disps, (size_t)side_sq * sizeof(float[3]));
+ }
+ else {
+ memset(ld->disps, 0, (size_t)side_sq * sizeof(float[3]));
+ }
+ }
+ }
+ }
}
-
void BKE_mesh_convert_mfaces_to_mpolys(Mesh *mesh)
{
- BKE_mesh_convert_mfaces_to_mpolys_ex(
- &mesh->id, &mesh->fdata, &mesh->ldata, &mesh->pdata,
- mesh->totedge, mesh->totface, mesh->totloop, mesh->totpoly,
- mesh->medge, mesh->mface,
- &mesh->totloop, &mesh->totpoly, &mesh->mloop, &mesh->mpoly);
+ BKE_mesh_convert_mfaces_to_mpolys_ex(&mesh->id,
+ &mesh->fdata,
+ &mesh->ldata,
+ &mesh->pdata,
+ mesh->totedge,
+ mesh->totface,
+ mesh->totloop,
+ mesh->totpoly,
+ mesh->medge,
+ mesh->mface,
+ &mesh->totloop,
+ &mesh->totpoly,
+ &mesh->mloop,
+ &mesh->mpoly);
- BKE_mesh_update_customdata_pointers(mesh, true);
+ BKE_mesh_update_customdata_pointers(mesh, true);
}
/* the same as BKE_mesh_convert_mfaces_to_mpolys but oriented to be used in do_versions from readfile.c
@@ -3214,126 +3445,145 @@ void BKE_mesh_convert_mfaces_to_mpolys(Mesh *mesh)
*/
void BKE_mesh_do_versions_convert_mfaces_to_mpolys(Mesh *mesh)
{
- BKE_mesh_convert_mfaces_to_mpolys_ex(
- &mesh->id, &mesh->fdata, &mesh->ldata, &mesh->pdata,
- mesh->totedge, mesh->totface, mesh->totloop, mesh->totpoly,
- mesh->medge, mesh->mface,
- &mesh->totloop, &mesh->totpoly, &mesh->mloop, &mesh->mpoly);
-
- CustomData_bmesh_do_versions_update_active_layers(&mesh->fdata, &mesh->ldata);
-
- BKE_mesh_update_customdata_pointers(mesh, true);
-}
-
-void BKE_mesh_convert_mfaces_to_mpolys_ex(
- ID *id, CustomData *fdata, CustomData *ldata, CustomData *pdata,
- int totedge_i, int totface_i, int totloop_i, int totpoly_i,
- MEdge *medge, MFace *mface,
- int *r_totloop, int *r_totpoly,
- MLoop **r_mloop, MPoly **r_mpoly)
-{
- MFace *mf;
- MLoop *ml, *mloop;
- MPoly *mp, *mpoly;
- MEdge *me;
- EdgeHash *eh;
- int numTex, numCol;
- int i, j, totloop, totpoly, *polyindex;
-
- /* old flag, clear to allow for reuse */
+ BKE_mesh_convert_mfaces_to_mpolys_ex(&mesh->id,
+ &mesh->fdata,
+ &mesh->ldata,
+ &mesh->pdata,
+ mesh->totedge,
+ mesh->totface,
+ mesh->totloop,
+ mesh->totpoly,
+ mesh->medge,
+ mesh->mface,
+ &mesh->totloop,
+ &mesh->totpoly,
+ &mesh->mloop,
+ &mesh->mpoly);
+
+ CustomData_bmesh_do_versions_update_active_layers(&mesh->fdata, &mesh->ldata);
+
+ BKE_mesh_update_customdata_pointers(mesh, true);
+}
+
+void BKE_mesh_convert_mfaces_to_mpolys_ex(ID *id,
+ CustomData *fdata,
+ CustomData *ldata,
+ CustomData *pdata,
+ int totedge_i,
+ int totface_i,
+ int totloop_i,
+ int totpoly_i,
+ MEdge *medge,
+ MFace *mface,
+ int *r_totloop,
+ int *r_totpoly,
+ MLoop **r_mloop,
+ MPoly **r_mpoly)
+{
+ MFace *mf;
+ MLoop *ml, *mloop;
+ MPoly *mp, *mpoly;
+ MEdge *me;
+ EdgeHash *eh;
+ int numTex, numCol;
+ int i, j, totloop, totpoly, *polyindex;
+
+ /* old flag, clear to allow for reuse */
#define ME_FGON (1 << 3)
- /* just in case some of these layers are filled in (can happen with python created meshes) */
- CustomData_free(ldata, totloop_i);
- CustomData_free(pdata, totpoly_i);
+ /* just in case some of these layers are filled in (can happen with python created meshes) */
+ CustomData_free(ldata, totloop_i);
+ CustomData_free(pdata, totpoly_i);
- totpoly = totface_i;
- mpoly = MEM_calloc_arrayN((size_t)totpoly, sizeof(MPoly), "mpoly converted");
- CustomData_add_layer(pdata, CD_MPOLY, CD_ASSIGN, mpoly, totpoly);
+ totpoly = totface_i;
+ mpoly = MEM_calloc_arrayN((size_t)totpoly, sizeof(MPoly), "mpoly converted");
+ CustomData_add_layer(pdata, CD_MPOLY, CD_ASSIGN, mpoly, totpoly);
- numTex = CustomData_number_of_layers(fdata, CD_MTFACE);
- numCol = CustomData_number_of_layers(fdata, CD_MCOL);
+ numTex = CustomData_number_of_layers(fdata, CD_MTFACE);
+ numCol = CustomData_number_of_layers(fdata, CD_MCOL);
- totloop = 0;
- mf = mface;
- for (i = 0; i < totface_i; i++, mf++) {
- totloop += mf->v4 ? 4 : 3;
- }
+ totloop = 0;
+ mf = mface;
+ for (i = 0; i < totface_i; i++, mf++) {
+ totloop += mf->v4 ? 4 : 3;
+ }
- mloop = MEM_calloc_arrayN((size_t)totloop, sizeof(MLoop), "mloop converted");
+ mloop = MEM_calloc_arrayN((size_t)totloop, sizeof(MLoop), "mloop converted");
- CustomData_add_layer(ldata, CD_MLOOP, CD_ASSIGN, mloop, totloop);
+ CustomData_add_layer(ldata, CD_MLOOP, CD_ASSIGN, mloop, totloop);
- CustomData_to_bmeshpoly(fdata, ldata, totloop);
+ CustomData_to_bmeshpoly(fdata, ldata, totloop);
- if (id) {
- /* ensure external data is transferred */
- CustomData_external_read(fdata, id, CD_MASK_MDISPS, totface_i);
- }
+ if (id) {
+ /* ensure external data is transferred */
+ CustomData_external_read(fdata, id, CD_MASK_MDISPS, totface_i);
+ }
- eh = BLI_edgehash_new_ex(__func__, (unsigned int)totedge_i);
+ eh = BLI_edgehash_new_ex(__func__, (unsigned int)totedge_i);
- /* build edge hash */
- me = medge;
- for (i = 0; i < totedge_i; i++, me++) {
- BLI_edgehash_insert(eh, me->v1, me->v2, POINTER_FROM_UINT(i));
+ /* build edge hash */
+ me = medge;
+ for (i = 0; i < totedge_i; i++, me++) {
+ BLI_edgehash_insert(eh, me->v1, me->v2, POINTER_FROM_UINT(i));
- /* unrelated but avoid having the FGON flag enabled, so we can reuse it later for something else */
- me->flag &= ~ME_FGON;
- }
+ /* unrelated but avoid having the FGON flag enabled, so we can reuse it later for something else */
+ me->flag &= ~ME_FGON;
+ }
- polyindex = CustomData_get_layer(fdata, CD_ORIGINDEX);
+ polyindex = CustomData_get_layer(fdata, CD_ORIGINDEX);
- j = 0; /* current loop index */
- ml = mloop;
- mf = mface;
- mp = mpoly;
- for (i = 0; i < totface_i; i++, mf++, mp++) {
- mp->loopstart = j;
+ j = 0; /* current loop index */
+ ml = mloop;
+ mf = mface;
+ mp = mpoly;
+ for (i = 0; i < totface_i; i++, mf++, mp++) {
+ mp->loopstart = j;
- mp->totloop = mf->v4 ? 4 : 3;
+ mp->totloop = mf->v4 ? 4 : 3;
- mp->mat_nr = mf->mat_nr;
- mp->flag = mf->flag;
+ mp->mat_nr = mf->mat_nr;
+ mp->flag = mf->flag;
-# define ML(v1, v2) { \
- ml->v = mf->v1; \
- ml->e = POINTER_AS_UINT(BLI_edgehash_lookup(eh, mf->v1, mf->v2)); \
- ml++; j++; \
- } (void)0
+#define ML(v1, v2) \
+ { \
+ ml->v = mf->v1; \
+ ml->e = POINTER_AS_UINT(BLI_edgehash_lookup(eh, mf->v1, mf->v2)); \
+ ml++; \
+ j++; \
+ } \
+ (void)0
- ML(v1, v2);
- ML(v2, v3);
- if (mf->v4) {
- ML(v3, v4);
- ML(v4, v1);
- }
- else {
- ML(v3, v1);
- }
+ ML(v1, v2);
+ ML(v2, v3);
+ if (mf->v4) {
+ ML(v3, v4);
+ ML(v4, v1);
+ }
+ else {
+ ML(v3, v1);
+ }
-# undef ML
+#undef ML
- bm_corners_to_loops_ex(id, fdata, ldata, mface, totloop, i, mp->loopstart, numTex, numCol);
+ bm_corners_to_loops_ex(id, fdata, ldata, mface, totloop, i, mp->loopstart, numTex, numCol);
- if (polyindex) {
- *polyindex = i;
- polyindex++;
- }
- }
+ if (polyindex) {
+ *polyindex = i;
+ polyindex++;
+ }
+ }
- /* note, we don't convert NGons at all, these are not even real ngons,
- * they have their own UV's, colors etc - its more an editing feature. */
+ /* note, we don't convert NGons at all, these are not even real ngons,
+ * they have their own UV's, colors etc - its more an editing feature. */
- BLI_edgehash_free(eh, NULL);
+ BLI_edgehash_free(eh, NULL);
- *r_totpoly = totpoly;
- *r_totloop = totloop;
- *r_mpoly = mpoly;
- *r_mloop = mloop;
+ *r_totpoly = totpoly;
+ *r_totloop = totloop;
+ *r_mpoly = mpoly;
+ *r_mloop = mloop;
#undef ME_FGON
-
}
/** \} */
@@ -3343,38 +3593,38 @@ void BKE_mesh_convert_mfaces_to_mpolys_ex(
*/
void BKE_mesh_mdisp_flip(MDisps *md, const bool use_loop_mdisp_flip)
{
- if (UNLIKELY(!md->totdisp || !md->disps)) {
- return;
- }
+ if (UNLIKELY(!md->totdisp || !md->disps)) {
+ return;
+ }
- const int sides = (int)sqrt(md->totdisp);
- float (*co)[3] = md->disps;
+ const int sides = (int)sqrt(md->totdisp);
+ float(*co)[3] = md->disps;
- for (int x = 0; x < sides; x++) {
- float *co_a, *co_b;
+ for (int x = 0; x < sides; x++) {
+ float *co_a, *co_b;
- for (int y = 0; y < x; y++) {
- co_a = co[y * sides + x];
- co_b = co[x * sides + y];
+ for (int y = 0; y < x; y++) {
+ co_a = co[y * sides + x];
+ co_b = co[x * sides + y];
- swap_v3_v3(co_a, co_b);
- SWAP(float, co_a[0], co_a[1]);
- SWAP(float, co_b[0], co_b[1]);
+ swap_v3_v3(co_a, co_b);
+ SWAP(float, co_a[0], co_a[1]);
+ SWAP(float, co_b[0], co_b[1]);
- if (use_loop_mdisp_flip) {
- co_a[2] *= -1.0f;
- co_b[2] *= -1.0f;
- }
- }
+ if (use_loop_mdisp_flip) {
+ co_a[2] *= -1.0f;
+ co_b[2] *= -1.0f;
+ }
+ }
- co_a = co[x * sides + x];
+ co_a = co[x * sides + x];
- SWAP(float, co_a[0], co_a[1]);
+ SWAP(float, co_a[0], co_a[1]);
- if (use_loop_mdisp_flip) {
- co_a[2] *= -1.0f;
- }
- }
+ if (use_loop_mdisp_flip) {
+ co_a[2] *= -1.0f;
+ }
+ }
}
/**
@@ -3385,49 +3635,52 @@ void BKE_mesh_mdisp_flip(MDisps *md, const bool use_loop_mdisp_flip)
* \param mloop: the full loops array.
* \param ldata: the loops custom data.
*/
-void BKE_mesh_polygon_flip_ex(
- MPoly *mpoly, MLoop *mloop, CustomData *ldata,
- float (*lnors)[3], MDisps *mdisp, const bool use_loop_mdisp_flip)
-{
- int loopstart = mpoly->loopstart;
- int loopend = loopstart + mpoly->totloop - 1;
- const bool loops_in_ldata = (CustomData_get_layer(ldata, CD_MLOOP) == mloop);
-
- if (mdisp) {
- for (int i = loopstart; i <= loopend; i++) {
- BKE_mesh_mdisp_flip(&mdisp[i], use_loop_mdisp_flip);
- }
- }
-
- /* Note that we keep same start vertex for flipped face. */
-
- /* We also have to update loops edge
- * (they will get their original 'other edge', that is, the original edge of their original previous loop)... */
- unsigned int prev_edge_index = mloop[loopstart].e;
- mloop[loopstart].e = mloop[loopend].e;
-
- for (loopstart++; loopend > loopstart; loopstart++, loopend--) {
- mloop[loopend].e = mloop[loopend - 1].e;
- SWAP(unsigned int, mloop[loopstart].e, prev_edge_index);
-
- if (!loops_in_ldata) {
- SWAP(MLoop, mloop[loopstart], mloop[loopend]);
- }
- if (lnors) {
- swap_v3_v3(lnors[loopstart], lnors[loopend]);
- }
- CustomData_swap(ldata, loopstart, loopend);
- }
- /* Even if we did not swap the other 'pivot' loop, we need to set its swapped edge. */
- if (loopstart == loopend) {
- mloop[loopstart].e = prev_edge_index;
- }
+void BKE_mesh_polygon_flip_ex(MPoly *mpoly,
+ MLoop *mloop,
+ CustomData *ldata,
+ float (*lnors)[3],
+ MDisps *mdisp,
+ const bool use_loop_mdisp_flip)
+{
+ int loopstart = mpoly->loopstart;
+ int loopend = loopstart + mpoly->totloop - 1;
+ const bool loops_in_ldata = (CustomData_get_layer(ldata, CD_MLOOP) == mloop);
+
+ if (mdisp) {
+ for (int i = loopstart; i <= loopend; i++) {
+ BKE_mesh_mdisp_flip(&mdisp[i], use_loop_mdisp_flip);
+ }
+ }
+
+ /* Note that we keep same start vertex for flipped face. */
+
+ /* We also have to update loops edge
+ * (they will get their original 'other edge', that is, the original edge of their original previous loop)... */
+ unsigned int prev_edge_index = mloop[loopstart].e;
+ mloop[loopstart].e = mloop[loopend].e;
+
+ for (loopstart++; loopend > loopstart; loopstart++, loopend--) {
+ mloop[loopend].e = mloop[loopend - 1].e;
+ SWAP(unsigned int, mloop[loopstart].e, prev_edge_index);
+
+ if (!loops_in_ldata) {
+ SWAP(MLoop, mloop[loopstart], mloop[loopend]);
+ }
+ if (lnors) {
+ swap_v3_v3(lnors[loopstart], lnors[loopend]);
+ }
+ CustomData_swap(ldata, loopstart, loopend);
+ }
+ /* Even if we did not swap the other 'pivot' loop, we need to set its swapped edge. */
+ if (loopstart == loopend) {
+ mloop[loopstart].e = prev_edge_index;
+ }
}
void BKE_mesh_polygon_flip(MPoly *mpoly, MLoop *mloop, CustomData *ldata)
{
- MDisps *mdisp = CustomData_get_layer(ldata, CD_MDISPS);
- BKE_mesh_polygon_flip_ex(mpoly, mloop, ldata, NULL, mdisp, true);
+ MDisps *mdisp = CustomData_get_layer(ldata, CD_MDISPS);
+ BKE_mesh_polygon_flip_ex(mpoly, mloop, ldata, NULL, mdisp, true);
}
/**
@@ -3435,16 +3688,15 @@ void BKE_mesh_polygon_flip(MPoly *mpoly, MLoop *mloop, CustomData *ldata)
*
* \note Invalidates tessellation, caller must handle that.
*/
-void BKE_mesh_polygons_flip(
- MPoly *mpoly, MLoop *mloop, CustomData *ldata, int totpoly)
+void BKE_mesh_polygons_flip(MPoly *mpoly, MLoop *mloop, CustomData *ldata, int totpoly)
{
- MDisps *mdisp = CustomData_get_layer(ldata, CD_MDISPS);
- MPoly *mp;
- int i;
+ MDisps *mdisp = CustomData_get_layer(ldata, CD_MDISPS);
+ MPoly *mp;
+ int i;
- for (mp = mpoly, i = 0; i < totpoly; mp++, i++) {
- BKE_mesh_polygon_flip_ex(mp, mloop, ldata, NULL, mdisp, true);
- }
+ for (mp = mpoly, i = 0; i < totpoly; mp++, i++) {
+ BKE_mesh_polygon_flip_ex(mp, mloop, ldata, NULL, mdisp, true);
+ }
}
/* -------------------------------------------------------------------- */
@@ -3453,187 +3705,181 @@ void BKE_mesh_polygons_flip(
/* update the hide flag for edges and faces from the corresponding
* flag in verts */
-void BKE_mesh_flush_hidden_from_verts_ex(
- const MVert *mvert,
- const MLoop *mloop,
- MEdge *medge, const int totedge,
- MPoly *mpoly, const int totpoly)
-{
- int i, j;
-
- for (i = 0; i < totedge; i++) {
- MEdge *e = &medge[i];
- if (mvert[e->v1].flag & ME_HIDE ||
- mvert[e->v2].flag & ME_HIDE)
- {
- e->flag |= ME_HIDE;
- }
- else {
- e->flag &= ~ME_HIDE;
- }
- }
- for (i = 0; i < totpoly; i++) {
- MPoly *p = &mpoly[i];
- p->flag &= (char)~ME_HIDE;
- for (j = 0; j < p->totloop; j++) {
- if (mvert[mloop[p->loopstart + j].v].flag & ME_HIDE)
- p->flag |= ME_HIDE;
- }
- }
+void BKE_mesh_flush_hidden_from_verts_ex(const MVert *mvert,
+ const MLoop *mloop,
+ MEdge *medge,
+ const int totedge,
+ MPoly *mpoly,
+ const int totpoly)
+{
+ int i, j;
+
+ for (i = 0; i < totedge; i++) {
+ MEdge *e = &medge[i];
+ if (mvert[e->v1].flag & ME_HIDE || mvert[e->v2].flag & ME_HIDE) {
+ e->flag |= ME_HIDE;
+ }
+ else {
+ e->flag &= ~ME_HIDE;
+ }
+ }
+ for (i = 0; i < totpoly; i++) {
+ MPoly *p = &mpoly[i];
+ p->flag &= (char)~ME_HIDE;
+ for (j = 0; j < p->totloop; j++) {
+ if (mvert[mloop[p->loopstart + j].v].flag & ME_HIDE)
+ p->flag |= ME_HIDE;
+ }
+ }
}
void BKE_mesh_flush_hidden_from_verts(Mesh *me)
{
- BKE_mesh_flush_hidden_from_verts_ex(
- me->mvert, me->mloop,
- me->medge, me->totedge,
- me->mpoly, me->totpoly);
-}
-
-void BKE_mesh_flush_hidden_from_polys_ex(
- MVert *mvert,
- const MLoop *mloop,
- MEdge *medge, const int UNUSED(totedge),
- const MPoly *mpoly, const int totpoly)
-{
- const MPoly *mp;
- int i;
-
- i = totpoly;
- for (mp = mpoly; i--; mp++) {
- if (mp->flag & ME_HIDE) {
- const MLoop *ml;
- int j;
- j = mp->totloop;
- for (ml = &mloop[mp->loopstart]; j--; ml++) {
- mvert[ml->v].flag |= ME_HIDE;
- medge[ml->e].flag |= ME_HIDE;
- }
- }
- }
-
- i = totpoly;
- for (mp = mpoly; i--; mp++) {
- if ((mp->flag & ME_HIDE) == 0) {
- const MLoop *ml;
- int j;
- j = mp->totloop;
- for (ml = &mloop[mp->loopstart]; j--; ml++) {
- mvert[ml->v].flag &= (char)~ME_HIDE;
- medge[ml->e].flag &= (short)~ME_HIDE;
- }
- }
- }
+ BKE_mesh_flush_hidden_from_verts_ex(
+ me->mvert, me->mloop, me->medge, me->totedge, me->mpoly, me->totpoly);
+}
+
+void BKE_mesh_flush_hidden_from_polys_ex(MVert *mvert,
+ const MLoop *mloop,
+ MEdge *medge,
+ const int UNUSED(totedge),
+ const MPoly *mpoly,
+ const int totpoly)
+{
+ const MPoly *mp;
+ int i;
+
+ i = totpoly;
+ for (mp = mpoly; i--; mp++) {
+ if (mp->flag & ME_HIDE) {
+ const MLoop *ml;
+ int j;
+ j = mp->totloop;
+ for (ml = &mloop[mp->loopstart]; j--; ml++) {
+ mvert[ml->v].flag |= ME_HIDE;
+ medge[ml->e].flag |= ME_HIDE;
+ }
+ }
+ }
+
+ i = totpoly;
+ for (mp = mpoly; i--; mp++) {
+ if ((mp->flag & ME_HIDE) == 0) {
+ const MLoop *ml;
+ int j;
+ j = mp->totloop;
+ for (ml = &mloop[mp->loopstart]; j--; ml++) {
+ mvert[ml->v].flag &= (char)~ME_HIDE;
+ medge[ml->e].flag &= (short)~ME_HIDE;
+ }
+ }
+ }
}
void BKE_mesh_flush_hidden_from_polys(Mesh *me)
{
- BKE_mesh_flush_hidden_from_polys_ex(
- me->mvert, me->mloop,
- me->medge, me->totedge,
- me->mpoly, me->totpoly);
+ BKE_mesh_flush_hidden_from_polys_ex(
+ me->mvert, me->mloop, me->medge, me->totedge, me->mpoly, me->totpoly);
}
/**
* simple poly -> vert/edge selection.
*/
-void BKE_mesh_flush_select_from_polys_ex(
- MVert *mvert, const int totvert,
- const MLoop *mloop,
- MEdge *medge, const int totedge,
- const MPoly *mpoly, const int totpoly)
-{
- MVert *mv;
- MEdge *med;
- const MPoly *mp;
- int i;
-
- i = totvert;
- for (mv = mvert; i--; mv++) {
- mv->flag &= (char)~SELECT;
- }
-
- i = totedge;
- for (med = medge; i--; med++) {
- med->flag &= ~SELECT;
- }
-
- i = totpoly;
- for (mp = mpoly; i--; mp++) {
- /* assume if its selected its not hidden and none of its verts/edges are hidden
- * (a common assumption)*/
- if (mp->flag & ME_FACE_SEL) {
- const MLoop *ml;
- int j;
- j = mp->totloop;
- for (ml = &mloop[mp->loopstart]; j--; ml++) {
- mvert[ml->v].flag |= SELECT;
- medge[ml->e].flag |= SELECT;
- }
- }
- }
+void BKE_mesh_flush_select_from_polys_ex(MVert *mvert,
+ const int totvert,
+ const MLoop *mloop,
+ MEdge *medge,
+ const int totedge,
+ const MPoly *mpoly,
+ const int totpoly)
+{
+ MVert *mv;
+ MEdge *med;
+ const MPoly *mp;
+ int i;
+
+ i = totvert;
+ for (mv = mvert; i--; mv++) {
+ mv->flag &= (char)~SELECT;
+ }
+
+ i = totedge;
+ for (med = medge; i--; med++) {
+ med->flag &= ~SELECT;
+ }
+
+ i = totpoly;
+ for (mp = mpoly; i--; mp++) {
+ /* assume if its selected its not hidden and none of its verts/edges are hidden
+ * (a common assumption)*/
+ if (mp->flag & ME_FACE_SEL) {
+ const MLoop *ml;
+ int j;
+ j = mp->totloop;
+ for (ml = &mloop[mp->loopstart]; j--; ml++) {
+ mvert[ml->v].flag |= SELECT;
+ medge[ml->e].flag |= SELECT;
+ }
+ }
+ }
}
void BKE_mesh_flush_select_from_polys(Mesh *me)
{
- BKE_mesh_flush_select_from_polys_ex(
- me->mvert, me->totvert,
- me->mloop,
- me->medge, me->totedge,
- me->mpoly, me->totpoly);
-}
-
-void BKE_mesh_flush_select_from_verts_ex(
- const MVert *mvert, const int UNUSED(totvert),
- const MLoop *mloop,
- MEdge *medge, const int totedge,
- MPoly *mpoly, const int totpoly)
-{
- MEdge *med;
- MPoly *mp;
- int i;
-
- /* edges */
- i = totedge;
- for (med = medge; i--; med++) {
- if ((med->flag & ME_HIDE) == 0) {
- if ((mvert[med->v1].flag & SELECT) && (mvert[med->v2].flag & SELECT)) {
- med->flag |= SELECT;
- }
- else {
- med->flag &= ~SELECT;
- }
- }
- }
-
- /* polys */
- i = totpoly;
- for (mp = mpoly; i--; mp++) {
- if ((mp->flag & ME_HIDE) == 0) {
- bool ok = true;
- const MLoop *ml;
- int j;
- j = mp->totloop;
- for (ml = &mloop[mp->loopstart]; j--; ml++) {
- if ((mvert[ml->v].flag & SELECT) == 0) {
- ok = false;
- break;
- }
- }
-
- if (ok) {
- mp->flag |= ME_FACE_SEL;
- }
- else {
- mp->flag &= (char)~ME_FACE_SEL;
- }
- }
- }
+ BKE_mesh_flush_select_from_polys_ex(
+ me->mvert, me->totvert, me->mloop, me->medge, me->totedge, me->mpoly, me->totpoly);
+}
+
+void BKE_mesh_flush_select_from_verts_ex(const MVert *mvert,
+ const int UNUSED(totvert),
+ const MLoop *mloop,
+ MEdge *medge,
+ const int totedge,
+ MPoly *mpoly,
+ const int totpoly)
+{
+ MEdge *med;
+ MPoly *mp;
+ int i;
+
+ /* edges */
+ i = totedge;
+ for (med = medge; i--; med++) {
+ if ((med->flag & ME_HIDE) == 0) {
+ if ((mvert[med->v1].flag & SELECT) && (mvert[med->v2].flag & SELECT)) {
+ med->flag |= SELECT;
+ }
+ else {
+ med->flag &= ~SELECT;
+ }
+ }
+ }
+
+ /* polys */
+ i = totpoly;
+ for (mp = mpoly; i--; mp++) {
+ if ((mp->flag & ME_HIDE) == 0) {
+ bool ok = true;
+ const MLoop *ml;
+ int j;
+ j = mp->totloop;
+ for (ml = &mloop[mp->loopstart]; j--; ml++) {
+ if ((mvert[ml->v].flag & SELECT) == 0) {
+ ok = false;
+ break;
+ }
+ }
+
+ if (ok) {
+ mp->flag |= ME_FACE_SEL;
+ }
+ else {
+ mp->flag &= (char)~ME_FACE_SEL;
+ }
+ }
+ }
}
void BKE_mesh_flush_select_from_verts(Mesh *me)
{
- BKE_mesh_flush_select_from_verts_ex(
- me->mvert, me->totvert,
- me->mloop,
- me->medge, me->totedge,
- me->mpoly, me->totpoly);
+ BKE_mesh_flush_select_from_verts_ex(
+ me->mvert, me->totvert, me->mloop, me->medge, me->totedge, me->mpoly, me->totpoly);
}
/** \} */
@@ -3652,53 +3898,58 @@ void BKE_mesh_flush_select_from_verts(Mesh *me)
* \param vert_cos_org: reference for the output location.
* \param vert_cos_new: resulting coords.
*/
-void BKE_mesh_calc_relative_deform(
- const MPoly *mpoly, const int totpoly,
- const MLoop *mloop, const int totvert,
-
- const float (*vert_cos_src)[3],
- const float (*vert_cos_dst)[3],
-
- const float (*vert_cos_org)[3],
- float (*vert_cos_new)[3])
-{
- const MPoly *mp;
- int i;
-
- int *vert_accum = MEM_calloc_arrayN((size_t)totvert, sizeof(*vert_accum), __func__);
-
- memset(vert_cos_new, '\0', sizeof(*vert_cos_new) * (size_t)totvert);
-
- for (i = 0, mp = mpoly; i < totpoly; i++, mp++) {
- const MLoop *loopstart = mloop + mp->loopstart;
- int j;
-
- for (j = 0; j < mp->totloop; j++) {
- unsigned int v_prev = loopstart[(mp->totloop + (j - 1)) % mp->totloop].v;
- unsigned int v_curr = loopstart[j].v;
- unsigned int v_next = loopstart[(j + 1) % mp->totloop].v;
-
- float tvec[3];
-
- transform_point_by_tri_v3(
- tvec, vert_cos_dst[v_curr],
- vert_cos_org[v_prev], vert_cos_org[v_curr], vert_cos_org[v_next],
- vert_cos_src[v_prev], vert_cos_src[v_curr], vert_cos_src[v_next]);
-
- add_v3_v3(vert_cos_new[v_curr], tvec);
- vert_accum[v_curr] += 1;
- }
- }
-
- for (i = 0; i < totvert; i++) {
- if (vert_accum[i]) {
- mul_v3_fl(vert_cos_new[i], 1.0f / (float)vert_accum[i]);
- }
- else {
- copy_v3_v3(vert_cos_new[i], vert_cos_org[i]);
- }
- }
-
- MEM_freeN(vert_accum);
+void BKE_mesh_calc_relative_deform(const MPoly *mpoly,
+ const int totpoly,
+ const MLoop *mloop,
+ const int totvert,
+
+ const float (*vert_cos_src)[3],
+ const float (*vert_cos_dst)[3],
+
+ const float (*vert_cos_org)[3],
+ float (*vert_cos_new)[3])
+{
+ const MPoly *mp;
+ int i;
+
+ int *vert_accum = MEM_calloc_arrayN((size_t)totvert, sizeof(*vert_accum), __func__);
+
+ memset(vert_cos_new, '\0', sizeof(*vert_cos_new) * (size_t)totvert);
+
+ for (i = 0, mp = mpoly; i < totpoly; i++, mp++) {
+ const MLoop *loopstart = mloop + mp->loopstart;
+ int j;
+
+ for (j = 0; j < mp->totloop; j++) {
+ unsigned int v_prev = loopstart[(mp->totloop + (j - 1)) % mp->totloop].v;
+ unsigned int v_curr = loopstart[j].v;
+ unsigned int v_next = loopstart[(j + 1) % mp->totloop].v;
+
+ float tvec[3];
+
+ transform_point_by_tri_v3(tvec,
+ vert_cos_dst[v_curr],
+ vert_cos_org[v_prev],
+ vert_cos_org[v_curr],
+ vert_cos_org[v_next],
+ vert_cos_src[v_prev],
+ vert_cos_src[v_curr],
+ vert_cos_src[v_next]);
+
+ add_v3_v3(vert_cos_new[v_curr], tvec);
+ vert_accum[v_curr] += 1;
+ }
+ }
+
+ for (i = 0; i < totvert; i++) {
+ if (vert_accum[i]) {
+ mul_v3_fl(vert_cos_new[i], 1.0f / (float)vert_accum[i]);
+ }
+ else {
+ copy_v3_v3(vert_cos_new[i], vert_cos_org[i]);
+ }
+ }
+
+ MEM_freeN(vert_accum);
}
/** \} */