/* This is a Mesh-based copy of the same function in DerivedMesh.c */ static void shapekey_layers_to_keyblocks(Mesh *mesh_src, Mesh *mesh_dst, int actshape_uid) { KeyBlock *kb; int i, j, tot; if (!mesh_dst->key) { return; } tot = CustomData_number_of_layers(&mesh_src->vdata, CD_SHAPEKEY); for (i = 0; i < tot; i++) { CustomDataLayer *layer = &mesh_src->vdata.layers[CustomData_get_layer_index_n(&mesh_src->vdata, CD_SHAPEKEY, i)]; float(*cos)[3], (*kbcos)[3]; for (kb = mesh_dst->key->block.first; kb; kb = kb->next) { if (kb->uid == layer->uid) { break; } } if (!kb) { kb = BKE_keyblock_add(mesh_dst->key, layer->name); kb->uid = layer->uid; } if (kb->data) { MEM_freeN(kb->data); } cos = CustomData_get_layer_n(&mesh_src->vdata, CD_SHAPEKEY, i); kb->totelem = mesh_src->totvert; kb->data = kbcos = MEM_malloc_arrayN(kb->totelem, 3 * sizeof(float), __func__); if (kb->uid == actshape_uid) { MVert *mvert = mesh_src->mvert; for (j = 0; j < mesh_src->totvert; j++, kbcos++, mvert++) { copy_v3_v3(*kbcos, mvert->co); } } else { for (j = 0; j < kb->totelem; j++, cos++, kbcos++) { copy_v3_v3(*kbcos, *cos); } } } for (kb = mesh_dst->key->block.first; kb; kb = kb->next) { if (kb->totelem != mesh_src->totvert) { if (kb->data) { MEM_freeN(kb->data); } kb->totelem = mesh_src->totvert; kb->data = MEM_calloc_arrayN(kb->totelem, 3 * sizeof(float), __func__); CLOG_ERROR(&LOG, "lost a shapekey layer: '%s'! (bmesh internal error)", kb->name); } } }
static void mesh_get_boundaries(Mesh *mesh, float *smooth_weights) { const MPoly *mpoly = mesh->mpoly; const MLoop *mloop = mesh->mloop; const MEdge *medge = mesh->medge; unsigned int mpoly_num, medge_num, i; unsigned short *boundaries; mpoly_num = (unsigned int)mesh->totpoly; medge_num = (unsigned int)mesh->totedge; boundaries = MEM_calloc_arrayN(medge_num, sizeof(*boundaries), __func__); /* count the number of adjacent faces */ for (i = 0; i < mpoly_num; i++) { const MPoly *p = &mpoly[i]; const int totloop = p->totloop; int j; for (j = 0; j < totloop; j++) { boundaries[mloop[p->loopstart + j].e]++; } } for (i = 0; i < medge_num; i++) { if (boundaries[i] == 1) { smooth_weights[medge[i].v1] = 0.0f; smooth_weights[medge[i].v2] = 0.0f; } } MEM_freeN(boundaries); }
static void multires_reshape_allocate_displacement_grid(MDisps *displacement_grid, const int level) { const int grid_size = BKE_subdiv_grid_size_from_level(level); const int grid_area = grid_size * grid_size; float(*disps)[3] = MEM_calloc_arrayN(grid_area, 3 * sizeof(float), "multires disps"); if (displacement_grid->disps != NULL) { MEM_freeN(displacement_grid->disps); } displacement_grid->disps = disps; displacement_grid->totdisp = grid_area; displacement_grid->level = level; }
static void add_shapekey_layers(Mesh *mesh_dest, Mesh *mesh_src) { KeyBlock *kb; Key *key = mesh_src->key; int i; if (!mesh_src->key) { return; } /* ensure we can use mesh vertex count for derived mesh custom data */ if (mesh_src->totvert != mesh_dest->totvert) { CLOG_ERROR(&LOG, "vertex size mismatch (mesh/dm) '%s' (%d != %d)", mesh_src->id.name + 2, mesh_src->totvert, mesh_dest->totvert); return; } for (i = 0, kb = key->block.first; kb; kb = kb->next, i++) { int ci; float *array; if (mesh_src->totvert != kb->totelem) { CLOG_ERROR(&LOG, "vertex size mismatch (Mesh '%s':%d != KeyBlock '%s':%d)", mesh_src->id.name + 2, mesh_src->totvert, kb->name, kb->totelem); array = MEM_calloc_arrayN((size_t)mesh_src->totvert, 3 * sizeof(float), __func__); } else { array = MEM_malloc_arrayN((size_t)mesh_src->totvert, 3 * sizeof(float), __func__); memcpy(array, kb->data, (size_t)mesh_src->totvert * 3 * sizeof(float)); } CustomData_add_layer_named( &mesh_dest->vdata, CD_SHAPEKEY, CD_ASSIGN, array, mesh_dest->totvert, kb->name); ci = CustomData_get_layer_index_n(&mesh_dest->vdata, CD_SHAPEKEY, i); mesh_dest->vdata.layers[ci].uid = kb->uid; } }
static LaplacianSystem *init_laplacian_system(int a_numEdges, int a_numPolys, int a_numLoops, int a_numVerts) { LaplacianSystem *sys; sys = MEM_callocN(sizeof(LaplacianSystem), "ModLaplSmoothSystem"); sys->numEdges = a_numEdges; sys->numPolys = a_numPolys; sys->numLoops = a_numLoops; sys->numVerts = a_numVerts; sys->eweights = MEM_calloc_arrayN(sys->numEdges, sizeof(float), __func__); sys->fweights = MEM_calloc_arrayN(sys->numLoops, sizeof(float[3]), __func__); sys->numNeEd = MEM_calloc_arrayN(sys->numVerts, sizeof(short), __func__); sys->numNeFa = MEM_calloc_arrayN(sys->numVerts, sizeof(short), __func__); sys->ring_areas = MEM_calloc_arrayN(sys->numVerts, sizeof(float), __func__); sys->vlengths = MEM_calloc_arrayN(sys->numVerts, sizeof(float), __func__); sys->vweights = MEM_calloc_arrayN(sys->numVerts, sizeof(float), __func__); sys->zerola = MEM_calloc_arrayN(sys->numVerts, sizeof(short), __func__); return sys; }
/** * This calculates #CorrectiveSmoothModifierData.delta_cache * It's not run on every update (during animation for example). */ static void calc_deltas(CorrectiveSmoothModifierData *csmd, Mesh *mesh, MDeformVert *dvert, const int defgrp_index, const float (*rest_coords)[3], unsigned int numVerts) { float(*smooth_vertex_coords)[3] = MEM_dupallocN(rest_coords); float(*tangent_spaces)[3][3]; unsigned int i; tangent_spaces = MEM_calloc_arrayN(numVerts, sizeof(float[3][3]), __func__); if (csmd->delta_cache_num != numVerts) { MEM_SAFE_FREE(csmd->delta_cache); } /* allocate deltas if they have not yet been allocated, otheriwse we will just write over them */ if (!csmd->delta_cache) { csmd->delta_cache_num = numVerts; csmd->delta_cache = MEM_malloc_arrayN(numVerts, sizeof(float[3]), __func__); } smooth_verts(csmd, mesh, dvert, defgrp_index, smooth_vertex_coords, numVerts); calc_tangent_spaces(mesh, smooth_vertex_coords, tangent_spaces); for (i = 0; i < numVerts; i++) { float imat[3][3], delta[3]; #ifdef USE_TANGENT_CALC_INLINE calc_tangent_ortho(tangent_spaces[i]); #endif sub_v3_v3v3(delta, rest_coords[i], smooth_vertex_coords[i]); if (UNLIKELY(!invert_m3_m3(imat, tangent_spaces[i]))) { transpose_m3_m3(imat, tangent_spaces[i]); } mul_v3_m3v3(csmd->delta_cache[i], imat, delta); } MEM_freeN(tangent_spaces); MEM_freeN(smooth_vertex_coords); }
static void multires_reshape_ensure_mask_grids(Mesh *mesh, const int grid_level) { GridPaintMask *grid_paint_masks = CustomData_get_layer(&mesh->ldata, CD_GRID_PAINT_MASK); if (grid_paint_masks == NULL) { return; } const int num_grids = mesh->totloop; const int grid_size = BKE_subdiv_grid_size_from_level(grid_level); const int grid_area = grid_size * grid_size; for (int grid_index = 0; grid_index < num_grids; grid_index++) { GridPaintMask *grid_paint_mask = &grid_paint_masks[grid_index]; if (grid_paint_mask->level == grid_level) { continue; } grid_paint_mask->level = grid_level; if (grid_paint_mask->data) { MEM_freeN(grid_paint_mask->data); } grid_paint_mask->data = MEM_calloc_arrayN(grid_area, sizeof(float), "gpm.data"); } }
void get_texture_coords( MappingInfoModifierData *dmd, Object *ob, DerivedMesh *dm, float (*co)[3], float (*texco)[3], int numVerts) { int i; int texmapping = dmd->texmapping; float mapob_imat[4][4]; if (texmapping == MOD_DISP_MAP_OBJECT) { if (dmd->map_object) invert_m4_m4(mapob_imat, dmd->map_object->obmat); else /* if there is no map object, default to local */ texmapping = MOD_DISP_MAP_LOCAL; } /* UVs need special handling, since they come from faces */ if (texmapping == MOD_DISP_MAP_UV) { if (CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) { MPoly *mpoly = dm->getPolyArray(dm); MPoly *mp; MLoop *mloop = dm->getLoopArray(dm); char *done = MEM_calloc_arrayN(numVerts, sizeof(*done), "get_texture_coords done"); int numPolys = dm->getNumPolys(dm); char uvname[MAX_CUSTOMDATA_LAYER_NAME]; MLoopUV *mloop_uv; CustomData_validate_layer_name(&dm->loopData, CD_MLOOPUV, dmd->uvlayer_name, uvname); mloop_uv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, uvname); /* verts are given the UV from the first face that uses them */ for (i = 0, mp = mpoly; i < numPolys; ++i, ++mp) { unsigned int fidx = mp->totloop - 1; do { unsigned int lidx = mp->loopstart + fidx; unsigned int vidx = mloop[lidx].v; if (done[vidx] == 0) { /* remap UVs from [0, 1] to [-1, 1] */ texco[vidx][0] = (mloop_uv[lidx].uv[0] * 2.0f) - 1.0f; texco[vidx][1] = (mloop_uv[lidx].uv[1] * 2.0f) - 1.0f; done[vidx] = 1; } } while (fidx--); } MEM_freeN(done); return; } else /* if there are no UVs, default to local */ texmapping = MOD_DISP_MAP_LOCAL; } for (i = 0; i < numVerts; ++i, ++co, ++texco) { switch (texmapping) { case MOD_DISP_MAP_LOCAL: copy_v3_v3(*texco, *co); break; case MOD_DISP_MAP_GLOBAL: mul_v3_m4v3(*texco, ob->obmat, *co); break; case MOD_DISP_MAP_OBJECT: mul_v3_m4v3(*texco, ob->obmat, *co); mul_m4_v3(mapob_imat, *texco); break; } } }
void BKE_mesh_to_curve_nurblist(const Mesh *me, ListBase *nurblist, const int edge_users_test) { MVert *mvert = me->mvert; MEdge *med, *medge = me->medge; MPoly *mp, *mpoly = me->mpoly; MLoop *mloop = me->mloop; int medge_len = me->totedge; int mpoly_len = me->totpoly; int totedges = 0; int i; /* only to detect edge polylines */ int *edge_users; ListBase edges = {NULL, NULL}; /* get boundary edges */ edge_users = MEM_calloc_arrayN(medge_len, sizeof(int), __func__); for (i = 0, mp = mpoly; i < mpoly_len; i++, mp++) { MLoop *ml = &mloop[mp->loopstart]; int j; for (j = 0; j < mp->totloop; j++, ml++) { edge_users[ml->e]++; } } /* create edges from all faces (so as to find edges not in any faces) */ med = medge; for (i = 0; i < medge_len; i++, med++) { if (edge_users[i] == edge_users_test) { EdgeLink *edl = MEM_callocN(sizeof(EdgeLink), "EdgeLink"); edl->edge = med; BLI_addtail(&edges, edl); totedges++; } } MEM_freeN(edge_users); if (edges.first) { while (edges.first) { /* each iteration find a polyline and add this as a nurbs poly spline */ ListBase polyline = {NULL, NULL}; /* store a list of VertLink's */ bool closed = false; int totpoly = 0; MEdge *med_current = ((EdgeLink *)edges.last)->edge; unsigned int startVert = med_current->v1; unsigned int endVert = med_current->v2; bool ok = true; appendPolyLineVert(&polyline, startVert); totpoly++; appendPolyLineVert(&polyline, endVert); totpoly++; BLI_freelinkN(&edges, edges.last); totedges--; while (ok) { /* while connected edges are found... */ EdgeLink *edl = edges.last; ok = false; while (edl) { EdgeLink *edl_prev = edl->prev; med = edl->edge; if (med->v1 == endVert) { endVert = med->v2; appendPolyLineVert(&polyline, med->v2); totpoly++; BLI_freelinkN(&edges, edl); totedges--; ok = true; } else if (med->v2 == endVert) { endVert = med->v1; appendPolyLineVert(&polyline, endVert); totpoly++; BLI_freelinkN(&edges, edl); totedges--; ok = true; } else if (med->v1 == startVert) { startVert = med->v2; prependPolyLineVert(&polyline, startVert); totpoly++; BLI_freelinkN(&edges, edl); totedges--; ok = true; } else if (med->v2 == startVert) { startVert = med->v1; prependPolyLineVert(&polyline, startVert); totpoly++; BLI_freelinkN(&edges, edl); totedges--; ok = true; } edl = edl_prev; } } /* Now we have a polyline, make into a curve */ if (startVert == endVert) { BLI_freelinkN(&polyline, polyline.last); totpoly--; closed = true; } /* --- nurbs --- */ { Nurb *nu; BPoint *bp; VertLink *vl; /* create new 'nurb' within the curve */ nu = (Nurb *)MEM_callocN(sizeof(Nurb), "MeshNurb"); nu->pntsu = totpoly; nu->pntsv = 1; nu->orderu = 4; nu->flagu = CU_NURB_ENDPOINT | (closed ? CU_NURB_CYCLIC : 0); /* endpoint */ nu->resolu = 12; nu->bp = (BPoint *)MEM_calloc_arrayN(totpoly, sizeof(BPoint), "bpoints"); /* add points */ vl = polyline.first; for (i = 0, bp = nu->bp; i < totpoly; i++, bp++, vl = (VertLink *)vl->next) { copy_v3_v3(bp->vec, mvert[vl->index].co); bp->f1 = SELECT; bp->radius = bp->weight = 1.0; } BLI_freelistN(&polyline); /* add nurb to curve */ BLI_addtail(nurblist, nu); } /* --- done with nurbs --- */ } } }
/* use specified dispbase */ int BKE_mesh_nurbs_displist_to_mdata(Object *ob, const ListBase *dispbase, MVert **r_allvert, int *r_totvert, MEdge **r_alledge, int *r_totedge, MLoop **r_allloop, MPoly **r_allpoly, MLoopUV **r_alluv, int *r_totloop, int *r_totpoly) { Curve *cu = ob->data; DispList *dl; MVert *mvert; MPoly *mpoly; MLoop *mloop; MLoopUV *mloopuv = NULL; MEdge *medge; const float *data; int a, b, ofs, vertcount, startvert, totvert = 0, totedge = 0, totloop = 0, totpoly = 0; int p1, p2, p3, p4, *index; const bool conv_polys = ((CU_DO_2DFILL(cu) == false) || /* 2d polys are filled with DL_INDEX3 displists */ (ob->type == OB_SURF)); /* surf polys are never filled */ /* count */ dl = dispbase->first; while (dl) { if (dl->type == DL_SEGM) { totvert += dl->parts * dl->nr; totedge += dl->parts * (dl->nr - 1); } else if (dl->type == DL_POLY) { if (conv_polys) { totvert += dl->parts * dl->nr; totedge += dl->parts * dl->nr; } } else if (dl->type == DL_SURF) { int tot; totvert += dl->parts * dl->nr; tot = (dl->parts - 1 + ((dl->flag & DL_CYCL_V) == 2)) * (dl->nr - 1 + (dl->flag & DL_CYCL_U)); totpoly += tot; totloop += tot * 4; } else if (dl->type == DL_INDEX3) { int tot; totvert += dl->nr; tot = dl->parts; totpoly += tot; totloop += tot * 3; } dl = dl->next; } if (totvert == 0) { /* error("can't convert"); */ /* Make Sure you check ob->data is a curve */ return -1; } *r_allvert = mvert = MEM_calloc_arrayN(totvert, sizeof(MVert), "nurbs_init mvert"); *r_alledge = medge = MEM_calloc_arrayN(totedge, sizeof(MEdge), "nurbs_init medge"); *r_allloop = mloop = MEM_calloc_arrayN( totpoly, 4 * sizeof(MLoop), "nurbs_init mloop"); // totloop *r_allpoly = mpoly = MEM_calloc_arrayN(totpoly, sizeof(MPoly), "nurbs_init mloop"); if (r_alluv) { *r_alluv = mloopuv = MEM_calloc_arrayN(totpoly, 4 * sizeof(MLoopUV), "nurbs_init mloopuv"); } /* verts and faces */ vertcount = 0; dl = dispbase->first; while (dl) { const bool is_smooth = (dl->rt & CU_SMOOTH) != 0; if (dl->type == DL_SEGM) { startvert = vertcount; a = dl->parts * dl->nr; data = dl->verts; while (a--) { copy_v3_v3(mvert->co, data); data += 3; vertcount++; mvert++; } for (a = 0; a < dl->parts; a++) { ofs = a * dl->nr; for (b = 1; b < dl->nr; b++) { medge->v1 = startvert + ofs + b - 1; medge->v2 = startvert + ofs + b; medge->flag = ME_LOOSEEDGE | ME_EDGERENDER | ME_EDGEDRAW; medge++; } } } else if (dl->type == DL_POLY) { if (conv_polys) { startvert = vertcount; a = dl->parts * dl->nr; data = dl->verts; while (a--) { copy_v3_v3(mvert->co, data); data += 3; vertcount++; mvert++; } for (a = 0; a < dl->parts; a++) { ofs = a * dl->nr; for (b = 0; b < dl->nr; b++) { medge->v1 = startvert + ofs + b; if (b == dl->nr - 1) { medge->v2 = startvert + ofs; } else { medge->v2 = startvert + ofs + b + 1; } medge->flag = ME_LOOSEEDGE | ME_EDGERENDER | ME_EDGEDRAW; medge++; } } } } else if (dl->type == DL_INDEX3) { startvert = vertcount; a = dl->nr; data = dl->verts; while (a--) { copy_v3_v3(mvert->co, data); data += 3; vertcount++; mvert++; } a = dl->parts; index = dl->index; while (a--) { mloop[0].v = startvert + index[0]; mloop[1].v = startvert + index[2]; mloop[2].v = startvert + index[1]; mpoly->loopstart = (int)(mloop - (*r_allloop)); mpoly->totloop = 3; mpoly->mat_nr = dl->col; if (mloopuv) { int i; for (i = 0; i < 3; i++, mloopuv++) { mloopuv->uv[0] = (mloop[i].v - startvert) / (float)(dl->nr - 1); mloopuv->uv[1] = 0.0f; } } if (is_smooth) { mpoly->flag |= ME_SMOOTH; } mpoly++; mloop += 3; index += 3; } } else if (dl->type == DL_SURF) { startvert = vertcount; a = dl->parts * dl->nr; data = dl->verts; while (a--) { copy_v3_v3(mvert->co, data); data += 3; vertcount++; mvert++; } for (a = 0; a < dl->parts; a++) { if ((dl->flag & DL_CYCL_V) == 0 && a == dl->parts - 1) { break; } if (dl->flag & DL_CYCL_U) { /* p2 -> p1 -> */ p1 = startvert + dl->nr * a; /* p4 -> p3 -> */ p2 = p1 + dl->nr - 1; /* -----> next row */ p3 = p1 + dl->nr; p4 = p2 + dl->nr; b = 0; } else { p2 = startvert + dl->nr * a; p1 = p2 + 1; p4 = p2 + dl->nr; p3 = p1 + dl->nr; b = 1; } if ((dl->flag & DL_CYCL_V) && a == dl->parts - 1) { p3 -= dl->parts * dl->nr; p4 -= dl->parts * dl->nr; } for (; b < dl->nr; b++) { mloop[0].v = p1; mloop[1].v = p3; mloop[2].v = p4; mloop[3].v = p2; mpoly->loopstart = (int)(mloop - (*r_allloop)); mpoly->totloop = 4; mpoly->mat_nr = dl->col; if (mloopuv) { int orco_sizeu = dl->nr - 1; int orco_sizev = dl->parts - 1; int i; /* exception as handled in convertblender.c too */ if (dl->flag & DL_CYCL_U) { orco_sizeu++; if (dl->flag & DL_CYCL_V) { orco_sizev++; } } else if (dl->flag & DL_CYCL_V) { orco_sizev++; } for (i = 0; i < 4; i++, mloopuv++) { /* find uv based on vertex index into grid array */ int v = mloop[i].v - startvert; mloopuv->uv[0] = (v / dl->nr) / (float)orco_sizev; mloopuv->uv[1] = (v % dl->nr) / (float)orco_sizeu; /* cyclic correction */ if ((i == 1 || i == 2) && mloopuv->uv[0] == 0.0f) { mloopuv->uv[0] = 1.0f; } if ((i == 0 || i == 1) && mloopuv->uv[1] == 0.0f) { mloopuv->uv[1] = 1.0f; } } } if (is_smooth) { mpoly->flag |= ME_SMOOTH; } mpoly++; mloop += 4; p4 = p3; p3++; p2 = p1; p1++; } } } dl = dl->next; } if (totpoly) { make_edges_mdata_extend(r_alledge, &totedge, *r_allpoly, *r_allloop, totpoly); } *r_totpoly = totpoly; *r_totloop = totloop; *r_totedge = totedge; *r_totvert = totvert; return 0; }
/** * Specialized function to use when we _know_ existing edges don't overlap with poly edges. */ static void make_edges_mdata_extend( MEdge **r_alledge, int *r_totedge, const MPoly *mpoly, MLoop *mloop, const int totpoly) { int totedge = *r_totedge; int totedge_new; EdgeHash *eh; unsigned int eh_reserve; const MPoly *mp; int i; eh_reserve = max_ii(totedge, BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(totpoly)); eh = BLI_edgehash_new_ex(__func__, eh_reserve); for (i = 0, mp = mpoly; i < totpoly; i++, mp++) { BKE_mesh_poly_edgehash_insert(eh, mp, mloop + mp->loopstart); } totedge_new = BLI_edgehash_len(eh); #ifdef DEBUG /* ensure that there's no overlap! */ if (totedge_new) { MEdge *medge = *r_alledge; for (i = 0; i < totedge; i++, medge++) { BLI_assert(BLI_edgehash_haskey(eh, medge->v1, medge->v2) == false); } } #endif if (totedge_new) { EdgeHashIterator *ehi; MEdge *medge; unsigned int e_index = totedge; *r_alledge = medge = (*r_alledge ? MEM_reallocN(*r_alledge, sizeof(MEdge) * (totedge + totedge_new)) : MEM_calloc_arrayN(totedge_new, sizeof(MEdge), __func__)); medge += totedge; totedge += totedge_new; /* --- */ for (ehi = BLI_edgehashIterator_new(eh); BLI_edgehashIterator_isDone(ehi) == false; BLI_edgehashIterator_step(ehi), ++medge, e_index++) { BLI_edgehashIterator_getKey(ehi, &medge->v1, &medge->v2); BLI_edgehashIterator_setValue(ehi, POINTER_FROM_UINT(e_index)); medge->crease = medge->bweight = 0; medge->flag = ME_EDGEDRAW | ME_EDGERENDER; } BLI_edgehashIterator_free(ehi); *r_totedge = totedge; for (i = 0, mp = mpoly; i < totpoly; i++, mp++) { MLoop *l = &mloop[mp->loopstart]; MLoop *l_prev = (l + (mp->totloop - 1)); int j; for (j = 0; j < mp->totloop; j++, l++) { /* lookup hashed edge index */ l_prev->e = POINTER_AS_UINT(BLI_edgehash_lookup(eh, l_prev->v, l->v)); l_prev = l; } } } BLI_edgehash_free(eh, NULL); }
static void correctivesmooth_modifier_do(ModifierData *md, Depsgraph *depsgraph, Object *ob, Mesh *mesh, float (*vertexCos)[3], unsigned int numVerts, struct BMEditMesh *em) { CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md; const bool force_delta_cache_update = /* XXX, take care! if mesh data its self changes we need to forcefully recalculate deltas */ ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO) && (((ID *)ob->data)->recalc & ID_RECALC_ALL)); bool use_only_smooth = (csmd->flag & MOD_CORRECTIVESMOOTH_ONLY_SMOOTH) != 0; MDeformVert *dvert = NULL; int defgrp_index; MOD_get_vgroup(ob, mesh, csmd->defgrp_name, &dvert, &defgrp_index); /* if rest bind_coords not are defined, set them (only run during bind) */ if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) && /* signal to recalculate, whoever sets MUST also free bind coords */ (csmd->bind_coords_num == (unsigned int)-1)) { if (DEG_is_active(depsgraph)) { BLI_assert(csmd->bind_coords == NULL); csmd->bind_coords = MEM_dupallocN(vertexCos); csmd->bind_coords_num = numVerts; BLI_assert(csmd->bind_coords != NULL); /* Copy bound data to the original modifier. */ CorrectiveSmoothModifierData *csmd_orig = (CorrectiveSmoothModifierData *) modifier_get_original(&csmd->modifier); csmd_orig->bind_coords = MEM_dupallocN(csmd->bind_coords); csmd_orig->bind_coords_num = csmd->bind_coords_num; } else { modifier_setError(md, "Attempt to bind from inactive dependency graph"); } } if (UNLIKELY(use_only_smooth)) { smooth_verts(csmd, mesh, dvert, defgrp_index, vertexCos, numVerts); return; } if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) && (csmd->bind_coords == NULL)) { modifier_setError(md, "Bind data required"); goto error; } /* If the number of verts has changed, the bind is invalid, so we do nothing */ if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) { if (csmd->bind_coords_num != numVerts) { modifier_setError( md, "Bind vertex count mismatch: %u to %u", csmd->bind_coords_num, numVerts); goto error; } } else { /* MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO */ if (ob->type != OB_MESH) { modifier_setError(md, "Object is not a mesh"); goto error; } else { unsigned int me_numVerts = (unsigned int)((em) ? em->bm->totvert : ((Mesh *)ob->data)->totvert); if (me_numVerts != numVerts) { modifier_setError(md, "Original vertex count mismatch: %u to %u", me_numVerts, numVerts); goto error; } } } /* check to see if our deltas are still valid */ if (!csmd->delta_cache || (csmd->delta_cache_num != numVerts) || force_delta_cache_update) { const float(*rest_coords)[3]; bool is_rest_coords_alloc = false; if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) { /* caller needs to do sanity check here */ csmd->bind_coords_num = numVerts; rest_coords = (const float(*)[3])csmd->bind_coords; } else { int me_numVerts; rest_coords = (const float(*)[3])((em) ? BKE_editmesh_vertexCos_get_orco(em, &me_numVerts) : BKE_mesh_vertexCos_get(ob->data, &me_numVerts)); BLI_assert((unsigned int)me_numVerts == numVerts); is_rest_coords_alloc = true; } #ifdef DEBUG_TIME TIMEIT_START(corrective_smooth_deltas); #endif calc_deltas(csmd, mesh, dvert, defgrp_index, rest_coords, numVerts); #ifdef DEBUG_TIME TIMEIT_END(corrective_smooth_deltas); #endif if (is_rest_coords_alloc) { MEM_freeN((void *)rest_coords); } } if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) { /* this could be a check, but at this point it _must_ be valid */ BLI_assert(csmd->bind_coords_num == numVerts && csmd->delta_cache); } #ifdef DEBUG_TIME TIMEIT_START(corrective_smooth); #endif /* do the actual delta mush */ smooth_verts(csmd, mesh, dvert, defgrp_index, vertexCos, numVerts); { unsigned int i; float(*tangent_spaces)[3][3]; /* calloc, since values are accumulated */ tangent_spaces = MEM_calloc_arrayN(numVerts, sizeof(float[3][3]), __func__); calc_tangent_spaces(mesh, vertexCos, tangent_spaces); for (i = 0; i < numVerts; i++) { float delta[3]; #ifdef USE_TANGENT_CALC_INLINE calc_tangent_ortho(tangent_spaces[i]); #endif mul_v3_m3v3(delta, tangent_spaces[i], csmd->delta_cache[i]); add_v3_v3(vertexCos[i], delta); } MEM_freeN(tangent_spaces); } #ifdef DEBUG_TIME TIMEIT_END(corrective_smooth); #endif return; /* when the modifier fails to execute */ error: MEM_SAFE_FREE(csmd->delta_cache); csmd->delta_cache_num = 0; }
/* Edge-Length Weighted Smoothing */ static void smooth_iter__length_weight(CorrectiveSmoothModifierData *csmd, Mesh *mesh, float (*vertexCos)[3], unsigned int numVerts, const float *smooth_weights, unsigned int iterations) { const float eps = FLT_EPSILON * 10.0f; const unsigned int numEdges = (unsigned int)mesh->totedge; /* note: the way this smoothing method works, its approx half as strong as the simple-smooth, * and 2.0 rarely spikes, double the value for consistent behavior. */ const float lambda = csmd->lambda * 2.0f; const MEdge *edges = mesh->medge; float *vertex_edge_count; unsigned int i; struct SmoothingData_Weighted { float delta[3]; float edge_length_sum; } *smooth_data = MEM_calloc_arrayN(numVerts, sizeof(*smooth_data), __func__); /* calculate as floats to avoid int->float conversion in #smooth_iter */ vertex_edge_count = MEM_calloc_arrayN(numVerts, sizeof(float), __func__); for (i = 0; i < numEdges; i++) { vertex_edge_count[edges[i].v1] += 1.0f; vertex_edge_count[edges[i].v2] += 1.0f; } /* -------------------------------------------------------------------- */ /* Main Smoothing Loop */ while (iterations--) { for (i = 0; i < numEdges; i++) { struct SmoothingData_Weighted *sd_v1; struct SmoothingData_Weighted *sd_v2; float edge_dir[3]; float edge_dist; sub_v3_v3v3(edge_dir, vertexCos[edges[i].v2], vertexCos[edges[i].v1]); edge_dist = len_v3(edge_dir); /* weight by distance */ mul_v3_fl(edge_dir, edge_dist); sd_v1 = &smooth_data[edges[i].v1]; sd_v2 = &smooth_data[edges[i].v2]; add_v3_v3(sd_v1->delta, edge_dir); sub_v3_v3(sd_v2->delta, edge_dir); sd_v1->edge_length_sum += edge_dist; sd_v2->edge_length_sum += edge_dist; } if (smooth_weights == NULL) { /* fast-path */ for (i = 0; i < numVerts; i++) { struct SmoothingData_Weighted *sd = &smooth_data[i]; /* Divide by sum of all neighbour distances (weighted) and amount of neighbors, * (mean average). */ const float div = sd->edge_length_sum * vertex_edge_count[i]; if (div > eps) { #if 0 /* first calculate the new location */ mul_v3_fl(sd->delta, 1.0f / div); /* then interpolate */ madd_v3_v3fl(vertexCos[i], sd->delta, lambda); #else /* do this in one step */ madd_v3_v3fl(vertexCos[i], sd->delta, lambda / div); #endif } /* zero for the next iteration (saves memset on entire array) */ memset(sd, 0, sizeof(*sd)); } } else { for (i = 0; i < numVerts; i++) { struct SmoothingData_Weighted *sd = &smooth_data[i]; const float div = sd->edge_length_sum * vertex_edge_count[i]; if (div > eps) { const float lambda_w = lambda * smooth_weights[i]; madd_v3_v3fl(vertexCos[i], sd->delta, lambda_w / div); } memset(sd, 0, sizeof(*sd)); } } } MEM_freeN(vertex_edge_count); MEM_freeN(smooth_data); }
/* Simple Weighted Smoothing * * (average of surrounding verts) */ static void smooth_iter__simple(CorrectiveSmoothModifierData *csmd, Mesh *mesh, float (*vertexCos)[3], unsigned int numVerts, const float *smooth_weights, unsigned int iterations) { const float lambda = csmd->lambda; unsigned int i; const unsigned int numEdges = (unsigned int)mesh->totedge; const MEdge *edges = mesh->medge; float *vertex_edge_count_div; struct SmoothingData_Simple { float delta[3]; } *smooth_data = MEM_calloc_arrayN(numVerts, sizeof(*smooth_data), __func__); vertex_edge_count_div = MEM_calloc_arrayN(numVerts, sizeof(float), __func__); /* calculate as floats to avoid int->float conversion in #smooth_iter */ for (i = 0; i < numEdges; i++) { vertex_edge_count_div[edges[i].v1] += 1.0f; vertex_edge_count_div[edges[i].v2] += 1.0f; } /* a little confusing, but we can include 'lambda' and smoothing weight * here to avoid multiplying for every iteration */ if (smooth_weights == NULL) { for (i = 0; i < numVerts; i++) { vertex_edge_count_div[i] = lambda * (vertex_edge_count_div[i] ? (1.0f / vertex_edge_count_div[i]) : 1.0f); } } else { for (i = 0; i < numVerts; i++) { vertex_edge_count_div[i] = smooth_weights[i] * lambda * (vertex_edge_count_div[i] ? (1.0f / vertex_edge_count_div[i]) : 1.0f); } } /* -------------------------------------------------------------------- */ /* Main Smoothing Loop */ while (iterations--) { for (i = 0; i < numEdges; i++) { struct SmoothingData_Simple *sd_v1; struct SmoothingData_Simple *sd_v2; float edge_dir[3]; sub_v3_v3v3(edge_dir, vertexCos[edges[i].v2], vertexCos[edges[i].v1]); sd_v1 = &smooth_data[edges[i].v1]; sd_v2 = &smooth_data[edges[i].v2]; add_v3_v3(sd_v1->delta, edge_dir); sub_v3_v3(sd_v2->delta, edge_dir); } for (i = 0; i < numVerts; i++) { struct SmoothingData_Simple *sd = &smooth_data[i]; madd_v3_v3fl(vertexCos[i], sd->delta, vertex_edge_count_div[i]); /* zero for the next iteration (saves memset on entire array) */ memset(sd, 0, sizeof(*sd)); } } MEM_freeN(vertex_edge_count_div); MEM_freeN(smooth_data); }
static void createFacepa(ExplodeModifierData *emd, ParticleSystemModifierData *psmd, Mesh *mesh) { ParticleSystem *psys = psmd->psys; MFace *fa = NULL, *mface = NULL; MVert *mvert = NULL; ParticleData *pa; KDTree_3d *tree; RNG *rng; float center[3], co[3]; int *facepa = NULL, *vertpa = NULL, totvert = 0, totface = 0, totpart = 0; int i, p, v1, v2, v3, v4 = 0; mvert = mesh->mvert; mface = mesh->mface; totvert = mesh->totvert; totface = mesh->totface; totpart = psmd->psys->totpart; rng = BLI_rng_new_srandom(psys->seed); if (emd->facepa) { MEM_freeN(emd->facepa); } facepa = emd->facepa = MEM_calloc_arrayN(totface, sizeof(int), "explode_facepa"); vertpa = MEM_calloc_arrayN(totvert, sizeof(int), "explode_vertpa"); /* initialize all faces & verts to no particle */ for (i = 0; i < totface; i++) { facepa[i] = totpart; } for (i = 0; i < totvert; i++) { vertpa[i] = totpart; } /* set protected verts */ if (emd->vgroup) { MDeformVert *dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT); if (dvert) { const int defgrp_index = emd->vgroup - 1; for (i = 0; i < totvert; i++, dvert++) { float val = BLI_rng_get_float(rng); val = (1.0f - emd->protect) * val + emd->protect * 0.5f; if (val < defvert_find_weight(dvert, defgrp_index)) { vertpa[i] = -1; } } } } /* make tree of emitter locations */ tree = BLI_kdtree_3d_new(totpart); for (p = 0, pa = psys->particles; p < totpart; p++, pa++) { psys_particle_on_emitter(psmd, psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co, NULL, NULL, NULL, NULL); BLI_kdtree_3d_insert(tree, p, co); } BLI_kdtree_3d_balance(tree); /* set face-particle-indexes to nearest particle to face center */ for (i = 0, fa = mface; i < totface; i++, fa++) { add_v3_v3v3(center, mvert[fa->v1].co, mvert[fa->v2].co); add_v3_v3(center, mvert[fa->v3].co); if (fa->v4) { add_v3_v3(center, mvert[fa->v4].co); mul_v3_fl(center, 0.25); } else { mul_v3_fl(center, 1.0f / 3.0f); } p = BLI_kdtree_3d_find_nearest(tree, center, NULL); v1 = vertpa[fa->v1]; v2 = vertpa[fa->v2]; v3 = vertpa[fa->v3]; if (fa->v4) { v4 = vertpa[fa->v4]; } if (v1 >= 0 && v2 >= 0 && v3 >= 0 && (fa->v4 == 0 || v4 >= 0)) { facepa[i] = p; } if (v1 >= 0) { vertpa[fa->v1] = p; } if (v2 >= 0) { vertpa[fa->v2] = p; } if (v3 >= 0) { vertpa[fa->v3] = p; } if (fa->v4 && v4 >= 0) { vertpa[fa->v4] = p; } } if (vertpa) { MEM_freeN(vertpa); } BLI_kdtree_3d_free(tree); BLI_rng_free(rng); }
static Mesh *cutEdges(ExplodeModifierData *emd, Mesh *mesh) { Mesh *split_m; MFace *mf = NULL, *df1 = NULL; MFace *mface = mesh->mface; MVert *dupve, *mv; EdgeHash *edgehash; EdgeHashIterator *ehi; int totvert = mesh->totvert; int totface = mesh->totface; int *facesplit = MEM_calloc_arrayN(totface, sizeof(int), "explode_facesplit"); int *vertpa = MEM_calloc_arrayN(totvert, sizeof(int), "explode_vertpa2"); int *facepa = emd->facepa; int *fs, totesplit = 0, totfsplit = 0, curdupface = 0; int i, v1, v2, v3, v4, esplit, v[4] = {0, 0, 0, 0}, /* To quite gcc barking... */ uv[4] = {0, 0, 0, 0}; /* To quite gcc barking... */ int numlayer; unsigned int ed_v1, ed_v2; edgehash = BLI_edgehash_new(__func__); /* recreate vertpa from facepa calculation */ for (i = 0, mf = mface; i < totface; i++, mf++) { vertpa[mf->v1] = facepa[i]; vertpa[mf->v2] = facepa[i]; vertpa[mf->v3] = facepa[i]; if (mf->v4) { vertpa[mf->v4] = facepa[i]; } } /* mark edges for splitting and how to split faces */ for (i = 0, mf = mface, fs = facesplit; i < totface; i++, mf++, fs++) { v1 = vertpa[mf->v1]; v2 = vertpa[mf->v2]; v3 = vertpa[mf->v3]; if (v1 != v2) { BLI_edgehash_reinsert(edgehash, mf->v1, mf->v2, NULL); (*fs) |= 1; } if (v2 != v3) { BLI_edgehash_reinsert(edgehash, mf->v2, mf->v3, NULL); (*fs) |= 2; } if (mf->v4) { v4 = vertpa[mf->v4]; if (v3 != v4) { BLI_edgehash_reinsert(edgehash, mf->v3, mf->v4, NULL); (*fs) |= 4; } if (v1 != v4) { BLI_edgehash_reinsert(edgehash, mf->v1, mf->v4, NULL); (*fs) |= 8; } /* mark center vertex as a fake edge split */ if (*fs == 15) { BLI_edgehash_reinsert(edgehash, mf->v1, mf->v3, NULL); } } else { (*fs) |= 16; /* mark face as tri */ if (v1 != v3) { BLI_edgehash_reinsert(edgehash, mf->v1, mf->v3, NULL); (*fs) |= 4; } } } /* count splits & create indexes for new verts */ ehi = BLI_edgehashIterator_new(edgehash); totesplit = totvert; for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) { BLI_edgehashIterator_setValue(ehi, POINTER_FROM_INT(totesplit)); totesplit++; } BLI_edgehashIterator_free(ehi); /* count new faces due to splitting */ for (i = 0, fs = facesplit; i < totface; i++, fs++) { totfsplit += add_faces[*fs]; } split_m = BKE_mesh_new_nomain_from_template(mesh, totesplit, 0, totface + totfsplit, 0, 0); numlayer = CustomData_number_of_layers(&split_m->fdata, CD_MTFACE); /* copy new faces & verts (is it really this painful with custom data??) */ for (i = 0; i < totvert; i++) { MVert source; MVert *dest; source = mesh->mvert[i]; dest = &split_m->mvert[i]; CustomData_copy_data(&mesh->vdata, &split_m->vdata, i, i, 1); *dest = source; } /* override original facepa (original pointer is saved in caller function) */ /* BMESH_TODO, (totfsplit * 2) over allocation is used since the quads are * later interpreted as tri's, for this to work right I think we probably * have to stop using tessface - campbell */ facepa = MEM_calloc_arrayN((totface + (totfsplit * 2)), sizeof(int), "explode_facepa"); // memcpy(facepa, emd->facepa, totface*sizeof(int)); emd->facepa = facepa; /* create new verts */ ehi = BLI_edgehashIterator_new(edgehash); for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) { BLI_edgehashIterator_getKey(ehi, &ed_v1, &ed_v2); esplit = POINTER_AS_INT(BLI_edgehashIterator_getValue(ehi)); mv = &split_m->mvert[ed_v2]; dupve = &split_m->mvert[esplit]; CustomData_copy_data(&split_m->vdata, &split_m->vdata, ed_v2, esplit, 1); *dupve = *mv; mv = &split_m->mvert[ed_v1]; mid_v3_v3v3(dupve->co, dupve->co, mv->co); } BLI_edgehashIterator_free(ehi); /* create new faces */ curdupface = 0; //=totface; // curdupin=totesplit; for (i = 0, fs = facesplit; i < totface; i++, fs++) { mf = &mesh->mface[i]; switch (*fs) { case 3: case 10: case 11: case 15: SET_VERTS(1, 2, 3, 4); break; case 5: case 6: case 7: SET_VERTS(2, 3, 4, 1); break; case 9: case 13: SET_VERTS(4, 1, 2, 3); break; case 12: case 14: SET_VERTS(3, 4, 1, 2); break; case 21: case 23: SET_VERTS(1, 2, 3, 4); break; case 19: SET_VERTS(2, 3, 1, 4); break; case 22: SET_VERTS(3, 1, 2, 4); break; } switch (*fs) { case 3: case 6: case 9: case 12: remap_faces_3_6_9_12( mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]); if (numlayer) { remap_uvs_3_6_9_12(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]); } break; case 5: case 10: remap_faces_5_10( mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]); if (numlayer) { remap_uvs_5_10(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]); } break; case 15: remap_faces_15( mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]); if (numlayer) { remap_uvs_15(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]); } break; case 7: case 11: case 13: case 14: remap_faces_7_11_13_14( mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]); if (numlayer) { remap_uvs_7_11_13_14(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]); } break; case 19: case 21: case 22: remap_faces_19_21_22( mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2]); if (numlayer) { remap_uvs_19_21_22(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2]); } break; case 23: remap_faces_23( mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2]); if (numlayer) { remap_uvs_23(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2]); } break; case 0: case 16: df1 = get_dface(mesh, split_m, curdupface, i, mf); facepa[curdupface] = vertpa[mf->v1]; if (df1->v4) { df1->flag |= ME_FACE_SEL; } else { df1->flag &= ~ME_FACE_SEL; } break; } curdupface += add_faces[*fs] + 1; } for (i = 0; i < curdupface; i++) { mf = &split_m->mface[i]; test_index_face(mf, &split_m->fdata, i, ((mf->flag & ME_FACE_SEL) ? 4 : 3)); } BLI_edgehash_free(edgehash, NULL); MEM_freeN(facesplit); MEM_freeN(vertpa); BKE_mesh_calc_edges_tessface(split_m); BKE_mesh_convert_mfaces_to_mpolys(split_m); return split_m; }