Optimize tessellation code (min 20% better, up to 300% with some CD layers to tessellate).
The main idea is to store (during tessellation) or recreate (during tessdata update) a tessfaceverts-to-loops mapping, and then update all tessdata in one pass, instead of calling `BKE_mesh_loops_to_mface_corners` repeatedly for all tfaces! Differential Revision: https://developer.blender.org/D226 Reviewed by Campbell, thanks a lot!
This commit is contained in:
parent
cda894fcfd
commit
c691551249
Notes:
blender-bot
2023-02-14 10:04:50 +01:00
Referenced by commit 28ca299d4d
, Fix T38316: Half of a Face is Missing on Newly Created Cubes or Cylinders.
|
@ -215,6 +215,9 @@ void BKE_mesh_loops_to_mface_corners(
|
|||
const int polyindex, const int mf_len,
|
||||
const int numTex, const int numCol,
|
||||
const bool hasPCol, const bool hasOrigSpace);
|
||||
void BKE_mesh_loops_to_tessdata(
|
||||
struct CustomData *fdata, struct CustomData *ldata, struct CustomData *pdata,
|
||||
int *polyindices, unsigned int (*loopindices)[4], const int num_faces);
|
||||
int BKE_mesh_recalc_tessellation(
|
||||
struct CustomData *fdata, struct CustomData *ldata, struct CustomData *pdata,
|
||||
struct MVert *mvert,
|
||||
|
|
|
@ -129,4 +129,13 @@ int *BKE_mesh_calc_smoothgroups(
|
|||
const struct MLoop *mloop, const int totloop,
|
||||
int *r_totgroup, const bool use_bitflags);
|
||||
|
||||
/* No good (portable) way to have exported inlined functions... */
|
||||
#define BKE_MESH_TESSFACE_VINDEX_ORDER(_mf, _v) ( \
|
||||
(CHECK_TYPE_INLINE(_mf, MFace *), CHECK_TYPE_INLINE(_v, unsigned int)), \
|
||||
((_mf->v1 == _v) ? 0 : \
|
||||
(_mf->v2 == _v) ? 1 : \
|
||||
(_mf->v3 == _v) ? 2 : \
|
||||
(_mf->v4 && _mf->v4 == _v) ? 3 : -1) \
|
||||
)
|
||||
|
||||
#endif /* __BKE_MESH_MAPPING_H__ */
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
#include "BKE_key.h"
|
||||
#include "BKE_modifier.h"
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_mesh_mapping.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_object_deform.h"
|
||||
#include "BKE_paint.h"
|
||||
|
@ -431,16 +432,11 @@ void DM_update_tessface_data(DerivedMesh *dm)
|
|||
CustomData *pdata = dm->getPolyDataLayout(dm);
|
||||
CustomData *ldata = dm->getLoopDataLayout(dm);
|
||||
|
||||
const int numTex = CustomData_number_of_layers(pdata, CD_MTEXPOLY);
|
||||
const int numCol = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
|
||||
const int hasPCol = CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL);
|
||||
const int hasOrigSpace = CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP);
|
||||
|
||||
int *polyindex = CustomData_get_layer(fdata, CD_ORIGINDEX);
|
||||
|
||||
const int totface = dm->getNumTessFaces(dm);
|
||||
int mf_idx;
|
||||
int ml_idx[4];
|
||||
|
||||
int *polyindex = CustomData_get_layer(fdata, CD_ORIGINDEX);
|
||||
unsigned int (*loopindex)[4];
|
||||
|
||||
/* Should never occure, but better abort than segfault! */
|
||||
if (!polyindex)
|
||||
|
@ -448,36 +444,35 @@ void DM_update_tessface_data(DerivedMesh *dm)
|
|||
|
||||
CustomData_from_bmeshpoly(fdata, pdata, ldata, totface);
|
||||
|
||||
for (mf_idx = 0; mf_idx < totface; mf_idx++, mf++) {
|
||||
const int mf_len = mf->v4 ? 4 : 3;
|
||||
int i, not_done;
|
||||
if (CustomData_has_layer(fdata, CD_MTFACE) ||
|
||||
CustomData_has_layer(fdata, CD_MCOL) ||
|
||||
CustomData_has_layer(fdata, CD_PREVIEW_MCOL) ||
|
||||
CustomData_has_layer(fdata, CD_ORIGSPACE))
|
||||
{
|
||||
loopindex = MEM_mallocN(sizeof(*loopindex) * totface, __func__);
|
||||
|
||||
/* Find out loop indices. */
|
||||
/* XXX Is there a better way to do this? */
|
||||
/* NOTE: This assumes tessface are valid and in sync with loop/poly... Else, most likely, segfault! */
|
||||
for (i = mp[polyindex[mf_idx]].loopstart, not_done = mf_len; not_done; i++) {
|
||||
MLoop *tml = &ml[i];
|
||||
if (tml->v == mf->v1) {
|
||||
ml_idx[0] = i;
|
||||
not_done--;
|
||||
for (mf_idx = 0; mf_idx < totface; mf_idx++, mf++) {
|
||||
const int mf_len = mf->v4 ? 4 : 3;
|
||||
unsigned int *ml_idx = loopindex[mf_idx];
|
||||
int i, not_done;
|
||||
|
||||
/* Find out loop indices. */
|
||||
/* NOTE: This assumes tessface are valid and in sync with loop/poly... Else, most likely, segfault! */
|
||||
for (i = mp[polyindex[mf_idx]].loopstart, not_done = mf_len; not_done; i++) {
|
||||
const int tf_v = BKE_MESH_TESSFACE_VINDEX_ORDER(mf, ml[i].v);
|
||||
if (tf_v != -1) {
|
||||
ml_idx[tf_v] = i;
|
||||
not_done--;
|
||||
}
|
||||
}
|
||||
else if (tml->v == mf->v2) {
|
||||
ml_idx[1] = i;
|
||||
not_done--;
|
||||
}
|
||||
else if (tml->v == mf->v3) {
|
||||
ml_idx[2] = i;
|
||||
not_done--;
|
||||
}
|
||||
else if (mf_len == 4 && tml->v == mf->v4) {
|
||||
ml_idx[3] = i;
|
||||
not_done--;
|
||||
if (mf_len == 3) {
|
||||
ml_idx[3] = 0;
|
||||
}
|
||||
}
|
||||
BKE_mesh_loops_to_mface_corners(fdata, ldata, pdata,
|
||||
ml_idx, mf_idx, polyindex[mf_idx],
|
||||
mf_len,
|
||||
numTex, numCol, hasPCol, hasOrigSpace);
|
||||
|
||||
BKE_mesh_loops_to_tessdata(fdata, ldata, pdata, polyindex, loopindex, totface);
|
||||
|
||||
MEM_freeN(loopindex);
|
||||
}
|
||||
|
||||
if (G.debug & G_DEBUG)
|
||||
|
|
|
@ -1154,6 +1154,72 @@ void BKE_mesh_loops_to_mface_corners(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert all CD layers from loop/poly to tessface data.
|
||||
* @loopindices is an array of an int[4] per tessface, mapping tessface's verts to loops indices.
|
||||
*/
|
||||
void BKE_mesh_loops_to_tessdata(CustomData *fdata, CustomData *ldata, CustomData *pdata,
|
||||
int *polyindices, unsigned int (*loopindices)[4], const int num_faces)
|
||||
{
|
||||
const int numTex = CustomData_number_of_layers(pdata, CD_MTEXPOLY);
|
||||
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);
|
||||
int findex, i, j;
|
||||
int *pidx;
|
||||
unsigned int (*lidx)[4];
|
||||
|
||||
for (i = 0; i < numTex; i++) {
|
||||
MTFace *texface = CustomData_get_layer_n(fdata, CD_MTFACE, i);
|
||||
MTexPoly *texpoly = CustomData_get_layer_n(pdata, CD_MTEXPOLY, 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++)
|
||||
{
|
||||
ME_MTEXFACE_CPY(texface, &texpoly[*pidx]);
|
||||
|
||||
for (j = (*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 = (*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 = (*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 = (*lidx)[3] ? 4 : 3; j--;) {
|
||||
copy_v2_v2(of->uv[j], lof[(*lidx)[j]].uv);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recreate tessellation.
|
||||
*
|
||||
|
@ -1168,10 +1234,8 @@ void BKE_mesh_loops_to_mface_corners(
|
|||
*
|
||||
* \return number of tessellation faces.
|
||||
*/
|
||||
int BKE_mesh_recalc_tessellation(CustomData *fdata,
|
||||
CustomData *ldata, CustomData *pdata,
|
||||
MVert *mvert, int totface, int totloop,
|
||||
int totpoly,
|
||||
int BKE_mesh_recalc_tessellation(CustomData *fdata, CustomData *ldata, CustomData *pdata,
|
||||
MVert *mvert, int totface, int totloop, int totpoly,
|
||||
/* when tessellating to recalculate normals after
|
||||
* we can skip copying here */
|
||||
const bool do_face_nor_cpy)
|
||||
|
@ -1182,9 +1246,6 @@ int BKE_mesh_recalc_tessellation(CustomData *fdata,
|
|||
#define USE_TESSFACE_SPEEDUP
|
||||
#define USE_TESSFACE_QUADS // NEEDS FURTHER TESTING
|
||||
|
||||
#define TESSFACE_SCANFILL (1 << 0)
|
||||
#define TESSFACE_IS_QUAD (1 << 1)
|
||||
|
||||
const int looptris_tot = poly_to_tri_count(totpoly, totloop);
|
||||
|
||||
MPoly *mp, *mpoly;
|
||||
|
@ -1192,13 +1253,9 @@ int BKE_mesh_recalc_tessellation(CustomData *fdata,
|
|||
MFace *mface, *mf;
|
||||
MemArena *arena = NULL;
|
||||
int *mface_to_poly_map;
|
||||
int lindex[4]; /* only ever use 3 in this case */
|
||||
int poly_index, j, mface_index;
|
||||
|
||||
const int numTex = CustomData_number_of_layers(pdata, CD_MTEXPOLY);
|
||||
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);
|
||||
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);
|
||||
|
@ -1208,12 +1265,16 @@ int BKE_mesh_recalc_tessellation(CustomData *fdata,
|
|||
/* take care. we are _not_ calloc'ing so be sure to initialize each field */
|
||||
mface_to_poly_map = MEM_mallocN(sizeof(*mface_to_poly_map) * (size_t)looptris_tot, __func__);
|
||||
mface = MEM_mallocN(sizeof(*mface) * (size_t)looptris_tot, __func__);
|
||||
lindices = MEM_mallocN(sizeof(*lindices) * (size_t)looptris_tot, __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;
|
||||
if (mp->totloop < 3) {
|
||||
const unsigned int mp_totloop = (unsigned int)mp->totloop;
|
||||
unsigned int l1, l2, l3, l4;
|
||||
unsigned int *lidx;
|
||||
if (mp_totloop < 3) {
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
|
@ -1222,36 +1283,51 @@ int BKE_mesh_recalc_tessellation(CustomData *fdata,
|
|||
#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 */ \
|
||||
mf->v1 = mp_loopstart + i1; \
|
||||
mf->v2 = mp_loopstart + i2; \
|
||||
mf->v3 = mp_loopstart + i3; \
|
||||
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 */ \
|
||||
mf->v1 = mp_loopstart + 0; /* EXCEPTION */ \
|
||||
mf->v2 = mp_loopstart + 1; /* EXCEPTION */ \
|
||||
mf->v3 = mp_loopstart + 2; /* EXCEPTION */ \
|
||||
mf->v4 = mp_loopstart + 3; /* EXCEPTION */ \
|
||||
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; /* EXCEPTION */ \
|
||||
(void)0
|
||||
|
||||
|
||||
else if (mp->totloop == 3) {
|
||||
else if (mp_totloop == 3) {
|
||||
ML_TO_MF(0, 1, 2);
|
||||
mface_index++;
|
||||
}
|
||||
else if (mp->totloop == 4) {
|
||||
else if (mp_totloop == 4) {
|
||||
#ifdef USE_TESSFACE_QUADS
|
||||
ML_TO_MF_QUAD();
|
||||
mface_index++;
|
||||
|
@ -1272,22 +1348,21 @@ int BKE_mesh_recalc_tessellation(CustomData *fdata,
|
|||
float (*projverts)[2];
|
||||
unsigned int (*tris)[3];
|
||||
|
||||
const unsigned int loopstart = (unsigned int)mp->loopstart;
|
||||
const 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__);
|
||||
}
|
||||
|
||||
tris = BLI_memarena_alloc(arena, sizeof(*tris) * (size_t)totfilltri);
|
||||
projverts = BLI_memarena_alloc(arena, sizeof(*projverts) * (size_t)mp->totloop);
|
||||
projverts = BLI_memarena_alloc(arena, sizeof(*projverts) * (size_t)mp_totloop);
|
||||
|
||||
zero_v3(normal);
|
||||
|
||||
/* calc normal */
|
||||
ml = mloop + loopstart;
|
||||
co_prev = mvert[ml[mp->totloop - 1].v].co;
|
||||
for (j = 0; j < mp->totloop; j++, ml++) {
|
||||
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;
|
||||
|
@ -1299,34 +1374,44 @@ int BKE_mesh_recalc_tessellation(CustomData *fdata,
|
|||
/* project verts to 2d */
|
||||
axis_dominant_v3_to_m3(axis_mat, normal);
|
||||
|
||||
ml = mloop + loopstart;
|
||||
for (j = 0; j < mp->totloop; j++, ml++) {
|
||||
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((const float (*)[2])projverts, (unsigned int)mp->totloop, tris, arena);
|
||||
BLI_polyfill_calc_arena((const float (*)[2])projverts, mp_totloop, tris, arena);
|
||||
|
||||
/* apply fill */
|
||||
ml = mloop + loopstart;
|
||||
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 */
|
||||
mf->v1 = loopstart + tri[0];
|
||||
mf->v2 = loopstart + tri[1];
|
||||
mf->v3 = loopstart + tri[2];
|
||||
l1 = mp_loopstart + tri[0];
|
||||
l2 = mp_loopstart + tri[1];
|
||||
l3 = mp_loopstart + tri[2];
|
||||
|
||||
/* sort loop indices to ensure winding is correct */
|
||||
if (l1 > l2) SWAP(unsigned int, l1, l2);
|
||||
if (l2 > l3) SWAP(unsigned int, l2, l3);
|
||||
if (l1 > l2) SWAP(unsigned int, l1, l2);
|
||||
|
||||
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;
|
||||
|
||||
#ifdef USE_TESSFACE_SPEEDUP
|
||||
mf->edcode = TESSFACE_SCANFILL; /* tag for sorting loop indices */
|
||||
#endif
|
||||
|
||||
mface_index++;
|
||||
}
|
||||
|
||||
|
@ -1369,72 +1454,35 @@ int BKE_mesh_recalc_tessellation(CustomData *fdata,
|
|||
}
|
||||
}
|
||||
|
||||
BKE_mesh_loops_to_tessdata(fdata, ldata, pdata, mface_to_poly_map, lindices, totface);
|
||||
|
||||
/* XXX Is it really needed to call test_index_face here??? Since we reuse tris/quads as-is, and sort tris generated
|
||||
* by scanfill, our indices should always be OK?
|
||||
*/
|
||||
#if 0
|
||||
#ifdef USE_TESSFACE_QUADS
|
||||
mf = mface;
|
||||
for (mface_index = 0; mface_index < totface; mface_index++, mf++) {
|
||||
const int mf_len = mf->v4 ? 4 : 3;
|
||||
|
||||
#ifdef USE_TESSFACE_QUADS
|
||||
const int mf_len = mf->edcode & TESSFACE_IS_QUAD ? 4 : 3;
|
||||
#endif
|
||||
|
||||
#ifdef USE_TESSFACE_SPEEDUP
|
||||
/* skip sorting when not using ngons */
|
||||
if (UNLIKELY(mf->edcode & TESSFACE_SCANFILL))
|
||||
#endif
|
||||
{
|
||||
/* sort loop indices to ensure winding is correct */
|
||||
if (mf->v1 > mf->v2) SWAP(unsigned int, mf->v1, mf->v2);
|
||||
if (mf->v2 > mf->v3) SWAP(unsigned int, mf->v2, mf->v3);
|
||||
if (mf->v1 > mf->v2) SWAP(unsigned int, mf->v1, mf->v2);
|
||||
|
||||
if (mf->v1 > mf->v2) SWAP(unsigned int, mf->v1, mf->v2);
|
||||
if (mf->v2 > mf->v3) SWAP(unsigned int, mf->v2, mf->v3);
|
||||
if (mf->v1 > mf->v2) SWAP(unsigned int, mf->v1, mf->v2);
|
||||
}
|
||||
|
||||
/* end abusing the edcode */
|
||||
#if defined(USE_TESSFACE_QUADS) || defined(USE_TESSFACE_SPEEDUP)
|
||||
mf->edcode = 0;
|
||||
#endif
|
||||
|
||||
|
||||
lindex[0] = (int)mf->v1;
|
||||
lindex[1] = (int)mf->v2;
|
||||
lindex[2] = (int)mf->v3;
|
||||
#ifdef USE_TESSFACE_QUADS
|
||||
if (mf_len == 4) lindex[3] = (int)mf->v4;
|
||||
#endif
|
||||
|
||||
/*transform loop indices to vert indices*/
|
||||
mf->v1 = mloop[mf->v1].v;
|
||||
mf->v2 = mloop[mf->v2].v;
|
||||
mf->v3 = mloop[mf->v3].v;
|
||||
#ifdef USE_TESSFACE_QUADS
|
||||
if (mf_len == 4) mf->v4 = mloop[mf->v4].v;
|
||||
#endif
|
||||
|
||||
BKE_mesh_loops_to_mface_corners(fdata, ldata, pdata,
|
||||
lindex, mface_index, mface_to_poly_map[mface_index],
|
||||
#ifdef USE_TESSFACE_QUADS
|
||||
mf_len,
|
||||
#else
|
||||
3,
|
||||
#endif
|
||||
numTex, numCol, hasPCol, hasOrigSpace);
|
||||
|
||||
|
||||
#ifdef USE_TESSFACE_QUADS
|
||||
test_index_face(mf, fdata, mface_index, mf_len);
|
||||
#endif
|
||||
|
||||
if (test_index_face(mf, fdata, mface_index, mf_len) != mf_len)
|
||||
printf("%s: test_index_face had to make changes!!!\n", __func__);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
MEM_freeN(lindices);
|
||||
|
||||
return totface;
|
||||
|
||||
#undef USE_TESSFACE_SPEEDUP
|
||||
#undef USE_TESSFACE_QUADS
|
||||
|
||||
#undef ML_TO_MF
|
||||
#undef ML_TO_MF_QUAD
|
||||
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_BMESH_SAVE_AS_COMPAT
|
||||
|
||||
/**
|
||||
|
|
|
@ -2847,15 +2847,6 @@ static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const fl
|
|||
return 1;
|
||||
}
|
||||
|
||||
BLI_INLINE int mesh_tessface_vertex_index(MFace *tessface, unsigned int v)
|
||||
{
|
||||
if (tessface->v1 == v) return 0;
|
||||
if (tessface->v2 == v) return 1;
|
||||
if (tessface->v3 == v) return 2;
|
||||
if (v && (tessface->v4 == v)) return 3;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void vpaint_paint_poly(VPaint *vp, VPaintData *vpd, Mesh *me,
|
||||
const unsigned int index, const float mval[2],
|
||||
const float brush_size_pressure, const float brush_alpha_pressure)
|
||||
|
@ -2945,7 +2936,7 @@ static void vpaint_paint_poly(VPaint *vp, VPaintData *vpd, Mesh *me,
|
|||
|
||||
for (j = 0; j < totloop; j++, ml++, mlc++) {
|
||||
/* search for the loop vertex within the tessface */
|
||||
const int fidx = mesh_tessface_vertex_index(mf, ml->v);
|
||||
const int fidx = BKE_MESH_TESSFACE_VINDEX_ORDER(mf, ml->v);
|
||||
if (fidx != -1) {
|
||||
MESH_MLOOPCOL_TO_MCOL(mlc, mc + fidx);
|
||||
if (mlooptag) {
|
||||
|
|
Loading…
Reference in New Issue