static void cloth_from_mesh ( ClothModifierData *clmd, DerivedMesh *dm ) { const MLoop *mloop = dm->getLoopArray(dm); const MLoopTri *looptri = dm->getLoopTriArray(dm); const unsigned int mvert_num = dm->getNumVerts(dm); const unsigned int looptri_num = dm->getNumLoopTri(dm); /* Allocate our vertices. */ clmd->clothObject->mvert_num = mvert_num; clmd->clothObject->verts = MEM_callocN(sizeof(ClothVertex) * clmd->clothObject->mvert_num, "clothVertex"); if (clmd->clothObject->verts == NULL) { cloth_free_modifier(clmd); modifier_setError(&(clmd->modifier), "Out of memory on allocating clmd->clothObject->verts"); printf("cloth_free_modifier clmd->clothObject->verts\n"); return; } /* save face information */ clmd->clothObject->tri_num = looptri_num; clmd->clothObject->tri = MEM_mallocN(sizeof(MVertTri) * looptri_num, "clothLoopTris"); if (clmd->clothObject->tri == NULL) { cloth_free_modifier(clmd); modifier_setError(&(clmd->modifier), "Out of memory on allocating clmd->clothObject->looptri"); printf("cloth_free_modifier clmd->clothObject->looptri\n"); return; } DM_verttri_from_looptri(clmd->clothObject->tri, mloop, looptri, looptri_num); /* Free the springs since they can't be correct if the vertices * changed. */ if ( clmd->clothObject->springs != NULL ) MEM_freeN ( clmd->clothObject->springs ); }
static int do_init_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *result, int framenr) { PointCache *cache; cache= clmd->point_cache; /* initialize simulation data if it didn't exist already */ if (clmd->clothObject == NULL) { if (!cloth_from_object(ob, clmd, result, framenr, 1)) { BKE_ptcache_invalidate(cache); modifier_setError(&(clmd->modifier), "Can't initialize cloth"); return 0; } if (clmd->clothObject == NULL) { BKE_ptcache_invalidate(cache); modifier_setError(&(clmd->modifier), "Null cloth object"); return 0; } implicit_set_positions(clmd); clmd->clothObject->last_frame= MINFRAME-1; } return 1; }
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, ModifierApplyFlag flag) { SubsurfModifierData *smd = (SubsurfModifierData *) md; SubsurfFlags subsurf_flags = 0; DerivedMesh *result; const bool useRenderParams = (flag & MOD_APPLY_RENDER) != 0; const bool isFinalCalc = (flag & MOD_APPLY_USECACHE) != 0; #ifdef WITH_OPENSUBDIV const bool allow_gpu = (flag & MOD_APPLY_ALLOW_GPU) != 0; const bool do_cddm_convert = useRenderParams || (!isFinalCalc && !smd->use_opensubdiv); #else const bool do_cddm_convert = useRenderParams || !isFinalCalc; #endif if (useRenderParams) subsurf_flags |= SUBSURF_USE_RENDER_PARAMS; if (isFinalCalc) subsurf_flags |= SUBSURF_IS_FINAL_CALC; if (ob->mode & OB_MODE_EDIT) subsurf_flags |= SUBSURF_IN_EDIT_MODE; #ifdef WITH_OPENSUBDIV /* TODO(sergey): Not entirely correct, modifiers on top of subsurf * could be disabled. */ if (md->next == NULL && allow_gpu && do_cddm_convert == false && smd->use_opensubdiv) { if (U.opensubdiv_compute_type == USER_OPENSUBDIV_COMPUTE_NONE) { modifier_setError(md, "OpenSubdiv is disabled in User Preferences"); } else if ((DAG_get_eval_flags_for_object(md->scene, ob) & DAG_EVAL_NEED_CPU) == 0) { subsurf_flags |= SUBSURF_USE_GPU_BACKEND; } else { modifier_setError(md, "OpenSubdiv is disabled due to dependencies"); } } #endif result = subsurf_make_derived_from_derived(derivedData, smd, NULL, subsurf_flags); result->cd_flag = derivedData->cd_flag; if (do_cddm_convert) { DerivedMesh *cddm = CDDM_copy(result); result->release(result); result = cddm; } return result; }
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, ModifierApplyFlag UNUSED(flag)) { DataTransferModifierData *dtmd = (DataTransferModifierData *) md; DerivedMesh *dm = derivedData; ReportList reports; /* Only used to check wehther we are operating on org data or not... */ Mesh *me = ob->data; MVert *mvert; const bool invert_vgroup = (dtmd->flags & MOD_DATATRANSFER_INVERT_VGROUP) != 0; const float max_dist = (dtmd->flags & MOD_DATATRANSFER_MAP_MAXDIST) ? dtmd->map_max_distance : FLT_MAX; SpaceTransform space_transform_data; SpaceTransform *space_transform = (dtmd->flags & MOD_DATATRANSFER_OBSRC_TRANSFORM) ? &space_transform_data : NULL; if (space_transform) { BLI_SPACE_TRANSFORM_SETUP(space_transform, ob, dtmd->ob_source); } mvert = dm->getVertArray(dm); if ((me->mvert == mvert) && (dtmd->data_types & DT_TYPES_AFFECT_MESH)) { /* We need to duplicate data here, otherwise setting custom normals, edges' shaprness, etc., could * modify org mesh, see T43671. */ dm = CDDM_copy(dm); } BKE_reports_init(&reports, RPT_STORE); /* Note: no islands precision for now here. */ BKE_object_data_transfer_dm(md->scene, dtmd->ob_source, ob, dm, dtmd->data_types, false, dtmd->vmap_mode, dtmd->emap_mode, dtmd->lmap_mode, dtmd->pmap_mode, space_transform, max_dist, dtmd->map_ray_radius, 0.0f, dtmd->layers_select_src, dtmd->layers_select_dst, dtmd->mix_mode, dtmd->mix_factor, dtmd->defgrp_name, invert_vgroup, &reports); if (BKE_reports_contain(&reports, RPT_ERROR)) { modifier_setError(md, "%s", BKE_reports_string(&reports, RPT_ERROR)); } else if (dm->getNumVerts(dm) > HIGH_POLY_WARNING || ((Mesh *)(dtmd->ob_source->data))->totvert > HIGH_POLY_WARNING) { modifier_setError(md, "You are using a rather high poly as source or destination, computation might be slow"); } return dm; }
static bool is_valid_target(NormalEditModifierData *enmd) { if (enmd->mode == MOD_NORMALEDIT_MODE_RADIAL) { return true; } else if ((enmd->mode == MOD_NORMALEDIT_MODE_DIRECTIONAL) && enmd->target) { return true; } modifier_setError((ModifierData *)enmd, "Invalid target settings"); return false; }
static void cloth_from_mesh ( ClothModifierData *clmd, DerivedMesh *dm ) { unsigned int numverts = dm->getNumVerts ( dm ); unsigned int numfaces = dm->getNumFaces ( dm ); MFace *mface = dm->getFaceArray( dm ); unsigned int i = 0; /* Allocate our vertices. */ clmd->clothObject->numverts = numverts; clmd->clothObject->verts = MEM_callocN ( sizeof ( ClothVertex ) * clmd->clothObject->numverts, "clothVertex" ); if ( clmd->clothObject->verts == NULL ) { cloth_free_modifier ( clmd ); modifier_setError ( & ( clmd->modifier ), "Out of memory on allocating clmd->clothObject->verts." ); printf("cloth_free_modifier clmd->clothObject->verts\n"); return; } // save face information clmd->clothObject->numfaces = numfaces; clmd->clothObject->mfaces = MEM_callocN ( sizeof ( MFace ) * clmd->clothObject->numfaces, "clothMFaces" ); if ( clmd->clothObject->mfaces == NULL ) { cloth_free_modifier ( clmd ); modifier_setError ( & ( clmd->modifier ), "Out of memory on allocating clmd->clothObject->mfaces." ); printf("cloth_free_modifier clmd->clothObject->mfaces\n"); return; } for ( i = 0; i < numfaces; i++ ) memcpy ( &clmd->clothObject->mfaces[i], &mface[i], sizeof ( MFace ) ); /* Free the springs since they can't be correct if the vertices * changed. */ if ( clmd->clothObject->springs != NULL ) MEM_freeN ( clmd->clothObject->springs ); }
static DerivedMesh *applyModifierEM(ModifierData *md, Object *UNUSED(ob), struct BMEditMesh *UNUSED(editData), DerivedMesh *derivedData, ModifierApplyFlag flag) { SubsurfModifierData *smd = (SubsurfModifierData *) md; DerivedMesh *result; /* 'orco' using editmode flags would cause cache to be used twice in editbmesh_calc_modifiers */ SubsurfFlags ss_flags = (flag & MOD_APPLY_ORCO) ? 0 : (SUBSURF_FOR_EDIT_MODE | SUBSURF_IN_EDIT_MODE); #ifdef WITH_OPENSUBDIV const bool allow_gpu = (flag & MOD_APPLY_ALLOW_GPU) != 0; if (md->next == NULL && allow_gpu && smd->use_opensubdiv) { modifier_setError(md, "OpenSubdiv is not supported in edit mode"); } #endif result = subsurf_make_derived_from_derived(derivedData, smd, NULL, ss_flags); return result; }
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, ModifierApplyFlag flag) { BooleanModifierData *bmd = (BooleanModifierData *) md; DerivedMesh *dm; if (!bmd->object) return derivedData; dm = get_dm_for_modifier(bmd->object, flag); if (dm) { DerivedMesh *result; /* when one of objects is empty (has got no faces) we could speed up * calculation a bit returning one of objects' derived meshes (or empty one) * Returning mesh is depended on modifiers operation (sergey) */ result = get_quick_derivedMesh(derivedData, dm, bmd->operation); if (result == NULL) { // TIMEIT_START(NewBooleanDerivedMesh) result = NewBooleanDerivedMesh(dm, bmd->object, derivedData, ob, 1 + bmd->operation); // TIMEIT_END(NewBooleanDerivedMesh) } /* if new mesh returned, return it; otherwise there was * an error, so delete the modifier object */ if (result) return result; else modifier_setError(md, "Cannot execute boolean operation"); } return derivedData; }
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm, ModifierApplyFlag flag) { #ifdef WITH_ALEMBIC MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md; Scene *scene = md->scene; const float frame = BKE_scene_frame_get(scene); const float time = BKE_cachefile_time_offset(mcmd->cache_file, frame, FPS); const char *err_str = NULL; CacheFile *cache_file = mcmd->cache_file; BKE_cachefile_ensure_handle(G.main, cache_file); DerivedMesh *result = ABC_read_mesh(cache_file->handle, ob, dm, mcmd->object_path, time, &err_str, mcmd->read_flag); if (err_str) { modifier_setError(md, "%s", err_str); } return result ? result : dm; UNUSED_VARS(flag); #else return dm; UNUSED_VARS(md, ob, flag); #endif }
static void correctivesmooth_modifier_do( ModifierData *md, Object *ob, DerivedMesh *dm, 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)->tag & LIB_TAG_ID_RECALC)); bool use_only_smooth = (csmd->flag & MOD_CORRECTIVESMOOTH_ONLY_SMOOTH) != 0; MDeformVert *dvert = NULL; int defgrp_index; modifier_get_vgroup(ob, dm, 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)) { BLI_assert(csmd->bind_coords == NULL); csmd->bind_coords = MEM_dupallocN(vertexCos); csmd->bind_coords_num = numVerts; BLI_assert(csmd->bind_coords != NULL); } if (UNLIKELY(use_only_smooth)) { smooth_verts(csmd, dm, 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, dm, 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, dm, dvert, defgrp_index, vertexCos, numVerts); { unsigned int i; float (*tangent_spaces)[3][3]; /* calloc, since values are accumulated */ tangent_spaces = MEM_callocN((size_t)numVerts * sizeof(float[3][3]), __func__); calc_tangent_spaces(dm, 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; }
static DerivedMesh *normalEditModifier_do(NormalEditModifierData *enmd, Object *ob, DerivedMesh *dm) { Mesh *me = ob->data; const int num_verts = dm->getNumVerts(dm); const int num_edges = dm->getNumEdges(dm); const int num_loops = dm->getNumLoops(dm); const int num_polys = dm->getNumPolys(dm); MVert *mvert; MEdge *medge; MLoop *mloop; MPoly *mpoly; const bool use_invert_vgroup = ((enmd->flag & MOD_NORMALEDIT_INVERT_VGROUP) != 0); const bool use_current_clnors = !((enmd->mix_mode == MOD_NORMALEDIT_MIX_COPY) && (enmd->mix_factor == 1.0f) && (enmd->defgrp_name[0] == '\0') && (enmd->mix_limit == (float)M_PI)); int defgrp_index; MDeformVert *dvert; float (*loopnors)[3] = NULL; short (*clnors)[2]; float (*polynors)[3]; bool free_polynors = false; /* Do not run that modifier at all if autosmooth is disabled! */ if (!is_valid_target(enmd) || !num_loops) { return dm; } if (!(me->flag & ME_AUTOSMOOTH)) { modifier_setError((ModifierData *)enmd, "Enable 'Auto Smooth' option in mesh settings"); return dm; } medge = dm->getEdgeArray(dm); if (me->medge == medge) { /* We need to duplicate data here, otherwise setting custom normals (which may also affect sharp edges) could * modify org mesh, see T43671. */ dm = CDDM_copy(dm); medge = dm->getEdgeArray(dm); } mvert = dm->getVertArray(dm); mloop = dm->getLoopArray(dm); mpoly = dm->getPolyArray(dm); if (use_current_clnors) { dm->calcLoopNormals(dm, true, me->smoothresh); loopnors = dm->getLoopDataArray(dm, CD_NORMAL); } clnors = CustomData_duplicate_referenced_layer(&dm->loopData, CD_CUSTOMLOOPNORMAL, num_loops); if (!clnors) { DM_add_loop_layer(dm, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL); clnors = dm->getLoopDataArray(dm, CD_CUSTOMLOOPNORMAL); } polynors = dm->getPolyDataArray(dm, CD_NORMAL); if (!polynors) { polynors = MEM_malloc_arrayN((size_t)num_polys, sizeof(*polynors), __func__); BKE_mesh_calc_normals_poly(mvert, NULL, num_verts, mloop, mpoly, num_loops, num_polys, polynors, false); free_polynors = true; } modifier_get_vgroup(ob, dm, enmd->defgrp_name, &dvert, &defgrp_index); if (enmd->mode == MOD_NORMALEDIT_MODE_RADIAL) { normalEditModifier_do_radial( enmd, ob, dm, clnors, loopnors, polynors, enmd->mix_mode, enmd->mix_factor, enmd->mix_limit, dvert, defgrp_index, use_invert_vgroup, mvert, num_verts, medge, num_edges, mloop, num_loops, mpoly, num_polys); } else if (enmd->mode == MOD_NORMALEDIT_MODE_DIRECTIONAL) { normalEditModifier_do_directional( enmd, ob, dm, clnors, loopnors, polynors, enmd->mix_mode, enmd->mix_factor, enmd->mix_limit, dvert, defgrp_index, use_invert_vgroup, mvert, num_verts, medge, num_edges, mloop, num_loops, mpoly, num_polys); } if (free_polynors) { MEM_freeN(polynors); } return dm; }
static void LaplacianDeformModifier_do( LaplacianDeformModifierData *lmd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { float (*filevertexCos)[3]; int sysdif; LaplacianSystem *sys = NULL; filevertexCos = NULL; if (!(lmd->flag & MOD_LAPLACIANDEFORM_BIND)) { if (lmd->cache_system) { sys = lmd->cache_system; deleteLaplacianSystem(sys); lmd->cache_system = NULL; } lmd->total_verts = 0; MEM_SAFE_FREE(lmd->vertexco); return; } if (lmd->cache_system) { sysdif = isSystemDifferent(lmd, ob, dm, numVerts); sys = lmd->cache_system; if (sysdif) { if (sysdif == LAPDEFORM_SYSTEM_ONLY_CHANGE_ANCHORS || sysdif == LAPDEFORM_SYSTEM_ONLY_CHANGE_GROUP) { filevertexCos = MEM_mallocN(sizeof(float[3]) * numVerts, "TempModDeformCoordinates"); memcpy(filevertexCos, lmd->vertexco, sizeof(float[3]) * numVerts); MEM_SAFE_FREE(lmd->vertexco); lmd->total_verts = 0; deleteLaplacianSystem(sys); lmd->cache_system = NULL; initSystem(lmd, ob, dm, filevertexCos, numVerts); sys = lmd->cache_system; /* may have been reallocated */ MEM_SAFE_FREE(filevertexCos); if (sys) { laplacianDeformPreview(sys, vertexCos); } } else { if (sysdif == LAPDEFORM_SYSTEM_CHANGE_VERTEXES) { modifier_setError(&lmd->modifier, "Vertices changed from %d to %d", lmd->total_verts, numVerts); } else if (sysdif == LAPDEFORM_SYSTEM_CHANGE_EDGES) { modifier_setError(&lmd->modifier, "Edges changed from %d to %d", sys->total_edges, dm->getNumEdges(dm)); } else if (sysdif == LAPDEFORM_SYSTEM_CHANGE_NOT_VALID_GROUP) { modifier_setError(&lmd->modifier, "Vertex group '%s' is not valid", sys->anchor_grp_name); } } } else { sys->repeat = lmd->repeat; laplacianDeformPreview(sys, vertexCos); } } else { if (lmd->total_verts > 0 && lmd->total_verts == numVerts) { if (isValidVertexGroup(lmd, ob, dm)) { filevertexCos = MEM_mallocN(sizeof(float[3]) * numVerts, "TempDeformCoordinates"); memcpy(filevertexCos, lmd->vertexco, sizeof(float[3]) * numVerts); MEM_SAFE_FREE(lmd->vertexco); lmd->total_verts = 0; initSystem(lmd, ob, dm, filevertexCos, numVerts); sys = lmd->cache_system; MEM_SAFE_FREE(filevertexCos); laplacianDeformPreview(sys, vertexCos); } } else { if (isValidVertexGroup(lmd, ob, dm)) { initSystem(lmd, ob, dm, vertexCos, numVerts); sys = lmd->cache_system; laplacianDeformPreview(sys, vertexCos); } } } if (sys->is_matrix_computed && !sys->has_solution) { modifier_setError(&lmd->modifier, "The system did not find a solution"); } }
static void meshdeformModifier_do( ModifierData *md, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { MeshDeformModifierData *mmd = (MeshDeformModifierData *) md; struct Mesh *me = (mmd->object) ? mmd->object->data : NULL; BMEditMesh *em = me ? me->edit_btmesh : NULL; DerivedMesh *tmpdm, *cagedm; MDeformVert *dvert = NULL; MDefInfluence *influences; int *offsets; float imat[4][4], cagemat[4][4], iobmat[4][4], icagemat[3][3], cmat[4][4]; float weight, totweight, fac, co[3], (*dco)[3], (*bindcagecos)[3]; int a, b, totvert, totcagevert, defgrp_index; float (*cagecos)[3]; if (!mmd->object || (!mmd->bindcagecos && !mmd->bindfunc)) return; /* get cage derivedmesh */ if (em) { tmpdm = editbmesh_get_derived_cage_and_final(md->scene, ob, em, &cagedm, 0); if (tmpdm) tmpdm->release(tmpdm); } else cagedm = mmd->object->derivedFinal; /* if we don't have one computed, use derivedmesh from data * without any modifiers */ if (!cagedm) { cagedm = get_dm(mmd->object, NULL, NULL, NULL, 0); if (cagedm) cagedm->needsFree = 1; } if (!cagedm) { modifier_setError(md, "Cannot get mesh from cage object"); return; } /* compute matrices to go in and out of cage object space */ invert_m4_m4(imat, mmd->object->obmat); mult_m4_m4m4(cagemat, imat, ob->obmat); mult_m4_m4m4(cmat, mmd->bindmat, cagemat); invert_m4_m4(iobmat, cmat); copy_m3_m4(icagemat, iobmat); /* bind weights if needed */ if (!mmd->bindcagecos) { static int recursive = 0; /* progress bar redraw can make this recursive .. */ if (!recursive) { recursive = 1; mmd->bindfunc(md->scene, mmd, (float *)vertexCos, numVerts, cagemat); recursive = 0; } } /* verify we have compatible weights */ totvert = numVerts; totcagevert = cagedm->getNumVerts(cagedm); if (mmd->totvert != totvert) { modifier_setError(md, "Verts changed from %d to %d", mmd->totvert, totvert); cagedm->release(cagedm); return; } else if (mmd->totcagevert != totcagevert) { modifier_setError(md, "Cage verts changed from %d to %d", mmd->totcagevert, totcagevert); cagedm->release(cagedm); return; } else if (mmd->bindcagecos == NULL) { modifier_setError(md, "Bind data missing"); cagedm->release(cagedm); return; } cagecos = MEM_callocN(sizeof(*cagecos) * totcagevert, "meshdeformModifier vertCos"); /* setup deformation data */ cagedm->getVertCos(cagedm, cagecos); influences = mmd->bindinfluences; offsets = mmd->bindoffsets; bindcagecos = (float(*)[3])mmd->bindcagecos; dco = MEM_callocN(sizeof(*dco) * totcagevert, "MDefDco"); for (a = 0; a < totcagevert; a++) { /* get cage vertex in world space with binding transform */ copy_v3_v3(co, cagecos[a]); if (G.debug_value != 527) { mul_m4_v3(mmd->bindmat, co); /* compute difference with world space bind coord */ sub_v3_v3v3(dco[a], co, bindcagecos[a]); } else copy_v3_v3(dco[a], co); } modifier_get_vgroup(ob, dm, mmd->defgrp_name, &dvert, &defgrp_index); /* do deformation */ fac = 1.0f; for (b = 0; b < totvert; b++) { if (mmd->flag & MOD_MDEF_DYNAMIC_BIND) if (!mmd->dynverts[b]) continue; if (dvert) { fac = defvert_find_weight(&dvert[b], defgrp_index); if (mmd->flag & MOD_MDEF_INVERT_VGROUP) { fac = 1.0f - fac; } if (fac <= 0.0f) { continue; } } if (mmd->flag & MOD_MDEF_DYNAMIC_BIND) { /* transform coordinate into cage's local space */ mul_v3_m4v3(co, cagemat, vertexCos[b]); totweight = meshdeform_dynamic_bind(mmd, dco, co); } else { totweight = 0.0f; zero_v3(co); for (a = offsets[b]; a < offsets[b + 1]; a++) { weight = influences[a].weight; madd_v3_v3fl(co, dco[influences[a].vertex], weight); totweight += weight; } } if (totweight > 0.0f) { mul_v3_fl(co, fac / totweight); mul_m3_v3(icagemat, co); if (G.debug_value != 527) add_v3_v3(vertexCos[b], co); else copy_v3_v3(vertexCos[b], co); } } /* release cage derivedmesh */ MEM_freeN(dco); MEM_freeN(cagecos); cagedm->release(cagedm); }
static DerivedMesh *applyModifier( ModifierData *md, Object *ob, DerivedMesh *dm, ModifierApplyFlag UNUSED(flag)) { DerivedMesh *result; const SolidifyModifierData *smd = (SolidifyModifierData *) md; MVert *mv, *mvert, *orig_mvert; MEdge *ed, *medge, *orig_medge; MLoop *ml, *mloop, *orig_mloop; MPoly *mp, *mpoly, *orig_mpoly; const unsigned int numVerts = (unsigned int)dm->getNumVerts(dm); const unsigned int numEdges = (unsigned int)dm->getNumEdges(dm); const unsigned int numFaces = (unsigned int)dm->getNumPolys(dm); const unsigned int numLoops = (unsigned int)dm->getNumLoops(dm); unsigned int newLoops = 0, newFaces = 0, newEdges = 0, newVerts = 0, rimVerts = 0; /* only use material offsets if we have 2 or more materials */ const short mat_nr_max = ob->totcol > 1 ? ob->totcol - 1 : 0; const short mat_ofs = mat_nr_max ? smd->mat_ofs : 0; const short mat_ofs_rim = mat_nr_max ? smd->mat_ofs_rim : 0; /* use for edges */ /* over-alloc new_vert_arr, old_vert_arr */ unsigned int *new_vert_arr = NULL; STACK_DECLARE(new_vert_arr); unsigned int *new_edge_arr = NULL; STACK_DECLARE(new_edge_arr); unsigned int *old_vert_arr = MEM_callocN(sizeof(*old_vert_arr) * (size_t)numVerts, "old_vert_arr in solidify"); unsigned int *edge_users = NULL; char *edge_order = NULL; float (*vert_nors)[3] = NULL; float (*face_nors)[3] = NULL; const bool need_face_normals = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) || (smd->flag & MOD_SOLIDIFY_EVEN); const float ofs_orig = -(((-smd->offset_fac + 1.0f) * 0.5f) * smd->offset); const float ofs_new = smd->offset + ofs_orig; const float offset_fac_vg = smd->offset_fac_vg; const float offset_fac_vg_inv = 1.0f - smd->offset_fac_vg; const bool do_flip = (smd->flag & MOD_SOLIDIFY_FLIP) != 0; const bool do_clamp = (smd->offset_clamp != 0.0f); const bool do_shell = ((smd->flag & MOD_SOLIDIFY_RIM) && (smd->flag & MOD_SOLIDIFY_NOSHELL)) == 0; /* weights */ MDeformVert *dvert; const bool defgrp_invert = (smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0; int defgrp_index; /* array size is doubled in case of using a shell */ const unsigned int stride = do_shell ? 2 : 1; modifier_get_vgroup(ob, dm, smd->defgrp_name, &dvert, &defgrp_index); orig_mvert = dm->getVertArray(dm); orig_medge = dm->getEdgeArray(dm); orig_mloop = dm->getLoopArray(dm); orig_mpoly = dm->getPolyArray(dm); if (need_face_normals) { /* calculate only face normals */ face_nors = MEM_mallocN(sizeof(*face_nors) * (size_t)numFaces, __func__); BKE_mesh_calc_normals_poly( orig_mvert, NULL, (int)numVerts, orig_mloop, orig_mpoly, (int)numLoops, (int)numFaces, face_nors, true); } STACK_INIT(new_vert_arr, numVerts * 2); STACK_INIT(new_edge_arr, numEdges * 2); if (smd->flag & MOD_SOLIDIFY_RIM) { BLI_bitmap *orig_mvert_tag = BLI_BITMAP_NEW(numVerts, __func__); unsigned int eidx; unsigned int i; #define INVALID_UNUSED ((unsigned int)-1) #define INVALID_PAIR ((unsigned int)-2) new_vert_arr = MEM_mallocN(sizeof(*new_vert_arr) * (size_t)(numVerts * 2), __func__); new_edge_arr = MEM_mallocN(sizeof(*new_edge_arr) * (size_t)((numEdges * 2) + numVerts), __func__); edge_users = MEM_mallocN(sizeof(*edge_users) * (size_t)numEdges, "solid_mod edges"); edge_order = MEM_mallocN(sizeof(*edge_order) * (size_t)numEdges, "solid_mod eorder"); /* save doing 2 loops here... */ #if 0 copy_vn_i(edge_users, numEdges, INVALID_UNUSED); #endif for (eidx = 0, ed = orig_medge; eidx < numEdges; eidx++, ed++) { edge_users[eidx] = INVALID_UNUSED; } for (i = 0, mp = orig_mpoly; i < numFaces; i++, mp++) { MLoop *ml_prev; int j; ml = orig_mloop + mp->loopstart; ml_prev = ml + (mp->totloop - 1); for (j = 0; j < mp->totloop; j++, ml++) { /* add edge user */ eidx = ml_prev->e; if (edge_users[eidx] == INVALID_UNUSED) { ed = orig_medge + eidx; BLI_assert(ELEM(ml_prev->v, ed->v1, ed->v2) && ELEM(ml->v, ed->v1, ed->v2)); edge_users[eidx] = (ml_prev->v > ml->v) == (ed->v1 < ed->v2) ? i : (i + numFaces); edge_order[eidx] = j; } else { edge_users[eidx] = INVALID_PAIR; } ml_prev = ml; } } for (eidx = 0, ed = orig_medge; eidx < numEdges; eidx++, ed++) { if (!ELEM(edge_users[eidx], INVALID_UNUSED, INVALID_PAIR)) { BLI_BITMAP_ENABLE(orig_mvert_tag, ed->v1); BLI_BITMAP_ENABLE(orig_mvert_tag, ed->v2); STACK_PUSH(new_edge_arr, eidx); newFaces++; newLoops += 4; } } for (i = 0; i < numVerts; i++) { if (BLI_BITMAP_TEST(orig_mvert_tag, i)) { old_vert_arr[i] = STACK_SIZE(new_vert_arr); STACK_PUSH(new_vert_arr, i); rimVerts++; } else { old_vert_arr[i] = INVALID_UNUSED; } } MEM_freeN(orig_mvert_tag); } if (do_shell == false) { /* only add rim vertices */ newVerts = rimVerts; /* each extruded face needs an opposite edge */ newEdges = newFaces; } else { /* (stride == 2) in this case, so no need to add newVerts/newEdges */ BLI_assert(newVerts == 0); BLI_assert(newEdges == 0); } if (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) { vert_nors = MEM_callocN(sizeof(float) * (size_t)numVerts * 3, "mod_solid_vno_hq"); dm_calc_normal(dm, face_nors, vert_nors); } result = CDDM_from_template(dm, (int)((numVerts * stride) + newVerts), (int)((numEdges * stride) + newEdges + rimVerts), 0, (int)((numLoops * stride) + newLoops), (int)((numFaces * stride) + newFaces)); mpoly = CDDM_get_polys(result); mloop = CDDM_get_loops(result); medge = CDDM_get_edges(result); mvert = CDDM_get_verts(result); if (do_shell) { DM_copy_vert_data(dm, result, 0, 0, (int)numVerts); DM_copy_vert_data(dm, result, 0, (int)numVerts, (int)numVerts); DM_copy_edge_data(dm, result, 0, 0, (int)numEdges); DM_copy_edge_data(dm, result, 0, (int)numEdges, (int)numEdges); DM_copy_loop_data(dm, result, 0, 0, (int)numLoops); DM_copy_loop_data(dm, result, 0, (int)numLoops, (int)numLoops); DM_copy_poly_data(dm, result, 0, 0, (int)numFaces); DM_copy_poly_data(dm, result, 0, (int)numFaces, (int)numFaces); } else { int i, j; DM_copy_vert_data(dm, result, 0, 0, (int)numVerts); for (i = 0, j = (int)numVerts; i < numVerts; i++) { if (old_vert_arr[i] != INVALID_UNUSED) { DM_copy_vert_data(dm, result, i, j, 1); j++; } } DM_copy_edge_data(dm, result, 0, 0, (int)numEdges); for (i = 0, j = (int)numEdges; i < numEdges; i++) { if (!ELEM(edge_users[i], INVALID_UNUSED, INVALID_PAIR)) { MEdge *ed_src, *ed_dst; DM_copy_edge_data(dm, result, i, j, 1); ed_src = &medge[i]; ed_dst = &medge[j]; ed_dst->v1 = old_vert_arr[ed_src->v1] + numVerts; ed_dst->v2 = old_vert_arr[ed_src->v2] + numVerts; j++; } } /* will be created later */ DM_copy_loop_data(dm, result, 0, 0, (int)numLoops); DM_copy_poly_data(dm, result, 0, 0, (int)numFaces); } #undef INVALID_UNUSED #undef INVALID_PAIR /* initializes: (i_end, do_shell_align, mv) */ #define INIT_VERT_ARRAY_OFFSETS(test) \ if (((ofs_new >= ofs_orig) == do_flip) == test) { \ i_end = numVerts; \ do_shell_align = true; \ mv = mvert; \ } \ else { \ if (do_shell) { \ i_end = numVerts; \ do_shell_align = true; \ } \ else { \ i_end = newVerts ; \ do_shell_align = false; \ } \ mv = &mvert[numVerts]; \ } (void)0 /* flip normals */ if (do_shell) { unsigned int i; mp = mpoly + numFaces; for (i = 0; i < dm->numPolyData; i++, mp++) { MLoop *ml2; unsigned int e; int j; /* reverses the loop direction (MLoop.v as well as custom-data) * MLoop.e also needs to be corrected too, done in a separate loop below. */ ml2 = mloop + mp->loopstart + dm->numLoopData; for (j = 0; j < mp->totloop; j++) { CustomData_copy_data(&dm->loopData, &result->loopData, mp->loopstart + j, mp->loopstart + (mp->totloop - j - 1) + dm->numLoopData, 1); } if (mat_ofs) { mp->mat_nr += mat_ofs; CLAMP(mp->mat_nr, 0, mat_nr_max); } e = ml2[0].e; for (j = 0; j < mp->totloop - 1; j++) { ml2[j].e = ml2[j + 1].e; } ml2[mp->totloop - 1].e = e; mp->loopstart += dm->numLoopData; for (j = 0; j < mp->totloop; j++) { ml2[j].e += numEdges; ml2[j].v += numVerts; } } for (i = 0, ed = medge + numEdges; i < numEdges; i++, ed++) { ed->v1 += numVerts; ed->v2 += numVerts; } } /* note, copied vertex layers don't have flipped normals yet. do this after applying offset */ if ((smd->flag & MOD_SOLIDIFY_EVEN) == 0) { /* no even thickness, very simple */ float scalar_short; float scalar_short_vgroup; /* for clamping */ float *vert_lens = NULL; const float offset = fabsf(smd->offset) * smd->offset_clamp; const float offset_sq = offset * offset; if (do_clamp) { unsigned int i; vert_lens = MEM_mallocN(sizeof(float) * numVerts, "vert_lens"); copy_vn_fl(vert_lens, (int)numVerts, FLT_MAX); for (i = 0; i < numEdges; i++) { const float ed_len_sq = len_squared_v3v3(mvert[medge[i].v1].co, mvert[medge[i].v2].co); vert_lens[medge[i].v1] = min_ff(vert_lens[medge[i].v1], ed_len_sq); vert_lens[medge[i].v2] = min_ff(vert_lens[medge[i].v2], ed_len_sq); } } if (ofs_new != 0.0f) { unsigned int i_orig, i_end; bool do_shell_align; scalar_short = scalar_short_vgroup = ofs_new / 32767.0f; INIT_VERT_ARRAY_OFFSETS(false); for (i_orig = 0; i_orig < i_end; i_orig++, mv++) { const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig]; if (dvert) { MDeformVert *dv = &dvert[i]; if (defgrp_invert) scalar_short_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index); else scalar_short_vgroup = defvert_find_weight(dv, defgrp_index); scalar_short_vgroup = (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) * scalar_short; } if (do_clamp) { /* always reset becaise we may have set before */ if (dvert == NULL) { scalar_short_vgroup = scalar_short; } if (vert_lens[i] < offset_sq) { float scalar = sqrtf(vert_lens[i]) / offset; scalar_short_vgroup *= scalar; } } madd_v3v3short_fl(mv->co, mv->no, scalar_short_vgroup); } } if (ofs_orig != 0.0f) { unsigned int i_orig, i_end; bool do_shell_align; scalar_short = scalar_short_vgroup = ofs_orig / 32767.0f; /* as above but swapped */ INIT_VERT_ARRAY_OFFSETS(true); for (i_orig = 0; i_orig < i_end; i_orig++, mv++) { const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig]; if (dvert) { MDeformVert *dv = &dvert[i]; if (defgrp_invert) scalar_short_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index); else scalar_short_vgroup = defvert_find_weight(dv, defgrp_index); scalar_short_vgroup = (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) * scalar_short; } if (do_clamp) { /* always reset becaise we may have set before */ if (dvert == NULL) { scalar_short_vgroup = scalar_short; } if (vert_lens[i] < offset_sq) { float scalar = sqrtf(vert_lens[i]) / offset; scalar_short_vgroup *= scalar; } } madd_v3v3short_fl(mv->co, mv->no, scalar_short_vgroup); } } if (do_clamp) { MEM_freeN(vert_lens); } } else { #ifdef USE_NONMANIFOLD_WORKAROUND const bool check_non_manifold = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) != 0; #endif /* same as EM_solidify() in editmesh_lib.c */ float *vert_angles = MEM_callocN(sizeof(float) * numVerts * 2, "mod_solid_pair"); /* 2 in 1 */ float *vert_accum = vert_angles + numVerts; unsigned int vidx; unsigned int i; if (vert_nors == NULL) { vert_nors = MEM_mallocN(sizeof(float) * numVerts * 3, "mod_solid_vno"); for (i = 0, mv = mvert; i < numVerts; i++, mv++) { normal_short_to_float_v3(vert_nors[i], mv->no); } } for (i = 0, mp = mpoly; i < numFaces; i++, mp++) { /* #BKE_mesh_calc_poly_angles logic is inlined here */ float nor_prev[3]; float nor_next[3]; int i_curr = mp->totloop - 1; int i_next = 0; ml = &mloop[mp->loopstart]; sub_v3_v3v3(nor_prev, mvert[ml[i_curr - 1].v].co, mvert[ml[i_curr].v].co); normalize_v3(nor_prev); while (i_next < mp->totloop) { float angle; sub_v3_v3v3(nor_next, mvert[ml[i_curr].v].co, mvert[ml[i_next].v].co); normalize_v3(nor_next); angle = angle_normalized_v3v3(nor_prev, nor_next); /* --- not related to angle calc --- */ if (angle < FLT_EPSILON) { angle = FLT_EPSILON; } vidx = ml[i_curr].v; vert_accum[vidx] += angle; #ifdef USE_NONMANIFOLD_WORKAROUND /* skip 3+ face user edges */ if ((check_non_manifold == false) || LIKELY(((orig_medge[ml[i_curr].e].flag & ME_EDGE_TMP_TAG) == 0) && ((orig_medge[ml[i_next].e].flag & ME_EDGE_TMP_TAG) == 0))) { vert_angles[vidx] += shell_v3v3_normalized_to_dist(vert_nors[vidx], face_nors[i]) * angle; } else { vert_angles[vidx] += angle; } #else vert_angles[vidx] += shell_v3v3_normalized_to_dist(vert_nors[vidx], face_nors[i]) * angle; #endif /* --- end non-angle-calc section --- */ /* step */ copy_v3_v3(nor_prev, nor_next); i_curr = i_next; i_next++; } } /* vertex group support */ if (dvert) { MDeformVert *dv = dvert; float scalar; if (defgrp_invert) { for (i = 0; i < numVerts; i++, dv++) { scalar = 1.0f - defvert_find_weight(dv, defgrp_index); scalar = offset_fac_vg + (scalar * offset_fac_vg_inv); vert_angles[i] *= scalar; } } else { for (i = 0; i < numVerts; i++, dv++) { scalar = defvert_find_weight(dv, defgrp_index); scalar = offset_fac_vg + (scalar * offset_fac_vg_inv); vert_angles[i] *= scalar; } } } if (do_clamp) { float *vert_lens_sq = MEM_mallocN(sizeof(float) * numVerts, "vert_lens"); const float offset = fabsf(smd->offset) * smd->offset_clamp; const float offset_sq = offset * offset; copy_vn_fl(vert_lens_sq, (int)numVerts, FLT_MAX); for (i = 0; i < numEdges; i++) { const float ed_len = len_squared_v3v3(mvert[medge[i].v1].co, mvert[medge[i].v2].co); vert_lens_sq[medge[i].v1] = min_ff(vert_lens_sq[medge[i].v1], ed_len); vert_lens_sq[medge[i].v2] = min_ff(vert_lens_sq[medge[i].v2], ed_len); } for (i = 0; i < numVerts; i++) { if (vert_lens_sq[i] < offset_sq) { float scalar = sqrtf(vert_lens_sq[i]) / offset; vert_angles[i] *= scalar; } } MEM_freeN(vert_lens_sq); } if (ofs_new != 0.0f) { unsigned int i_orig, i_end; bool do_shell_align; INIT_VERT_ARRAY_OFFSETS(false); for (i_orig = 0; i_orig < i_end; i_orig++, mv++) { const unsigned int i_other = do_shell_align ? i_orig : new_vert_arr[i_orig]; if (vert_accum[i_other]) { /* zero if unselected */ madd_v3_v3fl(mv->co, vert_nors[i_other], ofs_new * (vert_angles[i_other] / vert_accum[i_other])); } } } if (ofs_orig != 0.0f) { unsigned int i_orig, i_end; bool do_shell_align; /* same as above but swapped, intentional use of 'ofs_new' */ INIT_VERT_ARRAY_OFFSETS(true); for (i_orig = 0; i_orig < i_end; i_orig++, mv++) { const unsigned int i_other = do_shell_align ? i_orig : new_vert_arr[i_orig]; if (vert_accum[i_other]) { /* zero if unselected */ madd_v3_v3fl(mv->co, vert_nors[i_other], ofs_orig * (vert_angles[i_other] / vert_accum[i_other])); } } } MEM_freeN(vert_angles); } if (vert_nors) MEM_freeN(vert_nors); /* must recalculate normals with vgroups since they can displace unevenly [#26888] */ if ((dm->dirty & DM_DIRTY_NORMALS) || (smd->flag & MOD_SOLIDIFY_RIM) || dvert) { result->dirty |= DM_DIRTY_NORMALS; } else if (do_shell) { unsigned int i; /* flip vertex normals for copied verts */ mv = mvert + numVerts; for (i = 0; i < numVerts; i++, mv++) { negate_v3_short(mv->no); } } if (smd->flag & MOD_SOLIDIFY_RIM) { unsigned int i; /* bugger, need to re-calculate the normals for the new edge faces. * This could be done in many ways, but probably the quickest way * is to calculate the average normals for side faces only. * Then blend them with the normals of the edge verts. * * at the moment its easiest to allocate an entire array for every vertex, * even though we only need edge verts - campbell */ #define SOLIDIFY_SIDE_NORMALS #ifdef SOLIDIFY_SIDE_NORMALS const bool do_side_normals = !(result->dirty & DM_DIRTY_NORMALS); /* annoying to allocate these since we only need the edge verts, */ float (*edge_vert_nos)[3] = do_side_normals ? MEM_callocN(sizeof(float) * numVerts * 3, __func__) : NULL; float nor[3]; #endif const unsigned char crease_rim = smd->crease_rim * 255.0f; const unsigned char crease_outer = smd->crease_outer * 255.0f; const unsigned char crease_inner = smd->crease_inner * 255.0f; int *origindex_edge; int *orig_ed; unsigned int j; if (crease_rim || crease_outer || crease_inner) { result->cd_flag |= ME_CDFLAG_EDGE_CREASE; } /* add faces & edges */ origindex_edge = result->getEdgeDataArray(result, CD_ORIGINDEX); ed = &medge[(numEdges * stride) + newEdges]; /* start after copied edges */ orig_ed = &origindex_edge[(numEdges * stride) + newEdges]; for (i = 0; i < rimVerts; i++, ed++, orig_ed++) { ed->v1 = new_vert_arr[i]; ed->v2 = (do_shell ? new_vert_arr[i] : i) + numVerts; ed->flag |= ME_EDGEDRAW; *orig_ed = ORIGINDEX_NONE; if (crease_rim) { ed->crease = crease_rim; } } /* faces */ mp = mpoly + (numFaces * stride); ml = mloop + (numLoops * stride); j = 0; for (i = 0; i < newFaces; i++, mp++) { unsigned int eidx = new_edge_arr[i]; unsigned int fidx = edge_users[eidx]; int k1, k2; bool flip; if (fidx >= numFaces) { fidx -= numFaces; flip = true; } else { flip = false; } ed = medge + eidx; /* copy most of the face settings */ DM_copy_poly_data(dm, result, (int)fidx, (int)((numFaces * stride) + i), 1); mp->loopstart = (int)(j + (numLoops * stride)); mp->flag = mpoly[fidx].flag; /* notice we use 'mp->totloop' which is later overwritten, * we could lookup the original face but theres no point since this is a copy * and will have the same value, just take care when changing order of assignment */ k1 = mpoly[fidx].loopstart + (((edge_order[eidx] - 1) + mp->totloop) % mp->totloop); /* prev loop */ k2 = mpoly[fidx].loopstart + (edge_order[eidx]); mp->totloop = 4; CustomData_copy_data(&dm->loopData, &result->loopData, k2, (int)((numLoops * stride) + j + 0), 1); CustomData_copy_data(&dm->loopData, &result->loopData, k1, (int)((numLoops * stride) + j + 1), 1); CustomData_copy_data(&dm->loopData, &result->loopData, k1, (int)((numLoops * stride) + j + 2), 1); CustomData_copy_data(&dm->loopData, &result->loopData, k2, (int)((numLoops * stride) + j + 3), 1); if (flip == false) { ml[j].v = ed->v1; ml[j++].e = eidx; ml[j].v = ed->v2; ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v2] + newEdges; ml[j].v = (do_shell ? ed->v2 : old_vert_arr[ed->v2]) + numVerts; ml[j++].e = (do_shell ? eidx : i) + numEdges; ml[j].v = (do_shell ? ed->v1 : old_vert_arr[ed->v1]) + numVerts; ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v1] + newEdges; } else { ml[j].v = ed->v2; ml[j++].e = eidx; ml[j].v = ed->v1; ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v1] + newEdges; ml[j].v = (do_shell ? ed->v1 : old_vert_arr[ed->v1]) + numVerts; ml[j++].e = (do_shell ? eidx : i) + numEdges; ml[j].v = (do_shell ? ed->v2 : old_vert_arr[ed->v2]) + numVerts; ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v2] + newEdges; } origindex_edge[ml[j - 3].e] = ORIGINDEX_NONE; origindex_edge[ml[j - 1].e] = ORIGINDEX_NONE; /* use the next material index if option enabled */ if (mat_ofs_rim) { mp->mat_nr += mat_ofs_rim; CLAMP(mp->mat_nr, 0, mat_nr_max); } if (crease_outer) { /* crease += crease_outer; without wrapping */ char *cr = &(ed->crease); int tcr = *cr + crease_outer; *cr = tcr > 255 ? 255 : tcr; } if (crease_inner) { /* crease += crease_inner; without wrapping */ char *cr = &(medge[numEdges + (do_shell ? eidx : i)].crease); int tcr = *cr + crease_inner; *cr = tcr > 255 ? 255 : tcr; } #ifdef SOLIDIFY_SIDE_NORMALS if (do_side_normals) { normal_quad_v3(nor, mvert[ml[j - 4].v].co, mvert[ml[j - 3].v].co, mvert[ml[j - 2].v].co, mvert[ml[j - 1].v].co); add_v3_v3(edge_vert_nos[ed->v1], nor); add_v3_v3(edge_vert_nos[ed->v2], nor); } #endif } #ifdef SOLIDIFY_SIDE_NORMALS if (do_side_normals) { ed = medge + (numEdges * stride); for (i = 0; i < rimVerts; i++, ed++) { float nor_cpy[3]; short *nor_short; int k; /* note, only the first vertex (lower half of the index) is calculated */ normalize_v3_v3(nor_cpy, edge_vert_nos[ed->v1]); for (k = 0; k < 2; k++) { /* loop over both verts of the edge */ nor_short = mvert[*(&ed->v1 + k)].no; normal_short_to_float_v3(nor, nor_short); add_v3_v3(nor, nor_cpy); normalize_v3(nor); normal_float_to_short_v3(nor_short, nor); } } MEM_freeN(edge_vert_nos); } #endif MEM_freeN(new_vert_arr); MEM_freeN(new_edge_arr); MEM_freeN(edge_users); MEM_freeN(edge_order); } if (old_vert_arr) MEM_freeN(old_vert_arr); if (face_nors) MEM_freeN(face_nors); if (numFaces == 0 && numEdges != 0) { modifier_setError(md, "Faces needed for useful output"); } return result; }
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm, ModifierApplyFlag UNUSED(flag)) { UVWarpModifierData *umd = (UVWarpModifierData *) md; int numPolys, numLoops; MPoly *mpoly; MLoop *mloop; MLoopUV *mloopuv; MDeformVert *dvert; int defgrp_index; char uvname[MAX_CUSTOMDATA_LAYER_NAME]; float mat_src[4][4]; float mat_dst[4][4]; float imat_dst[4][4]; float warp_mat[4][4]; const int axis_u = umd->axis_u; const int axis_v = umd->axis_v; /* make sure there are UV Maps available */ if (!CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) { return dm; } else if (ELEM(NULL, umd->object_src, umd->object_dst)) { modifier_setError(md, "From/To objects must be set"); return dm; } /* make sure anything moving UVs is available */ matrix_from_obj_pchan(mat_src, umd->object_src, umd->bone_src); matrix_from_obj_pchan(mat_dst, umd->object_dst, umd->bone_dst); invert_m4_m4(imat_dst, mat_dst); mul_m4_m4m4(warp_mat, imat_dst, mat_src); /* apply warp */ if (!is_zero_v2(umd->center)) { float mat_cent[4][4]; float imat_cent[4][4]; unit_m4(mat_cent); mat_cent[3][axis_u] = umd->center[0]; mat_cent[3][axis_v] = umd->center[1]; invert_m4_m4(imat_cent, mat_cent); mul_m4_m4m4(warp_mat, warp_mat, imat_cent); mul_m4_m4m4(warp_mat, mat_cent, warp_mat); } /* make sure we're using an existing layer */ CustomData_validate_layer_name(&dm->loopData, CD_MLOOPUV, umd->uvlayer_name, uvname); numPolys = dm->getNumPolys(dm); numLoops = dm->getNumLoops(dm); mpoly = dm->getPolyArray(dm); mloop = dm->getLoopArray(dm); /* make sure we are not modifying the original UV map */ mloopuv = CustomData_duplicate_referenced_layer_named(&dm->loopData, CD_MLOOPUV, uvname, numLoops); modifier_get_vgroup(ob, dm, umd->vgroup_name, &dvert, &defgrp_index); UVWarpData data = {.mpoly = mpoly, .mloop = mloop, .mloopuv = mloopuv, .dvert = dvert, .defgrp_index = defgrp_index, .warp_mat = warp_mat, .axis_u = axis_u, .axis_v = axis_v}; BLI_task_parallel_range(0, numPolys, &data, uv_warp_compute, numPolys > 1000); dm->dirty |= DM_DIRTY_TESS_CDLAYERS; return dm; }
static void meshdeform_matrix_solve(MeshDeformModifierData *mmd, MeshDeformBind *mdb) { LinearSolver *context; float vec[3], gridvec[3]; int a, b, x, y, z, totvar; char message[256]; /* setup variable indices */ mdb->varidx = MEM_callocN(sizeof(int) * mdb->size3, "MeshDeformDSvaridx"); for (a = 0, totvar = 0; a < mdb->size3; a++) mdb->varidx[a] = (mdb->tag[a] == MESHDEFORM_TAG_EXTERIOR) ? -1 : totvar++; if (totvar == 0) { MEM_freeN(mdb->varidx); return; } progress_bar(0, "Starting mesh deform solve"); /* setup linear solver */ context = EIG_linear_solver_new(totvar, totvar, 1); /* build matrix */ for (z = 0; z < mdb->size; z++) for (y = 0; y < mdb->size; y++) for (x = 0; x < mdb->size; x++) meshdeform_matrix_add_cell(mdb, context, x, y, z); /* solve for each cage vert */ for (a = 0; a < mdb->totcagevert; a++) { /* fill in right hand side and solve */ for (z = 0; z < mdb->size; z++) for (y = 0; y < mdb->size; y++) for (x = 0; x < mdb->size; x++) meshdeform_matrix_add_rhs(mdb, context, x, y, z, a); if (EIG_linear_solver_solve(context)) { for (z = 0; z < mdb->size; z++) for (y = 0; y < mdb->size; y++) for (x = 0; x < mdb->size; x++) meshdeform_matrix_add_semibound_phi(mdb, x, y, z, a); for (z = 0; z < mdb->size; z++) for (y = 0; y < mdb->size; y++) for (x = 0; x < mdb->size; x++) meshdeform_matrix_add_exterior_phi(mdb, x, y, z, a); for (b = 0; b < mdb->size3; b++) { if (mdb->tag[b] != MESHDEFORM_TAG_EXTERIOR) mdb->phi[b] = EIG_linear_solver_variable_get(context, 0, mdb->varidx[b]); mdb->totalphi[b] += mdb->phi[b]; } if (mdb->weights) { /* static bind : compute weights for each vertex */ for (b = 0; b < mdb->totvert; b++) { if (mdb->inside[b]) { copy_v3_v3(vec, mdb->vertexcos[b]); gridvec[0] = (vec[0] - mdb->min[0] - mdb->halfwidth[0]) / mdb->width[0]; gridvec[1] = (vec[1] - mdb->min[1] - mdb->halfwidth[1]) / mdb->width[1]; gridvec[2] = (vec[2] - mdb->min[2] - mdb->halfwidth[2]) / mdb->width[2]; mdb->weights[b * mdb->totcagevert + a] = meshdeform_interp_w(mdb, gridvec, vec, a); } } } else { MDefBindInfluence *inf; /* dynamic bind */ for (b = 0; b < mdb->size3; b++) { if (mdb->phi[b] >= MESHDEFORM_MIN_INFLUENCE) { inf = BLI_memarena_alloc(mdb->memarena, sizeof(*inf)); inf->vertex = a; inf->weight = mdb->phi[b]; inf->next = mdb->dyngrid[b]; mdb->dyngrid[b] = inf; } } } } else { modifier_setError(&mmd->modifier, "Failed to find bind solution (increase precision?)"); error("Mesh Deform: failed to find bind solution."); break; } BLI_snprintf(message, sizeof(message), "Mesh deform solve %d / %d |||", a + 1, mdb->totcagevert); progress_bar((float)(a + 1) / (float)(mdb->totcagevert), message); } #if 0 /* sanity check */ for (b = 0; b < mdb->size3; b++) if (mdb->tag[b] != MESHDEFORM_TAG_EXTERIOR) if (fabsf(mdb->totalphi[b] - 1.0f) > 1e-4f) printf("totalphi deficiency [%s|%d] %d: %.10f\n", (mdb->tag[b] == MESHDEFORM_TAG_INTERIOR) ? "interior" : "boundary", mdb->semibound[b], mdb->varidx[b], mdb->totalphi[b]); #endif /* free */ MEM_freeN(mdb->varidx); EIG_linear_solver_delete(context); }
static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float UNUSED(framenr), int first) { int i = 0; MVert *mvert = NULL; ClothVertex *verts = NULL; float (*shapekey_rest)[3]= NULL; float tnull[3] = {0,0,0}; Cloth *cloth = NULL; float maxdist = 0; // If we have a clothObject, free it. if ( clmd->clothObject != NULL ) { cloth_free_modifier ( clmd ); if(G.rt > 0) printf("cloth_free_modifier cloth_from_object\n"); } // Allocate a new cloth object. clmd->clothObject = MEM_callocN ( sizeof ( Cloth ), "cloth" ); if ( clmd->clothObject ) { clmd->clothObject->old_solver_type = 255; // clmd->clothObject->old_collision_type = 255; cloth = clmd->clothObject; clmd->clothObject->edgehash = NULL; } else if ( !clmd->clothObject ) { modifier_setError ( & ( clmd->modifier ), "Out of memory on allocating clmd->clothObject." ); return 0; } // mesh input objects need DerivedMesh if ( !dm ) return 0; cloth_from_mesh ( clmd, dm ); // create springs clmd->clothObject->springs = NULL; clmd->clothObject->numsprings = -1; if( clmd->sim_parms->shapekey_rest ) shapekey_rest = dm->getVertDataArray ( dm, CD_CLOTH_ORCO ); mvert = dm->getVertArray ( dm ); verts = clmd->clothObject->verts; // set initial values for ( i = 0; i < dm->getNumVerts(dm); i++, verts++ ) { if(first) { copy_v3_v3( verts->x, mvert[i].co ); mul_m4_v3( ob->obmat, verts->x ); if( shapekey_rest ) { verts->xrest= shapekey_rest[i]; mul_m4_v3( ob->obmat, verts->xrest ); } else verts->xrest = verts->x; } /* no GUI interface yet */ verts->mass = clmd->sim_parms->mass; verts->impulse_count = 0; if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) verts->goal= clmd->sim_parms->defgoal; else verts->goal= 0.0f; verts->flags = 0; copy_v3_v3 ( verts->xold, verts->x ); copy_v3_v3 ( verts->xconst, verts->x ); copy_v3_v3 ( verts->txold, verts->x ); copy_v3_v3 ( verts->tx, verts->x ); mul_v3_fl( verts->v, 0.0f ); verts->impulse_count = 0; copy_v3_v3 ( verts->impulse, tnull ); } // apply / set vertex groups // has to be happen before springs are build! cloth_apply_vgroup (clmd, dm); if ( !cloth_build_springs ( clmd, dm ) ) { cloth_free_modifier ( clmd ); modifier_setError ( & ( clmd->modifier ), "Can't build springs." ); printf("cloth_free_modifier cloth_build_springs\n"); return 0; } for ( i = 0; i < dm->getNumVerts(dm); i++) { if((!(cloth->verts[i].flags & CLOTH_VERT_FLAG_PINNED)) && (cloth->verts[i].goal > ALMOST_ZERO)) { cloth_add_spring (clmd, i, i, 0.0, CLOTH_SPRING_TYPE_GOAL); } } // init our solver if ( solvers [clmd->sim_parms->solver_type].init ) { solvers [clmd->sim_parms->solver_type].init ( ob, clmd ); } if(!first) implicit_set_positions(clmd); clmd->clothObject->bvhtree = bvhtree_build_from_cloth ( clmd, MAX2(clmd->coll_parms->epsilon, clmd->coll_parms->distance_repel) ); for(i = 0; i < dm->getNumVerts(dm); i++) { maxdist = MAX2(maxdist, clmd->coll_parms->selfepsilon* ( cloth->verts[i].avg_spring_len*2.0f)); } clmd->clothObject->bvhselftree = bvhselftree_build_from_cloth ( clmd, maxdist ); return 1; }
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm, ModifierApplyFlag UNUSED(flag)) { UVWarpModifierData *umd = (UVWarpModifierData *) md; int i, numPolys, numLoops; MPoly *mpoly; MLoop *mloop; MLoopUV *mloopuv; MDeformVert *dvert; int defgrp_index; char uvname[MAX_CUSTOMDATA_LAYER_NAME]; float mat_src[4][4]; float mat_dst[4][4]; float imat_dst[4][4]; float warp_mat[4][4]; const int axis_u = umd->axis_u; const int axis_v = umd->axis_v; /* make sure there are UV Maps available */ if (!CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) { return dm; } else if (ELEM(NULL, umd->object_src, umd->object_dst)) { modifier_setError(md, "From/To objects must be set"); return dm; } /* make sure anything moving UVs is available */ matrix_from_obj_pchan(mat_src, umd->object_src, umd->bone_src); matrix_from_obj_pchan(mat_dst, umd->object_dst, umd->bone_dst); invert_m4_m4(imat_dst, mat_dst); mul_m4_m4m4(warp_mat, imat_dst, mat_src); /* apply warp */ if (!is_zero_v2(umd->center)) { float mat_cent[4][4]; float imat_cent[4][4]; unit_m4(mat_cent); mat_cent[3][axis_u] = umd->center[0]; mat_cent[3][axis_v] = umd->center[1]; invert_m4_m4(imat_cent, mat_cent); mul_m4_m4m4(warp_mat, warp_mat, imat_cent); mul_m4_m4m4(warp_mat, mat_cent, warp_mat); } /* make sure we're using an existing layer */ CustomData_validate_layer_name(&dm->loopData, CD_MLOOPUV, umd->uvlayer_name, uvname); numPolys = dm->getNumPolys(dm); numLoops = dm->getNumLoops(dm); mpoly = dm->getPolyArray(dm); mloop = dm->getLoopArray(dm); /* make sure we are not modifying the original UV map */ mloopuv = CustomData_duplicate_referenced_layer_named(&dm->loopData, CD_MLOOPUV, uvname, numLoops); modifier_get_vgroup(ob, dm, umd->vgroup_name, &dvert, &defgrp_index); if (dvert) { #pragma omp parallel for if (numPolys > OMP_LIMIT) for (i = 0; i < numPolys; i++) { float uv[2]; MPoly *mp = &mpoly[i]; MLoop *ml = &mloop[mp->loopstart]; MLoopUV *mluv = &mloopuv[mp->loopstart]; int l; for (l = 0; l < mp->totloop; l++, ml++, mluv++) { const float weight = defvert_find_weight(&dvert[ml->v], defgrp_index); uv_warp_from_mat4_pair(uv, mluv->uv, warp_mat, axis_u, axis_v); interp_v2_v2v2(mluv->uv, mluv->uv, uv, weight); } } } else { #pragma omp parallel for if (numPolys > OMP_LIMIT) for (i = 0; i < numPolys; i++) { MPoly *mp = &mpoly[i]; // MLoop *ml = &mloop[mp->loopstart]; MLoopUV *mluv = &mloopuv[mp->loopstart]; int l; for (l = 0; l < mp->totloop; l++, /* ml++, */ mluv++) { uv_warp_from_mat4_pair(mluv->uv, mluv->uv, warp_mat, axis_u, axis_v); } } } dm->dirty |= DM_DIRTY_TESS_CDLAYERS; return dm; }
static void meshcache_do( MeshCacheModifierData *mcmd, Object *ob, DerivedMesh *UNUSED(dm), float (*vertexCos_Real)[3], int numVerts) { const bool use_factor = mcmd->factor < 1.0f; float (*vertexCos_Store)[3] = (use_factor || (mcmd->deform_mode == MOD_MESHCACHE_DEFORM_INTEGRATE)) ? MEM_mallocN(sizeof(*vertexCos_Store) * numVerts, __func__) : NULL; float (*vertexCos)[3] = vertexCos_Store ? vertexCos_Store : vertexCos_Real; Scene *scene = mcmd->modifier.scene; const float fps = FPS; char filepath[FILE_MAX]; const char *err_str = NULL; bool ok; float time; /* -------------------------------------------------------------------- */ /* Interpret Time (the reading functions also do some of this ) */ if (mcmd->play_mode == MOD_MESHCACHE_PLAY_CFEA) { const float cfra = BKE_scene_frame_get(scene); switch (mcmd->time_mode) { case MOD_MESHCACHE_TIME_FRAME: { time = cfra; break; } case MOD_MESHCACHE_TIME_SECONDS: { time = cfra / fps; break; } case MOD_MESHCACHE_TIME_FACTOR: default: { time = cfra / fps; break; } } /* apply offset and scale */ time = (mcmd->frame_scale * time) - mcmd->frame_start; } else { /* if (mcmd->play_mode == MOD_MESHCACHE_PLAY_EVAL) { */ switch (mcmd->time_mode) { case MOD_MESHCACHE_TIME_FRAME: { time = mcmd->eval_frame; break; } case MOD_MESHCACHE_TIME_SECONDS: { time = mcmd->eval_time; break; } case MOD_MESHCACHE_TIME_FACTOR: default: { time = mcmd->eval_factor; break; } } } /* -------------------------------------------------------------------- */ /* Read the File (or error out when the file is bad) */ /* would be nice if we could avoid doing this _every_ frame */ BLI_strncpy(filepath, mcmd->filepath, sizeof(filepath)); BLI_path_abs(filepath, ID_BLEND_PATH(G.main, (ID *)ob)); switch (mcmd->type) { case MOD_MESHCACHE_TYPE_MDD: ok = MOD_meshcache_read_mdd_times(filepath, vertexCos, numVerts, mcmd->interp, time, fps, mcmd->time_mode, &err_str); break; case MOD_MESHCACHE_TYPE_PC2: ok = MOD_meshcache_read_pc2_times(filepath, vertexCos, numVerts, mcmd->interp, time, fps, mcmd->time_mode, &err_str); break; default: ok = false; break; } /* -------------------------------------------------------------------- */ /* tricky shape key integration (slow!) */ if (mcmd->deform_mode == MOD_MESHCACHE_DEFORM_INTEGRATE) { Mesh *me = ob->data; /* we could support any object type */ if (UNLIKELY(ob->type != OB_MESH)) { modifier_setError(&mcmd->modifier, "'Integrate' only valid for Mesh objects"); } else if (UNLIKELY(me->totvert != numVerts)) { modifier_setError(&mcmd->modifier, "'Integrate' original mesh vertex mismatch"); } else if (UNLIKELY(me->totpoly == 0)) { modifier_setError(&mcmd->modifier, "'Integrate' requires faces"); } else { /* the moons align! */ int i; float (*vertexCos_Source)[3] = MEM_mallocN(sizeof(*vertexCos_Source) * numVerts, __func__); float (*vertexCos_New)[3] = MEM_mallocN(sizeof(*vertexCos_New) * numVerts, __func__); MVert *mv = me->mvert; for (i = 0; i < numVerts; i++, mv++) { copy_v3_v3(vertexCos_Source[i], mv->co); } BKE_mesh_calc_relative_deform( me->mpoly, me->totpoly, me->mloop, me->totvert, (const float (*)[3])vertexCos_Source, /* from the original Mesh*/ (const float (*)[3])vertexCos_Real, /* the input we've been given (shape keys!) */ (const float (*)[3])vertexCos, /* the result of this modifier */ vertexCos_New /* the result of this function */ ); /* write the corrected locations back into the result */ memcpy(vertexCos, vertexCos_New, sizeof(*vertexCos) * numVerts); MEM_freeN(vertexCos_Source); MEM_freeN(vertexCos_New); } } /* -------------------------------------------------------------------- */ /* Apply the transformation matrix (if needed) */ if (UNLIKELY(err_str)) { modifier_setError(&mcmd->modifier, "%s", err_str); } else if (ok) { bool use_matrix = false; float mat[3][3]; unit_m3(mat); if (mat3_from_axis_conversion(mcmd->forward_axis, mcmd->up_axis, 1, 2, mat)) { use_matrix = true; } if (mcmd->flip_axis) { float tmat[3][3]; unit_m3(tmat); if (mcmd->flip_axis & (1 << 0)) tmat[0][0] = -1.0f; if (mcmd->flip_axis & (1 << 1)) tmat[1][1] = -1.0f; if (mcmd->flip_axis & (1 << 2)) tmat[2][2] = -1.0f; mul_m3_m3m3(mat, tmat, mat); use_matrix = true; } if (use_matrix) { int i; for (i = 0; i < numVerts; i++) { mul_m3_v3(mat, vertexCos[i]); } } } if (vertexCos_Store) { if (ok) { if (use_factor) { interp_vn_vn(*vertexCos_Real, *vertexCos_Store, mcmd->factor, numVerts * 3); } else { memcpy(vertexCos_Real, vertexCos_Store, sizeof(*vertexCos_Store) * numVerts); } } MEM_freeN(vertexCos_Store); } }
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, ModifierApplyFlag UNUSED(flag)) { DecimateModifierData *dmd = (DecimateModifierData *) md; DerivedMesh *dm = derivedData, *result = NULL; BMesh *bm; bool calc_face_normal; float *vweights = NULL; #ifdef USE_TIMEIT TIMEIT_START(decim); #endif /* set up front so we dont show invalid info in the UI */ dmd->face_count = dm->getNumPolys(dm); switch (dmd->mode) { case MOD_DECIM_MODE_COLLAPSE: if (dmd->percent == 1.0f) { return dm; } calc_face_normal = true; break; case MOD_DECIM_MODE_UNSUBDIV: if (dmd->iter == 0) { return dm; } calc_face_normal = false; break; case MOD_DECIM_MODE_DISSOLVE: if (dmd->angle == 0.0f) { return dm; } calc_face_normal = true; break; default: return dm; } if (dmd->face_count <= 3) { modifier_setError(md, "Modifier requires more than 3 input faces"); return dm; } if (dmd->mode == MOD_DECIM_MODE_COLLAPSE) { if (dmd->defgrp_name[0]) { MDeformVert *dvert; int defgrp_index; modifier_get_vgroup(ob, dm, dmd->defgrp_name, &dvert, &defgrp_index); if (dvert) { const unsigned int vert_tot = dm->getNumVerts(dm); unsigned int i; vweights = MEM_mallocN(vert_tot * sizeof(float), __func__); if (dmd->flag & MOD_DECIM_FLAG_INVERT_VGROUP) { for (i = 0; i < vert_tot; i++) { const float f = 1.0f - defvert_find_weight(&dvert[i], defgrp_index); vweights[i] = f > BM_MESH_DECIM_WEIGHT_EPS ? (1.0f / f) : BM_MESH_DECIM_WEIGHT_MAX; } } else { for (i = 0; i < vert_tot; i++) { const float f = defvert_find_weight(&dvert[i], defgrp_index); vweights[i] = f > BM_MESH_DECIM_WEIGHT_EPS ? (1.0f / f) : BM_MESH_DECIM_WEIGHT_MAX; } } } } } bm = DM_to_bmesh(dm, calc_face_normal); switch (dmd->mode) { case MOD_DECIM_MODE_COLLAPSE: { const int do_triangulate = (dmd->flag & MOD_DECIM_FLAG_TRIANGULATE) != 0; BM_mesh_decimate_collapse(bm, dmd->percent, vweights, do_triangulate); break; } case MOD_DECIM_MODE_UNSUBDIV: { BM_mesh_decimate_unsubdivide(bm, dmd->iter); break; } case MOD_DECIM_MODE_DISSOLVE: { const int do_dissolve_boundaries = (dmd->flag & MOD_DECIM_FLAG_ALL_BOUNDARY_VERTS) != 0; BM_mesh_decimate_dissolve(bm, dmd->angle, do_dissolve_boundaries, (BMO_Delimit)dmd->delimit); break; } } if (vweights) { MEM_freeN(vweights); } /* update for display only */ dmd->face_count = bm->totface; result = CDDM_from_bmesh(bm, false); BLI_assert(bm->vtoolflagpool == NULL && bm->etoolflagpool == NULL && bm->ftoolflagpool == NULL); /* make sure we never alloc'd these */ BLI_assert(bm->vtable == NULL && bm->etable == NULL && bm->ftable == NULL); BM_mesh_free(bm); #ifdef USE_TIMEIT TIMEIT_END(decim); #endif result->dirty = DM_DIRTY_NORMALS; return result; }