Revision: 58825 http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=58825 Author: walid Date: 2013-08-02 10:07:15 +0000 (Fri, 02 Aug 2013) Log Message: ----------- UV transfer through faces: fully implementing the uv transfer
Modified Paths: -------------- branches/soc-2013-meshdata_transfer/source/blender/bmesh/tools/bmesh_data_transfer.c branches/soc-2013-meshdata_transfer/source/blender/bmesh/tools/bmesh_data_transfer.h Modified: branches/soc-2013-meshdata_transfer/source/blender/bmesh/tools/bmesh_data_transfer.c =================================================================== --- branches/soc-2013-meshdata_transfer/source/blender/bmesh/tools/bmesh_data_transfer.c 2013-08-02 09:40:42 UTC (rev 58824) +++ branches/soc-2013-meshdata_transfer/source/blender/bmesh/tools/bmesh_data_transfer.c 2013-08-02 10:07:15 UTC (rev 58825) @@ -1094,6 +1094,16 @@ return true; } +void mid_poly_v2(float r[2], float v[][2], const int n) +{ + int i; + + for (i = 0; i < n; i++) { + r[0] += v[i][0] * (1.0f/n); + r[1] += v[i][1] * (1.0f/n); + } +} + void mid_poly_v3(float r[3], float v[][3], const int n) { int i; @@ -1262,6 +1272,71 @@ int len; } BM_UV_per_face_mapping; +typedef struct BM_loop_pool { + struct BMLoop **l; + int count; +} BM_loop_pool; + +bool BM_loop_in_loops(BMLoop **l_grp, int len, BMLoop *l) +{ + int i; + + for (i = 0; i < len; i++) { + if (l == l_grp[i]) { + return true; + } + } + + return false; +} + +//consistency is based on uv coords of a given customdata offset +bool BM_edge_has_consistant_loops(BMEdge *e, int CD_offset) { + BMFace *f_first; + + //get the 2 loops corresponding to v1 in a face + BMVert *v1; + BMVert *v2; + + BMLoop *l1_first; + BMLoop *l2_first; + + BMFace *f; + BMLoop *l1, *l2; + + BMLoop *l_iter; + + if (e->l == e->l->radial_next) { // if only one face exists then the loops are surely consistant with themselves + return true; + } + + f_first = e->l->f; + v1 = e->v1; + v2 = e->v2; + + l1_first = BM_face_vert_share_loop(f_first, v1); + l2_first = BM_face_vert_share_loop(f_first, v2); + + //we won't use BM_ITER_ELEM to avoid comparing the first face to itself which will grind the speed to the half + //in most cases (having an edge connecting 2 face) + l_iter = e->l->radial_next; + do { + f = l_iter->f; + + l1 = BM_face_vert_share_loop(f, v1); + l2 = BM_face_vert_share_loop(f, v2); + //if both the loops weren't consistant return false! + if (!(equals_v2v2(BM_ELEM_CD_GET_VOID_P(l1, CD_offset), BM_ELEM_CD_GET_VOID_P(l1_first, CD_offset)) && + equals_v2v2(BM_ELEM_CD_GET_VOID_P(l2, CD_offset), BM_ELEM_CD_GET_VOID_P(l2_first, CD_offset)))) { + return false; + } + + l_iter = l_iter->radial_next; + } while (l_iter != e->l); + + return true; +} + bool BM_mesh_uv_copy2(BMesh *bm_src, BMesh *bm_dst, float UNUSED(tolerance), float UNUSED(radius_interp), int UNUSED(dist_pow), int UNUSED(no_pow), bool UNUSED(USE_NORMALS), ST_ShapekeyGroupMode replace_mode, int *act_shapekey_lay, float tmp_mat[4][4]) @@ -1287,7 +1362,7 @@ int v_src_count; int v_dst_count; - int a, b, c, d, g; + int a, b, c, d, g, h, i; //====algorithm definitions end int CD_src, CD_dst; @@ -1317,7 +1392,11 @@ BMEdge *e; BMIter eiter; BM_UV_per_face_mapping *fuv_table = MEM_mallocN(sizeof(*fuv_table) * bm_dst->totface, "fuv_table bmesh_data_transfer.c"); - BMLoop *l_iter; + BM_loop_pool *l_grp = MEM_mallocN(sizeof(*l_grp) * bm_dst->totloop, "l_grp bmesh_data_transfer.c"); + int l_grp_count; + float (*uv_buffer)[2]; + int uv_buffer_alloc_size; + float mid_uv[2]; //======end of loops connnecting definitions /* @@ -1529,8 +1608,8 @@ CD_src = CustomData_get_n_offset(&bm_src->ldata, CD_MLOOPUV, src_lay_iter); //get the offset of the CD_dst = CustomData_get_n_offset(&bm_dst->ldata, CD_MLOOPUV, dst_lay_iter); //lay_iter(th)CD_SHAPEKEY layer + l_grp_count = 0; //the way we do it is by looping over each face!! - BM_ITER_MESH (f_dst, &fiter, bm_dst, BM_FACES_OF_MESH) { //get a coordinate list of the f_dst verts @@ -1610,11 +1689,12 @@ //within it search for the neighboring faces BM_ITER_ELEM (e, &eiter, f_src, BM_EDGES_OF_FACE) { + if (BM_edge_face_pair (e, &fa, &fb) == true) { f_n = (fa->head.index == f_src->head.index) ? fb: fa; //if any of them was found in our src tables - if (fl_table[f_n->head.index].f != NULL) { ///we're missing a check ... connected face + if ((fl_table[f_n->head.index].f != NULL) && (BM_edge_has_consistant_loops(e, CD_dst))) { //search within the mapped -to the src face- loops in fl_table //for the loops that share the same vertex between f_src and f_n @@ -1626,39 +1706,53 @@ fl_table[f_n->head.index].l[g]->v->head.index) { //we finally found loops that shall be averaged from different faces! //we now shall average them into a buffer! - //currently we've a buffer that's the same size as as the dst faces + //we've got 2 loops ... search for them in the loop groups ... if found + //add a new entry to l_grp and eincrement l_grp_count + //else append the other loop + for (h = 0; h < l_grp_count; h++) { + if (BM_loop_in_loops(l_grp[h].l,l_grp[h].count, fl_table[f_n->head.index].l[g])) { + //found the neighboring face's loop in the group + if (!BM_loop_in_loops(l_grp[h].l,l_grp[h].count, fl_table[f_src->head.index].l[d])) { + //we ensured its the first time for this loop, not to add loops twice when we search from + //the neighboring face - //we got the loops .. we need to use the buffer now ... which doesn't see loops - //but rather their indices per their faces' indices + (l_grp[h].count)++; - l = fuv_table[fl_table[f_src->head.index].l[d]->f->head.index].f->l_first; - l_iter = l; - b = -1; - do { - b++; - l_iter = l_iter->next; - ///the first check should always be reached after/atm of the second!! - } while (l_iter != l && (l_iter != fl_table[f_src->head.index].l[d])); + l_grp[h].l = MEM_reallocN(l_grp[h].l, sizeof(*(l_grp->l)) * (l_grp[h].count)); + //and append it + l_grp[h].l[l_grp[h].count - 1] = fl_table[f_n->head.index].l[g]; - l = fuv_table[fl_table[f_n->head.index].l[g]->f->head.index].f->l_first; - l_iter = l; - a = -1; - do { - a++; - l_iter = l_iter->next; - ///the first check should always be reached after/atm of the second!! - } while (l_iter != l && (l_iter != fl_table[f_n->head.index].l[g])); + } - ///this interpolation will be dependent on the order of accessed faces - ///that could be eliminated by getting the average while copying (which will need - ///from us keeping track of each loop's number of assigned vertices) - mid_v2_v2v2(fuv_table[fl_table[f_src->head.index].l[d]->f->head.index].uv[b], - fuv_table[fl_table[f_src->head.index].l[d]->f->head.index].uv[b], - fuv_table[fl_table[f_n->head.index].l[g]->f->head.index].uv[a]); + break; + } - copy_v2_v2(fuv_table[fl_table[f_n->head.index].l[g]->f->head.index].uv[a], - fuv_table[fl_table[f_src->head.index].l[d]->f->head.index].uv[b]); + else if (BM_loop_in_loops(l_grp[h].l,l_grp[h].count, fl_table[f_src->head.index].l[d])) { + //found the source face's loop in the group + if (!BM_loop_in_loops(l_grp[h].l,l_grp[h].count, fl_table[f_n->head.index].l[g])) { + //now reallocate memory for a new loop + (l_grp[h].count)++; + + l_grp[h].l = MEM_reallocN(l_grp[h].l, sizeof(*(l_grp->l)) * (l_grp[h].count)); + //and append it + l_grp[h].l[l_grp[h].count - 1] = fl_table[f_n->head.index].l[g]; + } + + break; + } + } + + if ( h == l_grp_count) { + //the loops weren't found in any group + //make a new group entry and append it + l_grp[l_grp_count].count = 2; + //adding a place for 2 loops + l_grp[l_grp_count].l = MEM_mallocN(sizeof(*(l_grp->l)) * 2, "l_grp[].l bmesh_data_transfer"); + l_grp[l_grp_count].l[0] = fl_table[f_src->head.index].l[d]; + l_grp[l_grp_count].l[1] = fl_table[f_n->head.index].l[g]; + l_grp_count++; + } } } } @@ -1666,29 +1760,47 @@ } else { - //we've got an edge with no 2 faces + //we've got an edge with no 2 faces (either more or less) continue; } //we still need to generalize for manifolds! (the previous check would treat both tthe manifolds/single //face edge the same case - } + //currently we've passed by all the edges surrounding a source face + } - } ///we need an optimized way for having a buffer, a way that optimizes for the speed, memory and less complicated + ///currently we use the l_grp which optimizes mainly for the speed of access ... + ///its problem is nested reallocation + //get the mid of UVs into a buffer //get the UV coords after looping over the src faces!! - BM_ITER_MESH (f_dst, &fiter, bm_dst, BM_FACES_OF_MESH) { - BM_ITER_ELEM_INDEX (l, &liter, f_dst, BM_LOOPS_OF_FACE, b) { - //assuming: the looping over the face's loop is in the same order as in the prevloops of dst_f iteration - //which should be the case! - copy_v2_v2(BM_ELEM_CD_GET_VOID_P(l, CD_dst), fuv_table[f_dst->head.index].uv[b]); + for (h = 0; h < l_grp_count; h++) { + //average the loops' uvs + if (uv_buffer_alloc_size < l_grp[h].count) { //expand the buffer size when needed + uv_buffer_alloc_size = l_grp[h].count; + uv_buffer = MEM_reallocN(uv_buffer, sizeof(*uv_buffer) * uv_buffer_alloc_size); } + + //prepare the uvs to be averaged + for (i = 0; i < l_grp[h].count; i++) { + //copying each element is really inefficient it -at least- doubles the time when we are already accessing + //the pointer for read only! .. we should copy the pointer itself + copy_v2_v2(uv_buffer[i], BM_ELEM_CD_GET_VOID_P(l_grp[h].l[i], CD_dst)); + } + + //get the mid value + zero_v2(mid_uv); + mid_poly_v2(mid_uv, uv_buffer, l_grp[h].count); + + //copy the value to each of them + for (i = 0; i < l_grp[h].count; i++) { + //commenting this would leave us with the output of interpolation for each face ^_^ + copy_v2_v2(BM_ELEM_CD_GET_VOID_P(l_grp[h].l[i], CD_dst),mid_uv); + } } - //loop over the src faces to apply the changes made to the buffer - } return true; Modified: branches/soc-2013-meshdata_transfer/source/blender/bmesh/tools/bmesh_data_transfer.h =================================================================== @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org http://lists.blender.org/mailman/listinfo/bf-blender-cvs