static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) { BLI_assert(mesh != NULL); WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md; MDeformVert *dvert = NULL; MDeformWeight **dw1, **tdw1, **dw2, **tdw2; float *org_w; float *new_w; int *tidx, *indices = NULL; int numIdx = 0; int i; /* Flags. */ #if 0 const bool do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview) != 0; #endif /* Get number of verts. */ const int numVerts = mesh->totvert; /* Check if we can just return the original mesh. * Must have verts and therefore verts assigned to vgroups to do anything useful! */ if ((numVerts == 0) || BLI_listbase_is_empty(&ctx->object->defbase)) { return mesh; } /* Get vgroup idx from its name. */ const int defgrp_index = defgroup_name_index(ctx->object, wmd->defgrp_name_a); if (defgrp_index == -1) { return mesh; } /* Get second vgroup idx from its name, if given. */ int defgrp_index_other = -1; if (wmd->defgrp_name_b[0] != '\0') { defgrp_index_other = defgroup_name_index(ctx->object, wmd->defgrp_name_b); if (defgrp_index_other == -1) { return mesh; } } const bool has_mdef = CustomData_has_layer(&mesh->vdata, CD_MDEFORMVERT); /* If no vertices were ever added to an object's vgroup, dvert might be NULL. */ if (!has_mdef) { /* If not affecting all vertices, just return. */ if (wmd->mix_set != MOD_WVG_SET_ALL) { return mesh; } } if (has_mdef) { dvert = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MDEFORMVERT, numVerts); } else { /* Add a valid data layer! */ dvert = CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, numVerts); } /* Ultimate security check. */ if (!dvert) { return mesh; } mesh->dvert = dvert; /* Find out which vertices to work on. */ tidx = MEM_malloc_arrayN(numVerts, sizeof(int), "WeightVGMix Modifier, tidx"); tdw1 = MEM_malloc_arrayN(numVerts, sizeof(MDeformWeight *), "WeightVGMix Modifier, tdw1"); tdw2 = MEM_malloc_arrayN(numVerts, sizeof(MDeformWeight *), "WeightVGMix Modifier, tdw2"); switch (wmd->mix_set) { case MOD_WVG_SET_A: /* All vertices in first vgroup. */ for (i = 0; i < numVerts; i++) { MDeformWeight *dw = defvert_find_index(&dvert[i], defgrp_index); if (dw) { tdw1[numIdx] = dw; tdw2[numIdx] = (defgrp_index_other >= 0) ? defvert_find_index(&dvert[i], defgrp_index_other) : NULL; tidx[numIdx++] = i; } } break; case MOD_WVG_SET_B: /* All vertices in second vgroup. */ for (i = 0; i < numVerts; i++) { MDeformWeight *dw = (defgrp_index_other >= 0) ? defvert_find_index(&dvert[i], defgrp_index_other) : NULL; if (dw) { tdw1[numIdx] = defvert_find_index(&dvert[i], defgrp_index); tdw2[numIdx] = dw; tidx[numIdx++] = i; } } break; case MOD_WVG_SET_OR: /* All vertices in one vgroup or the other. */ for (i = 0; i < numVerts; i++) { MDeformWeight *adw = defvert_find_index(&dvert[i], defgrp_index); MDeformWeight *bdw = (defgrp_index_other >= 0) ? defvert_find_index(&dvert[i], defgrp_index_other) : NULL; if (adw || bdw) { tdw1[numIdx] = adw; tdw2[numIdx] = bdw; tidx[numIdx++] = i; } } break; case MOD_WVG_SET_AND: /* All vertices in both vgroups. */ for (i = 0; i < numVerts; i++) { MDeformWeight *adw = defvert_find_index(&dvert[i], defgrp_index); MDeformWeight *bdw = (defgrp_index_other >= 0) ? defvert_find_index(&dvert[i], defgrp_index_other) : NULL; if (adw && bdw) { tdw1[numIdx] = adw; tdw2[numIdx] = bdw; tidx[numIdx++] = i; } } break; case MOD_WVG_SET_ALL: default: /* Use all vertices. */ for (i = 0; i < numVerts; i++) { tdw1[i] = defvert_find_index(&dvert[i], defgrp_index); tdw2[i] = (defgrp_index_other >= 0) ? defvert_find_index(&dvert[i], defgrp_index_other) : NULL; } numIdx = -1; break; } if (numIdx == 0) { /* Use no vertices! Hence, return org data. */ MEM_freeN(tdw1); MEM_freeN(tdw2); MEM_freeN(tidx); return mesh; } if (numIdx != -1) { indices = MEM_malloc_arrayN(numIdx, sizeof(int), "WeightVGMix Modifier, indices"); memcpy(indices, tidx, sizeof(int) * numIdx); dw1 = MEM_malloc_arrayN(numIdx, sizeof(MDeformWeight *), "WeightVGMix Modifier, dw1"); memcpy(dw1, tdw1, sizeof(MDeformWeight *) * numIdx); MEM_freeN(tdw1); dw2 = MEM_malloc_arrayN(numIdx, sizeof(MDeformWeight *), "WeightVGMix Modifier, dw2"); memcpy(dw2, tdw2, sizeof(MDeformWeight *) * numIdx); MEM_freeN(tdw2); } else { /* Use all vertices. */ numIdx = numVerts; /* Just copy MDeformWeight pointers arrays, they will be freed at the end. */ dw1 = tdw1; dw2 = tdw2; } MEM_freeN(tidx); org_w = MEM_malloc_arrayN(numIdx, sizeof(float), "WeightVGMix Modifier, org_w"); new_w = MEM_malloc_arrayN(numIdx, sizeof(float), "WeightVGMix Modifier, new_w"); /* Mix weights. */ for (i = 0; i < numIdx; i++) { float weight2; org_w[i] = dw1[i] ? dw1[i]->weight : wmd->default_weight_a; weight2 = dw2[i] ? dw2[i]->weight : wmd->default_weight_b; new_w[i] = mix_weight(org_w[i], weight2, wmd->mix_mode); } /* Do masking. */ struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); weightvg_do_mask(ctx, numIdx, indices, org_w, new_w, ctx->object, mesh, wmd->mask_constant, wmd->mask_defgrp_name, scene, wmd->mask_texture, wmd->mask_tex_use_channel, wmd->mask_tex_mapping, wmd->mask_tex_map_obj, wmd->mask_tex_uvlayer_name); /* Update (add to) vgroup. * XXX Depending on the MOD_WVG_SET_xxx option chosen, we might have to add vertices to vgroup. */ weightvg_update_vg( dvert, defgrp_index, dw1, numIdx, indices, org_w, true, -FLT_MAX, false, 0.0f); /* If weight preview enabled... */ #if 0 /* XXX Currently done in mod stack :/ */ if (do_prev) DM_update_weight_mcol(ob, dm, 0, org_w, numIdx, indices); #endif /* Freeing stuff. */ MEM_freeN(org_w); MEM_freeN(new_w); MEM_freeN(dw1); MEM_freeN(dw2); MEM_SAFE_FREE(indices); /* Return the vgroup-modified mesh. */ return mesh; }
void calc_latt_deform(LatticeDeformData *lattice_deform_data, float co[3], float weight) { Object *ob = lattice_deform_data->object; Lattice *lt = ob->data; float u, v, w, tu[4], tv[4], tw[4]; float vec[3]; int idx_w, idx_v, idx_u; int ui, vi, wi, uu, vv, ww; /* vgroup influence */ int defgrp_index = -1; float co_prev[3], weight_blend = 0.0f; MDeformVert *dvert = BKE_lattice_deform_verts_get(ob); if (lt->editlatt) lt = lt->editlatt->latt; if (lattice_deform_data->latticedata == NULL) return; if (lt->vgroup[0] && dvert) { defgrp_index = defgroup_name_index(ob, lt->vgroup); copy_v3_v3(co_prev, co); } /* co is in local coords, treat with latmat */ mul_v3_m4v3(vec, lattice_deform_data->latmat, co); /* u v w coords */ if (lt->pntsu > 1) { u = (vec[0] - lt->fu) / lt->du; ui = (int)floor(u); u -= ui; key_curve_position_weights(u, tu, lt->typeu); } else { tu[0] = tu[2] = tu[3] = 0.0; tu[1] = 1.0; ui = 0; } if (lt->pntsv > 1) { v = (vec[1] - lt->fv) / lt->dv; vi = (int)floor(v); v -= vi; key_curve_position_weights(v, tv, lt->typev); } else { tv[0] = tv[2] = tv[3] = 0.0; tv[1] = 1.0; vi = 0; } if (lt->pntsw > 1) { w = (vec[2] - lt->fw) / lt->dw; wi = (int)floor(w); w -= wi; key_curve_position_weights(w, tw, lt->typew); } else { tw[0] = tw[2] = tw[3] = 0.0; tw[1] = 1.0; wi = 0; } for (ww = wi - 1; ww <= wi + 2; ww++) { w = tw[ww - wi + 1]; if (w != 0.0f) { if (ww > 0) { if (ww < lt->pntsw) idx_w = ww * lt->pntsu * lt->pntsv; else idx_w = (lt->pntsw - 1) * lt->pntsu * lt->pntsv; } else { idx_w = 0; } for (vv = vi - 1; vv <= vi + 2; vv++) { v = w * tv[vv - vi + 1]; if (v != 0.0f) { if (vv > 0) { if (vv < lt->pntsv) idx_v = idx_w + vv * lt->pntsu; else idx_v = idx_w + (lt->pntsv - 1) * lt->pntsu; } else { idx_v = idx_w; } for (uu = ui - 1; uu <= ui + 2; uu++) { u = weight * v * tu[uu - ui + 1]; if (u != 0.0f) { if (uu > 0) { if (uu < lt->pntsu) idx_u = idx_v + uu; else idx_u = idx_v + (lt->pntsu - 1); } else { idx_u = idx_v; } madd_v3_v3fl(co, &lattice_deform_data->latticedata[idx_u * 3], u); if (defgrp_index != -1) weight_blend += (u * defvert_find_weight(dvert + idx_u, defgrp_index)); } } } } } } if (defgrp_index != -1) interp_v3_v3v3(co, co_prev, co, weight_blend); }
void curve_deform_verts( Scene *scene, Object *cuOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3], int numVerts, const char *vgroup, short defaxis) { Curve *cu; int a; CurveDeform cd; MDeformVert *dvert = NULL; int defgrp_index = -1; const bool is_neg_axis = (defaxis > 2); if (cuOb->type != OB_CURVE) return; cu = cuOb->data; init_curve_deform(cuOb, target, &cd); /* dummy bounds, keep if CU_DEFORM_BOUNDS_OFF is set */ if (is_neg_axis == false) { cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = 0.0f; cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 1.0f; } else { /* negative, these bounds give a good rest position */ cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = -1.0f; cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 0.0f; } /* Check whether to use vertex groups (only possible if target is a Mesh or Lattice). * We want either a Mesh/Lattice with no derived data, or derived data with deformverts. */ if (vgroup && vgroup[0] && ELEM(target->type, OB_MESH, OB_LATTICE)) { defgrp_index = defgroup_name_index(target, vgroup); if (defgrp_index != -1) { /* if there's derived data without deformverts, don't use vgroups */ if (dm) { dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); } else if (target->type == OB_LATTICE) { dvert = ((Lattice *)target->data)->dvert; } else { dvert = ((Mesh *)target->data)->dvert; } } } if (dvert) { MDeformVert *dvert_iter; float vec[3]; if (cu->flag & CU_DEFORM_BOUNDS_OFF) { for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) { const float weight = defvert_find_weight(dvert_iter, defgrp_index); if (weight > 0.0f) { mul_m4_v3(cd.curvespace, vertexCos[a]); copy_v3_v3(vec, vertexCos[a]); calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL); interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight); mul_m4_v3(cd.objectspace, vertexCos[a]); } } } else { /* set mesh min/max bounds */ INIT_MINMAX(cd.dmin, cd.dmax); for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) { if (defvert_find_weight(dvert_iter, defgrp_index) > 0.0f) { mul_m4_v3(cd.curvespace, vertexCos[a]); minmax_v3v3_v3(cd.dmin, cd.dmax, vertexCos[a]); } } for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) { const float weight = defvert_find_weight(dvert_iter, defgrp_index); if (weight > 0.0f) { /* already in 'cd.curvespace', prev for loop */ copy_v3_v3(vec, vertexCos[a]); calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL); interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight); mul_m4_v3(cd.objectspace, vertexCos[a]); } } } } else { if (cu->flag & CU_DEFORM_BOUNDS_OFF) { for (a = 0; a < numVerts; a++) { mul_m4_v3(cd.curvespace, vertexCos[a]); calc_curve_deform(scene, cuOb, vertexCos[a], defaxis, &cd, NULL); mul_m4_v3(cd.objectspace, vertexCos[a]); } } else { /* set mesh min max bounds */ INIT_MINMAX(cd.dmin, cd.dmax); for (a = 0; a < numVerts; a++) { mul_m4_v3(cd.curvespace, vertexCos[a]); minmax_v3v3_v3(cd.dmin, cd.dmax, vertexCos[a]); } for (a = 0; a < numVerts; a++) { /* already in 'cd.curvespace', prev for loop */ calc_curve_deform(scene, cuOb, vertexCos[a], defaxis, &cd, NULL); mul_m4_v3(cd.objectspace, vertexCos[a]); } } } }
void curve_deform_verts(Scene *scene, Object *cuOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3], int numVerts, const char *vgroup, short defaxis) { Curve *cu; int a, flag; CurveDeform cd; int use_vgroups; const int is_neg_axis = (defaxis > 2); if (cuOb->type != OB_CURVE) return; cu = cuOb->data; flag = cu->flag; cu->flag |= (CU_PATH | CU_FOLLOW); // needed for path & bevlist init_curve_deform(cuOb, target, &cd); /* dummy bounds, keep if CU_DEFORM_BOUNDS_OFF is set */ if (is_neg_axis == FALSE) { cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = 0.0f; cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 1.0f; } else { /* negative, these bounds give a good rest position */ cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = -1.0f; cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 0.0f; } /* check whether to use vertex groups (only possible if target is a Mesh) * we want either a Mesh with no derived data, or derived data with * deformverts */ if (target && target->type == OB_MESH) { /* if there's derived data without deformverts, don't use vgroups */ if (dm) { use_vgroups = (dm->getVertData(dm, 0, CD_MDEFORMVERT) != NULL); } else { Mesh *me = target->data; use_vgroups = (me->dvert != NULL); } } else { use_vgroups = FALSE; } if (vgroup && vgroup[0] && use_vgroups) { Mesh *me = target->data; const int defgrp_index = defgroup_name_index(target, vgroup); if (defgrp_index != -1 && (me->dvert || dm)) { MDeformVert *dvert = me->dvert; float vec[3]; float weight; if (cu->flag & CU_DEFORM_BOUNDS_OFF) { dvert = me->dvert; for (a = 0; a < numVerts; a++, dvert++) { if (dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT); weight = defvert_find_weight(dvert, defgrp_index); if (weight > 0.0f) { mul_m4_v3(cd.curvespace, vertexCos[a]); copy_v3_v3(vec, vertexCos[a]); calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL); interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight); mul_m4_v3(cd.objectspace, vertexCos[a]); } } } else { /* set mesh min/max bounds */ INIT_MINMAX(cd.dmin, cd.dmax); for (a = 0; a < numVerts; a++, dvert++) { if (dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT); if (defvert_find_weight(dvert, defgrp_index) > 0.0f) { mul_m4_v3(cd.curvespace, vertexCos[a]); minmax_v3v3_v3(cd.dmin, cd.dmax, vertexCos[a]); } } dvert = me->dvert; for (a = 0; a < numVerts; a++, dvert++) { if (dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT); weight = defvert_find_weight(dvert, defgrp_index); if (weight > 0.0f) { /* already in 'cd.curvespace', prev for loop */ copy_v3_v3(vec, vertexCos[a]); calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL); interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight); mul_m4_v3(cd.objectspace, vertexCos[a]); } } } } } else { if (cu->flag & CU_DEFORM_BOUNDS_OFF) { for (a = 0; a < numVerts; a++) { mul_m4_v3(cd.curvespace, vertexCos[a]); calc_curve_deform(scene, cuOb, vertexCos[a], defaxis, &cd, NULL); mul_m4_v3(cd.objectspace, vertexCos[a]); } } else { /* set mesh min max bounds */ INIT_MINMAX(cd.dmin, cd.dmax); for (a = 0; a < numVerts; a++) { mul_m4_v3(cd.curvespace, vertexCos[a]); minmax_v3v3_v3(cd.dmin, cd.dmax, vertexCos[a]); } for (a = 0; a < numVerts; a++) { /* already in 'cd.curvespace', prev for loop */ calc_curve_deform(scene, cuOb, vertexCos[a], defaxis, &cd, NULL); mul_m4_v3(cd.objectspace, vertexCos[a]); } } } cu->flag = flag; }
/* Applies new_w weights to org_w ones, using either a texture, vgroup or constant value as factor. * Return values are in org_w. * If indices is not NULL, it must be a table of same length as org_w and new_w, mapping to the real * vertex index (in case the weight tables do not cover the whole vertices...). * XXX The standard "factor" value is assumed in [0.0, 1.0] range. Else, weird results might appear. */ void weightvg_do_mask(int num, const int *indices, float *org_w, const float *new_w, Object *ob, DerivedMesh *dm, float fact, const char defgrp_name[MAX_VGROUP_NAME], Scene *scene, Tex *texture, int tex_use_channel, int tex_mapping, Object *tex_map_object, const char *tex_uvlayer_name) { int ref_didx; int i; /* If influence factor is null, nothing to do! */ if (fact == 0.0f) return; /* If we want to mask vgroup weights from a texture. */ if (texture) { /* The texture coordinates. */ float (*tex_co)[3]; /* See mapping note below... */ MappingInfoModifierData t_map; float (*v_co)[3]; int numVerts = dm->getNumVerts(dm); /* Use new generic get_texture_coords, but do not modify our DNA struct for it... * XXX Why use a ModifierData stuff here ? Why not a simple, generic struct for parameters ? * What e.g. if a modifier wants to use several textures ? * Why use only v_co, and not MVert (or both) ? */ t_map.texture = texture; t_map.map_object = tex_map_object; BLI_strncpy(t_map.uvlayer_name, tex_uvlayer_name, sizeof(t_map.uvlayer_name)); t_map.texmapping = tex_mapping; v_co = MEM_mallocN(sizeof(*v_co) * numVerts, "WeightVG Modifier, TEX mode, v_co"); dm->getVertCos(dm, v_co); tex_co = MEM_callocN(sizeof(*tex_co) * numVerts, "WeightVG Modifier, TEX mode, tex_co"); get_texture_coords(&t_map, ob, dm, v_co, tex_co, num); MEM_freeN(v_co); modifier_init_texture(scene, texture); /* For each weight (vertex), make the mix between org and new weights. */ for (i = 0; i < num; ++i) { int idx = indices ? indices[i] : i; TexResult texres; float hsv[3]; /* For HSV color space. */ bool do_color_manage; do_color_manage = tex_use_channel != MOD_WVG_MASK_TEX_USE_INT; texres.nor = NULL; BKE_texture_get_value(scene, texture, tex_co[idx], &texres, do_color_manage); /* Get the good channel value... */ switch (tex_use_channel) { case MOD_WVG_MASK_TEX_USE_INT: org_w[i] = (new_w[i] * texres.tin * fact) + (org_w[i] * (1.0f - (texres.tin * fact))); break; case MOD_WVG_MASK_TEX_USE_RED: org_w[i] = (new_w[i] * texres.tr * fact) + (org_w[i] * (1.0f - (texres.tr * fact))); break; case MOD_WVG_MASK_TEX_USE_GREEN: org_w[i] = (new_w[i] * texres.tg * fact) + (org_w[i] * (1.0f - (texres.tg * fact))); break; case MOD_WVG_MASK_TEX_USE_BLUE: org_w[i] = (new_w[i] * texres.tb * fact) + (org_w[i] * (1.0f - (texres.tb * fact))); break; case MOD_WVG_MASK_TEX_USE_HUE: rgb_to_hsv_v(&texres.tr, hsv); org_w[i] = (new_w[i] * hsv[0] * fact) + (org_w[i] * (1.0f - (hsv[0] * fact))); break; case MOD_WVG_MASK_TEX_USE_SAT: rgb_to_hsv_v(&texres.tr, hsv); org_w[i] = (new_w[i] * hsv[1] * fact) + (org_w[i] * (1.0f - (hsv[1] * fact))); break; case MOD_WVG_MASK_TEX_USE_VAL: rgb_to_hsv_v(&texres.tr, hsv); org_w[i] = (new_w[i] * hsv[2] * fact) + (org_w[i] * (1.0f - (hsv[2] * fact))); break; case MOD_WVG_MASK_TEX_USE_ALPHA: org_w[i] = (new_w[i] * texres.ta * fact) + (org_w[i] * (1.0f - (texres.ta * fact))); break; default: org_w[i] = (new_w[i] * texres.tin * fact) + (org_w[i] * (1.0f - (texres.tin * fact))); break; } } MEM_freeN(tex_co); } else if ((ref_didx = defgroup_name_index(ob, defgrp_name)) != -1) { MDeformVert *dvert = NULL; /* Check whether we want to set vgroup weights from a constant weight factor or a vertex * group. */ /* Get vgroup idx from its name. */ /* Proceed only if vgroup is valid, else use constant factor. */ /* Get actual dverts (ie vertex group data). */ dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); /* Proceed only if vgroup is valid, else assume factor = O. */ if (dvert == NULL) return; /* For each weight (vertex), make the mix between org and new weights. */ for (i = 0; i < num; i++) { int idx = indices ? indices[i] : i; const float f = defvert_find_weight(&dvert[idx], ref_didx) * fact; org_w[i] = (new_w[i] * f) + (org_w[i] * (1.0f - f)); /* If that vertex is not in ref vgroup, assume null factor, and hence do nothing! */ } } else { /* Default "influence" behavior. */ /* For each weight (vertex), make the mix between org and new weights. */ const float ifact = 1.0f - fact; for (i = 0; i < num; i++) { org_w[i] = (new_w[i] * fact) + (org_w[i] * ifact); } } }
static bool data_transfer_layersmapping_vgroups_multisrc_to_dst( ListBase *r_map, const int mix_mode, const float mix_factor, const float *mix_weights, const int num_elem_dst, const bool use_create, const bool use_delete, Object *ob_src, Object *ob_dst, MDeformVert *data_src, MDeformVert *data_dst, CustomData *UNUSED(cd_src), CustomData *cd_dst, const bool UNUSED(use_dupref_dst), const int tolayers, bool *use_layers_src, const int num_layers_src) { int idx_src; int idx_dst; int tot_dst = BLI_listbase_count(&ob_dst->defbase); const size_t elem_size = sizeof(*((MDeformVert *)NULL)); switch (tolayers) { case DT_LAYERS_INDEX_DST: idx_dst = tot_dst; /* Find last source actually used! */ idx_src = num_layers_src; while (idx_src-- && !use_layers_src[idx_src]); idx_src++; if (idx_dst < idx_src) { if (!use_create) { return false; } /* Create as much vgroups as necessary! */ for (; idx_dst < idx_src; idx_dst++) { BKE_object_defgroup_add(ob_dst); } } else if (use_delete && idx_dst > idx_src) { while (idx_dst-- > idx_src) { BKE_object_defgroup_remove(ob_dst, ob_dst->defbase.last); } } if (r_map) { /* At this stage, we **need** a valid CD_MDEFORMVERT layer on dest! * Again, use_create is not relevant in this case */ if (!data_dst) { data_dst = CustomData_add_layer(cd_dst, CD_MDEFORMVERT, CD_CALLOC, NULL, num_elem_dst); } while (idx_src--) { if (!use_layers_src[idx_src]) { continue; } data_transfer_layersmapping_add_item(r_map, CD_FAKE_MDEFORMVERT, mix_mode, mix_factor, mix_weights, data_src, data_dst, idx_src, idx_src, elem_size, 0, 0, 0, vgroups_datatransfer_interp); } } break; case DT_LAYERS_NAME_DST: { bDeformGroup *dg_src, *dg_dst; if (use_delete) { /* Remove all unused dst vgroups first, simpler in this case. */ for (dg_dst = ob_dst->defbase.first; dg_dst;) { bDeformGroup *dg_dst_next = dg_dst->next; if (defgroup_name_index(ob_src, dg_dst->name) == -1) { BKE_object_defgroup_remove(ob_dst, dg_dst); } dg_dst = dg_dst_next; } } for (idx_src = 0, dg_src = ob_src->defbase.first; idx_src < num_layers_src; idx_src++, dg_src = dg_src->next) { if (!use_layers_src[idx_src]) { continue; } if ((idx_dst = defgroup_name_index(ob_dst, dg_src->name)) == -1) { if (!use_create) { if (r_map) { BLI_freelistN(r_map); } return false; } BKE_object_defgroup_add_name(ob_dst, dg_src->name); idx_dst = ob_dst->actdef - 1; } if (r_map) { /* At this stage, we **need** a valid CD_MDEFORMVERT layer on dest! * use_create is not relevant in this case */ if (!data_dst) { data_dst = CustomData_add_layer(cd_dst, CD_MDEFORMVERT, CD_CALLOC, NULL, num_elem_dst); } data_transfer_layersmapping_add_item( r_map, CD_FAKE_MDEFORMVERT, mix_mode, mix_factor, mix_weights, data_src, data_dst, idx_src, idx_dst, elem_size, 0, 0, 0, vgroups_datatransfer_interp); } } break; } default: return false; } return true; }
bool data_transfer_layersmapping_vgroups( ListBase *r_map, const int mix_mode, const float mix_factor, const float *mix_weights, const int num_elem_dst, const bool use_create, const bool use_delete, Object *ob_src, Object *ob_dst, CustomData *cd_src, CustomData *cd_dst, const bool use_dupref_dst, const int fromlayers, const int tolayers) { int idx_src, idx_dst; MDeformVert *data_src, *data_dst = NULL; const size_t elem_size = sizeof(*((MDeformVert *)NULL)); /* Note: VGroups are a bit hairy, since their layout is defined on object level (ob->defbase), while their actual * data is a (mesh) CD layer. * This implies we may have to handle data layout itself while having NULL data itself, * and even have to support NULL data_src in transfer data code (we always create a data_dst, though). */ if (BLI_listbase_is_empty(&ob_src->defbase)) { if (use_delete) { BKE_object_defgroup_remove_all(ob_dst); } return true; } data_src = CustomData_get_layer(cd_src, CD_MDEFORMVERT); data_dst = CustomData_get_layer(cd_dst, CD_MDEFORMVERT); if (data_dst && use_dupref_dst && r_map) { /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */ data_dst = CustomData_duplicate_referenced_layer(cd_dst, CD_MDEFORMVERT, num_elem_dst); } if (fromlayers == DT_LAYERS_ACTIVE_SRC || fromlayers >= 0) { /* Note: use_delete has not much meaning in this case, ignored. */ if (fromlayers >= 0) { idx_src = fromlayers; BLI_assert(idx_src < BLI_listbase_count(&ob_src->defbase)); } else if ((idx_src = ob_src->actdef - 1) == -1) { return false; } if (tolayers >= 0) { /* Note: in this case we assume layer exists! */ idx_dst = tolayers; BLI_assert(idx_dst < BLI_listbase_count(&ob_dst->defbase)); } else if (tolayers == DT_LAYERS_ACTIVE_DST) { if ((idx_dst = ob_dst->actdef - 1) == -1) { bDeformGroup *dg_src; if (!use_create) { return true; } dg_src = BLI_findlink(&ob_src->defbase, idx_src); BKE_object_defgroup_add_name(ob_dst, dg_src->name); idx_dst = ob_dst->actdef - 1; } } else if (tolayers == DT_LAYERS_INDEX_DST) { int num = BLI_listbase_count(&ob_src->defbase); idx_dst = idx_src; if (num <= idx_dst) { if (!use_create) { return true; } /* Create as much vgroups as necessary! */ for (; num <= idx_dst; num++) { BKE_object_defgroup_add(ob_dst); } } } else if (tolayers == DT_LAYERS_NAME_DST) { bDeformGroup *dg_src = BLI_findlink(&ob_src->defbase, idx_src); if ((idx_dst = defgroup_name_index(ob_dst, dg_src->name)) == -1) { if (!use_create) { return true; } BKE_object_defgroup_add_name(ob_dst, dg_src->name); idx_dst = ob_dst->actdef - 1; } } else { return false; } if (r_map) { /* At this stage, we **need** a valid CD_MDEFORMVERT layer on dest! * use_create is not relevant in this case */ if (!data_dst) { data_dst = CustomData_add_layer(cd_dst, CD_MDEFORMVERT, CD_CALLOC, NULL, num_elem_dst); } data_transfer_layersmapping_add_item(r_map, CD_FAKE_MDEFORMVERT, mix_mode, mix_factor, mix_weights, data_src, data_dst, idx_src, idx_dst, elem_size, 0, 0, 0, vgroups_datatransfer_interp); } } else { int num_src, num_sel_unused; bool *use_layers_src = NULL; bool ret = false; switch (fromlayers) { case DT_LAYERS_ALL_SRC: use_layers_src = BKE_object_defgroup_subset_from_select_type(ob_src, WT_VGROUP_ALL, &num_src, &num_sel_unused); break; case DT_LAYERS_VGROUP_SRC_BONE_SELECT: use_layers_src = BKE_object_defgroup_subset_from_select_type(ob_src, WT_VGROUP_BONE_SELECT, &num_src, &num_sel_unused); break; case DT_LAYERS_VGROUP_SRC_BONE_DEFORM: use_layers_src = BKE_object_defgroup_subset_from_select_type(ob_src, WT_VGROUP_BONE_DEFORM, &num_src, &num_sel_unused); break; } if (use_layers_src) { ret = data_transfer_layersmapping_vgroups_multisrc_to_dst( r_map, mix_mode, mix_factor, mix_weights, num_elem_dst, use_create, use_delete, ob_src, ob_dst, data_src, data_dst, cd_src, cd_dst, use_dupref_dst, tolayers, use_layers_src, num_src); } MEM_SAFE_FREE(use_layers_src); return ret; } return true; }
bool BKE_object_data_transfer_dm( Scene *scene, Object *ob_src, Object *ob_dst, DerivedMesh *dm_dst, const int data_types, bool use_create, const int map_vert_mode, const int map_edge_mode, const int map_loop_mode, const int map_poly_mode, SpaceTransform *space_transform, const bool auto_transform, const float max_distance, const float ray_radius, const float islands_handling_precision, const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX], const int mix_mode, const float mix_factor, const char *vgroup_name, const bool invert_vgroup, ReportList *reports) { #define VDATA 0 #define EDATA 1 #define LDATA 2 #define PDATA 3 #define DATAMAX 4 SpaceTransform auto_space_transform; DerivedMesh *dm_src; Mesh *me_dst, *me_src; bool dirty_nors_dst = true; /* Assumed always true if not using a dm as destination. */ int i; MDeformVert *mdef = NULL; int vg_idx = -1; float *weights[DATAMAX] = {NULL}; MeshPairRemap geom_map[DATAMAX] = {{0}}; bool geom_map_init[DATAMAX] = {0}; ListBase lay_map = {NULL}; bool changed = false; const bool use_delete = false; /* We never delete data layers from destination here. */ CustomDataMask dm_src_mask = CD_MASK_BAREMESH; BLI_assert((ob_src != ob_dst) && (ob_src->type == OB_MESH) && (ob_dst->type == OB_MESH)); me_dst = ob_dst->data; me_src = ob_src->data; if (dm_dst) { dirty_nors_dst = (dm_dst->dirty & DM_DIRTY_NORMALS) != 0; use_create = false; /* Never create needed custom layers on DM (modifier case). */ } if (vgroup_name) { if (dm_dst) { mdef = dm_dst->getVertDataArray(dm_dst, CD_MDEFORMVERT); } else { mdef = CustomData_get_layer(&me_dst->vdata, CD_MDEFORMVERT); } if (mdef) { vg_idx = defgroup_name_index(ob_dst, vgroup_name); } } /* Get source DM.*/ dm_src_mask |= BKE_object_data_transfer_dttypes_to_cdmask(data_types); /* XXX Hack! In case this is being evaluated from dm stack, we cannot compute final dm, * can lead to infinite recursion in case of dependency cycles of DataTransfer modifiers... * Issue is, this means we cannot be sure to have requested cd layers in source. * * Also, we need to make a local copy of dm_src, otherwise we may end with concurrent creation * of data in it (multi-threaded evaluation of the modifier stack, see T46672). */ dm_src = dm_dst ? ob_src->derivedFinal : mesh_get_derived_final(scene, ob_src, dm_src_mask); if (!dm_src) { return changed; } dm_src = CDDM_copy(dm_src); if (auto_transform) { MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert; const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert; if (space_transform == NULL) { space_transform = &auto_space_transform; } BKE_mesh_remap_find_best_match_from_dm(verts_dst, num_verts_dst, dm_src, space_transform); } /* Check all possible data types. * Note item mappings and dest mix weights are cached. */ for (i = 0; i < DT_TYPE_MAX; i++) { const int dtdata_type = 1 << i; int cddata_type; int fromlayers, tolayers, fromto_idx; if (!(data_types & dtdata_type)) { continue; } data_transfer_dtdata_type_preprocess(ob_src, ob_dst, dm_src, dm_dst, me_dst, dtdata_type, dirty_nors_dst, (me_src->flag & ME_AUTOSMOOTH) != 0, me_src->smoothresh); cddata_type = BKE_object_data_transfer_dttype_to_cdtype(dtdata_type); fromto_idx = BKE_object_data_transfer_dttype_to_srcdst_index(dtdata_type); if (fromto_idx != DT_MULTILAYER_INDEX_INVALID) { fromlayers = fromlayers_select[fromto_idx]; tolayers = tolayers_select[fromto_idx]; } else { fromlayers = tolayers = 0; } if (DT_DATATYPE_IS_VERT(dtdata_type)) { MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert; const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert; if (!geom_map_init[VDATA]) { const int num_verts_src = dm_src->getNumVerts(dm_src); if ((map_vert_mode == MREMAP_MODE_TOPOLOGY) && (num_verts_dst != num_verts_src)) { BKE_report(reports, RPT_ERROR, "Source and destination meshes do not have the same amount of vertices, " "'Topology' mapping cannot be used in this case"); continue; } if (ELEM(0, num_verts_dst, num_verts_src)) { BKE_report(reports, RPT_ERROR, "Source or destination meshes do not have any vertices, cannot transfer vertex data"); continue; } BKE_mesh_remap_calc_verts_from_dm( map_vert_mode, space_transform, max_distance, ray_radius, verts_dst, num_verts_dst, dirty_nors_dst, dm_src, &geom_map[VDATA]); geom_map_init[VDATA] = true; } if (mdef && vg_idx != -1 && !weights[VDATA]) { weights[VDATA] = MEM_mallocN(sizeof(*(weights[VDATA])) * (size_t)num_verts_dst, __func__); BKE_defvert_extract_vgroup_to_vertweights(mdef, vg_idx, num_verts_dst, weights[VDATA], invert_vgroup); } if (data_transfer_layersmapping_generate( &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_VERT, cddata_type, mix_mode, mix_factor, weights[VDATA], num_verts_dst, use_create, use_delete, fromlayers, tolayers, space_transform)) { CustomDataTransferLayerMap *lay_mapit; changed = (lay_map.first != NULL); for (lay_mapit = lay_map.first; lay_mapit; lay_mapit = lay_mapit->next) { CustomData_data_transfer(&geom_map[VDATA], lay_mapit); } BLI_freelistN(&lay_map); } } if (DT_DATATYPE_IS_EDGE(dtdata_type)) { MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert; const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert; MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge; const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge; if (!geom_map_init[EDATA]) { const int num_edges_src = dm_src->getNumEdges(dm_src); if ((map_edge_mode == MREMAP_MODE_TOPOLOGY) && (num_edges_dst != num_edges_src)) { BKE_report(reports, RPT_ERROR, "Source and destination meshes do not have the same amount of edges, " "'Topology' mapping cannot be used in this case"); continue; } if (ELEM(0, num_edges_dst, num_edges_src)) { BKE_report(reports, RPT_ERROR, "Source or destination meshes do not have any edges, cannot transfer edge data"); continue; } BKE_mesh_remap_calc_edges_from_dm( map_edge_mode, space_transform, max_distance, ray_radius, verts_dst, num_verts_dst, edges_dst, num_edges_dst, dirty_nors_dst, dm_src, &geom_map[EDATA]); geom_map_init[EDATA] = true; } if (mdef && vg_idx != -1 && !weights[EDATA]) { weights[EDATA] = MEM_mallocN(sizeof(*weights[EDATA]) * (size_t)num_edges_dst, __func__); BKE_defvert_extract_vgroup_to_edgeweights( mdef, vg_idx, num_verts_dst, edges_dst, num_edges_dst, weights[EDATA], invert_vgroup); } if (data_transfer_layersmapping_generate( &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_EDGE, cddata_type, mix_mode, mix_factor, weights[EDATA], num_edges_dst, use_create, use_delete, fromlayers, tolayers, space_transform)) { CustomDataTransferLayerMap *lay_mapit; changed = (lay_map.first != NULL); for (lay_mapit = lay_map.first; lay_mapit; lay_mapit = lay_mapit->next) { CustomData_data_transfer(&geom_map[EDATA], lay_mapit); } BLI_freelistN(&lay_map); } } if (DT_DATATYPE_IS_LOOP(dtdata_type)) { MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert; const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert; MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge; const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge; MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly; const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly; MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop; const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop; CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata; CustomData *ldata_dst = dm_dst ? dm_dst->getLoopDataLayout(dm_dst) : &me_dst->ldata; MeshRemapIslandsCalc island_callback = data_transfer_get_loop_islands_generator(cddata_type); if (!geom_map_init[LDATA]) { const int num_loops_src = dm_src->getNumLoops(dm_src); if ((map_loop_mode == MREMAP_MODE_TOPOLOGY) && (num_loops_dst != num_loops_src)) { BKE_report(reports, RPT_ERROR, "Source and destination meshes do not have the same amount of face corners, " "'Topology' mapping cannot be used in this case"); continue; } if (ELEM(0, num_loops_dst, num_loops_src)) { BKE_report(reports, RPT_ERROR, "Source or destination meshes do not have any polygons, cannot transfer loop data"); continue; } BKE_mesh_remap_calc_loops_from_dm( map_loop_mode, space_transform, max_distance, ray_radius, verts_dst, num_verts_dst, edges_dst, num_edges_dst, loops_dst, num_loops_dst, polys_dst, num_polys_dst, ldata_dst, pdata_dst, (me_dst->flag & ME_AUTOSMOOTH) != 0, me_dst->smoothresh, dirty_nors_dst, dm_src, (me_src->flag & ME_AUTOSMOOTH) != 0, me_src->smoothresh, island_callback, islands_handling_precision, &geom_map[LDATA]); geom_map_init[LDATA] = true; } if (mdef && vg_idx != -1 && !weights[LDATA]) { weights[LDATA] = MEM_mallocN(sizeof(*weights[LDATA]) * (size_t)num_loops_dst, __func__); BKE_defvert_extract_vgroup_to_loopweights( mdef, vg_idx, num_verts_dst, loops_dst, num_loops_dst, weights[LDATA], invert_vgroup); } if (data_transfer_layersmapping_generate( &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_LOOP, cddata_type, mix_mode, mix_factor, weights[LDATA], num_loops_dst, use_create, use_delete, fromlayers, tolayers, space_transform)) { CustomDataTransferLayerMap *lay_mapit; changed = (lay_map.first != NULL); for (lay_mapit = lay_map.first; lay_mapit; lay_mapit = lay_mapit->next) { CustomData_data_transfer(&geom_map[LDATA], lay_mapit); } BLI_freelistN(&lay_map); } } if (DT_DATATYPE_IS_POLY(dtdata_type)) { MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert; const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert; MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly; const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly; MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop; const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop; CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata; if (!geom_map_init[PDATA]) { const int num_polys_src = dm_src->getNumPolys(dm_src); if ((map_poly_mode == MREMAP_MODE_TOPOLOGY) && (num_polys_dst != num_polys_src)) { BKE_report(reports, RPT_ERROR, "Source and destination meshes do not have the same amount of faces, " "'Topology' mapping cannot be used in this case"); continue; } if (ELEM(0, num_polys_dst, num_polys_src)) { BKE_report(reports, RPT_ERROR, "Source or destination meshes do not have any polygons, cannot transfer poly data"); continue; } BKE_mesh_remap_calc_polys_from_dm( map_poly_mode, space_transform, max_distance, ray_radius, verts_dst, num_verts_dst, loops_dst, num_loops_dst, polys_dst, num_polys_dst, pdata_dst, dirty_nors_dst, dm_src, &geom_map[PDATA]); geom_map_init[PDATA] = true; } if (mdef && vg_idx != -1 && !weights[PDATA]) { weights[PDATA] = MEM_mallocN(sizeof(*weights[PDATA]) * (size_t)num_polys_dst, __func__); BKE_defvert_extract_vgroup_to_polyweights( mdef, vg_idx, num_verts_dst, loops_dst, num_loops_dst, polys_dst, num_polys_dst, weights[PDATA], invert_vgroup); } if (data_transfer_layersmapping_generate( &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_POLY, cddata_type, mix_mode, mix_factor, weights[PDATA], num_polys_dst, use_create, use_delete, fromlayers, tolayers, space_transform)) { CustomDataTransferLayerMap *lay_mapit; changed = (lay_map.first != NULL); for (lay_mapit = lay_map.first; lay_mapit; lay_mapit = lay_mapit->next) { CustomData_data_transfer(&geom_map[PDATA], lay_mapit); } BLI_freelistN(&lay_map); } } data_transfer_dtdata_type_postprocess(ob_src, ob_dst, dm_src, dm_dst, me_dst, dtdata_type, changed); } for (i = 0; i < DATAMAX; i++) { BKE_mesh_remap_free(&geom_map[i]); MEM_SAFE_FREE(weights[i]); } dm_src->release(dm_src); return changed; #undef VDATA #undef EDATA #undef LDATA #undef PDATA #undef DATAMAX }
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, int UNUSED(useRenderParams), int UNUSED(isFinalCalc)) { MaskModifierData *mmd= (MaskModifierData *)md; DerivedMesh *dm= derivedData, *result= NULL; GHash *vertHash=NULL, *edgeHash, *faceHash; GHashIterator *hashIter; MDeformVert *dvert= NULL, *dv; int numFaces=0, numEdges=0, numVerts=0; int maxVerts, maxEdges, maxFaces; int i; /* Overview of Method: * 1. Get the vertices that are in the vertexgroup of interest * 2. Filter out unwanted geometry (i.e. not in vertexgroup), by populating mappings with new vs old indices * 3. Make a new mesh containing only the mapping data */ /* get original number of verts, edges, and faces */ maxVerts= dm->getNumVerts(dm); maxEdges= dm->getNumEdges(dm); maxFaces= dm->getNumFaces(dm); /* check if we can just return the original mesh * - must have verts and therefore verts assigned to vgroups to do anything useful */ if ( !(ELEM(mmd->mode, MOD_MASK_MODE_ARM, MOD_MASK_MODE_VGROUP)) || (maxVerts == 0) || (ob->defbase.first == NULL) ) { return derivedData; } /* if mode is to use selected armature bones, aggregate the bone groups */ if (mmd->mode == MOD_MASK_MODE_ARM) /* --- using selected bones --- */ { GHash *vgroupHash; Object *oba= mmd->ob_arm; bPoseChannel *pchan; bDeformGroup *def; char *bone_select_array; int bone_select_tot= 0; /* check that there is armature object with bones to use, otherwise return original mesh */ if (ELEM3(NULL, mmd->ob_arm, mmd->ob_arm->pose, ob->defbase.first)) return derivedData; bone_select_array= MEM_mallocN(BLI_countlist(&ob->defbase) * sizeof(char), "mask array"); for (i = 0, def = ob->defbase.first; def; def = def->next, i++) { if (((pchan= get_pose_channel(oba->pose, def->name)) && pchan->bone && (pchan->bone->flag & BONE_SELECTED))) { bone_select_array[i]= TRUE; bone_select_tot++; } else { bone_select_array[i]= FALSE; } } /* hashes for finding mapping of: * - vgroups to indices -> vgroupHash (string, int) * - bones to vgroup indices -> boneHash (index of vgroup, dummy) */ vgroupHash= BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp, "mask vgroup gh"); /* build mapping of names of vertex groups to indices */ for (i = 0, def = ob->defbase.first; def; def = def->next, i++) BLI_ghash_insert(vgroupHash, def->name, SET_INT_IN_POINTER(i)); /* if no bones selected, free hashes and return original mesh */ if (bone_select_tot == 0) { BLI_ghash_free(vgroupHash, NULL, NULL); MEM_freeN(bone_select_array); return derivedData; } /* repeat the previous check, but for dverts */ dvert= dm->getVertDataArray(dm, CD_MDEFORMVERT); if (dvert == NULL) { BLI_ghash_free(vgroupHash, NULL, NULL); MEM_freeN(bone_select_array); return derivedData; } /* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */ vertHash= BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask vert gh"); /* add vertices which exist in vertexgroups into vertHash for filtering */ for (i= 0, dv= dvert; i < maxVerts; i++, dv++) { MDeformWeight *dw= dv->dw; int j; for (j= dv->totweight; j > 0; j--, dw++) { if (bone_select_array[dw->def_nr]) { if(dw->weight != 0.0f) { break; } } } /* check if include vert in vertHash */ if (mmd->flag & MOD_MASK_INV) { /* if this vert is in the vgroup, don't include it in vertHash */ if (dw) continue; } else { /* if this vert isn't in the vgroup, don't include it in vertHash */ if (!dw) continue; } /* add to ghash for verts (numVerts acts as counter for mapping) */ BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numVerts)); numVerts++; } /* free temp hashes */ BLI_ghash_free(vgroupHash, NULL, NULL); MEM_freeN(bone_select_array); } else /* --- Using Nominated VertexGroup only --- */ { int defgrp_index = defgroup_name_index(ob, mmd->vgroup); /* get dverts */ if (defgrp_index >= 0) dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); /* if no vgroup (i.e. dverts) found, return the initial mesh */ if ((defgrp_index < 0) || (dvert == NULL)) return dm; /* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */ vertHash= BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask vert2 bh"); /* add vertices which exist in vertexgroup into ghash for filtering */ for (i= 0, dv= dvert; i < maxVerts; i++, dv++) { const int weight_set= defvert_find_weight(dv, defgrp_index) != 0.0f; /* check if include vert in vertHash */ if (mmd->flag & MOD_MASK_INV) { /* if this vert is in the vgroup, don't include it in vertHash */ if (weight_set) continue; } else { /* if this vert isn't in the vgroup, don't include it in vertHash */ if (!weight_set) continue; } /* add to ghash for verts (numVerts acts as counter for mapping) */ BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numVerts)); numVerts++; } } /* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */ edgeHash= BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask ed2 gh"); faceHash= BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask fa2 gh"); /* loop over edges and faces, and do the same thing to * ensure that they only reference existing verts */ for (i = 0; i < maxEdges; i++) { MEdge me; dm->getEdge(dm, i, &me); /* only add if both verts will be in new mesh */ if ( BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v1)) && BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v2)) ) { BLI_ghash_insert(edgeHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numEdges)); numEdges++; } } for (i = 0; i < maxFaces; i++) { MFace mf; dm->getFace(dm, i, &mf); /* all verts must be available */ if ( BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v1)) && BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v2)) && BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v3)) && (mf.v4==0 || BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v4))) ) { BLI_ghash_insert(faceHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numFaces)); numFaces++; } } /* now we know the number of verts, edges and faces, * we can create the new (reduced) mesh */ result = CDDM_from_template(dm, numVerts, numEdges, numFaces); /* using ghash-iterators, map data into new mesh */ /* vertices */ for ( hashIter = BLI_ghashIterator_new(vertHash); !BLI_ghashIterator_isDone(hashIter); BLI_ghashIterator_step(hashIter) ) { MVert source; MVert *dest; int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter)); int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter)); dm->getVert(dm, oldIndex, &source); dest = CDDM_get_vert(result, newIndex); DM_copy_vert_data(dm, result, oldIndex, newIndex, 1); *dest = source; } BLI_ghashIterator_free(hashIter); /* edges */ for ( hashIter = BLI_ghashIterator_new(edgeHash); !BLI_ghashIterator_isDone(hashIter); BLI_ghashIterator_step(hashIter) ) { MEdge source; MEdge *dest; int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter)); int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter)); dm->getEdge(dm, oldIndex, &source); dest = CDDM_get_edge(result, newIndex); source.v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v1))); source.v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v2))); DM_copy_edge_data(dm, result, oldIndex, newIndex, 1); *dest = source; } BLI_ghashIterator_free(hashIter); /* faces */ for ( hashIter = BLI_ghashIterator_new(faceHash); !BLI_ghashIterator_isDone(hashIter); BLI_ghashIterator_step(hashIter) ) { MFace source; MFace *dest; int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter)); int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter)); int orig_v4; dm->getFace(dm, oldIndex, &source); dest = CDDM_get_face(result, newIndex); orig_v4 = source.v4; source.v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v1))); source.v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v2))); source.v3 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v3))); if (source.v4) source.v4 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v4))); DM_copy_face_data(dm, result, oldIndex, newIndex, 1); *dest = source; test_index_face(dest, &result->faceData, newIndex, (orig_v4 ? 4 : 3)); } BLI_ghashIterator_free(hashIter); /* recalculate normals */ CDDM_calc_normals(result); /* free hashes */ BLI_ghash_free(vertHash, NULL, NULL); BLI_ghash_free(edgeHash, NULL, NULL); BLI_ghash_free(faceHash, NULL, NULL); /* return the new mesh */ return result; }
static DerivedMesh *applyModifier( ModifierData *md, Object *ob, DerivedMesh *dm, ModifierApplyFlag UNUSED(flag)) { MaskModifierData *mmd = (MaskModifierData *)md; const bool found_test = (mmd->flag & MOD_MASK_INV) == 0; DerivedMesh *result = NULL; GHash *vertHash = NULL, *edgeHash, *polyHash; GHashIterator gh_iter; MDeformVert *dvert, *dv; int numPolys = 0, numLoops = 0, numEdges = 0, numVerts = 0; int maxVerts, maxEdges, maxPolys; int i; const MVert *mvert_src; const MEdge *medge_src; const MPoly *mpoly_src; const MLoop *mloop_src; MPoly *mpoly_dst; MLoop *mloop_dst; MEdge *medge_dst; MVert *mvert_dst; int *loop_mapping; dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); if (dvert == NULL) { return found_test ? CDDM_from_template(dm, 0, 0, 0, 0, 0) : dm; } /* Overview of Method: * 1. Get the vertices that are in the vertexgroup of interest * 2. Filter out unwanted geometry (i.e. not in vertexgroup), by populating mappings with new vs old indices * 3. Make a new mesh containing only the mapping data */ /* get original number of verts, edges, and faces */ maxVerts = dm->getNumVerts(dm); maxEdges = dm->getNumEdges(dm); maxPolys = dm->getNumPolys(dm); /* check if we can just return the original mesh * - must have verts and therefore verts assigned to vgroups to do anything useful */ if (!(ELEM(mmd->mode, MOD_MASK_MODE_ARM, MOD_MASK_MODE_VGROUP)) || (maxVerts == 0) || BLI_listbase_is_empty(&ob->defbase)) { return dm; } /* if mode is to use selected armature bones, aggregate the bone groups */ if (mmd->mode == MOD_MASK_MODE_ARM) { /* --- using selected bones --- */ Object *oba = mmd->ob_arm; bPoseChannel *pchan; bDeformGroup *def; bool *bone_select_array; int bone_select_tot = 0; const int defbase_tot = BLI_listbase_count(&ob->defbase); /* check that there is armature object with bones to use, otherwise return original mesh */ if (ELEM(NULL, oba, oba->pose, ob->defbase.first)) return dm; /* determine whether each vertexgroup is associated with a selected bone or not * - each cell is a boolean saying whether bone corresponding to the ith group is selected * - groups that don't match a bone are treated as not existing (along with the corresponding ungrouped verts) */ bone_select_array = MEM_malloc_arrayN((size_t)defbase_tot, sizeof(char), "mask array"); for (i = 0, def = ob->defbase.first; def; def = def->next, i++) { pchan = BKE_pose_channel_find_name(oba->pose, def->name); if (pchan && pchan->bone && (pchan->bone->flag & BONE_SELECTED)) { bone_select_array[i] = true; bone_select_tot++; } else { bone_select_array[i] = false; } } /* verthash gives mapping from original vertex indices to the new indices (including selected matches only) * key = oldindex, value = newindex */ vertHash = BLI_ghash_int_new_ex("mask vert gh", (unsigned int)maxVerts); /* add vertices which exist in vertexgroups into vertHash for filtering * - dv = for each vertex, what vertexgroups does it belong to * - dw = weight that vertex was assigned to a vertexgroup it belongs to */ for (i = 0, dv = dvert; i < maxVerts; i++, dv++) { MDeformWeight *dw = dv->dw; bool found = false; int j; /* check the groups that vertex is assigned to, and see if it was any use */ for (j = 0; j < dv->totweight; j++, dw++) { if (dw->def_nr < defbase_tot) { if (bone_select_array[dw->def_nr]) { if (dw->weight != 0.0f) { found = true; break; } } } } if (found_test != found) { continue; } /* add to ghash for verts (numVerts acts as counter for mapping) */ BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numVerts)); numVerts++; } /* free temp hashes */ MEM_freeN(bone_select_array); } else { /* --- Using Nominated VertexGroup only --- */ int defgrp_index = defgroup_name_index(ob, mmd->vgroup); /* if no vgroup (i.e. dverts) found, return the initial mesh */ if (defgrp_index == -1) return dm; /* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */ vertHash = BLI_ghash_int_new_ex("mask vert2 bh", (unsigned int)maxVerts); /* add vertices which exist in vertexgroup into ghash for filtering */ for (i = 0, dv = dvert; i < maxVerts; i++, dv++) { const bool found = defvert_find_weight(dv, defgrp_index) != 0.0f; if (found_test != found) { continue; } /* add to ghash for verts (numVerts acts as counter for mapping) */ BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numVerts)); numVerts++; } } /* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */ edgeHash = BLI_ghash_int_new_ex("mask ed2 gh", (unsigned int)maxEdges); polyHash = BLI_ghash_int_new_ex("mask fa2 gh", (unsigned int)maxPolys); mvert_src = dm->getVertArray(dm); medge_src = dm->getEdgeArray(dm); mpoly_src = dm->getPolyArray(dm); mloop_src = dm->getLoopArray(dm); /* overalloc, assume all polys are seen */ loop_mapping = MEM_malloc_arrayN((size_t)maxPolys, sizeof(int), "mask loopmap"); /* loop over edges and faces, and do the same thing to * ensure that they only reference existing verts */ for (i = 0; i < maxEdges; i++) { const MEdge *me = &medge_src[i]; /* only add if both verts will be in new mesh */ if (BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me->v1)) && BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me->v2))) { BLI_ghash_insert(edgeHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numEdges)); numEdges++; } } for (i = 0; i < maxPolys; i++) { const MPoly *mp_src = &mpoly_src[i]; const MLoop *ml_src = &mloop_src[mp_src->loopstart]; bool ok = true; int j; for (j = 0; j < mp_src->totloop; j++, ml_src++) { if (!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(ml_src->v))) { ok = false; break; } } /* all verts must be available */ if (ok) { BLI_ghash_insert(polyHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numPolys)); loop_mapping[numPolys] = numLoops; numPolys++; numLoops += mp_src->totloop; } } /* now we know the number of verts, edges and faces, * we can create the new (reduced) mesh */ result = CDDM_from_template(dm, numVerts, numEdges, 0, numLoops, numPolys); mpoly_dst = CDDM_get_polys(result); mloop_dst = CDDM_get_loops(result); medge_dst = CDDM_get_edges(result); mvert_dst = CDDM_get_verts(result); /* using ghash-iterators, map data into new mesh */ /* vertices */ GHASH_ITER (gh_iter, vertHash) { const MVert *v_src; MVert *v_dst; const int i_src = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&gh_iter)); const int i_dst = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(&gh_iter)); v_src = &mvert_src[i_src]; v_dst = &mvert_dst[i_dst]; *v_dst = *v_src; DM_copy_vert_data(dm, result, i_src, i_dst, 1); } /* edges */ GHASH_ITER (gh_iter, edgeHash) { const MEdge *e_src; MEdge *e_dst; const int i_src = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&gh_iter)); const int i_dst = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(&gh_iter)); e_src = &medge_src[i_src]; e_dst = &medge_dst[i_dst]; DM_copy_edge_data(dm, result, i_src, i_dst, 1); *e_dst = *e_src; e_dst->v1 = GET_UINT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_UINT_IN_POINTER(e_src->v1))); e_dst->v2 = GET_UINT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_UINT_IN_POINTER(e_src->v2))); } /* faces */ GHASH_ITER (gh_iter, polyHash) { const int i_src = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&gh_iter)); const int i_dst = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(&gh_iter)); const MPoly *mp_src = &mpoly_src[i_src]; MPoly *mp_dst = &mpoly_dst[i_dst]; const int i_ml_src = mp_src->loopstart; const int i_ml_dst = loop_mapping[i_dst]; const MLoop *ml_src = &mloop_src[i_ml_src]; MLoop *ml_dst = &mloop_dst[i_ml_dst]; DM_copy_poly_data(dm, result, i_src, i_dst, 1); DM_copy_loop_data(dm, result, i_ml_src, i_ml_dst, mp_src->totloop); *mp_dst = *mp_src; mp_dst->loopstart = i_ml_dst; for (i = 0; i < mp_src->totloop; i++) { ml_dst[i].v = GET_UINT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_UINT_IN_POINTER(ml_src[i].v))); ml_dst[i].e = GET_UINT_FROM_POINTER(BLI_ghash_lookup(edgeHash, SET_UINT_IN_POINTER(ml_src[i].e))); } } MEM_freeN(loop_mapping); /* why is this needed? - campbell */ /* recalculate normals */ result->dirty |= DM_DIRTY_NORMALS; /* free hashes */ BLI_ghash_free(vertHash, NULL, NULL); BLI_ghash_free(edgeHash, NULL, NULL); BLI_ghash_free(polyHash, NULL, NULL); /* return the new mesh */ return result; }
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, ModifierApplyFlag UNUSED(flag)) { WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md; DerivedMesh *dm = derivedData; MDeformVert *dvert = NULL; MDeformWeight **dw, **tdw; int numVerts; float (*v_cos)[3] = NULL; /* The vertices coordinates. */ Object *obr = NULL; /* Our target object. */ int defgrp_index; float *tw = NULL; float *org_w = NULL; float *new_w = NULL; int *tidx, *indices = NULL; int numIdx = 0; int i; /* Flags. */ #if 0 const bool do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview) != 0; #endif #ifdef USE_TIMEIT TIMEIT_START(perf); #endif /* Get number of verts. */ numVerts = dm->getNumVerts(dm); /* Check if we can just return the original mesh. * Must have verts and therefore verts assigned to vgroups to do anything useful! */ if ((numVerts == 0) || BLI_listbase_is_empty(&ob->defbase)) return dm; /* Get our target object. */ obr = wmd->proximity_ob_target; if (obr == NULL) return dm; /* Get vgroup idx from its name. */ defgrp_index = defgroup_name_index(ob, wmd->defgrp_name); if (defgrp_index == -1) return dm; dvert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MDEFORMVERT, numVerts); /* If no vertices were ever added to an object's vgroup, dvert might be NULL. * As this modifier never add vertices to vgroup, just return. */ if (!dvert) return dm; /* Find out which vertices to work on (all vertices in vgroup), and get their relevant weight. */ tidx = MEM_mallocN(sizeof(int) * numVerts, "WeightVGProximity Modifier, tidx"); tw = MEM_mallocN(sizeof(float) * numVerts, "WeightVGProximity Modifier, tw"); tdw = MEM_mallocN(sizeof(MDeformWeight *) * numVerts, "WeightVGProximity Modifier, tdw"); for (i = 0; i < numVerts; i++) { MDeformWeight *_dw = defvert_find_index(&dvert[i], defgrp_index); if (_dw) { tidx[numIdx] = i; tw[numIdx] = _dw->weight; tdw[numIdx++] = _dw; } } /* If no vertices found, return org data! */ if (numIdx == 0) { MEM_freeN(tidx); MEM_freeN(tw); MEM_freeN(tdw); return dm; } if (numIdx != numVerts) { indices = MEM_mallocN(sizeof(int) * numIdx, "WeightVGProximity Modifier, indices"); memcpy(indices, tidx, sizeof(int) * numIdx); org_w = MEM_mallocN(sizeof(float) * numIdx, "WeightVGProximity Modifier, org_w"); memcpy(org_w, tw, sizeof(float) * numIdx); dw = MEM_mallocN(sizeof(MDeformWeight *) * numIdx, "WeightVGProximity Modifier, dw"); memcpy(dw, tdw, sizeof(MDeformWeight *) * numIdx); MEM_freeN(tw); MEM_freeN(tdw); } else { org_w = tw; dw = tdw; } new_w = MEM_mallocN(sizeof(float) * numIdx, "WeightVGProximity Modifier, new_w"); MEM_freeN(tidx); /* Get our vertex coordinates. */ v_cos = MEM_mallocN(sizeof(float[3]) * numIdx, "WeightVGProximity Modifier, v_cos"); if (numIdx != numVerts) { /* XXX In some situations, this code can be up to about 50 times more performant * than simply using getVertCo for each affected vertex... */ float (*tv_cos)[3] = MEM_mallocN(sizeof(float[3]) * numVerts, "WeightVGProximity Modifier, tv_cos"); dm->getVertCos(dm, tv_cos); for (i = 0; i < numIdx; i++) copy_v3_v3(v_cos[i], tv_cos[indices[i]]); MEM_freeN(tv_cos); } else dm->getVertCos(dm, v_cos); /* Compute wanted distances. */ if (wmd->proximity_mode == MOD_WVG_PROXIMITY_OBJECT) { const float dist = get_ob2ob_distance(ob, obr); for (i = 0; i < numIdx; i++) new_w[i] = dist; } else if (wmd->proximity_mode == MOD_WVG_PROXIMITY_GEOMETRY) { const short use_trgt_verts = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_VERTS); const short use_trgt_edges = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_EDGES); const short use_trgt_faces = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_FACES); if (use_trgt_verts || use_trgt_edges || use_trgt_faces) { DerivedMesh *target_dm = obr->derivedFinal; bool free_target_dm = false; if (!target_dm) { if (ELEM(obr->type, OB_CURVE, OB_SURF, OB_FONT)) target_dm = CDDM_from_curve(obr); else if (obr->type == OB_MESH) { Mesh *me = (Mesh *)obr->data; if (me->edit_btmesh) target_dm = CDDM_from_editbmesh(me->edit_btmesh, false, false); else target_dm = CDDM_from_mesh(me); } free_target_dm = true; } /* We must check that we do have a valid target_dm! */ if (target_dm) { SpaceTransform loc2trgt; float *dists_v = use_trgt_verts ? MEM_mallocN(sizeof(float) * numIdx, "dists_v") : NULL; float *dists_e = use_trgt_edges ? MEM_mallocN(sizeof(float) * numIdx, "dists_e") : NULL; float *dists_f = use_trgt_faces ? MEM_mallocN(sizeof(float) * numIdx, "dists_f") : NULL; BLI_SPACE_TRANSFORM_SETUP(&loc2trgt, ob, obr); get_vert2geom_distance(numIdx, v_cos, dists_v, dists_e, dists_f, target_dm, &loc2trgt); for (i = 0; i < numIdx; i++) { new_w[i] = dists_v ? dists_v[i] : FLT_MAX; if (dists_e) new_w[i] = min_ff(dists_e[i], new_w[i]); if (dists_f) new_w[i] = min_ff(dists_f[i], new_w[i]); } if (free_target_dm) target_dm->release(target_dm); if (dists_v) MEM_freeN(dists_v); if (dists_e) MEM_freeN(dists_e); if (dists_f) MEM_freeN(dists_f); } /* Else, fall back to default obj2vert behavior. */ else { get_vert2ob_distance(numIdx, v_cos, new_w, ob, obr); } } else { get_vert2ob_distance(numIdx, v_cos, new_w, ob, obr); } } /* Map distances to weights. */ do_map(ob, new_w, numIdx, wmd->min_dist, wmd->max_dist, wmd->falloff_type); /* Do masking. */ weightvg_do_mask(numIdx, indices, org_w, new_w, ob, dm, wmd->mask_constant, wmd->mask_defgrp_name, wmd->modifier.scene, wmd->mask_texture, wmd->mask_tex_use_channel, wmd->mask_tex_mapping, wmd->mask_tex_map_obj, wmd->mask_tex_uvlayer_name); /* Update vgroup. Note we never add nor remove vertices from vgroup here. */ weightvg_update_vg(dvert, defgrp_index, dw, numIdx, indices, org_w, false, 0.0f, false, 0.0f); /* If weight preview enabled... */ #if 0 /* XXX Currently done in mod stack :/ */ if (do_prev) DM_update_weight_mcol(ob, dm, 0, org_w, numIdx, indices); #endif /* Freeing stuff. */ MEM_freeN(org_w); MEM_freeN(new_w); MEM_freeN(dw); if (indices) MEM_freeN(indices); MEM_freeN(v_cos); #ifdef USE_TIMEIT TIMEIT_END(perf); #endif /* Return the vgroup-modified mesh. */ return dm; }
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, ModifierApplyFlag UNUSED(flag)) { MaskModifierData *mmd = (MaskModifierData *)md; DerivedMesh *dm = derivedData, *result = NULL; GHash *vertHash = NULL, *edgeHash, *polyHash; GHashIterator *hashIter; MDeformVert *dvert = NULL, *dv; int numPolys = 0, numLoops = 0, numEdges = 0, numVerts = 0; int maxVerts, maxEdges, maxPolys; int i; MPoly *mpoly; MLoop *mloop; MPoly *mpoly_new; MLoop *mloop_new; MEdge *medge_new; MVert *mvert_new; int *loop_mapping; /* Overview of Method: * 1. Get the vertices that are in the vertexgroup of interest * 2. Filter out unwanted geometry (i.e. not in vertexgroup), by populating mappings with new vs old indices * 3. Make a new mesh containing only the mapping data */ /* get original number of verts, edges, and faces */ maxVerts = dm->getNumVerts(dm); maxEdges = dm->getNumEdges(dm); maxPolys = dm->getNumPolys(dm); /* check if we can just return the original mesh * - must have verts and therefore verts assigned to vgroups to do anything useful */ if (!(ELEM(mmd->mode, MOD_MASK_MODE_ARM, MOD_MASK_MODE_VGROUP)) || (maxVerts == 0) || (ob->defbase.first == NULL) ) { return derivedData; } /* if mode is to use selected armature bones, aggregate the bone groups */ if (mmd->mode == MOD_MASK_MODE_ARM) { /* --- using selected bones --- */ GHash *vgroupHash; Object *oba = mmd->ob_arm; bPoseChannel *pchan; bDeformGroup *def; char *bone_select_array; int bone_select_tot = 0; const int defbase_tot = BLI_countlist(&ob->defbase); /* check that there is armature object with bones to use, otherwise return original mesh */ if (ELEM3(NULL, mmd->ob_arm, mmd->ob_arm->pose, ob->defbase.first)) return derivedData; bone_select_array = MEM_mallocN(defbase_tot * sizeof(char), "mask array"); for (i = 0, def = ob->defbase.first; def; def = def->next, i++) { pchan = BKE_pose_channel_find_name(oba->pose, def->name); if (pchan && pchan->bone && (pchan->bone->flag & BONE_SELECTED)) { bone_select_array[i] = TRUE; bone_select_tot++; } else { bone_select_array[i] = FALSE; } } /* hashes for finding mapping of: * - vgroups to indices -> vgroupHash (string, int) * - bones to vgroup indices -> boneHash (index of vgroup, dummy) */ vgroupHash = BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp, "mask vgroup gh"); /* build mapping of names of vertex groups to indices */ for (i = 0, def = ob->defbase.first; def; def = def->next, i++) BLI_ghash_insert(vgroupHash, def->name, SET_INT_IN_POINTER(i)); /* if no bones selected, free hashes and return original mesh */ if (bone_select_tot == 0) { BLI_ghash_free(vgroupHash, NULL, NULL); MEM_freeN(bone_select_array); return derivedData; } /* repeat the previous check, but for dverts */ dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); if (dvert == NULL) { BLI_ghash_free(vgroupHash, NULL, NULL); MEM_freeN(bone_select_array); return derivedData; } /* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */ vertHash = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask vert gh"); /* add vertices which exist in vertexgroups into vertHash for filtering */ for (i = 0, dv = dvert; i < maxVerts; i++, dv++) { MDeformWeight *dw = dv->dw; int j; for (j = dv->totweight; j > 0; j--, dw++) { if (dw->def_nr < defbase_tot) { if (bone_select_array[dw->def_nr]) { if (dw->weight != 0.0f) { break; } } } } /* check if include vert in vertHash */ if (mmd->flag & MOD_MASK_INV) { /* if this vert is in the vgroup, don't include it in vertHash */ if (dw) continue; } else { /* if this vert isn't in the vgroup, don't include it in vertHash */ if (!dw) continue; } /* add to ghash for verts (numVerts acts as counter for mapping) */ BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numVerts)); numVerts++; } /* free temp hashes */ BLI_ghash_free(vgroupHash, NULL, NULL); MEM_freeN(bone_select_array); } else { /* --- Using Nominated VertexGroup only --- */ int defgrp_index = defgroup_name_index(ob, mmd->vgroup); /* get dverts */ if (defgrp_index >= 0) dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); /* if no vgroup (i.e. dverts) found, return the initial mesh */ if ((defgrp_index < 0) || (dvert == NULL)) return dm; /* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */ vertHash = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask vert2 bh"); /* add vertices which exist in vertexgroup into ghash for filtering */ for (i = 0, dv = dvert; i < maxVerts; i++, dv++) { const int weight_set = defvert_find_weight(dv, defgrp_index) != 0.0f; /* check if include vert in vertHash */ if (mmd->flag & MOD_MASK_INV) { /* if this vert is in the vgroup, don't include it in vertHash */ if (weight_set) continue; } else { /* if this vert isn't in the vgroup, don't include it in vertHash */ if (!weight_set) continue; } /* add to ghash for verts (numVerts acts as counter for mapping) */ BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numVerts)); numVerts++; } } /* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */ edgeHash = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask ed2 gh"); polyHash = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask fa2 gh"); mpoly = dm->getPolyArray(dm); mloop = dm->getLoopArray(dm); loop_mapping = MEM_callocN(sizeof(int) * maxPolys, "mask loopmap"); /* overalloc, assume all polys are seen */ /* loop over edges and faces, and do the same thing to * ensure that they only reference existing verts */ for (i = 0; i < maxEdges; i++) { MEdge me; dm->getEdge(dm, i, &me); /* only add if both verts will be in new mesh */ if (BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v1)) && BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v2))) { BLI_ghash_insert(edgeHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numEdges)); numEdges++; } } for (i = 0; i < maxPolys; i++) { MPoly *mp = &mpoly[i]; MLoop *ml = mloop + mp->loopstart; int ok = TRUE; int j; for (j = 0; j < mp->totloop; j++, ml++) { if (!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(ml->v))) { ok = FALSE; break; } } /* all verts must be available */ if (ok) { BLI_ghash_insert(polyHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numPolys)); loop_mapping[numPolys] = numLoops; numPolys++; numLoops += mp->totloop; } } /* now we know the number of verts, edges and faces, * we can create the new (reduced) mesh */ result = CDDM_from_template(dm, numVerts, numEdges, 0, numLoops, numPolys); mpoly_new = CDDM_get_polys(result); mloop_new = CDDM_get_loops(result); medge_new = CDDM_get_edges(result); mvert_new = CDDM_get_verts(result); /* using ghash-iterators, map data into new mesh */ /* vertices */ for (hashIter = BLI_ghashIterator_new(vertHash); !BLI_ghashIterator_isDone(hashIter); BLI_ghashIterator_step(hashIter) ) { MVert source; MVert *dest; int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter)); int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter)); dm->getVert(dm, oldIndex, &source); dest = &mvert_new[newIndex]; DM_copy_vert_data(dm, result, oldIndex, newIndex, 1); *dest = source; } BLI_ghashIterator_free(hashIter); /* edges */ for (hashIter = BLI_ghashIterator_new(edgeHash); !BLI_ghashIterator_isDone(hashIter); BLI_ghashIterator_step(hashIter)) { MEdge source; MEdge *dest; int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter)); int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter)); dm->getEdge(dm, oldIndex, &source); dest = &medge_new[newIndex]; source.v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v1))); source.v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v2))); DM_copy_edge_data(dm, result, oldIndex, newIndex, 1); *dest = source; } BLI_ghashIterator_free(hashIter); /* faces */ for (hashIter = BLI_ghashIterator_new(polyHash); !BLI_ghashIterator_isDone(hashIter); BLI_ghashIterator_step(hashIter) ) { int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter)); int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter)); MPoly *source = &mpoly[oldIndex]; MPoly *dest = &mpoly_new[newIndex]; int oldLoopIndex = source->loopstart; int newLoopIndex = loop_mapping[newIndex]; MLoop *source_loop = &mloop[oldLoopIndex]; MLoop *dest_loop = &mloop_new[newLoopIndex]; DM_copy_poly_data(dm, result, oldIndex, newIndex, 1); DM_copy_loop_data(dm, result, oldLoopIndex, newLoopIndex, source->totloop); *dest = *source; dest->loopstart = newLoopIndex; for (i = 0; i < source->totloop; i++) { dest_loop[i].v = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source_loop[i].v))); dest_loop[i].e = GET_INT_FROM_POINTER(BLI_ghash_lookup(edgeHash, SET_INT_IN_POINTER(source_loop[i].e))); } } BLI_ghashIterator_free(hashIter); MEM_freeN(loop_mapping); /* why is this needed? - campbell */ /* recalculate normals */ CDDM_calc_normals(result); /* free hashes */ BLI_ghash_free(vertHash, NULL, NULL); BLI_ghash_free(edgeHash, NULL, NULL); BLI_ghash_free(polyHash, NULL, NULL); /* return the new mesh */ return result; }
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, ModifierApplyFlag UNUSED(flag)) { WeightVGEditModifierData *wmd = (WeightVGEditModifierData *) md; DerivedMesh *dm = derivedData; MDeformVert *dvert = NULL; MDeformWeight **dw = NULL; float *org_w; /* Array original weights. */ float *new_w; /* Array new weights. */ int numVerts; int defgrp_index; int i; /* Flags. */ const bool do_add = (wmd->edit_flags & MOD_WVG_EDIT_ADD2VG) != 0; const bool do_rem = (wmd->edit_flags & MOD_WVG_EDIT_REMFVG) != 0; /* Only do weight-preview in Object, Sculpt and Pose modes! */ #if 0 const bool do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview); #endif /* Get number of verts. */ numVerts = dm->getNumVerts(dm); /* Check if we can just return the original mesh. * Must have verts and therefore verts assigned to vgroups to do anything useful! */ if ((numVerts == 0) || BLI_listbase_is_empty(&ob->defbase)) return dm; /* Get vgroup idx from its name. */ defgrp_index = defgroup_name_index(ob, wmd->defgrp_name); if (defgrp_index == -1) return dm; dvert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MDEFORMVERT, numVerts); /* If no vertices were ever added to an object's vgroup, dvert might be NULL. */ if (!dvert) { /* If this modifier is not allowed to add vertices, just return. */ if (!do_add) return dm; /* Else, add a valid data layer! */ dvert = CustomData_add_layer_named(&dm->vertData, CD_MDEFORMVERT, CD_CALLOC, NULL, numVerts, wmd->defgrp_name); /* Ultimate security check. */ if (!dvert) return dm; } /* Get org weights, assuming 0.0 for vertices not in given vgroup. */ org_w = MEM_mallocN(sizeof(float) * numVerts, "WeightVGEdit Modifier, org_w"); new_w = MEM_mallocN(sizeof(float) * numVerts, "WeightVGEdit Modifier, new_w"); dw = MEM_mallocN(sizeof(MDeformWeight *) * numVerts, "WeightVGEdit Modifier, dw"); for (i = 0; i < numVerts; i++) { dw[i] = defvert_find_index(&dvert[i], defgrp_index); if (dw[i]) { org_w[i] = new_w[i] = dw[i]->weight; } else { org_w[i] = new_w[i] = wmd->default_weight; } } /* Do mapping. */ if (wmd->falloff_type != MOD_WVG_MAPPING_NONE) { RNG *rng = NULL; if (wmd->falloff_type == MOD_WVG_MAPPING_RANDOM) rng = BLI_rng_new_srandom(BLI_ghashutil_strhash(ob->id.name + 2)); weightvg_do_map(numVerts, new_w, wmd->falloff_type, wmd->cmap_curve, rng); if (rng) BLI_rng_free(rng); } /* Do masking. */ weightvg_do_mask(numVerts, NULL, org_w, new_w, ob, dm, wmd->mask_constant, wmd->mask_defgrp_name, wmd->modifier.scene, wmd->mask_texture, wmd->mask_tex_use_channel, wmd->mask_tex_mapping, wmd->mask_tex_map_obj, wmd->mask_tex_uvlayer_name); /* Update/add/remove from vgroup. */ weightvg_update_vg(dvert, defgrp_index, dw, numVerts, NULL, org_w, do_add, wmd->add_threshold, do_rem, wmd->rem_threshold); /* If weight preview enabled... */ #if 0 /* XXX Currently done in mod stack :/ */ if (do_prev) DM_update_weight_mcol(ob, dm, 0, org_w, 0, NULL); #endif /* Freeing stuff. */ MEM_freeN(org_w); MEM_freeN(new_w); MEM_freeN(dw); /* Return the vgroup-modified mesh. */ return dm; }
static void smoothModifier_do( SmoothModifierData *smd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { MDeformVert *dvert = NULL; MEdge *medges = NULL; int i, j, numDMEdges, defgrp_index; unsigned char *uctmp; float *ftmp, fac, facm; ftmp = (float*)MEM_callocN(3*sizeof(float)*numVerts, "smoothmodifier_f"); if (!ftmp) return; uctmp = (unsigned char*)MEM_callocN(sizeof(unsigned char)*numVerts, "smoothmodifier_uc"); if (!uctmp) { if (ftmp) MEM_freeN(ftmp); return; } fac = smd->fac; facm = 1 - fac; medges = dm->getEdgeArray(dm); numDMEdges = dm->getNumEdges(dm); defgrp_index = defgroup_name_index(ob, smd->defgrp_name); if (defgrp_index >= 0) dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); /* NOTICE: this can be optimized a little bit by moving the * if (dvert) out of the loop, if needed */ for (j = 0; j < smd->repeat; j++) { for (i = 0; i < numDMEdges; i++) { float fvec[3]; float *v1, *v2; unsigned int idx1, idx2; idx1 = medges[i].v1; idx2 = medges[i].v2; v1 = vertexCos[idx1]; v2 = vertexCos[idx2]; fvec[0] = (v1[0] + v2[0]) / 2.0; fvec[1] = (v1[1] + v2[1]) / 2.0; fvec[2] = (v1[2] + v2[2]) / 2.0; v1 = &ftmp[idx1*3]; v2 = &ftmp[idx2*3]; if (uctmp[idx1] < 255) { uctmp[idx1]++; add_v3_v3(v1, fvec); } if (uctmp[idx2] < 255) { uctmp[idx2]++; add_v3_v3(v2, fvec); } } if (dvert) { for (i = 0; i < numVerts; i++) { MDeformWeight *dw = NULL; float f, fm, facw, *fp, *v; int k; short flag = smd->flag; v = vertexCos[i]; fp = &ftmp[i*3]; for (k = 0; k < dvert[i].totweight; ++k) { if(dvert[i].dw[k].def_nr == defgrp_index) { dw = &dvert[i].dw[k]; break; } } if (!dw) continue; f = fac * dw->weight; fm = 1.0f - f; /* fp is the sum of uctmp[i] verts, so must be averaged */ facw = 0.0f; if (uctmp[i]) facw = f / (float)uctmp[i]; if (flag & MOD_SMOOTH_X) v[0] = fm * v[0] + facw * fp[0]; if (flag & MOD_SMOOTH_Y) v[1] = fm * v[1] + facw * fp[1]; if (flag & MOD_SMOOTH_Z) v[2] = fm * v[2] + facw * fp[2]; } } else { /* no vertex group */ for (i = 0; i < numVerts; i++) { float facw, *fp, *v; short flag = smd->flag; v = vertexCos[i]; fp = &ftmp[i*3]; /* fp is the sum of uctmp[i] verts, so must be averaged */ facw = 0.0f; if (uctmp[i]) facw = fac / (float)uctmp[i]; if (flag & MOD_SMOOTH_X) v[0] = facm * v[0] + facw * fp[0]; if (flag & MOD_SMOOTH_Y) v[1] = facm * v[1] + facw * fp[1]; if (flag & MOD_SMOOTH_Z) v[2] = facm * v[2] + facw * fp[2]; } } memset(ftmp, 0, 3*sizeof(float)*numVerts); memset(uctmp, 0, sizeof(unsigned char)*numVerts); } MEM_freeN(ftmp); MEM_freeN(uctmp); }
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, int UNUSED(useRenderParams), int UNUSED(isFinalCalc)) { WeightVGMixModifierData *wmd = (WeightVGMixModifierData*) md; DerivedMesh *dm = derivedData; MDeformVert *dvert = NULL; MDeformWeight **dw1, **tdw1, **dw2, **tdw2; int numVerts; int defgrp_idx, defgrp_idx2 = -1; float *org_w; float *new_w; int *tidx, *indices = NULL; int numIdx = 0; int i; /* Flags. */ #if 0 int do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview); #endif /* Get number of verts. */ numVerts = dm->getNumVerts(dm); /* Check if we can just return the original mesh. * Must have verts and therefore verts assigned to vgroups to do anything useful! */ if ((numVerts == 0) || (ob->defbase.first == NULL)) return dm; /* Get vgroup idx from its name. */ defgrp_idx = defgroup_name_index(ob, wmd->defgrp_name_a); if (defgrp_idx < 0) return dm; /* Get seconf vgroup idx from its name, if given. */ if (wmd->defgrp_name_b[0] != (char)0) { defgrp_idx2 = defgroup_name_index(ob, wmd->defgrp_name_b); if (defgrp_idx2 < 0) return dm; } dvert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MDEFORMVERT, numVerts); /* If no vertices were ever added to an object's vgroup, dvert might be NULL. */ if (!dvert) { /* If not affecting all vertices, just return. */ if (wmd->mix_set != MOD_WVG_SET_ALL) return dm; /* Else, add a valid data layer! */ dvert = CustomData_add_layer_named(&dm->vertData, CD_MDEFORMVERT, CD_CALLOC, NULL, numVerts, wmd->defgrp_name_a); /* Ultimate security check. */ if (!dvert) return dm; } /* Find out which vertices to work on. */ tidx = MEM_mallocN(sizeof(int) * numVerts, "WeightVGMix Modifier, tidx"); tdw1 = MEM_mallocN(sizeof(MDeformWeight*) * numVerts, "WeightVGMix Modifier, tdw1"); tdw2 = MEM_mallocN(sizeof(MDeformWeight*) * numVerts, "WeightVGMix Modifier, tdw2"); switch (wmd->mix_set) { case MOD_WVG_SET_A: /* All vertices in first vgroup. */ for (i = 0; i < numVerts; i++) { MDeformWeight *dw = defvert_find_index(&dvert[i], defgrp_idx); if (dw) { tdw1[numIdx] = dw; tdw2[numIdx] = defvert_find_index(&dvert[i], defgrp_idx2); tidx[numIdx++] = i; } } break; case MOD_WVG_SET_B: /* All vertices in second vgroup. */ for (i = 0; i < numVerts; i++) { MDeformWeight *dw = defvert_find_index(&dvert[i], defgrp_idx2); if (dw) { tdw1[numIdx] = defvert_find_index(&dvert[i], defgrp_idx); tdw2[numIdx] = dw; tidx[numIdx++] = i; } } break; case MOD_WVG_SET_OR: /* All vertices in one vgroup or the other. */ for (i = 0; i < numVerts; i++) { MDeformWeight *adw = defvert_find_index(&dvert[i], defgrp_idx); MDeformWeight *bdw = defvert_find_index(&dvert[i], defgrp_idx2); if (adw || bdw) { tdw1[numIdx] = adw; tdw2[numIdx] = bdw; tidx[numIdx++] = i; } } break; case MOD_WVG_SET_AND: /* All vertices in both vgroups. */ for (i = 0; i < numVerts; i++) { MDeformWeight *adw = defvert_find_index(&dvert[i], defgrp_idx); MDeformWeight *bdw = defvert_find_index(&dvert[i], defgrp_idx2); if (adw && bdw) { tdw1[numIdx] = adw; tdw2[numIdx] = bdw; tidx[numIdx++] = i; } } break; case MOD_WVG_SET_ALL: default: /* Use all vertices. */ for (i = 0; i < numVerts; i++) { tdw1[i] = defvert_find_index(&dvert[i], defgrp_idx); tdw2[i] = defvert_find_index(&dvert[i], defgrp_idx2); } numIdx = -1; break; } if (numIdx == 0) { /* Use no vertices! Hence, return org data. */ MEM_freeN(tdw1); MEM_freeN(tdw2); MEM_freeN(tidx); return dm; } if (numIdx != -1) { indices = MEM_mallocN(sizeof(int) * numIdx, "WeightVGMix Modifier, indices"); memcpy(indices, tidx, sizeof(int) * numIdx); dw1 = MEM_mallocN(sizeof(MDeformWeight*) * numIdx, "WeightVGMix Modifier, dw1"); memcpy(dw1, tdw1, sizeof(MDeformWeight*) * numIdx); MEM_freeN(tdw1); dw2 = MEM_mallocN(sizeof(MDeformWeight*) * numIdx, "WeightVGMix Modifier, dw2"); memcpy(dw2, tdw2, sizeof(MDeformWeight*) * numIdx); MEM_freeN(tdw2); } else { /* Use all vertices. */ numIdx = numVerts; /* Just copy MDeformWeight pointers arrays, they will be freed at the end. */ dw1 = tdw1; dw2 = tdw2; } MEM_freeN(tidx); org_w = MEM_mallocN(sizeof(float) * numIdx, "WeightVGMix Modifier, org_w"); new_w = MEM_mallocN(sizeof(float) * numIdx, "WeightVGMix Modifier, new_w"); /* Mix weights. */ for (i = 0; i < numIdx; i++) { float weight2 = 0.0; org_w[i] = dw1[i] ? dw1[i]->weight : wmd->default_weight_a; weight2 = dw2[i] ? dw2[i]->weight : wmd->default_weight_b; new_w[i] = mix_weight(org_w[i], weight2, wmd->mix_mode); } /* Do masking. */ weightvg_do_mask(numIdx, indices, org_w, new_w, ob, dm, wmd->mask_constant, wmd->mask_defgrp_name, wmd->modifier.scene, wmd->mask_texture, wmd->mask_tex_use_channel, wmd->mask_tex_mapping, wmd->mask_tex_map_obj, wmd->mask_tex_uvlayer_name); /* Update (add to) vgroup. * XXX Depending on the MOD_WVG_SET_xxx option chosen, we might have to add vertices to vgroup. */ weightvg_update_vg(dvert, defgrp_idx, dw1, numIdx, indices, org_w, TRUE, -FLT_MAX, FALSE, 0.0f); /* If weight preview enabled... */ #if 0 /* XXX Currently done in mod stack :/ */ if (do_prev) DM_update_weight_mcol(ob, dm, 0, org_w, numIdx, indices); #endif /* Freeing stuff. */ MEM_freeN(org_w); MEM_freeN(new_w); MEM_freeN(dw1); MEM_freeN(dw2); if (indices) MEM_freeN(indices); /* Return the vgroup-modified mesh. */ return dm; }
/* Main shrinkwrap function */ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { DerivedMesh *ss_mesh = NULL; ShrinkwrapCalcData calc = NULL_ShrinkwrapCalcData; //remove loop dependencies on derived meshs (TODO should this be done elsewhere?) if (smd->target == ob) smd->target = NULL; if (smd->auxTarget == ob) smd->auxTarget = NULL; //Configure Shrinkwrap calc data calc.smd = smd; calc.ob = ob; calc.numVerts = numVerts; calc.vertexCos = vertexCos; //DeformVertex calc.vgroup = defgroup_name_index(calc.ob, calc.smd->vgroup_name); if (dm) { calc.dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); } else if (calc.ob->type == OB_LATTICE) { calc.dvert = BKE_lattice_deform_verts_get(calc.ob); } if (smd->target) { calc.target = object_get_derived_final(smd->target); //TODO there might be several "bugs" on non-uniform scales matrixs //because it will no longer be nearest surface, not sphere projection //because space has been deformed space_transform_setup(&calc.local2target, ob, smd->target); //TODO: smd->keepDist is in global units.. must change to local calc.keepDist = smd->keepDist; } calc.vgroup = defgroup_name_index(calc.ob, smd->vgroup_name); if (dm != NULL && smd->shrinkType == MOD_SHRINKWRAP_PROJECT) { //Setup arrays to get vertexs positions, normals and deform weights calc.vert = dm->getVertDataArray(dm, CD_MVERT); calc.dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); //Using vertexs positions/normals as if a subsurface was applied if (smd->subsurfLevels) { SubsurfModifierData ssmd= {{NULL}}; ssmd.subdivType = ME_CC_SUBSURF; //catmull clark ssmd.levels = smd->subsurfLevels; //levels ss_mesh = subsurf_make_derived_from_derived(dm, &ssmd, FALSE, NULL, 0, 0, (ob->mode & OB_MODE_EDIT)); if (ss_mesh) { calc.vert = ss_mesh->getVertDataArray(ss_mesh, CD_MVERT); if (calc.vert) { /* TRICKY: this code assumes subsurface will have the transformed original vertices * in their original order at the end of the vert array. */ calc.vert = calc.vert + ss_mesh->getNumVerts(ss_mesh) - dm->getNumVerts(dm); } } //Just to make sure we are not leaving any memory behind assert(ssmd.emCache == NULL); assert(ssmd.mCache == NULL); } } //Projecting target defined - lets work! if (calc.target) { switch (smd->shrinkType) { case MOD_SHRINKWRAP_NEAREST_SURFACE: BENCH(shrinkwrap_calc_nearest_surface_point(&calc)); break; case MOD_SHRINKWRAP_PROJECT: BENCH(shrinkwrap_calc_normal_projection(&calc)); break; case MOD_SHRINKWRAP_NEAREST_VERTEX: BENCH(shrinkwrap_calc_nearest_vertex(&calc)); break; } } //free memory if (ss_mesh) ss_mesh->release(ss_mesh); }