diff options
author | Bastien Montagne <montagne29@wanadoo.fr> | 2014-01-22 22:49:14 +0400 |
---|---|---|
committer | Bastien Montagne <montagne29@wanadoo.fr> | 2014-01-22 22:56:21 +0400 |
commit | 28ca299d4dfc392462efd598f14b825ba8bd21ea (patch) | |
tree | e4e114d007363d7d4ec4b8e0e0abbcfbda0466c6 /source/blender | |
parent | c2fbec7bf1e0ec07f96f3f65a28a5afc1a71595d (diff) |
Fix T38316: Half of a Face is Missing on Newly Created Cubes or Cylinders.
Own bug from rBc691551249f3. Now at least I understand why `test_index_face()` is needed for tessellated quads!
Added a bunch of comments to explain the issue, as it's far from an obvious one...
We loose some performances, but it's still much quicker than org code.
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/BKE_mesh.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/DerivedMesh.c | 14 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/mesh_evaluate.c | 63 |
3 files changed, 45 insertions, 34 deletions
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 47fd7dab2e5..7b1f39ab643 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -216,7 +216,7 @@ void BKE_mesh_loops_to_mface_corners( 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, + struct CustomData *fdata, struct CustomData *ldata, struct CustomData *pdata, struct MFace *mface, int *polyindices, unsigned int (*loopindices)[4], const int num_faces); int BKE_mesh_recalc_tessellation( struct CustomData *fdata, struct CustomData *ldata, struct CustomData *pdata, diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index c1424381ce6..49147db3323 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -424,7 +424,7 @@ void DM_ensure_tessface(DerivedMesh *dm) /* NOTE: Assumes dm has valid tessellated data! */ void DM_update_tessface_data(DerivedMesh *dm) { - MFace *mf = dm->getTessFaceArray(dm); + MFace *mf, *mface = dm->getTessFaceArray(dm); MPoly *mp = dm->getPolyArray(dm); MLoop *ml = dm->getLoopArray(dm); @@ -451,7 +451,7 @@ void DM_update_tessface_data(DerivedMesh *dm) { loopindex = MEM_mallocN(sizeof(*loopindex) * totface, __func__); - for (mf_idx = 0; mf_idx < totface; mf_idx++, mf++) { + for (mf_idx = 0, mf = mface; 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; @@ -465,12 +465,14 @@ void DM_update_tessface_data(DerivedMesh *dm) not_done--; } } - if (mf_len == 3) { - ml_idx[3] = 0; - } } - BKE_mesh_loops_to_tessdata(fdata, ldata, pdata, polyindex, loopindex, totface); + /* NOTE: quad detection issue - forth vertidx vs forth loopidx: + * Here, our tfaces' forth vertex index is never 0 for a quad. However, we know our forth loop index may be + * 0 for quads (because our quads may have been rotated compared to their org poly, see tessellation code). + * So we pass the MFace's, and BKE_mesh_loops_to_tessdata will use MFace->v4 index as quad test. + */ + BKE_mesh_loops_to_tessdata(fdata, ldata, pdata, mface, polyindex, loopindex, totface); MEM_freeN(loopindex); } diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index 320714b9eb3..797d4b42f79 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -1156,11 +1156,18 @@ 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. + * + * 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, CustomData *pdata, +void BKE_mesh_loops_to_tessdata(CustomData *fdata, CustomData *ldata, CustomData *pdata, 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 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); @@ -1180,7 +1187,7 @@ void BKE_mesh_loops_to_tessdata(CustomData *fdata, CustomData *ldata, CustomData { ME_MTEXFACE_CPY(texface, &texpoly[*pidx]); - for (j = (*lidx)[3] ? 4 : 3; j--;) { + for (j = (mface ? mface[findex].v4 : (*lidx[3])) ? 4 : 3; j--;) { copy_v2_v2(texface->uv[j], mloopuv[(*lidx)[j]].uv); } } @@ -1191,7 +1198,7 @@ void BKE_mesh_loops_to_tessdata(CustomData *fdata, CustomData *ldata, CustomData 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--;) { + for (j = (mface ? mface[findex].v4 : (*lidx[3])) ? 4 : 3; j--;) { MESH_MLOOPCOL_TO_MCOL(&mloopcol[(*lidx)[j]], &(*mcol)[j]); } } @@ -1202,7 +1209,7 @@ void BKE_mesh_loops_to_tessdata(CustomData *fdata, CustomData *ldata, CustomData 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--;) { + for (j = (mface ? mface[findex].v4 : (*lidx[3])) ? 4 : 3; j--;) { MESH_MLOOPCOL_TO_MCOL(&mloopcol[(*lidx)[j]], &(*mcol)[j]); } } @@ -1213,7 +1220,7 @@ void BKE_mesh_loops_to_tessdata(CustomData *fdata, CustomData *ldata, CustomData 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--;) { + for (j = (mface ? mface[findex].v4 : (*lidx[3])) ? 4 : 3; j--;) { copy_v2_v2(of->uv[j], lof[(*lidx)[j]].uv); } } @@ -1223,28 +1230,21 @@ void BKE_mesh_loops_to_tessdata(CustomData *fdata, CustomData *ldata, CustomData /** * Recreate tessellation. * - * use_poly_origindex sets whether or not the tessellation faces' origindex - * layer should point to original poly indices or real poly indices. - * - * use_face_origindex sets the tessellation faces' origindex layer - * to point to the tessellation faces themselves, not the polys. - * - * if both of the above are 0, it'll use the indices of the mpolys of the MPoly - * data in pdata, and ignore the origindex layer altogether. + * @do_face_nor_copy controls whether the normals from the poly are copied to the tessellated faces. * * \return number of tessellation faces. */ 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) + MVert *mvert, int totface, int totloop, int totpoly, const bool do_face_nor_cpy) { /* 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 looptris_tot = poly_to_tri_count(totpoly, totloop); @@ -1298,6 +1298,7 @@ int BKE_mesh_recalc_tessellation(CustomData *fdata, CustomData *ldata, CustomDat 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) */ @@ -1320,6 +1321,7 @@ int BKE_mesh_recalc_tessellation(CustomData *fdata, CustomData *ldata, CustomDat lidx[3] = l4; \ mf->mat_nr = mp->mat_nr; \ mf->flag = mp->flag; \ + mf->edcode = TESSFACE_IS_QUAD; \ (void)0 @@ -1411,6 +1413,7 @@ int BKE_mesh_recalc_tessellation(CustomData *fdata, CustomData *ldata, CustomDat mf->mat_nr = mp->mat_nr; mf->flag = mp->flag; + mf->edcode = 0; mface_index++; } @@ -1454,22 +1457,28 @@ int BKE_mesh_recalc_tessellation(CustomData *fdata, CustomData *ldata, CustomDat } } - BKE_mesh_loops_to_tessdata(fdata, ldata, pdata, mface_to_poly_map, lindices, totface); + /* NOTE: quad detection issue - forth vertidx vs forth loopidx: + * Polygons take care of their loops ordering, hence not of their vertices ordering. + * Currently, our tfaces' forth vertex index might be 0 even for a quad. However, we know our forth 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 forth loop index as quad test. + * ... + */ + BKE_mesh_loops_to_tessdata(fdata, ldata, pdata, NULL, 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? + /* NOTE: quad detection issue - forth vertidx vs forth 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. */ -#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; - - if (test_index_face(mf, fdata, mface_index, mf_len) != mf_len) - printf("%s: test_index_face had to make changes!!!\n", __func__); + if (mf->edcode == TESSFACE_IS_QUAD) { + test_index_face(mf, fdata, mface_index, 4); + mf->edcode = 0; + } } #endif -#endif MEM_freeN(lindices); |