static void editmesh_tessface_calc_intern(BMEditMesh *em) { /* allocating space before calculating the tessellation */ BMesh *bm = em->bm; /* this assumes all faces can be scan-filled, which isn't always true, * worst case we over alloc a little which is acceptable */ const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop); const int looptris_tot_prev_alloc = em->looptris ? (MEM_allocN_len(em->looptris) / sizeof(*em->looptris)) : 0; BMLoop *(*looptris)[3]; #if 0 /* note, we could be clever and re-use this array but would need to ensure * its realloced at some point, for now just free it */ if (em->looptris) MEM_freeN(em->looptris); /* Use em->tottri when set, this means no reallocs while transforming, * (unless scanfill fails), otherwise... */ /* allocate the length of totfaces, avoid many small reallocs, * if all faces are tri's it will be correct, quads == 2x allocs */ BLI_array_reserve(looptris, (em->tottri && em->tottri < bm->totface * 3) ? em->tottri : bm->totface); #else /* this means no reallocs for quad dominant models, for */ if ((em->looptris != NULL) && /* (*em->tottri >= looptris_tot)) */ /* check against alloc'd size incase we over alloc'd a little */ ((looptris_tot_prev_alloc >= looptris_tot) && (looptris_tot_prev_alloc <= looptris_tot * 2))) { looptris = em->looptris; } else { if (em->looptris) MEM_freeN(em->looptris); looptris = MEM_mallocN(sizeof(*looptris) * looptris_tot, __func__); } #endif em->looptris = looptris; /* after allocating the em->looptris, we're ready to tessellate */ BM_bmesh_calc_tessellation(em->bm, em->looptris, &em->tottri); }
/** * This function populates an array of verts for the triangles of a mesh * Tangent and Normals are also stored */ static void mesh_calc_tri_tessface( TriTessFace *triangles, Mesh *me, bool tangent, DerivedMesh *dm) { int i; MVert *mvert; TSpace *tspace; float *precomputed_normals = NULL; bool calculate_normal; const int tottri = poly_to_tri_count(me->totpoly, me->totloop); MLoopTri *looptri; /* calculate normal for each polygon only once */ unsigned int mpoly_prev = UINT_MAX; float no[3]; mvert = CustomData_get_layer(&me->vdata, CD_MVERT); looptri = MEM_mallocN(sizeof(*looptri) * tottri, __func__); if (tangent) { DM_ensure_normals(dm); DM_calc_loop_tangents(dm); precomputed_normals = dm->getPolyDataArray(dm, CD_NORMAL); calculate_normal = precomputed_normals ? false : true; tspace = dm->getLoopDataArray(dm, CD_TANGENT); BLI_assert(tspace); } BKE_mesh_recalc_looptri( me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, looptri); for (i = 0; i < tottri; i++) { MLoopTri *lt = &looptri[i]; MPoly *mp = &me->mpoly[lt->poly]; triangles[i].mverts[0] = &mvert[me->mloop[lt->tri[0]].v]; triangles[i].mverts[1] = &mvert[me->mloop[lt->tri[1]].v]; triangles[i].mverts[2] = &mvert[me->mloop[lt->tri[2]].v]; triangles[i].is_smooth = (mp->flag & ME_SMOOTH) != 0; if (tangent) { triangles[i].tspace[0] = &tspace[lt->tri[0]]; triangles[i].tspace[1] = &tspace[lt->tri[1]]; triangles[i].tspace[2] = &tspace[lt->tri[2]]; if (calculate_normal) { if (lt->poly != mpoly_prev) { const MPoly *mp = &me->mpoly[lt->poly]; BKE_mesh_calc_poly_normal(mp, &me->mloop[mp->loopstart], me->mvert, no); mpoly_prev = lt->poly; } copy_v3_v3(triangles[i].normal, no); } else { copy_v3_v3(triangles[i].normal, &precomputed_normals[lt->poly]); } } } MEM_freeN(looptri); }
void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource, bDeformGroup **dgrouplist, bDeformGroup **dgroupflip, float (*root)[3], float (*tip)[3], int *selected, const char **err_str) { LaplacianSystem *sys; MLoopTri *mlooptri; MPoly *mp; MLoop *ml; float solution, weight; int *vertsflipped = NULL, *mask = NULL; int a, tottri, j, bbone, firstsegment, lastsegment; bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; MVert *mvert = me->mvert; bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; *err_str = NULL; /* bone heat needs triangulated faces */ tottri = poly_to_tri_count(me->totpoly, me->totloop); /* count triangles and create mask */ if (ob->mode & OB_MODE_WEIGHT_PAINT && (use_face_sel || use_vert_sel)) { mask = MEM_callocN(sizeof(int) * me->totvert, "heat_bone_weighting mask"); /* (added selectedVerts content for vertex mask, they used to just equal 1) */ if (use_vert_sel) { for (a = 0, mp = me->mpoly; a < me->totpoly; mp++, a++) { for (j = 0, ml = me->mloop + mp->loopstart; j < mp->totloop; j++, ml++) { mask[ml->v] = (mvert[ml->v].flag & SELECT) != 0; } } } else if (use_face_sel) { for (a = 0, mp = me->mpoly; a < me->totpoly; mp++, a++) { if (mp->flag & ME_FACE_SEL) { for (j = 0, ml = me->mloop + mp->loopstart; j < mp->totloop; j++, ml++) { mask[ml->v] = 1; } } } } } /* create laplacian */ sys = laplacian_system_construct_begin(me->totvert, tottri, 1); sys->heat.tottri = poly_to_tri_count(me->totpoly, me->totloop); mlooptri = MEM_mallocN(sizeof(*sys->heat.mlooptri) * sys->heat.tottri, __func__); BKE_mesh_recalc_looptri( me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, mlooptri); sys->heat.mlooptri = mlooptri; sys->heat.mloop = me->mloop; sys->heat.totvert = me->totvert; sys->heat.verts = verts; sys->heat.root = root; sys->heat.tip = tip; sys->heat.numsource = numsource; heat_ray_tree_create(sys); heat_laplacian_create(sys); laplacian_system_construct_end(sys); if (dgroupflip) { vertsflipped = MEM_callocN(sizeof(int) * me->totvert, "vertsflipped"); for (a = 0; a < me->totvert; a++) vertsflipped[a] = mesh_get_x_mirror_vert(ob, NULL, a, use_topology); } /* compute weights per bone */ for (j = 0; j < numsource; j++) { if (!selected[j]) continue; firstsegment = (j == 0 || dgrouplist[j - 1] != dgrouplist[j]); lastsegment = (j == numsource - 1 || dgrouplist[j] != dgrouplist[j + 1]); bbone = !(firstsegment && lastsegment); /* clear weights */ if (bbone && firstsegment) { for (a = 0; a < me->totvert; a++) { if (mask && !mask[a]) continue; ED_vgroup_vert_remove(ob, dgrouplist[j], a); if (vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0) ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]); } } /* fill right hand side */ laplacian_begin_solve(sys, -1); for (a = 0; a < me->totvert; a++) if (heat_source_closest(sys, a, j)) laplacian_add_right_hand_side(sys, a, sys->heat.H[a] * sys->heat.p[a]); /* solve */ if (laplacian_system_solve(sys)) { /* load solution into vertex groups */ for (a = 0; a < me->totvert; a++) { if (mask && !mask[a]) continue; solution = laplacian_system_get_solution(sys, a); if (bbone) { if (solution > 0.0f) ED_vgroup_vert_add(ob, dgrouplist[j], a, solution, WEIGHT_ADD); } else { weight = heat_limit_weight(solution); if (weight > 0.0f) ED_vgroup_vert_add(ob, dgrouplist[j], a, weight, WEIGHT_REPLACE); else ED_vgroup_vert_remove(ob, dgrouplist[j], a); } /* do same for mirror */ if (vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0) { if (bbone) { if (solution > 0.0f) ED_vgroup_vert_add(ob, dgroupflip[j], vertsflipped[a], solution, WEIGHT_ADD); } else { weight = heat_limit_weight(solution); if (weight > 0.0f) ED_vgroup_vert_add(ob, dgroupflip[j], vertsflipped[a], weight, WEIGHT_REPLACE); else ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]); } } } } else if (*err_str == NULL) { *err_str = N_("Bone Heat Weighting: failed to find solution for one or more bones"); break; } /* remove too small vertex weights */ if (bbone && lastsegment) { for (a = 0; a < me->totvert; a++) { if (mask && !mask[a]) continue; weight = ED_vgroup_vert_weight(ob, dgrouplist[j], a); weight = heat_limit_weight(weight); if (weight <= 0.0f) ED_vgroup_vert_remove(ob, dgrouplist[j], a); if (vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0) { weight = ED_vgroup_vert_weight(ob, dgroupflip[j], vertsflipped[a]); weight = heat_limit_weight(weight); if (weight <= 0.0f) ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]); } } } } /* free */ if (vertsflipped) MEM_freeN(vertsflipped); if (mask) MEM_freeN(mask); heat_system_free(sys); laplacian_system_delete(sys); }
void RE_bake_pixels_populate( Mesh *me, BakePixel pixel_array[], const size_t num_pixels, const BakeImages *bake_images, const char *uv_layer) { BakeDataZSpan bd; size_t i; int a, p_id; const MLoopUV *mloopuv; const int tottri = poly_to_tri_count(me->totpoly, me->totloop); MLoopTri *looptri; #ifdef USE_MFACE_WORKAROUND unsigned int mpoly_prev_testindex = UINT_MAX; #endif /* we can't bake in edit mode */ if (me->edit_btmesh) return; if ((uv_layer == NULL) || (uv_layer[0] == '\0')) { mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV); } else { int uv_id = CustomData_get_named_layer(&me->ldata, CD_MLOOPUV, uv_layer); mloopuv = CustomData_get_layer_n(&me->ldata, CD_MTFACE, uv_id); } if (mloopuv == NULL) return; bd.pixel_array = pixel_array; bd.zspan = MEM_callocN(sizeof(ZSpan) * bake_images->size, "bake zspan"); /* initialize all pixel arrays so we know which ones are 'blank' */ for (i = 0; i < num_pixels; i++) { pixel_array[i].primitive_id = -1; } for (i = 0; i < bake_images->size; i++) { zbuf_alloc_span(&bd.zspan[i], bake_images->data[i].width, bake_images->data[i].height, R.clipcrop); } looptri = MEM_mallocN(sizeof(*looptri) * tottri, __func__); BKE_mesh_recalc_looptri( me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, looptri); p_id = -1; for (i = 0; i < tottri; i++) { const MLoopTri *lt = &looptri[i]; const MPoly *mp = &me->mpoly[lt->poly]; float vec[3][2]; int mat_nr = mp->mat_nr; int image_id = bake_images->lookup[mat_nr]; bd.bk_image = &bake_images->data[image_id]; bd.primitive_id = ++p_id; #ifdef USE_MFACE_WORKAROUND if (lt->poly != mpoly_prev_testindex) { test_index_face_looptri(mp, me->mloop, &looptri[i]); mpoly_prev_testindex = lt->poly; } #endif for (a = 0; a < 3; a++) { const float *uv = mloopuv[lt->tri[a]].uv; /* Note, workaround for pixel aligned UVs which are common and can screw up our intersection tests * where a pixel gets in between 2 faces or the middle of a quad, * camera aligned quads also have this problem but they are less common. * Add a small offset to the UVs, fixes bug #18685 - Campbell */ vec[a][0] = uv[0] * (float)bd.bk_image->width - (0.5f + 0.001f); vec[a][1] = uv[1] * (float)bd.bk_image->height - (0.5f + 0.002f); } bake_differentials(&bd, vec[0], vec[1], vec[2]); zspan_scanconvert(&bd.zspan[image_id], (void *)&bd, vec[0], vec[1], vec[2], store_bake_pixel); } for (i = 0; i < bake_images->size; i++) { zbuf_free_span(&bd.zspan[i]); } MEM_freeN(looptri); MEM_freeN(bd.zspan); }