From e12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 17 Apr 2019 06:17:24 +0200 Subject: ClangFormat: apply to source, most of intern Apply clang format as proposed in T53211. For details on usage and instructions for migrating branches without conflicts, see: https://wiki.blender.org/wiki/Tools/ClangFormat --- source/blender/modifiers/intern/MOD_armature.c | 268 +- source/blender/modifiers/intern/MOD_array.c | 1370 ++++----- source/blender/modifiers/intern/MOD_bevel.c | 350 +-- source/blender/modifiers/intern/MOD_boolean.c | 482 +-- source/blender/modifiers/intern/MOD_build.c | 500 ++-- source/blender/modifiers/intern/MOD_cast.c | 847 +++--- source/blender/modifiers/intern/MOD_cloth.c | 349 +-- source/blender/modifiers/intern/MOD_collision.c | 408 ++- .../modifiers/intern/MOD_correctivesmooth.c | 1108 ++++--- source/blender/modifiers/intern/MOD_curve.c | 186 +- source/blender/modifiers/intern/MOD_datatransfer.c | 320 +- source/blender/modifiers/intern/MOD_decimate.c | 329 ++- source/blender/modifiers/intern/MOD_displace.c | 625 ++-- source/blender/modifiers/intern/MOD_dynamicpaint.c | 227 +- source/blender/modifiers/intern/MOD_edgesplit.c | 203 +- source/blender/modifiers/intern/MOD_explode.c | 1975 +++++++------ source/blender/modifiers/intern/MOD_fluidsim.c | 166 +- .../blender/modifiers/intern/MOD_fluidsim_util.c | 897 +++--- .../blender/modifiers/intern/MOD_fluidsim_util.h | 8 +- source/blender/modifiers/intern/MOD_hook.c | 585 ++-- .../blender/modifiers/intern/MOD_laplaciandeform.c | 1286 ++++---- .../blender/modifiers/intern/MOD_laplaciansmooth.c | 904 +++--- source/blender/modifiers/intern/MOD_lattice.c | 148 +- source/blender/modifiers/intern/MOD_mask.c | 616 ++-- source/blender/modifiers/intern/MOD_meshcache.c | 484 +-- .../blender/modifiers/intern/MOD_meshcache_mdd.c | 438 +-- .../blender/modifiers/intern/MOD_meshcache_pc2.c | 411 +-- .../blender/modifiers/intern/MOD_meshcache_util.c | 69 +- .../blender/modifiers/intern/MOD_meshcache_util.h | 82 +- source/blender/modifiers/intern/MOD_meshdeform.c | 814 +++--- .../modifiers/intern/MOD_meshsequencecache.c | 228 +- source/blender/modifiers/intern/MOD_mirror.c | 748 +++-- source/blender/modifiers/intern/MOD_multires.c | 279 +- source/blender/modifiers/intern/MOD_none.c | 51 +- source/blender/modifiers/intern/MOD_normal_edit.c | 1071 ++++--- source/blender/modifiers/intern/MOD_ocean.c | 719 ++--- .../modifiers/intern/MOD_particleinstance.c | 929 +++--- .../blender/modifiers/intern/MOD_particlesystem.c | 377 ++- source/blender/modifiers/intern/MOD_remesh.c | 263 +- source/blender/modifiers/intern/MOD_screw.c | 2129 +++++++------- source/blender/modifiers/intern/MOD_shapekey.c | 165 +- source/blender/modifiers/intern/MOD_shrinkwrap.c | 244 +- source/blender/modifiers/intern/MOD_simpledeform.c | 679 ++--- source/blender/modifiers/intern/MOD_skin.c | 3080 ++++++++++---------- source/blender/modifiers/intern/MOD_smoke.c | 189 +- source/blender/modifiers/intern/MOD_smooth.c | 384 +-- source/blender/modifiers/intern/MOD_softbody.c | 81 +- source/blender/modifiers/intern/MOD_solidify.c | 1696 +++++------ source/blender/modifiers/intern/MOD_subsurf.c | 287 +- source/blender/modifiers/intern/MOD_surface.c | 279 +- .../blender/modifiers/intern/MOD_surfacedeform.c | 2235 +++++++------- source/blender/modifiers/intern/MOD_triangulate.c | 170 +- source/blender/modifiers/intern/MOD_util.c | 436 +-- source/blender/modifiers/intern/MOD_util.h | 35 +- source/blender/modifiers/intern/MOD_uvproject.c | 514 ++-- source/blender/modifiers/intern/MOD_uvwarp.c | 378 ++- source/blender/modifiers/intern/MOD_warp.c | 538 ++-- source/blender/modifiers/intern/MOD_wave.c | 558 ++-- .../blender/modifiers/intern/MOD_weighted_normal.c | 1082 +++---- .../blender/modifiers/intern/MOD_weightvg_util.c | 371 +-- .../blender/modifiers/intern/MOD_weightvg_util.h | 40 +- source/blender/modifiers/intern/MOD_weightvgedit.c | 390 +-- source/blender/modifiers/intern/MOD_weightvgmix.c | 631 ++-- .../modifiers/intern/MOD_weightvgproximity.c | 855 +++--- source/blender/modifiers/intern/MOD_wireframe.c | 162 +- 65 files changed, 19669 insertions(+), 19059 deletions(-) (limited to 'source/blender/modifiers/intern') diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c index 4cc780431d0..ce58fd172a2 100644 --- a/source/blender/modifiers/intern/MOD_armature.c +++ b/source/blender/modifiers/intern/MOD_armature.c @@ -21,7 +21,6 @@ * \ingroup modifiers */ - #include #include "BLI_utildefines.h" @@ -46,157 +45,198 @@ #include "MOD_util.h" - static void initData(ModifierData *md) { - ArmatureModifierData *amd = (ArmatureModifierData *) md; + ArmatureModifierData *amd = (ArmatureModifierData *)md; - amd->deformflag = ARM_DEF_VGROUP; + amd->deformflag = ARM_DEF_VGROUP; } static void copyData(const ModifierData *md, ModifierData *target, const int flag) { #if 0 - const ArmatureModifierData *amd = (const ArmatureModifierData *) md; + const ArmatureModifierData *amd = (const ArmatureModifierData *) md; #endif - ArmatureModifierData *tamd = (ArmatureModifierData *) target; + ArmatureModifierData *tamd = (ArmatureModifierData *)target; - modifier_copyData_generic(md, target, flag); - tamd->prevCos = NULL; + modifier_copyData_generic(md, target, flag); + tamd->prevCos = NULL; } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *UNUSED(md), CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *UNUSED(md), + CustomData_MeshMasks *r_cddata_masks) { - /* ask for vertexgroups */ - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + /* ask for vertexgroups */ + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; } -static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams)) +static bool isDisabled(const struct Scene *UNUSED(scene), + ModifierData *md, + bool UNUSED(useRenderParams)) { - ArmatureModifierData *amd = (ArmatureModifierData *) md; + ArmatureModifierData *amd = (ArmatureModifierData *)md; - return !amd->object; + return !amd->object; } -static void foreachObjectLink( - ModifierData *md, Object *ob, - ObjectWalkFunc walk, void *userData) +static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) { - ArmatureModifierData *amd = (ArmatureModifierData *) md; + ArmatureModifierData *amd = (ArmatureModifierData *)md; - walk(userData, ob, &amd->object, IDWALK_CB_NOP); + walk(userData, ob, &amd->object, IDWALK_CB_NOP); } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { - ArmatureModifierData *amd = (ArmatureModifierData *)md; - if (amd->object != NULL) { - DEG_add_object_relation(ctx->node, amd->object, DEG_OB_COMP_EVAL_POSE, "Armature Modifier"); - DEG_add_object_relation(ctx->node, amd->object, DEG_OB_COMP_TRANSFORM, "Armature Modifier"); - } - DEG_add_modifier_to_transform_relation(ctx->node, "Armature Modifier"); + ArmatureModifierData *amd = (ArmatureModifierData *)md; + if (amd->object != NULL) { + DEG_add_object_relation(ctx->node, amd->object, DEG_OB_COMP_EVAL_POSE, "Armature Modifier"); + DEG_add_object_relation(ctx->node, amd->object, DEG_OB_COMP_TRANSFORM, "Armature Modifier"); + } + DEG_add_modifier_to_transform_relation(ctx->node, "Armature Modifier"); } -static void deformVerts( - ModifierData *md, const ModifierEvalContext *ctx, - Mesh *mesh, - float (*vertexCos)[3], - int numVerts) +static void deformVerts(ModifierData *md, + const ModifierEvalContext *ctx, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - ArmatureModifierData *amd = (ArmatureModifierData *) md; - - MOD_previous_vcos_store(md, vertexCos); /* if next modifier needs original vertices */ - - armature_deform_verts(amd->object, ctx->object, mesh, vertexCos, NULL, - numVerts, amd->deformflag, (float(*)[3])amd->prevCos, amd->defgrp_name, NULL); - - /* free cache */ - if (amd->prevCos) { - MEM_freeN(amd->prevCos); - amd->prevCos = NULL; - } + ArmatureModifierData *amd = (ArmatureModifierData *)md; + + MOD_previous_vcos_store(md, vertexCos); /* if next modifier needs original vertices */ + + armature_deform_verts(amd->object, + ctx->object, + mesh, + vertexCos, + NULL, + numVerts, + amd->deformflag, + (float(*)[3])amd->prevCos, + amd->defgrp_name, + NULL); + + /* free cache */ + if (amd->prevCos) { + MEM_freeN(amd->prevCos); + amd->prevCos = NULL; + } } -static void deformVertsEM( - ModifierData *md, const ModifierEvalContext *ctx, struct BMEditMesh *em, - Mesh *mesh, float (*vertexCos)[3], int numVerts) +static void deformVertsEM(ModifierData *md, + const ModifierEvalContext *ctx, + struct BMEditMesh *em, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - ArmatureModifierData *amd = (ArmatureModifierData *) md; - Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, numVerts, false, false); - - MOD_previous_vcos_store(md, vertexCos); /* if next modifier needs original vertices */ - - armature_deform_verts(amd->object, ctx->object, mesh_src, vertexCos, NULL, - numVerts, amd->deformflag, (float(*)[3])amd->prevCos, amd->defgrp_name, NULL); - - /* free cache */ - if (amd->prevCos) { - MEM_freeN(amd->prevCos); - amd->prevCos = NULL; - } - - if (mesh_src != mesh) { - BKE_id_free(NULL, mesh_src); - } + ArmatureModifierData *amd = (ArmatureModifierData *)md; + Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, numVerts, false, false); + + MOD_previous_vcos_store(md, vertexCos); /* if next modifier needs original vertices */ + + armature_deform_verts(amd->object, + ctx->object, + mesh_src, + vertexCos, + NULL, + numVerts, + amd->deformflag, + (float(*)[3])amd->prevCos, + amd->defgrp_name, + NULL); + + /* free cache */ + if (amd->prevCos) { + MEM_freeN(amd->prevCos); + amd->prevCos = NULL; + } + + if (mesh_src != mesh) { + BKE_id_free(NULL, mesh_src); + } } -static void deformMatricesEM( - ModifierData *md, const ModifierEvalContext *ctx, struct BMEditMesh *em, - Mesh *mesh, float (*vertexCos)[3], - float (*defMats)[3][3], int numVerts) +static void deformMatricesEM(ModifierData *md, + const ModifierEvalContext *ctx, + struct BMEditMesh *em, + Mesh *mesh, + float (*vertexCos)[3], + float (*defMats)[3][3], + int numVerts) { - ArmatureModifierData *amd = (ArmatureModifierData *) md; - Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, numVerts, false, false); - - armature_deform_verts(amd->object, ctx->object, mesh_src, vertexCos, defMats, - numVerts, amd->deformflag, NULL, amd->defgrp_name, NULL); - - if (mesh_src != mesh) { - BKE_id_free(NULL, mesh_src); - } + ArmatureModifierData *amd = (ArmatureModifierData *)md; + Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, numVerts, false, false); + + armature_deform_verts(amd->object, + ctx->object, + mesh_src, + vertexCos, + defMats, + numVerts, + amd->deformflag, + NULL, + amd->defgrp_name, + NULL); + + if (mesh_src != mesh) { + BKE_id_free(NULL, mesh_src); + } } -static void deformMatrices( - ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh, - float (*vertexCos)[3], float (*defMats)[3][3], int numVerts) +static void deformMatrices(ModifierData *md, + const ModifierEvalContext *ctx, + Mesh *mesh, + float (*vertexCos)[3], + float (*defMats)[3][3], + int numVerts) { - ArmatureModifierData *amd = (ArmatureModifierData *) md; - Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); - - armature_deform_verts(amd->object, ctx->object, mesh_src, vertexCos, defMats, - numVerts, amd->deformflag, NULL, amd->defgrp_name, NULL); - - if (mesh_src != mesh) { - BKE_id_free(NULL, mesh_src); - } + ArmatureModifierData *amd = (ArmatureModifierData *)md; + Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); + + armature_deform_verts(amd->object, + ctx->object, + mesh_src, + vertexCos, + defMats, + numVerts, + amd->deformflag, + NULL, + amd->defgrp_name, + NULL); + + if (mesh_src != mesh) { + BKE_id_free(NULL, mesh_src); + } } ModifierTypeInfo modifierType_Armature = { - /* name */ "Armature", - /* structName */ "ArmatureModifierData", - /* structSize */ sizeof(ArmatureModifierData), - /* type */ eModifierTypeType_OnlyDeform, - /* flags */ eModifierTypeFlag_AcceptsCVs | - eModifierTypeFlag_AcceptsLattice | - eModifierTypeFlag_SupportsEditmode, - - /* copyData */ copyData, - - /* deformVerts */ deformVerts, - /* deformMatrices */ deformMatrices, - /* deformVertsEM */ deformVertsEM, - /* deformMatricesEM */ deformMatricesEM, - /* applyModifier */ NULL, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ NULL, - /* isDisabled */ isDisabled, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ foreachObjectLink, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Armature", + /* structName */ "ArmatureModifierData", + /* structSize */ sizeof(ArmatureModifierData), + /* type */ eModifierTypeType_OnlyDeform, + /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice | + eModifierTypeFlag_SupportsEditmode, + + /* copyData */ copyData, + + /* deformVerts */ deformVerts, + /* deformMatrices */ deformMatrices, + /* deformVertsEM */ deformVertsEM, + /* deformMatricesEM */ deformMatricesEM, + /* applyModifier */ NULL, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ NULL, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c index 542c7665807..c909f9dc076 100644 --- a/source/blender/modifiers/intern/MOD_array.c +++ b/source/blender/modifiers/intern/MOD_array.c @@ -50,87 +50,96 @@ static void initData(ModifierData *md) { - ArrayModifierData *amd = (ArrayModifierData *) md; - - /* default to 2 duplicates distributed along the x-axis by an - * offset of 1 object-width - */ - amd->start_cap = amd->end_cap = amd->curve_ob = amd->offset_ob = NULL; - amd->count = 2; - zero_v3(amd->offset); - amd->scale[0] = 1; - amd->scale[1] = amd->scale[2] = 0; - amd->length = 0; - amd->merge_dist = 0.01; - amd->fit_type = MOD_ARR_FIXEDCOUNT; - amd->offset_type = MOD_ARR_OFF_RELATIVE; - amd->flags = 0; + ArrayModifierData *amd = (ArrayModifierData *)md; + + /* default to 2 duplicates distributed along the x-axis by an + * offset of 1 object-width + */ + amd->start_cap = amd->end_cap = amd->curve_ob = amd->offset_ob = NULL; + amd->count = 2; + zero_v3(amd->offset); + amd->scale[0] = 1; + amd->scale[1] = amd->scale[2] = 0; + amd->length = 0; + amd->merge_dist = 0.01; + amd->fit_type = MOD_ARR_FIXEDCOUNT; + amd->offset_type = MOD_ARR_OFF_RELATIVE; + amd->flags = 0; } -static void foreachObjectLink( - ModifierData *md, Object *ob, - ObjectWalkFunc walk, void *userData) +static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) { - ArrayModifierData *amd = (ArrayModifierData *) md; + ArrayModifierData *amd = (ArrayModifierData *)md; - walk(userData, ob, &amd->start_cap, IDWALK_CB_NOP); - walk(userData, ob, &amd->end_cap, IDWALK_CB_NOP); - walk(userData, ob, &amd->curve_ob, IDWALK_CB_NOP); - walk(userData, ob, &amd->offset_ob, IDWALK_CB_NOP); + walk(userData, ob, &amd->start_cap, IDWALK_CB_NOP); + walk(userData, ob, &amd->end_cap, IDWALK_CB_NOP); + walk(userData, ob, &amd->curve_ob, IDWALK_CB_NOP); + walk(userData, ob, &amd->offset_ob, IDWALK_CB_NOP); } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { - ArrayModifierData *amd = (ArrayModifierData *)md; - if (amd->start_cap != NULL) { - DEG_add_object_relation(ctx->node, amd->start_cap, DEG_OB_COMP_TRANSFORM, "Array Modifier Start Cap"); - DEG_add_object_relation(ctx->node, amd->start_cap, DEG_OB_COMP_GEOMETRY, "Array Modifier Start Cap"); - } - if (amd->end_cap != NULL) { - DEG_add_object_relation(ctx->node, amd->end_cap, DEG_OB_COMP_TRANSFORM, "Array Modifier End Cap"); - DEG_add_object_relation(ctx->node, amd->end_cap, DEG_OB_COMP_GEOMETRY, "Array Modifier End Cap"); - } - if (amd->curve_ob) { - DEG_add_object_relation(ctx->node, amd->curve_ob, DEG_OB_COMP_GEOMETRY, "Array Modifier Curve"); - DEG_add_special_eval_flag(ctx->node, &amd->curve_ob->id, DAG_EVAL_NEED_CURVE_PATH); - } - if (amd->offset_ob != NULL) { - DEG_add_object_relation(ctx->node, amd->offset_ob, DEG_OB_COMP_TRANSFORM, "Array Modifier Offset"); - } - DEG_add_modifier_to_transform_relation(ctx->node, "Array Modifier"); + ArrayModifierData *amd = (ArrayModifierData *)md; + if (amd->start_cap != NULL) { + DEG_add_object_relation( + ctx->node, amd->start_cap, DEG_OB_COMP_TRANSFORM, "Array Modifier Start Cap"); + DEG_add_object_relation( + ctx->node, amd->start_cap, DEG_OB_COMP_GEOMETRY, "Array Modifier Start Cap"); + } + if (amd->end_cap != NULL) { + DEG_add_object_relation( + ctx->node, amd->end_cap, DEG_OB_COMP_TRANSFORM, "Array Modifier End Cap"); + DEG_add_object_relation( + ctx->node, amd->end_cap, DEG_OB_COMP_GEOMETRY, "Array Modifier End Cap"); + } + if (amd->curve_ob) { + DEG_add_object_relation( + ctx->node, amd->curve_ob, DEG_OB_COMP_GEOMETRY, "Array Modifier Curve"); + DEG_add_special_eval_flag(ctx->node, &amd->curve_ob->id, DAG_EVAL_NEED_CURVE_PATH); + } + if (amd->offset_ob != NULL) { + DEG_add_object_relation( + ctx->node, amd->offset_ob, DEG_OB_COMP_TRANSFORM, "Array Modifier Offset"); + } + DEG_add_modifier_to_transform_relation(ctx->node, "Array Modifier"); } BLI_INLINE float sum_v3(const float v[3]) { - return v[0] + v[1] + v[2]; + return v[0] + v[1] + v[2]; } /* Structure used for sorting vertices, when processing doubles */ typedef struct SortVertsElem { - int vertex_num; /* The original index of the vertex, prior to sorting */ - float co[3]; /* Its coordinates */ - float sum_co; /* sum_v3(co), just so we don't do the sum many times. */ + int vertex_num; /* The original index of the vertex, prior to sorting */ + float co[3]; /* Its coordinates */ + float sum_co; /* sum_v3(co), just so we don't do the sum many times. */ } SortVertsElem; - static int svert_sum_cmp(const void *e1, const void *e2) { - const SortVertsElem *sv1 = e1; - const SortVertsElem *sv2 = e2; - - if (sv1->sum_co > sv2->sum_co) return 1; - else if (sv1->sum_co < sv2->sum_co) return -1; - else return 0; + const SortVertsElem *sv1 = e1; + const SortVertsElem *sv2 = e2; + + if (sv1->sum_co > sv2->sum_co) + return 1; + else if (sv1->sum_co < sv2->sum_co) + return -1; + else + return 0; } -static void svert_from_mvert(SortVertsElem *sv, const MVert *mv, const int i_begin, const int i_end) +static void svert_from_mvert(SortVertsElem *sv, + const MVert *mv, + const int i_begin, + const int i_end) { - int i; - for (i = i_begin; i < i_end; i++, sv++, mv++) { - sv->vertex_num = i; - copy_v3_v3(sv->co, mv->co); - sv->sum_co = sum_v3(mv->co); - } + int i; + for (i = i_begin; i < i_end; i++, sv++, mv++) { + sv->vertex_num = i; + copy_v3_v3(sv->co, mv->co); + sv->sum_co = sum_v3(mv->co); + } } /** @@ -139,637 +148,642 @@ static void svert_from_mvert(SortVertsElem *sv, const MVert *mv, const int i_beg * It builds a mapping for all vertices within source, to vertices within target, or -1 if no double found * The int doubles_map[num_verts_source] array must have been allocated by caller. */ -static void dm_mvert_map_doubles( - int *doubles_map, - const MVert *mverts, - const int target_start, - const int target_num_verts, - const int source_start, - const int source_num_verts, - const float dist) +static void dm_mvert_map_doubles(int *doubles_map, + const MVert *mverts, + const int target_start, + const int target_num_verts, + const int source_start, + const int source_num_verts, + const float dist) { - const float dist3 = ((float)M_SQRT3 + 0.00005f) * dist; /* Just above sqrt(3) */ - int i_source, i_target, i_target_low_bound, target_end, source_end; - SortVertsElem *sorted_verts_target, *sorted_verts_source; - SortVertsElem *sve_source, *sve_target, *sve_target_low_bound; - bool target_scan_completed; - - target_end = target_start + target_num_verts; - source_end = source_start + source_num_verts; - - /* build array of MVerts to be tested for merging */ - sorted_verts_target = MEM_malloc_arrayN(target_num_verts, sizeof(SortVertsElem), __func__); - sorted_verts_source = MEM_malloc_arrayN(source_num_verts, sizeof(SortVertsElem), __func__); - - /* Copy target vertices index and cos into SortVertsElem array */ - svert_from_mvert(sorted_verts_target, mverts + target_start, target_start, target_end); - - /* Copy source vertices index and cos into SortVertsElem array */ - svert_from_mvert(sorted_verts_source, mverts + source_start, source_start, source_end); - - /* sort arrays according to sum of vertex coordinates (sumco) */ - qsort(sorted_verts_target, target_num_verts, sizeof(SortVertsElem), svert_sum_cmp); - qsort(sorted_verts_source, source_num_verts, sizeof(SortVertsElem), svert_sum_cmp); - - sve_target_low_bound = sorted_verts_target; - i_target_low_bound = 0; - target_scan_completed = false; - - /* Scan source vertices, in SortVertsElem sorted array, */ - /* all the while maintaining the lower bound of possible doubles in target vertices */ - for (i_source = 0, sve_source = sorted_verts_source; - i_source < source_num_verts; - i_source++, sve_source++) - { - int best_target_vertex = -1; - float best_dist_sq = dist * dist; - float sve_source_sumco; - - /* If source has already been assigned to a target (in an earlier call, with other chunks) */ - if (doubles_map[sve_source->vertex_num] != -1) { - continue; - } - - /* If target fully scanned already, then all remaining source vertices cannot have a double */ - if (target_scan_completed) { - doubles_map[sve_source->vertex_num] = -1; - continue; - } - - sve_source_sumco = sum_v3(sve_source->co); - - /* Skip all target vertices that are more than dist3 lower in terms of sumco */ - /* and advance the overall lower bound, applicable to all remaining vertices as well. */ - while ((i_target_low_bound < target_num_verts) && - (sve_target_low_bound->sum_co < sve_source_sumco - dist3)) - { - i_target_low_bound++; - sve_target_low_bound++; - } - /* If end of target list reached, then no more possible doubles */ - if (i_target_low_bound >= target_num_verts) { - doubles_map[sve_source->vertex_num] = -1; - target_scan_completed = true; - continue; - } - /* Test target candidates starting at the low bound of possible doubles, ordered in terms of sumco */ - i_target = i_target_low_bound; - sve_target = sve_target_low_bound; - - /* i_target will scan vertices in the [v_source_sumco - dist3; v_source_sumco + dist3] range */ - - while ((i_target < target_num_verts) && - (sve_target->sum_co <= sve_source_sumco + dist3)) - { - /* Testing distance for candidate double in target */ - /* v_target is within dist3 of v_source in terms of sumco; check real distance */ - float dist_sq; - if ((dist_sq = len_squared_v3v3(sve_source->co, sve_target->co)) <= best_dist_sq) { - /* Potential double found */ - best_dist_sq = dist_sq; - best_target_vertex = sve_target->vertex_num; - - /* If target is already mapped, we only follow that mapping if final target remains - * close enough from current vert (otherwise no mapping at all). - * Note that if we later find another target closer than this one, then we check it. But if other - * potential targets are farther, then there will be no mapping at all for this source. */ - while (best_target_vertex != -1 && !ELEM(doubles_map[best_target_vertex], -1, best_target_vertex)) { - if (compare_len_v3v3(mverts[sve_source->vertex_num].co, - mverts[doubles_map[best_target_vertex]].co, - dist)) - { - best_target_vertex = doubles_map[best_target_vertex]; - } - else { - best_target_vertex = -1; - } - } - } - i_target++; - sve_target++; - } - /* End of candidate scan: if none found then no doubles */ - doubles_map[sve_source->vertex_num] = best_target_vertex; - } - - MEM_freeN(sorted_verts_source); - MEM_freeN(sorted_verts_target); + const float dist3 = ((float)M_SQRT3 + 0.00005f) * dist; /* Just above sqrt(3) */ + int i_source, i_target, i_target_low_bound, target_end, source_end; + SortVertsElem *sorted_verts_target, *sorted_verts_source; + SortVertsElem *sve_source, *sve_target, *sve_target_low_bound; + bool target_scan_completed; + + target_end = target_start + target_num_verts; + source_end = source_start + source_num_verts; + + /* build array of MVerts to be tested for merging */ + sorted_verts_target = MEM_malloc_arrayN(target_num_verts, sizeof(SortVertsElem), __func__); + sorted_verts_source = MEM_malloc_arrayN(source_num_verts, sizeof(SortVertsElem), __func__); + + /* Copy target vertices index and cos into SortVertsElem array */ + svert_from_mvert(sorted_verts_target, mverts + target_start, target_start, target_end); + + /* Copy source vertices index and cos into SortVertsElem array */ + svert_from_mvert(sorted_verts_source, mverts + source_start, source_start, source_end); + + /* sort arrays according to sum of vertex coordinates (sumco) */ + qsort(sorted_verts_target, target_num_verts, sizeof(SortVertsElem), svert_sum_cmp); + qsort(sorted_verts_source, source_num_verts, sizeof(SortVertsElem), svert_sum_cmp); + + sve_target_low_bound = sorted_verts_target; + i_target_low_bound = 0; + target_scan_completed = false; + + /* Scan source vertices, in SortVertsElem sorted array, */ + /* all the while maintaining the lower bound of possible doubles in target vertices */ + for (i_source = 0, sve_source = sorted_verts_source; i_source < source_num_verts; + i_source++, sve_source++) { + int best_target_vertex = -1; + float best_dist_sq = dist * dist; + float sve_source_sumco; + + /* If source has already been assigned to a target (in an earlier call, with other chunks) */ + if (doubles_map[sve_source->vertex_num] != -1) { + continue; + } + + /* If target fully scanned already, then all remaining source vertices cannot have a double */ + if (target_scan_completed) { + doubles_map[sve_source->vertex_num] = -1; + continue; + } + + sve_source_sumco = sum_v3(sve_source->co); + + /* Skip all target vertices that are more than dist3 lower in terms of sumco */ + /* and advance the overall lower bound, applicable to all remaining vertices as well. */ + while ((i_target_low_bound < target_num_verts) && + (sve_target_low_bound->sum_co < sve_source_sumco - dist3)) { + i_target_low_bound++; + sve_target_low_bound++; + } + /* If end of target list reached, then no more possible doubles */ + if (i_target_low_bound >= target_num_verts) { + doubles_map[sve_source->vertex_num] = -1; + target_scan_completed = true; + continue; + } + /* Test target candidates starting at the low bound of possible doubles, ordered in terms of sumco */ + i_target = i_target_low_bound; + sve_target = sve_target_low_bound; + + /* i_target will scan vertices in the [v_source_sumco - dist3; v_source_sumco + dist3] range */ + + while ((i_target < target_num_verts) && (sve_target->sum_co <= sve_source_sumco + dist3)) { + /* Testing distance for candidate double in target */ + /* v_target is within dist3 of v_source in terms of sumco; check real distance */ + float dist_sq; + if ((dist_sq = len_squared_v3v3(sve_source->co, sve_target->co)) <= best_dist_sq) { + /* Potential double found */ + best_dist_sq = dist_sq; + best_target_vertex = sve_target->vertex_num; + + /* If target is already mapped, we only follow that mapping if final target remains + * close enough from current vert (otherwise no mapping at all). + * Note that if we later find another target closer than this one, then we check it. But if other + * potential targets are farther, then there will be no mapping at all for this source. */ + while (best_target_vertex != -1 && + !ELEM(doubles_map[best_target_vertex], -1, best_target_vertex)) { + if (compare_len_v3v3(mverts[sve_source->vertex_num].co, + mverts[doubles_map[best_target_vertex]].co, + dist)) { + best_target_vertex = doubles_map[best_target_vertex]; + } + else { + best_target_vertex = -1; + } + } + } + i_target++; + sve_target++; + } + /* End of candidate scan: if none found then no doubles */ + doubles_map[sve_source->vertex_num] = best_target_vertex; + } + + MEM_freeN(sorted_verts_source); + MEM_freeN(sorted_verts_target); } - -static void mesh_merge_transform( - Mesh *result, Mesh *cap_mesh, float cap_offset[4][4], - unsigned int cap_verts_index, unsigned int cap_edges_index, int cap_loops_index, int cap_polys_index, - int cap_nverts, int cap_nedges, int cap_nloops, int cap_npolys, int *remap, int remap_len) +static void mesh_merge_transform(Mesh *result, + Mesh *cap_mesh, + float cap_offset[4][4], + unsigned int cap_verts_index, + unsigned int cap_edges_index, + int cap_loops_index, + int cap_polys_index, + int cap_nverts, + int cap_nedges, + int cap_nloops, + int cap_npolys, + int *remap, + int remap_len) { - int *index_orig; - int i; - MVert *mv; - MEdge *me; - MLoop *ml; - MPoly *mp; - - CustomData_copy_data(&cap_mesh->vdata, &result->vdata, 0, cap_verts_index, cap_nverts); - CustomData_copy_data(&cap_mesh->edata, &result->edata, 0, cap_edges_index, cap_nedges); - CustomData_copy_data(&cap_mesh->ldata, &result->ldata, 0, cap_loops_index, cap_nloops); - CustomData_copy_data(&cap_mesh->pdata, &result->pdata, 0, cap_polys_index, cap_npolys); - - mv = result->mvert + cap_verts_index; - - for (i = 0; i < cap_nverts; i++, mv++) { - mul_m4_v3(cap_offset, mv->co); - /* Reset MVert flags for caps */ - mv->flag = mv->bweight = 0; - } - - /* remap the vertex groups if necessary */ - if (result->dvert != NULL) { - BKE_object_defgroup_index_map_apply(&result->dvert[cap_verts_index], cap_nverts, remap, remap_len); - } - - /* adjust cap edge vertex indices */ - me = result->medge + cap_edges_index; - for (i = 0; i < cap_nedges; i++, me++) { - me->v1 += cap_verts_index; - me->v2 += cap_verts_index; - } - - /* adjust cap poly loopstart indices */ - mp = result->mpoly + cap_polys_index; - for (i = 0; i < cap_npolys; i++, mp++) { - mp->loopstart += cap_loops_index; - } - - /* adjust cap loop vertex and edge indices */ - ml = result->mloop + cap_loops_index; - for (i = 0; i < cap_nloops; i++, ml++) { - ml->v += cap_verts_index; - ml->e += cap_edges_index; - } - - /* set origindex */ - index_orig = CustomData_get_layer(&result->vdata, CD_ORIGINDEX); - if (index_orig) { - copy_vn_i(index_orig + cap_verts_index, cap_nverts, ORIGINDEX_NONE); - } - - index_orig = CustomData_get_layer(&result->edata, CD_ORIGINDEX); - if (index_orig) { - copy_vn_i(index_orig + cap_edges_index, cap_nedges, ORIGINDEX_NONE); - } - - index_orig = CustomData_get_layer(&result->pdata, CD_ORIGINDEX); - if (index_orig) { - copy_vn_i(index_orig + cap_polys_index, cap_npolys, ORIGINDEX_NONE); - } - - index_orig = CustomData_get_layer(&result->ldata, CD_ORIGINDEX); - if (index_orig) { - copy_vn_i(index_orig + cap_loops_index, cap_nloops, ORIGINDEX_NONE); - } + int *index_orig; + int i; + MVert *mv; + MEdge *me; + MLoop *ml; + MPoly *mp; + + CustomData_copy_data(&cap_mesh->vdata, &result->vdata, 0, cap_verts_index, cap_nverts); + CustomData_copy_data(&cap_mesh->edata, &result->edata, 0, cap_edges_index, cap_nedges); + CustomData_copy_data(&cap_mesh->ldata, &result->ldata, 0, cap_loops_index, cap_nloops); + CustomData_copy_data(&cap_mesh->pdata, &result->pdata, 0, cap_polys_index, cap_npolys); + + mv = result->mvert + cap_verts_index; + + for (i = 0; i < cap_nverts; i++, mv++) { + mul_m4_v3(cap_offset, mv->co); + /* Reset MVert flags for caps */ + mv->flag = mv->bweight = 0; + } + + /* remap the vertex groups if necessary */ + if (result->dvert != NULL) { + BKE_object_defgroup_index_map_apply( + &result->dvert[cap_verts_index], cap_nverts, remap, remap_len); + } + + /* adjust cap edge vertex indices */ + me = result->medge + cap_edges_index; + for (i = 0; i < cap_nedges; i++, me++) { + me->v1 += cap_verts_index; + me->v2 += cap_verts_index; + } + + /* adjust cap poly loopstart indices */ + mp = result->mpoly + cap_polys_index; + for (i = 0; i < cap_npolys; i++, mp++) { + mp->loopstart += cap_loops_index; + } + + /* adjust cap loop vertex and edge indices */ + ml = result->mloop + cap_loops_index; + for (i = 0; i < cap_nloops; i++, ml++) { + ml->v += cap_verts_index; + ml->e += cap_edges_index; + } + + /* set origindex */ + index_orig = CustomData_get_layer(&result->vdata, CD_ORIGINDEX); + if (index_orig) { + copy_vn_i(index_orig + cap_verts_index, cap_nverts, ORIGINDEX_NONE); + } + + index_orig = CustomData_get_layer(&result->edata, CD_ORIGINDEX); + if (index_orig) { + copy_vn_i(index_orig + cap_edges_index, cap_nedges, ORIGINDEX_NONE); + } + + index_orig = CustomData_get_layer(&result->pdata, CD_ORIGINDEX); + if (index_orig) { + copy_vn_i(index_orig + cap_polys_index, cap_npolys, ORIGINDEX_NONE); + } + + index_orig = CustomData_get_layer(&result->ldata, CD_ORIGINDEX); + if (index_orig) { + copy_vn_i(index_orig + cap_loops_index, cap_nloops, ORIGINDEX_NONE); + } } -static Mesh *arrayModifier_doArray( - ArrayModifierData *amd, const ModifierEvalContext *ctx, Mesh *mesh) +static Mesh *arrayModifier_doArray(ArrayModifierData *amd, + const ModifierEvalContext *ctx, + Mesh *mesh) { - const float eps = 1e-6f; - const MVert *src_mvert; - MVert *mv, *mv_prev, *result_dm_verts; - - MEdge *me; - MLoop *ml; - MPoly *mp; - int i, j, c, count; - float length = amd->length; - /* offset matrix */ - float offset[4][4]; - float scale[3]; - bool offset_has_scale; - float current_offset[4][4]; - float final_offset[4][4]; - int *full_doubles_map = NULL; - int tot_doubles; - - const bool use_merge = (amd->flags & MOD_ARR_MERGE) != 0; - const bool use_recalc_normals = (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) || use_merge; - const bool use_offset_ob = ((amd->offset_type & MOD_ARR_OFF_OBJ) && amd->offset_ob != NULL); - - int start_cap_nverts = 0, start_cap_nedges = 0, start_cap_npolys = 0, start_cap_nloops = 0; - int end_cap_nverts = 0, end_cap_nedges = 0, end_cap_npolys = 0, end_cap_nloops = 0; - int result_nverts = 0, result_nedges = 0, result_npolys = 0, result_nloops = 0; - int chunk_nverts, chunk_nedges, chunk_nloops, chunk_npolys; - int first_chunk_start, first_chunk_nverts, last_chunk_start, last_chunk_nverts; - - Mesh *result, *start_cap_mesh = NULL, *end_cap_mesh = NULL; - - int *vgroup_start_cap_remap = NULL; - int vgroup_start_cap_remap_len = 0; - int *vgroup_end_cap_remap = NULL; - int vgroup_end_cap_remap_len = 0; - - chunk_nverts = mesh->totvert; - chunk_nedges = mesh->totedge; - chunk_nloops = mesh->totloop; - chunk_npolys = mesh->totpoly; - - count = amd->count; - - Object *start_cap_ob = amd->start_cap; - if (start_cap_ob && start_cap_ob != ctx->object && start_cap_ob->type == OB_MESH) { - vgroup_start_cap_remap = BKE_object_defgroup_index_map_create( - start_cap_ob, ctx->object, &vgroup_start_cap_remap_len); - - start_cap_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(start_cap_ob, false); - if (start_cap_mesh) { - start_cap_nverts = start_cap_mesh->totvert; - start_cap_nedges = start_cap_mesh->totedge; - start_cap_nloops = start_cap_mesh->totloop; - start_cap_npolys = start_cap_mesh->totpoly; - } - } - Object *end_cap_ob = amd->end_cap; - if (end_cap_ob && end_cap_ob != ctx->object && end_cap_ob->type == OB_MESH) { - vgroup_end_cap_remap = BKE_object_defgroup_index_map_create( - end_cap_ob, ctx->object, &vgroup_end_cap_remap_len); - - end_cap_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(end_cap_ob, false); - if (end_cap_mesh) { - end_cap_nverts = end_cap_mesh->totvert; - end_cap_nedges = end_cap_mesh->totedge; - end_cap_nloops = end_cap_mesh->totloop; - end_cap_npolys = end_cap_mesh->totpoly; - } - } - - /* Build up offset array, cumulating all settings options */ - - unit_m4(offset); - src_mvert = mesh->mvert; - - if (amd->offset_type & MOD_ARR_OFF_CONST) { - add_v3_v3(offset[3], amd->offset); - } - - if (amd->offset_type & MOD_ARR_OFF_RELATIVE) { - float min[3], max[3]; - const MVert *src_mv; - - INIT_MINMAX(min, max); - for (src_mv = src_mvert, j = chunk_nverts; j--; src_mv++) { - minmax_v3v3_v3(min, max, src_mv->co); - } - - for (j = 3; j--; ) { - offset[3][j] += amd->scale[j] * (max[j] - min[j]); - } - } - - if (use_offset_ob) { - float obinv[4][4]; - float result_mat[4][4]; - - if (ctx->object) - invert_m4_m4(obinv, ctx->object->obmat); - else - unit_m4(obinv); - - mul_m4_series(result_mat, offset, obinv, amd->offset_ob->obmat); - copy_m4_m4(offset, result_mat); - } - - /* Check if there is some scaling. If scaling, then we will not translate mapping */ - mat4_to_size(scale, offset); - offset_has_scale = !is_one_v3(scale); - - if (amd->fit_type == MOD_ARR_FITCURVE && amd->curve_ob != NULL) { - Object *curve_ob = amd->curve_ob; - Curve *cu = curve_ob->data; - if (cu) { - CurveCache *curve_cache = curve_ob->runtime.curve_cache; - if (curve_cache != NULL && curve_cache->path != NULL) { - float scale_fac = mat4_to_scale(curve_ob->obmat); - length = scale_fac * curve_cache->path->totdist; - } - } - } - - /* calculate the maximum number of copies which will fit within the - * prescribed length */ - if (amd->fit_type == MOD_ARR_FITLENGTH || amd->fit_type == MOD_ARR_FITCURVE) { - float dist = len_v3(offset[3]); - - if (dist > eps) { - /* this gives length = first copy start to last copy end - * add a tiny offset for floating point rounding errors */ - count = (length + eps) / dist + 1; - } - else { - /* if the offset has no translation, just make one copy */ - count = 1; - } - } - - if (count < 1) - count = 1; - - /* The number of verts, edges, loops, polys, before eventually merging doubles */ - result_nverts = chunk_nverts * count + start_cap_nverts + end_cap_nverts; - result_nedges = chunk_nedges * count + start_cap_nedges + end_cap_nedges; - result_nloops = chunk_nloops * count + start_cap_nloops + end_cap_nloops; - result_npolys = chunk_npolys * count + start_cap_npolys + end_cap_npolys; - - /* Initialize a result dm */ - result = BKE_mesh_new_nomain_from_template(mesh, result_nverts, result_nedges, 0, result_nloops, result_npolys); - result_dm_verts = result->mvert; - - if (use_merge) { - /* Will need full_doubles_map for handling merge */ - full_doubles_map = MEM_malloc_arrayN(result_nverts, sizeof(int), "mod array doubles map"); - copy_vn_i(full_doubles_map, result_nverts, -1); - } - - /* copy customdata to original geometry */ - CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, chunk_nverts); - CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, chunk_nedges); - CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, chunk_nloops); - CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, chunk_npolys); - - /* Subsurf for eg won't have mesh data in the custom data arrays. - * now add mvert/medge/mpoly layers. */ - if (!CustomData_has_layer(&mesh->vdata, CD_MVERT)) { - memcpy(result->mvert, mesh->mvert, sizeof(*result->mvert) * mesh->totvert); - } - if (!CustomData_has_layer(&mesh->edata, CD_MEDGE)) { - memcpy(result->medge, mesh->medge, sizeof(*result->medge) * mesh->totedge); - } - if (!CustomData_has_layer(&mesh->pdata, CD_MPOLY)) { - memcpy(result->mloop, mesh->mloop, sizeof(*result->mloop) * mesh->totloop); - memcpy(result->mpoly, mesh->mpoly, sizeof(*result->mpoly) * mesh->totpoly); - } - - /* Remember first chunk, in case of cap merge */ - first_chunk_start = 0; - first_chunk_nverts = chunk_nverts; - - unit_m4(current_offset); - for (c = 1; c < count; c++) { - /* copy customdata to new geometry */ - CustomData_copy_data(&mesh->vdata, &result->vdata, 0, c * chunk_nverts, chunk_nverts); - CustomData_copy_data(&mesh->edata, &result->edata, 0, c * chunk_nedges, chunk_nedges); - CustomData_copy_data(&mesh->ldata, &result->ldata, 0, c * chunk_nloops, chunk_nloops); - CustomData_copy_data(&mesh->pdata, &result->pdata, 0, c * chunk_npolys, chunk_npolys); - - mv_prev = result_dm_verts; - mv = mv_prev + c * chunk_nverts; - - /* recalculate cumulative offset here */ - mul_m4_m4m4(current_offset, current_offset, offset); - - /* apply offset to all new verts */ - for (i = 0; i < chunk_nverts; i++, mv++, mv_prev++) { - mul_m4_v3(current_offset, mv->co); - - /* We have to correct normals too, if we do not tag them as dirty! */ - if (!use_recalc_normals) { - float no[3]; - normal_short_to_float_v3(no, mv->no); - mul_mat3_m4_v3(current_offset, no); - normalize_v3(no); - normal_float_to_short_v3(mv->no, no); - } - } - - /* adjust edge vertex indices */ - me = result->medge + c * chunk_nedges; - for (i = 0; i < chunk_nedges; i++, me++) { - me->v1 += c * chunk_nverts; - me->v2 += c * chunk_nverts; - } - - mp = result->mpoly + c * chunk_npolys; - for (i = 0; i < chunk_npolys; i++, mp++) { - mp->loopstart += c * chunk_nloops; - } - - /* adjust loop vertex and edge indices */ - ml = result->mloop + c * chunk_nloops; - for (i = 0; i < chunk_nloops; i++, ml++) { - ml->v += c * chunk_nverts; - ml->e += c * chunk_nedges; - } - - /* Handle merge between chunk n and n-1 */ - if (use_merge && (c >= 1)) { - if (!offset_has_scale && (c >= 2)) { - /* Mapping chunk 3 to chunk 2 is a translation of mapping 2 to 1 - * ... that is except if scaling makes the distance grow */ - int k; - int this_chunk_index = c * chunk_nverts; - int prev_chunk_index = (c - 1) * chunk_nverts; - for (k = 0; k < chunk_nverts; k++, this_chunk_index++, prev_chunk_index++) { - int target = full_doubles_map[prev_chunk_index]; - if (target != -1) { - target += chunk_nverts; /* translate mapping */ - while (target != -1 && !ELEM(full_doubles_map[target], -1, target)) { - /* If target is already mapped, we only follow that mapping if final target remains - * close enough from current vert (otherwise no mapping at all). */ - if (compare_len_v3v3(result_dm_verts[this_chunk_index].co, - result_dm_verts[full_doubles_map[target]].co, - amd->merge_dist)) - { - target = full_doubles_map[target]; - } - else { - target = -1; - } - } - } - full_doubles_map[this_chunk_index] = target; - } - } - else { - dm_mvert_map_doubles( - full_doubles_map, - result_dm_verts, - (c - 1) * chunk_nverts, - chunk_nverts, - c * chunk_nverts, - chunk_nverts, - amd->merge_dist); - } - } - } - - /* handle UVs */ - if (chunk_nloops > 0 && is_zero_v2(amd->uv_offset) == false) { - const int totuv = CustomData_number_of_layers(&result->ldata, CD_MLOOPUV); - for (i = 0; i < totuv; i++) { - MLoopUV *dmloopuv = CustomData_get_layer_n(&result->ldata, CD_MLOOPUV, i); - dmloopuv += chunk_nloops; - for (c = 1; c < count; c++) { - const float uv_offset[2] = { - amd->uv_offset[0] * (float)c, - amd->uv_offset[1] * (float)c, - }; - int l_index = chunk_nloops; - for (; l_index-- != 0; dmloopuv++) { - dmloopuv->uv[0] += uv_offset[0]; - dmloopuv->uv[1] += uv_offset[1]; - } - } - } - } - - last_chunk_start = (count - 1) * chunk_nverts; - last_chunk_nverts = chunk_nverts; - - copy_m4_m4(final_offset, current_offset); - - if (use_merge && (amd->flags & MOD_ARR_MERGEFINAL) && (count > 1)) { - /* Merge first and last copies */ - dm_mvert_map_doubles( - full_doubles_map, - result_dm_verts, - last_chunk_start, - last_chunk_nverts, - first_chunk_start, - first_chunk_nverts, - amd->merge_dist); - } - - /* start capping */ - if (start_cap_mesh) { - float start_offset[4][4]; - int start_cap_start = result_nverts - start_cap_nverts - end_cap_nverts; - invert_m4_m4(start_offset, offset); - mesh_merge_transform( - result, start_cap_mesh, start_offset, - result_nverts - start_cap_nverts - end_cap_nverts, - result_nedges - start_cap_nedges - end_cap_nedges, - result_nloops - start_cap_nloops - end_cap_nloops, - result_npolys - start_cap_npolys - end_cap_npolys, - start_cap_nverts, start_cap_nedges, start_cap_nloops, start_cap_npolys, - vgroup_start_cap_remap, vgroup_start_cap_remap_len); - /* Identify doubles with first chunk */ - if (use_merge) { - dm_mvert_map_doubles( - full_doubles_map, - result_dm_verts, - first_chunk_start, - first_chunk_nverts, - start_cap_start, - start_cap_nverts, - amd->merge_dist); - } - } - - if (end_cap_mesh) { - float end_offset[4][4]; - int end_cap_start = result_nverts - end_cap_nverts; - mul_m4_m4m4(end_offset, current_offset, offset); - mesh_merge_transform( - result, end_cap_mesh, end_offset, - result_nverts - end_cap_nverts, - result_nedges - end_cap_nedges, - result_nloops - end_cap_nloops, - result_npolys - end_cap_npolys, - end_cap_nverts, end_cap_nedges, end_cap_nloops, end_cap_npolys, - vgroup_end_cap_remap, vgroup_end_cap_remap_len); - /* Identify doubles with last chunk */ - if (use_merge) { - dm_mvert_map_doubles( - full_doubles_map, - result_dm_verts, - last_chunk_start, - last_chunk_nverts, - end_cap_start, - end_cap_nverts, - amd->merge_dist); - } - } - /* done capping */ - - /* Handle merging */ - tot_doubles = 0; - if (use_merge) { - for (i = 0; i < result_nverts; i++) { - int new_i = full_doubles_map[i]; - if (new_i != -1) { - /* We have to follow chains of doubles (merge start/end especially is likely to create some), - * those are not supported at all by BKE_mesh_merge_verts! */ - while (!ELEM(full_doubles_map[new_i], -1, new_i)) { - new_i = full_doubles_map[new_i]; - } - if (i == new_i) { - full_doubles_map[i] = -1; - } - else { - full_doubles_map[i] = new_i; - tot_doubles++; - } - } - } - if (tot_doubles > 0) { - result = BKE_mesh_merge_verts(result, full_doubles_map, tot_doubles, MESH_MERGE_VERTS_DUMP_IF_EQUAL); - } - MEM_freeN(full_doubles_map); - } - - /* In case org dm has dirty normals, or we made some merging, mark normals as dirty in new mesh! - * TODO: we may need to set other dirty flags as well? - */ - if (use_recalc_normals) { - result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; - } - - if (vgroup_start_cap_remap) { - MEM_freeN(vgroup_start_cap_remap); - } - if (vgroup_end_cap_remap) { - MEM_freeN(vgroup_end_cap_remap); - } - - return result; + const float eps = 1e-6f; + const MVert *src_mvert; + MVert *mv, *mv_prev, *result_dm_verts; + + MEdge *me; + MLoop *ml; + MPoly *mp; + int i, j, c, count; + float length = amd->length; + /* offset matrix */ + float offset[4][4]; + float scale[3]; + bool offset_has_scale; + float current_offset[4][4]; + float final_offset[4][4]; + int *full_doubles_map = NULL; + int tot_doubles; + + const bool use_merge = (amd->flags & MOD_ARR_MERGE) != 0; + const bool use_recalc_normals = (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) || use_merge; + const bool use_offset_ob = ((amd->offset_type & MOD_ARR_OFF_OBJ) && amd->offset_ob != NULL); + + int start_cap_nverts = 0, start_cap_nedges = 0, start_cap_npolys = 0, start_cap_nloops = 0; + int end_cap_nverts = 0, end_cap_nedges = 0, end_cap_npolys = 0, end_cap_nloops = 0; + int result_nverts = 0, result_nedges = 0, result_npolys = 0, result_nloops = 0; + int chunk_nverts, chunk_nedges, chunk_nloops, chunk_npolys; + int first_chunk_start, first_chunk_nverts, last_chunk_start, last_chunk_nverts; + + Mesh *result, *start_cap_mesh = NULL, *end_cap_mesh = NULL; + + int *vgroup_start_cap_remap = NULL; + int vgroup_start_cap_remap_len = 0; + int *vgroup_end_cap_remap = NULL; + int vgroup_end_cap_remap_len = 0; + + chunk_nverts = mesh->totvert; + chunk_nedges = mesh->totedge; + chunk_nloops = mesh->totloop; + chunk_npolys = mesh->totpoly; + + count = amd->count; + + Object *start_cap_ob = amd->start_cap; + if (start_cap_ob && start_cap_ob != ctx->object && start_cap_ob->type == OB_MESH) { + vgroup_start_cap_remap = BKE_object_defgroup_index_map_create( + start_cap_ob, ctx->object, &vgroup_start_cap_remap_len); + + start_cap_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(start_cap_ob, false); + if (start_cap_mesh) { + start_cap_nverts = start_cap_mesh->totvert; + start_cap_nedges = start_cap_mesh->totedge; + start_cap_nloops = start_cap_mesh->totloop; + start_cap_npolys = start_cap_mesh->totpoly; + } + } + Object *end_cap_ob = amd->end_cap; + if (end_cap_ob && end_cap_ob != ctx->object && end_cap_ob->type == OB_MESH) { + vgroup_end_cap_remap = BKE_object_defgroup_index_map_create( + end_cap_ob, ctx->object, &vgroup_end_cap_remap_len); + + end_cap_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(end_cap_ob, false); + if (end_cap_mesh) { + end_cap_nverts = end_cap_mesh->totvert; + end_cap_nedges = end_cap_mesh->totedge; + end_cap_nloops = end_cap_mesh->totloop; + end_cap_npolys = end_cap_mesh->totpoly; + } + } + + /* Build up offset array, cumulating all settings options */ + + unit_m4(offset); + src_mvert = mesh->mvert; + + if (amd->offset_type & MOD_ARR_OFF_CONST) { + add_v3_v3(offset[3], amd->offset); + } + + if (amd->offset_type & MOD_ARR_OFF_RELATIVE) { + float min[3], max[3]; + const MVert *src_mv; + + INIT_MINMAX(min, max); + for (src_mv = src_mvert, j = chunk_nverts; j--; src_mv++) { + minmax_v3v3_v3(min, max, src_mv->co); + } + + for (j = 3; j--;) { + offset[3][j] += amd->scale[j] * (max[j] - min[j]); + } + } + + if (use_offset_ob) { + float obinv[4][4]; + float result_mat[4][4]; + + if (ctx->object) + invert_m4_m4(obinv, ctx->object->obmat); + else + unit_m4(obinv); + + mul_m4_series(result_mat, offset, obinv, amd->offset_ob->obmat); + copy_m4_m4(offset, result_mat); + } + + /* Check if there is some scaling. If scaling, then we will not translate mapping */ + mat4_to_size(scale, offset); + offset_has_scale = !is_one_v3(scale); + + if (amd->fit_type == MOD_ARR_FITCURVE && amd->curve_ob != NULL) { + Object *curve_ob = amd->curve_ob; + Curve *cu = curve_ob->data; + if (cu) { + CurveCache *curve_cache = curve_ob->runtime.curve_cache; + if (curve_cache != NULL && curve_cache->path != NULL) { + float scale_fac = mat4_to_scale(curve_ob->obmat); + length = scale_fac * curve_cache->path->totdist; + } + } + } + + /* calculate the maximum number of copies which will fit within the + * prescribed length */ + if (amd->fit_type == MOD_ARR_FITLENGTH || amd->fit_type == MOD_ARR_FITCURVE) { + float dist = len_v3(offset[3]); + + if (dist > eps) { + /* this gives length = first copy start to last copy end + * add a tiny offset for floating point rounding errors */ + count = (length + eps) / dist + 1; + } + else { + /* if the offset has no translation, just make one copy */ + count = 1; + } + } + + if (count < 1) + count = 1; + + /* The number of verts, edges, loops, polys, before eventually merging doubles */ + result_nverts = chunk_nverts * count + start_cap_nverts + end_cap_nverts; + result_nedges = chunk_nedges * count + start_cap_nedges + end_cap_nedges; + result_nloops = chunk_nloops * count + start_cap_nloops + end_cap_nloops; + result_npolys = chunk_npolys * count + start_cap_npolys + end_cap_npolys; + + /* Initialize a result dm */ + result = BKE_mesh_new_nomain_from_template( + mesh, result_nverts, result_nedges, 0, result_nloops, result_npolys); + result_dm_verts = result->mvert; + + if (use_merge) { + /* Will need full_doubles_map for handling merge */ + full_doubles_map = MEM_malloc_arrayN(result_nverts, sizeof(int), "mod array doubles map"); + copy_vn_i(full_doubles_map, result_nverts, -1); + } + + /* copy customdata to original geometry */ + CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, chunk_nverts); + CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, chunk_nedges); + CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, chunk_nloops); + CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, chunk_npolys); + + /* Subsurf for eg won't have mesh data in the custom data arrays. + * now add mvert/medge/mpoly layers. */ + if (!CustomData_has_layer(&mesh->vdata, CD_MVERT)) { + memcpy(result->mvert, mesh->mvert, sizeof(*result->mvert) * mesh->totvert); + } + if (!CustomData_has_layer(&mesh->edata, CD_MEDGE)) { + memcpy(result->medge, mesh->medge, sizeof(*result->medge) * mesh->totedge); + } + if (!CustomData_has_layer(&mesh->pdata, CD_MPOLY)) { + memcpy(result->mloop, mesh->mloop, sizeof(*result->mloop) * mesh->totloop); + memcpy(result->mpoly, mesh->mpoly, sizeof(*result->mpoly) * mesh->totpoly); + } + + /* Remember first chunk, in case of cap merge */ + first_chunk_start = 0; + first_chunk_nverts = chunk_nverts; + + unit_m4(current_offset); + for (c = 1; c < count; c++) { + /* copy customdata to new geometry */ + CustomData_copy_data(&mesh->vdata, &result->vdata, 0, c * chunk_nverts, chunk_nverts); + CustomData_copy_data(&mesh->edata, &result->edata, 0, c * chunk_nedges, chunk_nedges); + CustomData_copy_data(&mesh->ldata, &result->ldata, 0, c * chunk_nloops, chunk_nloops); + CustomData_copy_data(&mesh->pdata, &result->pdata, 0, c * chunk_npolys, chunk_npolys); + + mv_prev = result_dm_verts; + mv = mv_prev + c * chunk_nverts; + + /* recalculate cumulative offset here */ + mul_m4_m4m4(current_offset, current_offset, offset); + + /* apply offset to all new verts */ + for (i = 0; i < chunk_nverts; i++, mv++, mv_prev++) { + mul_m4_v3(current_offset, mv->co); + + /* We have to correct normals too, if we do not tag them as dirty! */ + if (!use_recalc_normals) { + float no[3]; + normal_short_to_float_v3(no, mv->no); + mul_mat3_m4_v3(current_offset, no); + normalize_v3(no); + normal_float_to_short_v3(mv->no, no); + } + } + + /* adjust edge vertex indices */ + me = result->medge + c * chunk_nedges; + for (i = 0; i < chunk_nedges; i++, me++) { + me->v1 += c * chunk_nverts; + me->v2 += c * chunk_nverts; + } + + mp = result->mpoly + c * chunk_npolys; + for (i = 0; i < chunk_npolys; i++, mp++) { + mp->loopstart += c * chunk_nloops; + } + + /* adjust loop vertex and edge indices */ + ml = result->mloop + c * chunk_nloops; + for (i = 0; i < chunk_nloops; i++, ml++) { + ml->v += c * chunk_nverts; + ml->e += c * chunk_nedges; + } + + /* Handle merge between chunk n and n-1 */ + if (use_merge && (c >= 1)) { + if (!offset_has_scale && (c >= 2)) { + /* Mapping chunk 3 to chunk 2 is a translation of mapping 2 to 1 + * ... that is except if scaling makes the distance grow */ + int k; + int this_chunk_index = c * chunk_nverts; + int prev_chunk_index = (c - 1) * chunk_nverts; + for (k = 0; k < chunk_nverts; k++, this_chunk_index++, prev_chunk_index++) { + int target = full_doubles_map[prev_chunk_index]; + if (target != -1) { + target += chunk_nverts; /* translate mapping */ + while (target != -1 && !ELEM(full_doubles_map[target], -1, target)) { + /* If target is already mapped, we only follow that mapping if final target remains + * close enough from current vert (otherwise no mapping at all). */ + if (compare_len_v3v3(result_dm_verts[this_chunk_index].co, + result_dm_verts[full_doubles_map[target]].co, + amd->merge_dist)) { + target = full_doubles_map[target]; + } + else { + target = -1; + } + } + } + full_doubles_map[this_chunk_index] = target; + } + } + else { + dm_mvert_map_doubles(full_doubles_map, + result_dm_verts, + (c - 1) * chunk_nverts, + chunk_nverts, + c * chunk_nverts, + chunk_nverts, + amd->merge_dist); + } + } + } + + /* handle UVs */ + if (chunk_nloops > 0 && is_zero_v2(amd->uv_offset) == false) { + const int totuv = CustomData_number_of_layers(&result->ldata, CD_MLOOPUV); + for (i = 0; i < totuv; i++) { + MLoopUV *dmloopuv = CustomData_get_layer_n(&result->ldata, CD_MLOOPUV, i); + dmloopuv += chunk_nloops; + for (c = 1; c < count; c++) { + const float uv_offset[2] = { + amd->uv_offset[0] * (float)c, + amd->uv_offset[1] * (float)c, + }; + int l_index = chunk_nloops; + for (; l_index-- != 0; dmloopuv++) { + dmloopuv->uv[0] += uv_offset[0]; + dmloopuv->uv[1] += uv_offset[1]; + } + } + } + } + + last_chunk_start = (count - 1) * chunk_nverts; + last_chunk_nverts = chunk_nverts; + + copy_m4_m4(final_offset, current_offset); + + if (use_merge && (amd->flags & MOD_ARR_MERGEFINAL) && (count > 1)) { + /* Merge first and last copies */ + dm_mvert_map_doubles(full_doubles_map, + result_dm_verts, + last_chunk_start, + last_chunk_nverts, + first_chunk_start, + first_chunk_nverts, + amd->merge_dist); + } + + /* start capping */ + if (start_cap_mesh) { + float start_offset[4][4]; + int start_cap_start = result_nverts - start_cap_nverts - end_cap_nverts; + invert_m4_m4(start_offset, offset); + mesh_merge_transform(result, + start_cap_mesh, + start_offset, + result_nverts - start_cap_nverts - end_cap_nverts, + result_nedges - start_cap_nedges - end_cap_nedges, + result_nloops - start_cap_nloops - end_cap_nloops, + result_npolys - start_cap_npolys - end_cap_npolys, + start_cap_nverts, + start_cap_nedges, + start_cap_nloops, + start_cap_npolys, + vgroup_start_cap_remap, + vgroup_start_cap_remap_len); + /* Identify doubles with first chunk */ + if (use_merge) { + dm_mvert_map_doubles(full_doubles_map, + result_dm_verts, + first_chunk_start, + first_chunk_nverts, + start_cap_start, + start_cap_nverts, + amd->merge_dist); + } + } + + if (end_cap_mesh) { + float end_offset[4][4]; + int end_cap_start = result_nverts - end_cap_nverts; + mul_m4_m4m4(end_offset, current_offset, offset); + mesh_merge_transform(result, + end_cap_mesh, + end_offset, + result_nverts - end_cap_nverts, + result_nedges - end_cap_nedges, + result_nloops - end_cap_nloops, + result_npolys - end_cap_npolys, + end_cap_nverts, + end_cap_nedges, + end_cap_nloops, + end_cap_npolys, + vgroup_end_cap_remap, + vgroup_end_cap_remap_len); + /* Identify doubles with last chunk */ + if (use_merge) { + dm_mvert_map_doubles(full_doubles_map, + result_dm_verts, + last_chunk_start, + last_chunk_nverts, + end_cap_start, + end_cap_nverts, + amd->merge_dist); + } + } + /* done capping */ + + /* Handle merging */ + tot_doubles = 0; + if (use_merge) { + for (i = 0; i < result_nverts; i++) { + int new_i = full_doubles_map[i]; + if (new_i != -1) { + /* We have to follow chains of doubles (merge start/end especially is likely to create some), + * those are not supported at all by BKE_mesh_merge_verts! */ + while (!ELEM(full_doubles_map[new_i], -1, new_i)) { + new_i = full_doubles_map[new_i]; + } + if (i == new_i) { + full_doubles_map[i] = -1; + } + else { + full_doubles_map[i] = new_i; + tot_doubles++; + } + } + } + if (tot_doubles > 0) { + result = BKE_mesh_merge_verts( + result, full_doubles_map, tot_doubles, MESH_MERGE_VERTS_DUMP_IF_EQUAL); + } + MEM_freeN(full_doubles_map); + } + + /* In case org dm has dirty normals, or we made some merging, mark normals as dirty in new mesh! + * TODO: we may need to set other dirty flags as well? + */ + if (use_recalc_normals) { + result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + } + + if (vgroup_start_cap_remap) { + MEM_freeN(vgroup_start_cap_remap); + } + if (vgroup_end_cap_remap) { + MEM_freeN(vgroup_end_cap_remap); + } + + return result; } - -static Mesh *applyModifier( - ModifierData *md, const ModifierEvalContext *ctx, - Mesh *mesh) +static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) { - ArrayModifierData *amd = (ArrayModifierData *) md; - return arrayModifier_doArray(amd, ctx, mesh); + ArrayModifierData *amd = (ArrayModifierData *)md; + return arrayModifier_doArray(amd, ctx, mesh); } - ModifierTypeInfo modifierType_Array = { - /* name */ "Array", - /* structName */ "ArrayModifierData", - /* structSize */ sizeof(ArrayModifierData), - /* type */ eModifierTypeType_Constructive, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_SupportsMapping | - eModifierTypeFlag_SupportsEditmode | - eModifierTypeFlag_EnableInEditmode | - eModifierTypeFlag_AcceptsCVs, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ initData, - /* requiredDataMask */ NULL, - /* freeData */ NULL, - /* isDisabled */ NULL, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ foreachObjectLink, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Array", + /* structName */ "ArrayModifierData", + /* structSize */ sizeof(ArrayModifierData), + /* type */ eModifierTypeType_Constructive, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping | + eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode | + eModifierTypeFlag_AcceptsCVs, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ initData, + /* requiredDataMask */ NULL, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index 567c74effe0..32a020a35ff 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -45,38 +45,40 @@ static void initData(ModifierData *md) { - BevelModifierData *bmd = (BevelModifierData *) md; - - bmd->value = 0.1f; - bmd->res = 1; - bmd->flags = 0; - bmd->val_flags = MOD_BEVEL_AMT_OFFSET; - bmd->lim_flags = 0; - bmd->e_flags = 0; - bmd->edge_flags = 0; - bmd->face_str_mode = MOD_BEVEL_FACE_STRENGTH_NONE; - bmd->miter_inner = MOD_BEVEL_MITER_SHARP; - bmd->miter_outer = MOD_BEVEL_MITER_SHARP; - bmd->spread = 0.1f; - bmd->mat = -1; - bmd->profile = 0.5f; - bmd->bevel_angle = DEG2RADF(30.0f); - bmd->defgrp_name[0] = '\0'; + BevelModifierData *bmd = (BevelModifierData *)md; + + bmd->value = 0.1f; + bmd->res = 1; + bmd->flags = 0; + bmd->val_flags = MOD_BEVEL_AMT_OFFSET; + bmd->lim_flags = 0; + bmd->e_flags = 0; + bmd->edge_flags = 0; + bmd->face_str_mode = MOD_BEVEL_FACE_STRENGTH_NONE; + bmd->miter_inner = MOD_BEVEL_MITER_SHARP; + bmd->miter_outer = MOD_BEVEL_MITER_SHARP; + bmd->spread = 0.1f; + bmd->mat = -1; + bmd->profile = 0.5f; + bmd->bevel_angle = DEG2RADF(30.0f); + bmd->defgrp_name[0] = '\0'; } static void copyData(const ModifierData *md_src, ModifierData *md_dst, const int flag) { - modifier_copyData_generic(md_src, md_dst, flag); + modifier_copyData_generic(md_src, md_dst, flag); } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - BevelModifierData *bmd = (BevelModifierData *)md; + BevelModifierData *bmd = (BevelModifierData *)md; - /* ask for vertexgroups if we need them */ - if (bmd->defgrp_name[0] != '\0') { - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; - } + /* ask for vertexgroups if we need them */ + if (bmd->defgrp_name[0] != '\0') { + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + } } /* @@ -84,154 +86,168 @@ static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_Me */ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) { - Mesh *result; - BMesh *bm; - BMIter iter; - BMEdge *e; - BMVert *v; - float weight, weight2; - int vgroup = -1; - MDeformVert *dvert = NULL; - BevelModifierData *bmd = (BevelModifierData *) md; - const float threshold = cosf(bmd->bevel_angle + 0.000000175f); - const bool vertex_only = (bmd->flags & MOD_BEVEL_VERT) != 0; - const bool do_clamp = !(bmd->flags & MOD_BEVEL_OVERLAP_OK); - const int offset_type = bmd->val_flags; - const float value = bmd->value; - const int mat = CLAMPIS(bmd->mat, -1, ctx->object->totcol - 1); - const bool loop_slide = (bmd->flags & MOD_BEVEL_EVEN_WIDTHS) == 0; - const bool mark_seam = (bmd->edge_flags & MOD_BEVEL_MARK_SEAM); - const bool mark_sharp = (bmd->edge_flags & MOD_BEVEL_MARK_SHARP); - bool harden_normals = (bmd->flags & MOD_BEVEL_HARDEN_NORMALS); - const int face_strength_mode = bmd->face_str_mode; - const int miter_outer = bmd->miter_outer; - const int miter_inner = bmd->miter_inner; - const float spread = bmd->spread; - - bm = BKE_mesh_to_bmesh_ex( - mesh, - &(struct BMeshCreateParams){0}, - &(struct BMeshFromMeshParams){ - .calc_face_normal = true, - .add_key_index = false, - .use_shapekey = false, - .active_shapekey = 0, - /* XXX We probably can use CD_MASK_BAREMESH_ORIGDINDEX here instead (also for other modifiers cases)? */ - .cd_mask_extra = {.vmask = CD_MASK_ORIGINDEX, .emask = CD_MASK_ORIGINDEX, .pmask = CD_MASK_ORIGINDEX}, - }); - - if ((bmd->lim_flags & MOD_BEVEL_VGROUP) && bmd->defgrp_name[0]) - MOD_get_vgroup(ctx->object, mesh, bmd->defgrp_name, &dvert, &vgroup); - - if (vertex_only) { - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - if (!BM_vert_is_manifold(v)) - continue; - if (bmd->lim_flags & MOD_BEVEL_WEIGHT) { - weight = BM_elem_float_data_get(&bm->vdata, v, CD_BWEIGHT); - if (weight == 0.0f) - continue; - } - else if (vgroup != -1) { - weight = defvert_array_find_weight_safe(dvert, BM_elem_index_get(v), vgroup); - /* Check is against 0.5 rather than != 0.0 because cascaded bevel modifiers will - * interpolate weights for newly created vertices, and may cause unexpected "selection" */ - if (weight < 0.5f) - continue; - } - BM_elem_flag_enable(v, BM_ELEM_TAG); - } - } - else if (bmd->lim_flags & MOD_BEVEL_ANGLE) { - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - /* check for 1 edge having 2 face users */ - BMLoop *l_a, *l_b; - if (BM_edge_loop_pair(e, &l_a, &l_b)) { - if (dot_v3v3(l_a->f->no, l_b->f->no) < threshold) { - BM_elem_flag_enable(e, BM_ELEM_TAG); - BM_elem_flag_enable(e->v1, BM_ELEM_TAG); - BM_elem_flag_enable(e->v2, BM_ELEM_TAG); - } - } - } - } - else { - /* crummy, is there a way just to operator on all? - campbell */ - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_edge_is_manifold(e)) { - if (bmd->lim_flags & MOD_BEVEL_WEIGHT) { - weight = BM_elem_float_data_get(&bm->edata, e, CD_BWEIGHT); - if (weight == 0.0f) - continue; - } - else if (vgroup != -1) { - weight = defvert_array_find_weight_safe(dvert, BM_elem_index_get(e->v1), vgroup); - weight2 = defvert_array_find_weight_safe(dvert, BM_elem_index_get(e->v2), vgroup); - if (weight < 0.5f || weight2 < 0.5f) - continue; - } - BM_elem_flag_enable(e, BM_ELEM_TAG); - BM_elem_flag_enable(e->v1, BM_ELEM_TAG); - BM_elem_flag_enable(e->v2, BM_ELEM_TAG); - } - } - } - - if (harden_normals && !(((Mesh *)ctx->object->data)->flag & ME_AUTOSMOOTH)) { - modifier_setError(md, "Enable 'Auto Smooth' option in mesh settings for hardening"); - harden_normals = false; - } - - BM_mesh_bevel(bm, value, offset_type, bmd->res, bmd->profile, - vertex_only, bmd->lim_flags & MOD_BEVEL_WEIGHT, do_clamp, - dvert, vgroup, mat, loop_slide, mark_seam, mark_sharp, - harden_normals, face_strength_mode, - miter_outer, miter_inner, spread, mesh->smoothresh); - - result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL); - - BLI_assert(bm->vtoolflagpool == NULL && - bm->etoolflagpool == NULL && - bm->ftoolflagpool == NULL); /* make sure we never alloc'd these */ - BM_mesh_free(bm); - - result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; - - return result; + Mesh *result; + BMesh *bm; + BMIter iter; + BMEdge *e; + BMVert *v; + float weight, weight2; + int vgroup = -1; + MDeformVert *dvert = NULL; + BevelModifierData *bmd = (BevelModifierData *)md; + const float threshold = cosf(bmd->bevel_angle + 0.000000175f); + const bool vertex_only = (bmd->flags & MOD_BEVEL_VERT) != 0; + const bool do_clamp = !(bmd->flags & MOD_BEVEL_OVERLAP_OK); + const int offset_type = bmd->val_flags; + const float value = bmd->value; + const int mat = CLAMPIS(bmd->mat, -1, ctx->object->totcol - 1); + const bool loop_slide = (bmd->flags & MOD_BEVEL_EVEN_WIDTHS) == 0; + const bool mark_seam = (bmd->edge_flags & MOD_BEVEL_MARK_SEAM); + const bool mark_sharp = (bmd->edge_flags & MOD_BEVEL_MARK_SHARP); + bool harden_normals = (bmd->flags & MOD_BEVEL_HARDEN_NORMALS); + const int face_strength_mode = bmd->face_str_mode; + const int miter_outer = bmd->miter_outer; + const int miter_inner = bmd->miter_inner; + const float spread = bmd->spread; + + bm = BKE_mesh_to_bmesh_ex( + mesh, + &(struct BMeshCreateParams){0}, + &(struct BMeshFromMeshParams){ + .calc_face_normal = true, + .add_key_index = false, + .use_shapekey = false, + .active_shapekey = 0, + /* XXX We probably can use CD_MASK_BAREMESH_ORIGDINDEX here instead (also for other modifiers cases)? */ + .cd_mask_extra = {.vmask = CD_MASK_ORIGINDEX, + .emask = CD_MASK_ORIGINDEX, + .pmask = CD_MASK_ORIGINDEX}, + }); + + if ((bmd->lim_flags & MOD_BEVEL_VGROUP) && bmd->defgrp_name[0]) + MOD_get_vgroup(ctx->object, mesh, bmd->defgrp_name, &dvert, &vgroup); + + if (vertex_only) { + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (!BM_vert_is_manifold(v)) + continue; + if (bmd->lim_flags & MOD_BEVEL_WEIGHT) { + weight = BM_elem_float_data_get(&bm->vdata, v, CD_BWEIGHT); + if (weight == 0.0f) + continue; + } + else if (vgroup != -1) { + weight = defvert_array_find_weight_safe(dvert, BM_elem_index_get(v), vgroup); + /* Check is against 0.5 rather than != 0.0 because cascaded bevel modifiers will + * interpolate weights for newly created vertices, and may cause unexpected "selection" */ + if (weight < 0.5f) + continue; + } + BM_elem_flag_enable(v, BM_ELEM_TAG); + } + } + else if (bmd->lim_flags & MOD_BEVEL_ANGLE) { + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + /* check for 1 edge having 2 face users */ + BMLoop *l_a, *l_b; + if (BM_edge_loop_pair(e, &l_a, &l_b)) { + if (dot_v3v3(l_a->f->no, l_b->f->no) < threshold) { + BM_elem_flag_enable(e, BM_ELEM_TAG); + BM_elem_flag_enable(e->v1, BM_ELEM_TAG); + BM_elem_flag_enable(e->v2, BM_ELEM_TAG); + } + } + } + } + else { + /* crummy, is there a way just to operator on all? - campbell */ + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_edge_is_manifold(e)) { + if (bmd->lim_flags & MOD_BEVEL_WEIGHT) { + weight = BM_elem_float_data_get(&bm->edata, e, CD_BWEIGHT); + if (weight == 0.0f) + continue; + } + else if (vgroup != -1) { + weight = defvert_array_find_weight_safe(dvert, BM_elem_index_get(e->v1), vgroup); + weight2 = defvert_array_find_weight_safe(dvert, BM_elem_index_get(e->v2), vgroup); + if (weight < 0.5f || weight2 < 0.5f) + continue; + } + BM_elem_flag_enable(e, BM_ELEM_TAG); + BM_elem_flag_enable(e->v1, BM_ELEM_TAG); + BM_elem_flag_enable(e->v2, BM_ELEM_TAG); + } + } + } + + if (harden_normals && !(((Mesh *)ctx->object->data)->flag & ME_AUTOSMOOTH)) { + modifier_setError(md, "Enable 'Auto Smooth' option in mesh settings for hardening"); + harden_normals = false; + } + + BM_mesh_bevel(bm, + value, + offset_type, + bmd->res, + bmd->profile, + vertex_only, + bmd->lim_flags & MOD_BEVEL_WEIGHT, + do_clamp, + dvert, + vgroup, + mat, + loop_slide, + mark_seam, + mark_sharp, + harden_normals, + face_strength_mode, + miter_outer, + miter_inner, + spread, + mesh->smoothresh); + + result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL); + + BLI_assert(bm->vtoolflagpool == NULL && bm->etoolflagpool == NULL && + bm->ftoolflagpool == NULL); /* make sure we never alloc'd these */ + BM_mesh_free(bm); + + result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + + return result; } static bool dependsOnNormals(ModifierData *UNUSED(md)) { - return true; + return true; } ModifierTypeInfo modifierType_Bevel = { - /* name */ "Bevel", - /* structName */ "BevelModifierData", - /* structSize */ sizeof(BevelModifierData), - /* type */ eModifierTypeType_Constructive, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_SupportsEditmode | - eModifierTypeFlag_EnableInEditmode | - eModifierTypeFlag_AcceptsCVs, - - /* copyData */ copyData, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ NULL, - /* isDisabled */ NULL, - /* updateDepsgraph */ NULL, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ dependsOnNormals, - /* foreachObjectLink */ NULL, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Bevel", + /* structName */ "BevelModifierData", + /* structSize */ sizeof(BevelModifierData), + /* type */ eModifierTypeType_Constructive, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsEditmode | + eModifierTypeFlag_EnableInEditmode | eModifierTypeFlag_AcceptsCVs, + + /* copyData */ copyData, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ dependsOnNormals, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c index 8e3a19e524a..6e6f98e9889 100644 --- a/source/blender/modifiers/intern/MOD_boolean.c +++ b/source/blender/modifiers/intern/MOD_boolean.c @@ -35,14 +35,13 @@ #include "DNA_meshdata_types.h" #include "DNA_object_types.h" -#include "BKE_global.h" /* only to check G.debug */ +#include "BKE_global.h" /* only to check G.debug */ #include "BKE_library.h" #include "BKE_library_query.h" #include "BKE_material.h" #include "BKE_mesh.h" #include "BKE_modifier.h" - #include "MOD_util.h" #include "DEG_depsgraph_query.h" @@ -60,87 +59,84 @@ static void initData(ModifierData *md) { - BooleanModifierData *bmd = (BooleanModifierData *)md; + BooleanModifierData *bmd = (BooleanModifierData *)md; - bmd->double_threshold = 1e-6f; - bmd->operation = eBooleanModifierOp_Difference; + bmd->double_threshold = 1e-6f; + bmd->operation = eBooleanModifierOp_Difference; } -static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams)) +static bool isDisabled(const struct Scene *UNUSED(scene), + ModifierData *md, + bool UNUSED(useRenderParams)) { - BooleanModifierData *bmd = (BooleanModifierData *) md; + BooleanModifierData *bmd = (BooleanModifierData *)md; - return !bmd->object; + return !bmd->object; } -static void foreachObjectLink( - ModifierData *md, Object *ob, - ObjectWalkFunc walk, void *userData) +static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) { - BooleanModifierData *bmd = (BooleanModifierData *) md; + BooleanModifierData *bmd = (BooleanModifierData *)md; - walk(userData, ob, &bmd->object, IDWALK_CB_NOP); + walk(userData, ob, &bmd->object, IDWALK_CB_NOP); } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { - BooleanModifierData *bmd = (BooleanModifierData *)md; - if (bmd->object != NULL) { - DEG_add_object_relation(ctx->node, bmd->object, DEG_OB_COMP_TRANSFORM, "Boolean Modifier"); - DEG_add_object_relation(ctx->node, bmd->object, DEG_OB_COMP_GEOMETRY, "Boolean Modifier"); - } - /* We need own transformation as well. */ - DEG_add_modifier_to_transform_relation(ctx->node, "Boolean Modifier"); + BooleanModifierData *bmd = (BooleanModifierData *)md; + if (bmd->object != NULL) { + DEG_add_object_relation(ctx->node, bmd->object, DEG_OB_COMP_TRANSFORM, "Boolean Modifier"); + DEG_add_object_relation(ctx->node, bmd->object, DEG_OB_COMP_GEOMETRY, "Boolean Modifier"); + } + /* We need own transformation as well. */ + DEG_add_modifier_to_transform_relation(ctx->node, "Boolean Modifier"); } static Mesh *get_quick_mesh( - Object *ob_self, Mesh *mesh_self, - Object *ob_other, Mesh *mesh_other, - int operation) + Object *ob_self, Mesh *mesh_self, Object *ob_other, Mesh *mesh_other, int operation) { - Mesh *result = NULL; + Mesh *result = NULL; - if (mesh_self->totpoly == 0 || mesh_other->totpoly == 0) { - switch (operation) { - case eBooleanModifierOp_Intersect: - result = BKE_mesh_new_nomain(0, 0, 0, 0, 0); - break; + if (mesh_self->totpoly == 0 || mesh_other->totpoly == 0) { + switch (operation) { + case eBooleanModifierOp_Intersect: + result = BKE_mesh_new_nomain(0, 0, 0, 0, 0); + break; - case eBooleanModifierOp_Union: - if (mesh_self->totpoly != 0) { - result = mesh_self; - } - else { - BKE_id_copy_ex(NULL, &mesh_other->id, (ID **)&result, LIB_ID_COPY_LOCALIZE); + case eBooleanModifierOp_Union: + if (mesh_self->totpoly != 0) { + result = mesh_self; + } + else { + BKE_id_copy_ex(NULL, &mesh_other->id, (ID **)&result, LIB_ID_COPY_LOCALIZE); - float imat[4][4]; - float omat[4][4]; + float imat[4][4]; + float omat[4][4]; - invert_m4_m4(imat, ob_self->obmat); - mul_m4_m4m4(omat, imat, ob_other->obmat); + invert_m4_m4(imat, ob_self->obmat); + mul_m4_m4m4(omat, imat, ob_other->obmat); - const int mverts_len = result->totvert; - MVert *mv = result->mvert; + const int mverts_len = result->totvert; + MVert *mv = result->mvert; - for (int i = 0; i < mverts_len; i++, mv++) { - mul_m4_v3(omat, mv->co); - } + for (int i = 0; i < mverts_len; i++, mv++) { + mul_m4_v3(omat, mv->co); + } - result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; - } + result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + } - break; + break; - case eBooleanModifierOp_Difference: - result = mesh_self; - break; - } - } + case eBooleanModifierOp_Difference: + result = mesh_self; + break; + } + } - return result; + return result; } - /* has no meaning for faces, do this so we can tell which face is which */ #define BM_FACE_TAG BM_ELEM_DRAW @@ -149,210 +145,224 @@ static Mesh *get_quick_mesh( */ static int bm_face_isect_pair(BMFace *f, void *UNUSED(user_data)) { - return BM_elem_flag_test(f, BM_FACE_TAG) ? 1 : 0; + return BM_elem_flag_test(f, BM_FACE_TAG) ? 1 : 0; } static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) { - BooleanModifierData *bmd = (BooleanModifierData *) md; - Mesh *result = mesh; + BooleanModifierData *bmd = (BooleanModifierData *)md; + Mesh *result = mesh; - Mesh *mesh_other; + Mesh *mesh_other; - if (bmd->object == NULL) { - return result; - } + if (bmd->object == NULL) { + return result; + } - Object *other = bmd->object; - mesh_other = BKE_modifier_get_evaluated_mesh_from_evaluated_object(other, false); - if (mesh_other) { - Object *object = ctx->object; + Object *other = bmd->object; + mesh_other = BKE_modifier_get_evaluated_mesh_from_evaluated_object(other, false); + if (mesh_other) { + Object *object = ctx->object; - /* 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_mesh(object, mesh, other, mesh_other, bmd->operation); + /* 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_mesh(object, mesh, other, mesh_other, bmd->operation); - if (result == NULL) { - const bool is_flip = (is_negative_m4(object->obmat) != is_negative_m4(other->obmat)); + if (result == NULL) { + const bool is_flip = (is_negative_m4(object->obmat) != is_negative_m4(other->obmat)); - BMesh *bm; - const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh, mesh_other); + BMesh *bm; + const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh, mesh_other); #ifdef DEBUG_TIME - TIMEIT_START(boolean_bmesh); + TIMEIT_START(boolean_bmesh); #endif - bm = BM_mesh_create( - &allocsize, - &((struct BMeshCreateParams){.use_toolflags = false,})); - - BM_mesh_bm_from_me(bm, mesh_other, &((struct BMeshFromMeshParams){.calc_face_normal = true,})); - - if (UNLIKELY(is_flip)) { - const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS); - BMIter iter; - BMFace *efa; - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - BM_face_normal_flip_ex(bm, efa, cd_loop_mdisp_offset, true); - } - } - - BM_mesh_bm_from_me(bm, mesh, &((struct BMeshFromMeshParams){.calc_face_normal = true,})); - - /* main bmesh intersection setup */ - { - /* create tessface & intersect */ - const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop); - int tottri; - BMLoop *(*looptris)[3]; - - looptris = MEM_malloc_arrayN(looptris_tot, sizeof(*looptris), __func__); - - BM_mesh_calc_tessellation_beauty(bm, looptris, &tottri); - - /* postpone this until after tessellating - * so we can use the original normals before the vertex are moved */ - { - BMIter iter; - int i; - const int i_verts_end = mesh_other->totvert; - const int i_faces_end = mesh_other->totpoly; - - float imat[4][4]; - float omat[4][4]; - - invert_m4_m4(imat, object->obmat); - mul_m4_m4m4(omat, imat, other->obmat); - - BMVert *eve; - i = 0; - BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { - mul_m4_v3(omat, eve->co); - if (++i == i_verts_end) { - break; - } - } - - /* we need face normals because of 'BM_face_split_edgenet' - * we could calculate on the fly too (before calling split). */ - { - float nmat[3][3]; - copy_m3_m4(nmat, omat); - invert_m3(nmat); - - if (UNLIKELY(is_flip)) { - negate_m3(nmat); - } - - const short ob_src_totcol = other->totcol; - short *material_remap = BLI_array_alloca(material_remap, ob_src_totcol ? ob_src_totcol : 1); - - /* Using original (not evaluated) object here since we are writing to it. */ - /* XXX Pretty sure comment above is fully wrong now with CoW & co ? */ - BKE_material_remap_object_calc(ctx->object, other, material_remap); - - BMFace *efa; - i = 0; - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - mul_transposed_m3_v3(nmat, efa->no); - normalize_v3(efa->no); - BM_elem_flag_enable(efa, BM_FACE_TAG); /* temp tag to test which side split faces are from */ - - /* remap material */ - if (LIKELY(efa->mat_nr < ob_src_totcol)) { - efa->mat_nr = material_remap[efa->mat_nr]; - } - - if (++i == i_faces_end) { - break; - } - } - } - } - - /* not needed, but normals for 'dm' will be invalid, - * currently this is ok for 'BM_mesh_intersect' */ - // BM_mesh_normals_update(bm); - - bool use_separate = false; - bool use_dissolve = true; - bool use_island_connect = true; - - /* change for testing */ - if (G.debug & G_DEBUG) { - use_separate = (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_Separate) != 0; - use_dissolve = (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_NoDissolve) == 0; - use_island_connect = (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_NoConnectRegions) == 0; - } - - BM_mesh_intersect( - bm, - looptris, tottri, - bm_face_isect_pair, NULL, - false, - use_separate, - use_dissolve, - use_island_connect, - false, - false, - bmd->operation, - bmd->double_threshold); - - MEM_freeN(looptris); - } - - result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL); - - BM_mesh_free(bm); - - result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + bm = BM_mesh_create(&allocsize, + &((struct BMeshCreateParams){ + .use_toolflags = false, + })); + + BM_mesh_bm_from_me(bm, + mesh_other, + &((struct BMeshFromMeshParams){ + .calc_face_normal = true, + })); + + if (UNLIKELY(is_flip)) { + const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS); + BMIter iter; + BMFace *efa; + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + BM_face_normal_flip_ex(bm, efa, cd_loop_mdisp_offset, true); + } + } + + BM_mesh_bm_from_me(bm, + mesh, + &((struct BMeshFromMeshParams){ + .calc_face_normal = true, + })); + + /* main bmesh intersection setup */ + { + /* create tessface & intersect */ + const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop); + int tottri; + BMLoop *(*looptris)[3]; + + looptris = MEM_malloc_arrayN(looptris_tot, sizeof(*looptris), __func__); + + BM_mesh_calc_tessellation_beauty(bm, looptris, &tottri); + + /* postpone this until after tessellating + * so we can use the original normals before the vertex are moved */ + { + BMIter iter; + int i; + const int i_verts_end = mesh_other->totvert; + const int i_faces_end = mesh_other->totpoly; + + float imat[4][4]; + float omat[4][4]; + + invert_m4_m4(imat, object->obmat); + mul_m4_m4m4(omat, imat, other->obmat); + + BMVert *eve; + i = 0; + BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { + mul_m4_v3(omat, eve->co); + if (++i == i_verts_end) { + break; + } + } + + /* we need face normals because of 'BM_face_split_edgenet' + * we could calculate on the fly too (before calling split). */ + { + float nmat[3][3]; + copy_m3_m4(nmat, omat); + invert_m3(nmat); + + if (UNLIKELY(is_flip)) { + negate_m3(nmat); + } + + const short ob_src_totcol = other->totcol; + short *material_remap = BLI_array_alloca(material_remap, + ob_src_totcol ? ob_src_totcol : 1); + + /* Using original (not evaluated) object here since we are writing to it. */ + /* XXX Pretty sure comment above is fully wrong now with CoW & co ? */ + BKE_material_remap_object_calc(ctx->object, other, material_remap); + + BMFace *efa; + i = 0; + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + mul_transposed_m3_v3(nmat, efa->no); + normalize_v3(efa->no); + BM_elem_flag_enable( + efa, BM_FACE_TAG); /* temp tag to test which side split faces are from */ + + /* remap material */ + if (LIKELY(efa->mat_nr < ob_src_totcol)) { + efa->mat_nr = material_remap[efa->mat_nr]; + } + + if (++i == i_faces_end) { + break; + } + } + } + } + + /* not needed, but normals for 'dm' will be invalid, + * currently this is ok for 'BM_mesh_intersect' */ + // BM_mesh_normals_update(bm); + + bool use_separate = false; + bool use_dissolve = true; + bool use_island_connect = true; + + /* change for testing */ + if (G.debug & G_DEBUG) { + use_separate = (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_Separate) != 0; + use_dissolve = (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_NoDissolve) == 0; + use_island_connect = (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_NoConnectRegions) == + 0; + } + + BM_mesh_intersect(bm, + looptris, + tottri, + bm_face_isect_pair, + NULL, + false, + use_separate, + use_dissolve, + use_island_connect, + false, + false, + bmd->operation, + bmd->double_threshold); + + MEM_freeN(looptris); + } + + result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL); + + BM_mesh_free(bm); + + result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; #ifdef DEBUG_TIME - TIMEIT_END(boolean_bmesh); + TIMEIT_END(boolean_bmesh); #endif - } + } - /* if new mesh returned, return it; otherwise there was - * an error, so delete the modifier object */ - if (result == NULL) - modifier_setError(md, "Cannot execute boolean operation"); - } + /* if new mesh returned, return it; otherwise there was + * an error, so delete the modifier object */ + if (result == NULL) + modifier_setError(md, "Cannot execute boolean operation"); + } - return result; + return result; } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *UNUSED(md), CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *UNUSED(md), + CustomData_MeshMasks *r_cddata_masks) { - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; - r_cddata_masks->emask |= CD_MASK_MEDGE; - r_cddata_masks->fmask |= CD_MASK_MTFACE; + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + r_cddata_masks->emask |= CD_MASK_MEDGE; + r_cddata_masks->fmask |= CD_MASK_MTFACE; } ModifierTypeInfo modifierType_Boolean = { - /* name */ "Boolean", - /* structName */ "BooleanModifierData", - /* structSize */ sizeof(BooleanModifierData), - /* type */ eModifierTypeType_Nonconstructive, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_UsesPointCache, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ NULL, - /* isDisabled */ isDisabled, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ foreachObjectLink, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Boolean", + /* structName */ "BooleanModifierData", + /* structSize */ sizeof(BooleanModifierData), + /* type */ eModifierTypeType_Nonconstructive, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_UsesPointCache, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ NULL, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c index 01478c855bb..7c8470b26d9 100644 --- a/source/blender/modifiers/intern/MOD_build.c +++ b/source/blender/modifiers/intern/MOD_build.c @@ -44,270 +44,260 @@ static void initData(ModifierData *md) { - BuildModifierData *bmd = (BuildModifierData *) md; + BuildModifierData *bmd = (BuildModifierData *)md; - bmd->start = 1.0; - bmd->length = 100.0; + bmd->start = 1.0; + bmd->length = 100.0; } static bool dependsOnTime(ModifierData *UNUSED(md)) { - return true; + return true; } -static Mesh *applyModifier( - ModifierData *md, const ModifierEvalContext *ctx, - struct Mesh *mesh) +static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, struct Mesh *mesh) { - Mesh *result; - BuildModifierData *bmd = (BuildModifierData *) md; - int i, j, k; - int numFaces_dst, numEdges_dst, numLoops_dst = 0; - int *vertMap, *edgeMap, *faceMap; - float frac; - MPoly *mpoly_dst; - MLoop *ml_dst, *ml_src /*, *mloop_dst */; - GHashIterator gh_iter; - /* maps vert indices in old mesh to indices in new mesh */ - GHash *vertHash = BLI_ghash_int_new("build ve apply gh"); - /* maps edge indices in new mesh to indices in old mesh */ - GHash *edgeHash = BLI_ghash_int_new("build ed apply gh"); - /* maps edge indices in old mesh to indices in new mesh */ - GHash *edgeHash2 = BLI_ghash_int_new("build ed apply gh"); - - const int numVert_src = mesh->totvert; - const int numEdge_src = mesh->totedge; - const int numPoly_src = mesh->totpoly; - MPoly *mpoly_src = mesh->mpoly; - MLoop *mloop_src = mesh->mloop; - MEdge *medge_src = mesh->medge; - MVert *mvert_src = mesh->mvert; - - vertMap = MEM_malloc_arrayN(numVert_src, sizeof(*vertMap), "build modifier vertMap"); - edgeMap = MEM_malloc_arrayN(numEdge_src, sizeof(*edgeMap), "build modifier edgeMap"); - faceMap = MEM_malloc_arrayN(numPoly_src, sizeof(*faceMap), "build modifier faceMap"); - - range_vn_i(vertMap, numVert_src, 0); - range_vn_i(edgeMap, numEdge_src, 0); - range_vn_i(faceMap, numPoly_src, 0); - - struct Scene *scene = DEG_get_input_scene(ctx->depsgraph); - frac = (BKE_scene_frame_get(scene) - bmd->start) / bmd->length; - CLAMP(frac, 0.0f, 1.0f); - if (bmd->flag & MOD_BUILD_FLAG_REVERSE) { - frac = 1.0f - frac; - } - - numFaces_dst = numPoly_src * frac; - numEdges_dst = numEdge_src * frac; - - /* if there's at least one face, build based on faces */ - if (numFaces_dst) { - MPoly *mpoly, *mp; - MLoop *ml, *mloop; - uintptr_t hash_num, hash_num_alt; - - if (bmd->flag & MOD_BUILD_FLAG_RANDOMIZE) { - BLI_array_randomize(faceMap, sizeof(*faceMap), - numPoly_src, bmd->seed); - } - - /* get the set of all vert indices that will be in the final mesh, - * mapped to the new indices - */ - mpoly = mpoly_src; - mloop = mloop_src; - hash_num = 0; - for (i = 0; i < numFaces_dst; i++) { - mp = mpoly + faceMap[i]; - ml = mloop + mp->loopstart; - - for (j = 0; j < mp->totloop; j++, ml++) { - void **val_p; - if (!BLI_ghash_ensure_p(vertHash, POINTER_FROM_INT(ml->v), &val_p)) { - *val_p = (void *)hash_num; - hash_num++; - } - } - - numLoops_dst += mp->totloop; - } - BLI_assert(hash_num == BLI_ghash_len(vertHash)); - - /* get the set of edges that will be in the new mesh (i.e. all edges - * that have both verts in the new mesh) - */ - hash_num = 0; - hash_num_alt = 0; - for (i = 0; i < numEdge_src; i++, hash_num_alt++) { - MEdge *me = medge_src + i; - - if (BLI_ghash_haskey(vertHash, POINTER_FROM_INT(me->v1)) && - BLI_ghash_haskey(vertHash, POINTER_FROM_INT(me->v2))) - { - BLI_ghash_insert(edgeHash, (void *)hash_num, (void *)hash_num_alt); - BLI_ghash_insert(edgeHash2, (void *)hash_num_alt, (void *)hash_num); - hash_num++; - } - } - BLI_assert(hash_num == BLI_ghash_len(edgeHash)); - } - else if (numEdges_dst) { - MEdge *medge, *me; - uintptr_t hash_num; - - if (bmd->flag & MOD_BUILD_FLAG_RANDOMIZE) - BLI_array_randomize(edgeMap, sizeof(*edgeMap), - numEdge_src, bmd->seed); - - /* get the set of all vert indices that will be in the final mesh, - * mapped to the new indices - */ - medge = medge_src; - hash_num = 0; - BLI_assert(hash_num == BLI_ghash_len(vertHash)); - for (i = 0; i < numEdges_dst; i++) { - void **val_p; - me = medge + edgeMap[i]; - - if (!BLI_ghash_ensure_p(vertHash, POINTER_FROM_INT(me->v1), &val_p)) { - *val_p = (void *)hash_num; - hash_num++; - } - if (!BLI_ghash_ensure_p(vertHash, POINTER_FROM_INT(me->v2), &val_p)) { - *val_p = (void *)hash_num; - hash_num++; - } - } - BLI_assert(hash_num == BLI_ghash_len(vertHash)); - - /* get the set of edges that will be in the new mesh */ - for (i = 0; i < numEdges_dst; i++) { - j = BLI_ghash_len(edgeHash); - - BLI_ghash_insert(edgeHash, POINTER_FROM_INT(j), - POINTER_FROM_INT(edgeMap[i])); - BLI_ghash_insert(edgeHash2, POINTER_FROM_INT(edgeMap[i]), - POINTER_FROM_INT(j)); - } - } - else { - int numVerts = numVert_src * frac; - - if (bmd->flag & MOD_BUILD_FLAG_RANDOMIZE) { - BLI_array_randomize(vertMap, sizeof(*vertMap), - numVert_src, bmd->seed); - } - - /* get the set of all vert indices that will be in the final mesh, - * mapped to the new indices - */ - for (i = 0; i < numVerts; i++) { - BLI_ghash_insert(vertHash, POINTER_FROM_INT(vertMap[i]), POINTER_FROM_INT(i)); - } - } - - /* now we know the number of verts, edges and faces, we can create the mesh. */ - result = BKE_mesh_new_nomain_from_template( - mesh, BLI_ghash_len(vertHash), BLI_ghash_len(edgeHash), - 0, numLoops_dst, numFaces_dst); - - /* copy the vertices across */ - GHASH_ITER (gh_iter, vertHash) { - MVert source; - MVert *dest; - int oldIndex = POINTER_AS_INT(BLI_ghashIterator_getKey(&gh_iter)); - int newIndex = POINTER_AS_INT(BLI_ghashIterator_getValue(&gh_iter)); - - source = mvert_src[oldIndex]; - dest = &result->mvert[newIndex]; - - CustomData_copy_data(&mesh->vdata, &result->vdata, oldIndex, newIndex, 1); - *dest = source; - } - - /* copy the edges across, remapping indices */ - for (i = 0; i < BLI_ghash_len(edgeHash); i++) { - MEdge source; - MEdge *dest; - int oldIndex = POINTER_AS_INT(BLI_ghash_lookup(edgeHash, POINTER_FROM_INT(i))); - - source = medge_src[oldIndex]; - dest = &result->medge[i]; - - source.v1 = POINTER_AS_INT(BLI_ghash_lookup(vertHash, POINTER_FROM_INT(source.v1))); - source.v2 = POINTER_AS_INT(BLI_ghash_lookup(vertHash, POINTER_FROM_INT(source.v2))); - - CustomData_copy_data(&mesh->edata, &result->edata, oldIndex, i, 1); - *dest = source; - } - - mpoly_dst = result->mpoly; - ml_dst = result->mloop; - - /* copy the faces across, remapping indices */ - k = 0; - for (i = 0; i < numFaces_dst; i++) { - MPoly *source; - MPoly *dest; - - source = mpoly_src + faceMap[i]; - dest = mpoly_dst + i; - CustomData_copy_data(&mesh->pdata, &result->pdata, faceMap[i], i, 1); - - *dest = *source; - dest->loopstart = k; - CustomData_copy_data(&mesh->ldata, &result->ldata, source->loopstart, dest->loopstart, dest->totloop); - - ml_src = mloop_src + source->loopstart; - for (j = 0; j < source->totloop; j++, k++, ml_src++, ml_dst++) { - ml_dst->v = POINTER_AS_INT(BLI_ghash_lookup(vertHash, POINTER_FROM_INT(ml_src->v))); - ml_dst->e = POINTER_AS_INT(BLI_ghash_lookup(edgeHash2, POINTER_FROM_INT(ml_src->e))); - } - } - - BLI_ghash_free(vertHash, NULL, NULL); - BLI_ghash_free(edgeHash, NULL, NULL); - BLI_ghash_free(edgeHash2, NULL, NULL); - - MEM_freeN(vertMap); - MEM_freeN(edgeMap); - MEM_freeN(faceMap); - - if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) { - result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; - } - - /* TODO(sybren): also copy flags & tags? */ - return result; + Mesh *result; + BuildModifierData *bmd = (BuildModifierData *)md; + int i, j, k; + int numFaces_dst, numEdges_dst, numLoops_dst = 0; + int *vertMap, *edgeMap, *faceMap; + float frac; + MPoly *mpoly_dst; + MLoop *ml_dst, *ml_src /*, *mloop_dst */; + GHashIterator gh_iter; + /* maps vert indices in old mesh to indices in new mesh */ + GHash *vertHash = BLI_ghash_int_new("build ve apply gh"); + /* maps edge indices in new mesh to indices in old mesh */ + GHash *edgeHash = BLI_ghash_int_new("build ed apply gh"); + /* maps edge indices in old mesh to indices in new mesh */ + GHash *edgeHash2 = BLI_ghash_int_new("build ed apply gh"); + + const int numVert_src = mesh->totvert; + const int numEdge_src = mesh->totedge; + const int numPoly_src = mesh->totpoly; + MPoly *mpoly_src = mesh->mpoly; + MLoop *mloop_src = mesh->mloop; + MEdge *medge_src = mesh->medge; + MVert *mvert_src = mesh->mvert; + + vertMap = MEM_malloc_arrayN(numVert_src, sizeof(*vertMap), "build modifier vertMap"); + edgeMap = MEM_malloc_arrayN(numEdge_src, sizeof(*edgeMap), "build modifier edgeMap"); + faceMap = MEM_malloc_arrayN(numPoly_src, sizeof(*faceMap), "build modifier faceMap"); + + range_vn_i(vertMap, numVert_src, 0); + range_vn_i(edgeMap, numEdge_src, 0); + range_vn_i(faceMap, numPoly_src, 0); + + struct Scene *scene = DEG_get_input_scene(ctx->depsgraph); + frac = (BKE_scene_frame_get(scene) - bmd->start) / bmd->length; + CLAMP(frac, 0.0f, 1.0f); + if (bmd->flag & MOD_BUILD_FLAG_REVERSE) { + frac = 1.0f - frac; + } + + numFaces_dst = numPoly_src * frac; + numEdges_dst = numEdge_src * frac; + + /* if there's at least one face, build based on faces */ + if (numFaces_dst) { + MPoly *mpoly, *mp; + MLoop *ml, *mloop; + uintptr_t hash_num, hash_num_alt; + + if (bmd->flag & MOD_BUILD_FLAG_RANDOMIZE) { + BLI_array_randomize(faceMap, sizeof(*faceMap), numPoly_src, bmd->seed); + } + + /* get the set of all vert indices that will be in the final mesh, + * mapped to the new indices + */ + mpoly = mpoly_src; + mloop = mloop_src; + hash_num = 0; + for (i = 0; i < numFaces_dst; i++) { + mp = mpoly + faceMap[i]; + ml = mloop + mp->loopstart; + + for (j = 0; j < mp->totloop; j++, ml++) { + void **val_p; + if (!BLI_ghash_ensure_p(vertHash, POINTER_FROM_INT(ml->v), &val_p)) { + *val_p = (void *)hash_num; + hash_num++; + } + } + + numLoops_dst += mp->totloop; + } + BLI_assert(hash_num == BLI_ghash_len(vertHash)); + + /* get the set of edges that will be in the new mesh (i.e. all edges + * that have both verts in the new mesh) + */ + hash_num = 0; + hash_num_alt = 0; + for (i = 0; i < numEdge_src; i++, hash_num_alt++) { + MEdge *me = medge_src + i; + + if (BLI_ghash_haskey(vertHash, POINTER_FROM_INT(me->v1)) && + BLI_ghash_haskey(vertHash, POINTER_FROM_INT(me->v2))) { + BLI_ghash_insert(edgeHash, (void *)hash_num, (void *)hash_num_alt); + BLI_ghash_insert(edgeHash2, (void *)hash_num_alt, (void *)hash_num); + hash_num++; + } + } + BLI_assert(hash_num == BLI_ghash_len(edgeHash)); + } + else if (numEdges_dst) { + MEdge *medge, *me; + uintptr_t hash_num; + + if (bmd->flag & MOD_BUILD_FLAG_RANDOMIZE) + BLI_array_randomize(edgeMap, sizeof(*edgeMap), numEdge_src, bmd->seed); + + /* get the set of all vert indices that will be in the final mesh, + * mapped to the new indices + */ + medge = medge_src; + hash_num = 0; + BLI_assert(hash_num == BLI_ghash_len(vertHash)); + for (i = 0; i < numEdges_dst; i++) { + void **val_p; + me = medge + edgeMap[i]; + + if (!BLI_ghash_ensure_p(vertHash, POINTER_FROM_INT(me->v1), &val_p)) { + *val_p = (void *)hash_num; + hash_num++; + } + if (!BLI_ghash_ensure_p(vertHash, POINTER_FROM_INT(me->v2), &val_p)) { + *val_p = (void *)hash_num; + hash_num++; + } + } + BLI_assert(hash_num == BLI_ghash_len(vertHash)); + + /* get the set of edges that will be in the new mesh */ + for (i = 0; i < numEdges_dst; i++) { + j = BLI_ghash_len(edgeHash); + + BLI_ghash_insert(edgeHash, POINTER_FROM_INT(j), POINTER_FROM_INT(edgeMap[i])); + BLI_ghash_insert(edgeHash2, POINTER_FROM_INT(edgeMap[i]), POINTER_FROM_INT(j)); + } + } + else { + int numVerts = numVert_src * frac; + + if (bmd->flag & MOD_BUILD_FLAG_RANDOMIZE) { + BLI_array_randomize(vertMap, sizeof(*vertMap), numVert_src, bmd->seed); + } + + /* get the set of all vert indices that will be in the final mesh, + * mapped to the new indices + */ + for (i = 0; i < numVerts; i++) { + BLI_ghash_insert(vertHash, POINTER_FROM_INT(vertMap[i]), POINTER_FROM_INT(i)); + } + } + + /* now we know the number of verts, edges and faces, we can create the mesh. */ + result = BKE_mesh_new_nomain_from_template( + mesh, BLI_ghash_len(vertHash), BLI_ghash_len(edgeHash), 0, numLoops_dst, numFaces_dst); + + /* copy the vertices across */ + GHASH_ITER (gh_iter, vertHash) { + MVert source; + MVert *dest; + int oldIndex = POINTER_AS_INT(BLI_ghashIterator_getKey(&gh_iter)); + int newIndex = POINTER_AS_INT(BLI_ghashIterator_getValue(&gh_iter)); + + source = mvert_src[oldIndex]; + dest = &result->mvert[newIndex]; + + CustomData_copy_data(&mesh->vdata, &result->vdata, oldIndex, newIndex, 1); + *dest = source; + } + + /* copy the edges across, remapping indices */ + for (i = 0; i < BLI_ghash_len(edgeHash); i++) { + MEdge source; + MEdge *dest; + int oldIndex = POINTER_AS_INT(BLI_ghash_lookup(edgeHash, POINTER_FROM_INT(i))); + + source = medge_src[oldIndex]; + dest = &result->medge[i]; + + source.v1 = POINTER_AS_INT(BLI_ghash_lookup(vertHash, POINTER_FROM_INT(source.v1))); + source.v2 = POINTER_AS_INT(BLI_ghash_lookup(vertHash, POINTER_FROM_INT(source.v2))); + + CustomData_copy_data(&mesh->edata, &result->edata, oldIndex, i, 1); + *dest = source; + } + + mpoly_dst = result->mpoly; + ml_dst = result->mloop; + + /* copy the faces across, remapping indices */ + k = 0; + for (i = 0; i < numFaces_dst; i++) { + MPoly *source; + MPoly *dest; + + source = mpoly_src + faceMap[i]; + dest = mpoly_dst + i; + CustomData_copy_data(&mesh->pdata, &result->pdata, faceMap[i], i, 1); + + *dest = *source; + dest->loopstart = k; + CustomData_copy_data( + &mesh->ldata, &result->ldata, source->loopstart, dest->loopstart, dest->totloop); + + ml_src = mloop_src + source->loopstart; + for (j = 0; j < source->totloop; j++, k++, ml_src++, ml_dst++) { + ml_dst->v = POINTER_AS_INT(BLI_ghash_lookup(vertHash, POINTER_FROM_INT(ml_src->v))); + ml_dst->e = POINTER_AS_INT(BLI_ghash_lookup(edgeHash2, POINTER_FROM_INT(ml_src->e))); + } + } + + BLI_ghash_free(vertHash, NULL, NULL); + BLI_ghash_free(edgeHash, NULL, NULL); + BLI_ghash_free(edgeHash2, NULL, NULL); + + MEM_freeN(vertMap); + MEM_freeN(edgeMap); + MEM_freeN(faceMap); + + if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) { + result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + } + + /* TODO(sybren): also copy flags & tags? */ + return result; } - ModifierTypeInfo modifierType_Build = { - /* name */ "Build", - /* structName */ "BuildModifierData", - /* structSize */ sizeof(BuildModifierData), - /* type */ eModifierTypeType_Nonconstructive, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_AcceptsCVs, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ initData, - /* requiredDataMask */ NULL, - /* freeData */ NULL, - /* isDisabled */ NULL, - /* updateDepsgraph */ NULL, - /* dependsOnTime */ dependsOnTime, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ NULL, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Build", + /* structName */ "BuildModifierData", + /* structSize */ sizeof(BuildModifierData), + /* type */ eModifierTypeType_Nonconstructive, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ initData, + /* requiredDataMask */ NULL, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ dependsOnTime, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c index b8917f58234..b0a8a8c955f 100644 --- a/source/blender/modifiers/intern/MOD_cast.c +++ b/source/blender/modifiers/intern/MOD_cast.c @@ -21,7 +21,6 @@ * \ingroup modifiers */ - #include "BLI_utildefines.h" #include "BLI_math.h" @@ -43,452 +42,468 @@ static void initData(ModifierData *md) { - CastModifierData *cmd = (CastModifierData *) md; - - cmd->fac = 0.5f; - cmd->radius = 0.0f; - cmd->size = 0.0f; - cmd->flag = MOD_CAST_X | MOD_CAST_Y | MOD_CAST_Z | MOD_CAST_SIZE_FROM_RADIUS; - cmd->type = MOD_CAST_TYPE_SPHERE; - cmd->defgrp_name[0] = '\0'; - cmd->object = NULL; + CastModifierData *cmd = (CastModifierData *)md; + + cmd->fac = 0.5f; + cmd->radius = 0.0f; + cmd->size = 0.0f; + cmd->flag = MOD_CAST_X | MOD_CAST_Y | MOD_CAST_Z | MOD_CAST_SIZE_FROM_RADIUS; + cmd->type = MOD_CAST_TYPE_SPHERE; + cmd->defgrp_name[0] = '\0'; + cmd->object = NULL; } -static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams)) +static bool isDisabled(const struct Scene *UNUSED(scene), + ModifierData *md, + bool UNUSED(useRenderParams)) { - CastModifierData *cmd = (CastModifierData *) md; - short flag; + CastModifierData *cmd = (CastModifierData *)md; + short flag; - flag = cmd->flag & (MOD_CAST_X | MOD_CAST_Y | MOD_CAST_Z); + flag = cmd->flag & (MOD_CAST_X | MOD_CAST_Y | MOD_CAST_Z); - if ((cmd->fac == 0.0f) || flag == 0) return true; + if ((cmd->fac == 0.0f) || flag == 0) + return true; - return false; + return false; } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - CastModifierData *cmd = (CastModifierData *)md; + CastModifierData *cmd = (CastModifierData *)md; - /* ask for vertexgroups if we need them */ - if (cmd->defgrp_name[0] != '\0') { - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; - } + /* ask for vertexgroups if we need them */ + if (cmd->defgrp_name[0] != '\0') { + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + } } -static void foreachObjectLink( - ModifierData *md, Object *ob, - ObjectWalkFunc walk, void *userData) +static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) { - CastModifierData *cmd = (CastModifierData *) md; + CastModifierData *cmd = (CastModifierData *)md; - walk(userData, ob, &cmd->object, IDWALK_CB_NOP); + walk(userData, ob, &cmd->object, IDWALK_CB_NOP); } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { - CastModifierData *cmd = (CastModifierData *)md; - if (cmd->object != NULL) { - DEG_add_object_relation(ctx->node, cmd->object, DEG_OB_COMP_TRANSFORM, "Cast Modifier"); - DEG_add_modifier_to_transform_relation(ctx->node, "Cast Modifier"); - } + CastModifierData *cmd = (CastModifierData *)md; + if (cmd->object != NULL) { + DEG_add_object_relation(ctx->node, cmd->object, DEG_OB_COMP_TRANSFORM, "Cast Modifier"); + DEG_add_modifier_to_transform_relation(ctx->node, "Cast Modifier"); + } } -static void sphere_do( - CastModifierData *cmd, const ModifierEvalContext *UNUSED(ctx), - Object *ob, Mesh *mesh, - float (*vertexCos)[3], int numVerts) +static void sphere_do(CastModifierData *cmd, + const ModifierEvalContext *UNUSED(ctx), + Object *ob, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - MDeformVert *dvert = NULL; - - Object *ctrl_ob = NULL; - - int i, defgrp_index; - bool has_radius = false; - short flag, type; - float len = 0.0f; - float fac = cmd->fac; - float facm = 1.0f - fac; - const float fac_orig = fac; - float vec[3], center[3] = {0.0f, 0.0f, 0.0f}; - float mat[4][4], imat[4][4]; - - flag = cmd->flag; - type = cmd->type; /* projection type: sphere or cylinder */ - - if (type == MOD_CAST_TYPE_CYLINDER) - flag &= ~MOD_CAST_Z; - - ctrl_ob = cmd->object; - - /* spherify's center is {0, 0, 0} (the ob's own center in its local - * space), by default, but if the user defined a control object, - * we use its location, transformed to ob's local space */ - if (ctrl_ob) { - if (flag & MOD_CAST_USE_OB_TRANSFORM) { - invert_m4_m4(imat, ctrl_ob->obmat); - mul_m4_m4m4(mat, imat, ob->obmat); - invert_m4_m4(imat, mat); - } - - invert_m4_m4(ob->imat, ob->obmat); - mul_v3_m4v3(center, ob->imat, ctrl_ob->obmat[3]); - } - - /* now we check which options the user wants */ - - /* 1) (flag was checked in the "if (ctrl_ob)" block above) */ - /* 2) cmd->radius > 0.0f: only the vertices within this radius from - * the center of the effect should be deformed */ - if (cmd->radius > FLT_EPSILON) has_radius = 1; - - /* 3) if we were given a vertex group name, - * only those vertices should be affected */ - MOD_get_vgroup(ob, mesh, cmd->defgrp_name, &dvert, &defgrp_index); - - if (flag & MOD_CAST_SIZE_FROM_RADIUS) { - len = cmd->radius; - } - else { - len = cmd->size; - } - - if (len <= 0) { - for (i = 0; i < numVerts; i++) { - len += len_v3v3(center, vertexCos[i]); - } - len /= numVerts; - - if (len == 0.0f) len = 10.0f; - } - - for (i = 0; i < numVerts; i++) { - float tmp_co[3]; - - copy_v3_v3(tmp_co, vertexCos[i]); - if (ctrl_ob) { - if (flag & MOD_CAST_USE_OB_TRANSFORM) { - mul_m4_v3(mat, tmp_co); - } - else { - sub_v3_v3(tmp_co, center); - } - } - - copy_v3_v3(vec, tmp_co); - - if (type == MOD_CAST_TYPE_CYLINDER) - vec[2] = 0.0f; - - if (has_radius) { - if (len_v3(vec) > cmd->radius) continue; - } - - if (dvert) { - const float weight = defvert_find_weight(&dvert[i], defgrp_index); - if (weight == 0.0f) { - continue; - } - - fac = fac_orig * weight; - facm = 1.0f - fac; - } - - normalize_v3(vec); - - if (flag & MOD_CAST_X) - tmp_co[0] = fac * vec[0] * len + facm * tmp_co[0]; - if (flag & MOD_CAST_Y) - tmp_co[1] = fac * vec[1] * len + facm * tmp_co[1]; - if (flag & MOD_CAST_Z) - tmp_co[2] = fac * vec[2] * len + facm * tmp_co[2]; - - if (ctrl_ob) { - if (flag & MOD_CAST_USE_OB_TRANSFORM) { - mul_m4_v3(imat, tmp_co); - } - else { - add_v3_v3(tmp_co, center); - } - } - - copy_v3_v3(vertexCos[i], tmp_co); - } + MDeformVert *dvert = NULL; + + Object *ctrl_ob = NULL; + + int i, defgrp_index; + bool has_radius = false; + short flag, type; + float len = 0.0f; + float fac = cmd->fac; + float facm = 1.0f - fac; + const float fac_orig = fac; + float vec[3], center[3] = {0.0f, 0.0f, 0.0f}; + float mat[4][4], imat[4][4]; + + flag = cmd->flag; + type = cmd->type; /* projection type: sphere or cylinder */ + + if (type == MOD_CAST_TYPE_CYLINDER) + flag &= ~MOD_CAST_Z; + + ctrl_ob = cmd->object; + + /* spherify's center is {0, 0, 0} (the ob's own center in its local + * space), by default, but if the user defined a control object, + * we use its location, transformed to ob's local space */ + if (ctrl_ob) { + if (flag & MOD_CAST_USE_OB_TRANSFORM) { + invert_m4_m4(imat, ctrl_ob->obmat); + mul_m4_m4m4(mat, imat, ob->obmat); + invert_m4_m4(imat, mat); + } + + invert_m4_m4(ob->imat, ob->obmat); + mul_v3_m4v3(center, ob->imat, ctrl_ob->obmat[3]); + } + + /* now we check which options the user wants */ + + /* 1) (flag was checked in the "if (ctrl_ob)" block above) */ + /* 2) cmd->radius > 0.0f: only the vertices within this radius from + * the center of the effect should be deformed */ + if (cmd->radius > FLT_EPSILON) + has_radius = 1; + + /* 3) if we were given a vertex group name, + * only those vertices should be affected */ + MOD_get_vgroup(ob, mesh, cmd->defgrp_name, &dvert, &defgrp_index); + + if (flag & MOD_CAST_SIZE_FROM_RADIUS) { + len = cmd->radius; + } + else { + len = cmd->size; + } + + if (len <= 0) { + for (i = 0; i < numVerts; i++) { + len += len_v3v3(center, vertexCos[i]); + } + len /= numVerts; + + if (len == 0.0f) + len = 10.0f; + } + + for (i = 0; i < numVerts; i++) { + float tmp_co[3]; + + copy_v3_v3(tmp_co, vertexCos[i]); + if (ctrl_ob) { + if (flag & MOD_CAST_USE_OB_TRANSFORM) { + mul_m4_v3(mat, tmp_co); + } + else { + sub_v3_v3(tmp_co, center); + } + } + + copy_v3_v3(vec, tmp_co); + + if (type == MOD_CAST_TYPE_CYLINDER) + vec[2] = 0.0f; + + if (has_radius) { + if (len_v3(vec) > cmd->radius) + continue; + } + + if (dvert) { + const float weight = defvert_find_weight(&dvert[i], defgrp_index); + if (weight == 0.0f) { + continue; + } + + fac = fac_orig * weight; + facm = 1.0f - fac; + } + + normalize_v3(vec); + + if (flag & MOD_CAST_X) + tmp_co[0] = fac * vec[0] * len + facm * tmp_co[0]; + if (flag & MOD_CAST_Y) + tmp_co[1] = fac * vec[1] * len + facm * tmp_co[1]; + if (flag & MOD_CAST_Z) + tmp_co[2] = fac * vec[2] * len + facm * tmp_co[2]; + + if (ctrl_ob) { + if (flag & MOD_CAST_USE_OB_TRANSFORM) { + mul_m4_v3(imat, tmp_co); + } + else { + add_v3_v3(tmp_co, center); + } + } + + copy_v3_v3(vertexCos[i], tmp_co); + } } -static void cuboid_do( - CastModifierData *cmd, const ModifierEvalContext *UNUSED(ctx), - Object *ob, Mesh *mesh, - float (*vertexCos)[3], int numVerts) +static void cuboid_do(CastModifierData *cmd, + const ModifierEvalContext *UNUSED(ctx), + Object *ob, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - MDeformVert *dvert = NULL; - Object *ctrl_ob = NULL; - - int i, defgrp_index; - bool has_radius = false; - short flag; - float fac = cmd->fac; - float facm = 1.0f - fac; - const float fac_orig = fac; - float min[3], max[3], bb[8][3]; - float center[3] = {0.0f, 0.0f, 0.0f}; - float mat[4][4], imat[4][4]; - - flag = cmd->flag; - - ctrl_ob = cmd->object; - - /* now we check which options the user wants */ - - /* 1) (flag was checked in the "if (ctrl_ob)" block above) */ - /* 2) cmd->radius > 0.0f: only the vertices within this radius from - * the center of the effect should be deformed */ - if (cmd->radius > FLT_EPSILON) has_radius = 1; - - /* 3) if we were given a vertex group name, - * only those vertices should be affected */ - MOD_get_vgroup(ob, mesh, cmd->defgrp_name, &dvert, &defgrp_index); - - if (ctrl_ob) { - if (flag & MOD_CAST_USE_OB_TRANSFORM) { - invert_m4_m4(imat, ctrl_ob->obmat); - mul_m4_m4m4(mat, imat, ob->obmat); - invert_m4_m4(imat, mat); - } - - invert_m4_m4(ob->imat, ob->obmat); - mul_v3_m4v3(center, ob->imat, ctrl_ob->obmat[3]); - } - - if ((flag & MOD_CAST_SIZE_FROM_RADIUS) && has_radius) { - for (i = 0; i < 3; i++) { - min[i] = -cmd->radius; - max[i] = cmd->radius; - } - } - else if (!(flag & MOD_CAST_SIZE_FROM_RADIUS) && cmd->size > 0) { - for (i = 0; i < 3; i++) { - min[i] = -cmd->size; - max[i] = cmd->size; - } - } - else { - /* get bound box */ - /* We can't use the object's bound box because other modifiers - * may have changed the vertex data. */ - INIT_MINMAX(min, max); - - /* Cast's center is the ob's own center in its local space, - * by default, but if the user defined a control object, we use - * its location, transformed to ob's local space. */ - if (ctrl_ob) { - float vec[3]; - - /* let the center of the ctrl_ob be part of the bound box: */ - minmax_v3v3_v3(min, max, center); - - for (i = 0; i < numVerts; i++) { - sub_v3_v3v3(vec, vertexCos[i], center); - minmax_v3v3_v3(min, max, vec); - } - } - else { - for (i = 0; i < numVerts; i++) { - minmax_v3v3_v3(min, max, vertexCos[i]); - } - } - - /* we want a symmetric bound box around the origin */ - if (fabsf(min[0]) > fabsf(max[0])) max[0] = fabsf(min[0]); - if (fabsf(min[1]) > fabsf(max[1])) max[1] = fabsf(min[1]); - if (fabsf(min[2]) > fabsf(max[2])) max[2] = fabsf(min[2]); - min[0] = -max[0]; - min[1] = -max[1]; - min[2] = -max[2]; - } - - /* building our custom bounding box */ - bb[0][0] = bb[2][0] = bb[4][0] = bb[6][0] = min[0]; - bb[1][0] = bb[3][0] = bb[5][0] = bb[7][0] = max[0]; - bb[0][1] = bb[1][1] = bb[4][1] = bb[5][1] = min[1]; - bb[2][1] = bb[3][1] = bb[6][1] = bb[7][1] = max[1]; - bb[0][2] = bb[1][2] = bb[2][2] = bb[3][2] = min[2]; - bb[4][2] = bb[5][2] = bb[6][2] = bb[7][2] = max[2]; - - /* ready to apply the effect, one vertex at a time */ - for (i = 0; i < numVerts; i++) { - int octant, coord; - float d[3], dmax, apex[3], fbb; - float tmp_co[3]; - - copy_v3_v3(tmp_co, vertexCos[i]); - if (ctrl_ob) { - if (flag & MOD_CAST_USE_OB_TRANSFORM) { - mul_m4_v3(mat, tmp_co); - } - else { - sub_v3_v3(tmp_co, center); - } - } - - if (has_radius) { - if (fabsf(tmp_co[0]) > cmd->radius || - fabsf(tmp_co[1]) > cmd->radius || - fabsf(tmp_co[2]) > cmd->radius) - { - continue; - } - } - - if (dvert) { - const float weight = defvert_find_weight(&dvert[i], defgrp_index); - if (weight == 0.0f) { - continue; - } - - fac = fac_orig * weight; - facm = 1.0f - fac; - } - - /* The algo used to project the vertices to their - * bounding box (bb) is pretty simple: - * for each vertex v: - * 1) find in which octant v is in; - * 2) find which outer "wall" of that octant is closer to v; - * 3) calculate factor (var fbb) to project v to that wall; - * 4) project. */ - - /* find in which octant this vertex is in */ - octant = 0; - if (tmp_co[0] > 0.0f) octant += 1; - if (tmp_co[1] > 0.0f) octant += 2; - if (tmp_co[2] > 0.0f) octant += 4; - - /* apex is the bb's vertex at the chosen octant */ - copy_v3_v3(apex, bb[octant]); - - /* find which bb plane is closest to this vertex ... */ - d[0] = tmp_co[0] / apex[0]; - d[1] = tmp_co[1] / apex[1]; - d[2] = tmp_co[2] / apex[2]; - - /* ... (the closest has the higher (closer to 1) d value) */ - dmax = d[0]; - coord = 0; - if (d[1] > dmax) { - dmax = d[1]; - coord = 1; - } - if (d[2] > dmax) { - /* dmax = d[2]; */ /* commented, we don't need it */ - coord = 2; - } - - /* ok, now we know which coordinate of the vertex to use */ - - if (fabsf(tmp_co[coord]) < FLT_EPSILON) /* avoid division by zero */ - continue; - - /* finally, this is the factor we wanted, to project the vertex - * to its bounding box (bb) */ - fbb = apex[coord] / tmp_co[coord]; - - /* calculate the new vertex position */ - if (flag & MOD_CAST_X) - tmp_co[0] = facm * tmp_co[0] + fac * tmp_co[0] * fbb; - if (flag & MOD_CAST_Y) - tmp_co[1] = facm * tmp_co[1] + fac * tmp_co[1] * fbb; - if (flag & MOD_CAST_Z) - tmp_co[2] = facm * tmp_co[2] + fac * tmp_co[2] * fbb; - - if (ctrl_ob) { - if (flag & MOD_CAST_USE_OB_TRANSFORM) { - mul_m4_v3(imat, tmp_co); - } - else { - add_v3_v3(tmp_co, center); - } - } - - copy_v3_v3(vertexCos[i], tmp_co); - } + MDeformVert *dvert = NULL; + Object *ctrl_ob = NULL; + + int i, defgrp_index; + bool has_radius = false; + short flag; + float fac = cmd->fac; + float facm = 1.0f - fac; + const float fac_orig = fac; + float min[3], max[3], bb[8][3]; + float center[3] = {0.0f, 0.0f, 0.0f}; + float mat[4][4], imat[4][4]; + + flag = cmd->flag; + + ctrl_ob = cmd->object; + + /* now we check which options the user wants */ + + /* 1) (flag was checked in the "if (ctrl_ob)" block above) */ + /* 2) cmd->radius > 0.0f: only the vertices within this radius from + * the center of the effect should be deformed */ + if (cmd->radius > FLT_EPSILON) + has_radius = 1; + + /* 3) if we were given a vertex group name, + * only those vertices should be affected */ + MOD_get_vgroup(ob, mesh, cmd->defgrp_name, &dvert, &defgrp_index); + + if (ctrl_ob) { + if (flag & MOD_CAST_USE_OB_TRANSFORM) { + invert_m4_m4(imat, ctrl_ob->obmat); + mul_m4_m4m4(mat, imat, ob->obmat); + invert_m4_m4(imat, mat); + } + + invert_m4_m4(ob->imat, ob->obmat); + mul_v3_m4v3(center, ob->imat, ctrl_ob->obmat[3]); + } + + if ((flag & MOD_CAST_SIZE_FROM_RADIUS) && has_radius) { + for (i = 0; i < 3; i++) { + min[i] = -cmd->radius; + max[i] = cmd->radius; + } + } + else if (!(flag & MOD_CAST_SIZE_FROM_RADIUS) && cmd->size > 0) { + for (i = 0; i < 3; i++) { + min[i] = -cmd->size; + max[i] = cmd->size; + } + } + else { + /* get bound box */ + /* We can't use the object's bound box because other modifiers + * may have changed the vertex data. */ + INIT_MINMAX(min, max); + + /* Cast's center is the ob's own center in its local space, + * by default, but if the user defined a control object, we use + * its location, transformed to ob's local space. */ + if (ctrl_ob) { + float vec[3]; + + /* let the center of the ctrl_ob be part of the bound box: */ + minmax_v3v3_v3(min, max, center); + + for (i = 0; i < numVerts; i++) { + sub_v3_v3v3(vec, vertexCos[i], center); + minmax_v3v3_v3(min, max, vec); + } + } + else { + for (i = 0; i < numVerts; i++) { + minmax_v3v3_v3(min, max, vertexCos[i]); + } + } + + /* we want a symmetric bound box around the origin */ + if (fabsf(min[0]) > fabsf(max[0])) + max[0] = fabsf(min[0]); + if (fabsf(min[1]) > fabsf(max[1])) + max[1] = fabsf(min[1]); + if (fabsf(min[2]) > fabsf(max[2])) + max[2] = fabsf(min[2]); + min[0] = -max[0]; + min[1] = -max[1]; + min[2] = -max[2]; + } + + /* building our custom bounding box */ + bb[0][0] = bb[2][0] = bb[4][0] = bb[6][0] = min[0]; + bb[1][0] = bb[3][0] = bb[5][0] = bb[7][0] = max[0]; + bb[0][1] = bb[1][1] = bb[4][1] = bb[5][1] = min[1]; + bb[2][1] = bb[3][1] = bb[6][1] = bb[7][1] = max[1]; + bb[0][2] = bb[1][2] = bb[2][2] = bb[3][2] = min[2]; + bb[4][2] = bb[5][2] = bb[6][2] = bb[7][2] = max[2]; + + /* ready to apply the effect, one vertex at a time */ + for (i = 0; i < numVerts; i++) { + int octant, coord; + float d[3], dmax, apex[3], fbb; + float tmp_co[3]; + + copy_v3_v3(tmp_co, vertexCos[i]); + if (ctrl_ob) { + if (flag & MOD_CAST_USE_OB_TRANSFORM) { + mul_m4_v3(mat, tmp_co); + } + else { + sub_v3_v3(tmp_co, center); + } + } + + if (has_radius) { + if (fabsf(tmp_co[0]) > cmd->radius || fabsf(tmp_co[1]) > cmd->radius || + fabsf(tmp_co[2]) > cmd->radius) { + continue; + } + } + + if (dvert) { + const float weight = defvert_find_weight(&dvert[i], defgrp_index); + if (weight == 0.0f) { + continue; + } + + fac = fac_orig * weight; + facm = 1.0f - fac; + } + + /* The algo used to project the vertices to their + * bounding box (bb) is pretty simple: + * for each vertex v: + * 1) find in which octant v is in; + * 2) find which outer "wall" of that octant is closer to v; + * 3) calculate factor (var fbb) to project v to that wall; + * 4) project. */ + + /* find in which octant this vertex is in */ + octant = 0; + if (tmp_co[0] > 0.0f) + octant += 1; + if (tmp_co[1] > 0.0f) + octant += 2; + if (tmp_co[2] > 0.0f) + octant += 4; + + /* apex is the bb's vertex at the chosen octant */ + copy_v3_v3(apex, bb[octant]); + + /* find which bb plane is closest to this vertex ... */ + d[0] = tmp_co[0] / apex[0]; + d[1] = tmp_co[1] / apex[1]; + d[2] = tmp_co[2] / apex[2]; + + /* ... (the closest has the higher (closer to 1) d value) */ + dmax = d[0]; + coord = 0; + if (d[1] > dmax) { + dmax = d[1]; + coord = 1; + } + if (d[2] > dmax) { + /* dmax = d[2]; */ /* commented, we don't need it */ + coord = 2; + } + + /* ok, now we know which coordinate of the vertex to use */ + + if (fabsf(tmp_co[coord]) < FLT_EPSILON) /* avoid division by zero */ + continue; + + /* finally, this is the factor we wanted, to project the vertex + * to its bounding box (bb) */ + fbb = apex[coord] / tmp_co[coord]; + + /* calculate the new vertex position */ + if (flag & MOD_CAST_X) + tmp_co[0] = facm * tmp_co[0] + fac * tmp_co[0] * fbb; + if (flag & MOD_CAST_Y) + tmp_co[1] = facm * tmp_co[1] + fac * tmp_co[1] * fbb; + if (flag & MOD_CAST_Z) + tmp_co[2] = facm * tmp_co[2] + fac * tmp_co[2] * fbb; + + if (ctrl_ob) { + if (flag & MOD_CAST_USE_OB_TRANSFORM) { + mul_m4_v3(imat, tmp_co); + } + else { + add_v3_v3(tmp_co, center); + } + } + + copy_v3_v3(vertexCos[i], tmp_co); + } } -static void deformVerts( - ModifierData *md, const ModifierEvalContext *ctx, - Mesh *mesh, - float (*vertexCos)[3], - int numVerts) +static void deformVerts(ModifierData *md, + const ModifierEvalContext *ctx, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - CastModifierData *cmd = (CastModifierData *)md; - Mesh *mesh_src = NULL; - - if (ctx->object->type == OB_MESH && cmd->defgrp_name[0] != '\0') { - /* mesh_src is only needed for vgroups. */ - mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); - } - - if (cmd->type == MOD_CAST_TYPE_CUBOID) { - cuboid_do(cmd, ctx, ctx->object, mesh_src, vertexCos, numVerts); - } - else { /* MOD_CAST_TYPE_SPHERE or MOD_CAST_TYPE_CYLINDER */ - sphere_do(cmd, ctx, ctx->object, mesh_src, vertexCos, numVerts); - } - - if (!ELEM(mesh_src, NULL, mesh)) { - BKE_id_free(NULL, mesh_src); - } + CastModifierData *cmd = (CastModifierData *)md; + Mesh *mesh_src = NULL; + + if (ctx->object->type == OB_MESH && cmd->defgrp_name[0] != '\0') { + /* mesh_src is only needed for vgroups. */ + mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); + } + + if (cmd->type == MOD_CAST_TYPE_CUBOID) { + cuboid_do(cmd, ctx, ctx->object, mesh_src, vertexCos, numVerts); + } + else { /* MOD_CAST_TYPE_SPHERE or MOD_CAST_TYPE_CYLINDER */ + sphere_do(cmd, ctx, ctx->object, mesh_src, vertexCos, numVerts); + } + + if (!ELEM(mesh_src, NULL, mesh)) { + BKE_id_free(NULL, mesh_src); + } } -static void deformVertsEM( - ModifierData *md, const ModifierEvalContext *ctx, - struct BMEditMesh *editData, - Mesh *mesh, float (*vertexCos)[3], int numVerts) +static void deformVertsEM(ModifierData *md, + const ModifierEvalContext *ctx, + struct BMEditMesh *editData, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - CastModifierData *cmd = (CastModifierData *)md; - Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false); - - BLI_assert(mesh_src->totvert == numVerts); - - if (cmd->type == MOD_CAST_TYPE_CUBOID) { - cuboid_do(cmd, ctx, ctx->object, mesh_src, vertexCos, numVerts); - } - else { /* MOD_CAST_TYPE_SPHERE or MOD_CAST_TYPE_CYLINDER */ - sphere_do(cmd, ctx, ctx->object, mesh_src, vertexCos, numVerts); - } - - if (mesh_src != mesh) { - BKE_id_free(NULL, mesh_src); - } + CastModifierData *cmd = (CastModifierData *)md; + Mesh *mesh_src = MOD_deform_mesh_eval_get( + ctx->object, editData, mesh, NULL, numVerts, false, false); + + BLI_assert(mesh_src->totvert == numVerts); + + if (cmd->type == MOD_CAST_TYPE_CUBOID) { + cuboid_do(cmd, ctx, ctx->object, mesh_src, vertexCos, numVerts); + } + else { /* MOD_CAST_TYPE_SPHERE or MOD_CAST_TYPE_CYLINDER */ + sphere_do(cmd, ctx, ctx->object, mesh_src, vertexCos, numVerts); + } + + if (mesh_src != mesh) { + BKE_id_free(NULL, mesh_src); + } } - ModifierTypeInfo modifierType_Cast = { - /* name */ "Cast", - /* structName */ "CastModifierData", - /* structSize */ sizeof(CastModifierData), - /* type */ eModifierTypeType_OnlyDeform, - /* flags */ eModifierTypeFlag_AcceptsCVs | - eModifierTypeFlag_AcceptsLattice | - eModifierTypeFlag_SupportsEditmode, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ deformVerts, - /* deformMatrices */ NULL, - /* deformVertsEM */ deformVertsEM, - /* deformMatricesEM */ NULL, - /* applyModifier */ NULL, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ NULL, - /* isDisabled */ isDisabled, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ foreachObjectLink, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Cast", + /* structName */ "CastModifierData", + /* structSize */ sizeof(CastModifierData), + /* type */ eModifierTypeType_OnlyDeform, + /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice | + eModifierTypeFlag_SupportsEditmode, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ deformVerts, + /* deformMatrices */ NULL, + /* deformVertsEM */ deformVertsEM, + /* deformMatricesEM */ NULL, + /* applyModifier */ NULL, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ NULL, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c index 8bf9d50cda7..9eeef583e44 100644 --- a/source/blender/modifiers/intern/MOD_cloth.c +++ b/source/blender/modifiers/intern/MOD_cloth.c @@ -52,210 +52,217 @@ static void initData(ModifierData *md) { - ClothModifierData *clmd = (ClothModifierData *) md; + ClothModifierData *clmd = (ClothModifierData *)md; - clmd->sim_parms = MEM_callocN(sizeof(ClothSimSettings), "cloth sim parms"); - clmd->coll_parms = MEM_callocN(sizeof(ClothCollSettings), "cloth coll parms"); - clmd->point_cache = BKE_ptcache_add(&clmd->ptcaches); + clmd->sim_parms = MEM_callocN(sizeof(ClothSimSettings), "cloth sim parms"); + clmd->coll_parms = MEM_callocN(sizeof(ClothCollSettings), "cloth coll parms"); + clmd->point_cache = BKE_ptcache_add(&clmd->ptcaches); - /* check for alloc failing */ - if (!clmd->sim_parms || !clmd->coll_parms || !clmd->point_cache) - return; + /* check for alloc failing */ + if (!clmd->sim_parms || !clmd->coll_parms || !clmd->point_cache) + return; - cloth_init(clmd); + cloth_init(clmd); } -static void deformVerts( - ModifierData *md, const ModifierEvalContext *ctx, - Mesh *mesh, float (*vertexCos)[3], - int numVerts) +static void deformVerts(ModifierData *md, + const ModifierEvalContext *ctx, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - Mesh *mesh_src; - ClothModifierData *clmd = (ClothModifierData *) md; - Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); - - /* check for alloc failing */ - if (!clmd->sim_parms || !clmd->coll_parms) { - initData(md); - - if (!clmd->sim_parms || !clmd->coll_parms) - return; - } - - if (mesh == NULL) { - mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, NULL, NULL, numVerts, false, false); - } - else { - /* Not possible to use get_mesh() in this case as we'll modify its vertices - * and get_mesh() would return 'mesh' directly. */ - BKE_id_copy_ex(NULL, (ID *)mesh, (ID **)&mesh_src, LIB_ID_COPY_LOCALIZE); - } - - /* TODO(sergey): For now it actually duplicates logic from DerivedMesh.c - * and needs some more generic solution. But starting experimenting with - * this so close to the release is not that nice.. - * - * Also hopefully new cloth system will arrive soon.. - */ - if (mesh == NULL && clmd->sim_parms->shapekey_rest) { - KeyBlock *kb = BKE_keyblock_from_key(BKE_key_from_object(ctx->object), - clmd->sim_parms->shapekey_rest); - if (kb && kb->data != NULL) { - float (*layerorco)[3]; - if (!(layerorco = CustomData_get_layer(&mesh_src->vdata, CD_CLOTH_ORCO))) { - layerorco = CustomData_add_layer(&mesh_src->vdata, CD_CLOTH_ORCO, CD_CALLOC, NULL, mesh_src->totvert); - } - - memcpy(layerorco, kb->data, sizeof(float) * 3 * numVerts); - } - } - - BKE_mesh_apply_vert_coords(mesh_src, vertexCos); - - clothModifier_do(clmd, ctx->depsgraph, scene, ctx->object, mesh_src, vertexCos); - - BKE_id_free(NULL, mesh_src); + Mesh *mesh_src; + ClothModifierData *clmd = (ClothModifierData *)md; + Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); + + /* check for alloc failing */ + if (!clmd->sim_parms || !clmd->coll_parms) { + initData(md); + + if (!clmd->sim_parms || !clmd->coll_parms) + return; + } + + if (mesh == NULL) { + mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, NULL, NULL, numVerts, false, false); + } + else { + /* Not possible to use get_mesh() in this case as we'll modify its vertices + * and get_mesh() would return 'mesh' directly. */ + BKE_id_copy_ex(NULL, (ID *)mesh, (ID **)&mesh_src, LIB_ID_COPY_LOCALIZE); + } + + /* TODO(sergey): For now it actually duplicates logic from DerivedMesh.c + * and needs some more generic solution. But starting experimenting with + * this so close to the release is not that nice.. + * + * Also hopefully new cloth system will arrive soon.. + */ + if (mesh == NULL && clmd->sim_parms->shapekey_rest) { + KeyBlock *kb = BKE_keyblock_from_key(BKE_key_from_object(ctx->object), + clmd->sim_parms->shapekey_rest); + if (kb && kb->data != NULL) { + float(*layerorco)[3]; + if (!(layerorco = CustomData_get_layer(&mesh_src->vdata, CD_CLOTH_ORCO))) { + layerorco = CustomData_add_layer( + &mesh_src->vdata, CD_CLOTH_ORCO, CD_CALLOC, NULL, mesh_src->totvert); + } + + memcpy(layerorco, kb->data, sizeof(float) * 3 * numVerts); + } + } + + BKE_mesh_apply_vert_coords(mesh_src, vertexCos); + + clothModifier_do(clmd, ctx->depsgraph, scene, ctx->object, mesh_src, vertexCos); + + BKE_id_free(NULL, mesh_src); } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { - ClothModifierData *clmd = (ClothModifierData *)md; - if (clmd != NULL) { - DEG_add_collision_relations(ctx->node, ctx->object, clmd->coll_parms->group, eModifierType_Collision, NULL, "Cloth Collision"); - DEG_add_forcefield_relations(ctx->node, ctx->object, clmd->sim_parms->effector_weights, true, 0, "Cloth Field"); - } - DEG_add_modifier_to_transform_relation(ctx->node, "Cloth Modifier"); + ClothModifierData *clmd = (ClothModifierData *)md; + if (clmd != NULL) { + DEG_add_collision_relations(ctx->node, + ctx->object, + clmd->coll_parms->group, + eModifierType_Collision, + NULL, + "Cloth Collision"); + DEG_add_forcefield_relations( + ctx->node, ctx->object, clmd->sim_parms->effector_weights, true, 0, "Cloth Field"); + } + DEG_add_modifier_to_transform_relation(ctx->node, "Cloth Modifier"); } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - ClothModifierData *clmd = (ClothModifierData *)md; + ClothModifierData *clmd = (ClothModifierData *)md; - if (cloth_uses_vgroup(clmd)) { - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; - } + if (cloth_uses_vgroup(clmd)) { + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + } - if (clmd->sim_parms->shapekey_rest != 0) { - r_cddata_masks->vmask |= CD_MASK_CLOTH_ORCO; - } + if (clmd->sim_parms->shapekey_rest != 0) { + r_cddata_masks->vmask |= CD_MASK_CLOTH_ORCO; + } } static void copyData(const ModifierData *md, ModifierData *target, const int flag) { - const ClothModifierData *clmd = (const ClothModifierData *) md; - ClothModifierData *tclmd = (ClothModifierData *) target; - - if (tclmd->sim_parms) { - if (tclmd->sim_parms->effector_weights) - MEM_freeN(tclmd->sim_parms->effector_weights); - MEM_freeN(tclmd->sim_parms); - } - - if (tclmd->coll_parms) - MEM_freeN(tclmd->coll_parms); - - BKE_ptcache_free_list(&tclmd->ptcaches); - if (flag & LIB_ID_CREATE_NO_MAIN) { - /* Share the cache with the original object's modifier. */ - tclmd->modifier.flag |= eModifierFlag_SharedCaches; - tclmd->ptcaches = clmd->ptcaches; - tclmd->point_cache = clmd->point_cache; - } - else { - tclmd->point_cache = BKE_ptcache_add(&tclmd->ptcaches); - tclmd->point_cache->step = 1; - } - - tclmd->sim_parms = MEM_dupallocN(clmd->sim_parms); - if (clmd->sim_parms->effector_weights) - tclmd->sim_parms->effector_weights = MEM_dupallocN(clmd->sim_parms->effector_weights); - tclmd->coll_parms = MEM_dupallocN(clmd->coll_parms); - tclmd->clothObject = NULL; - tclmd->hairdata = NULL; - tclmd->solver_result = NULL; + const ClothModifierData *clmd = (const ClothModifierData *)md; + ClothModifierData *tclmd = (ClothModifierData *)target; + + if (tclmd->sim_parms) { + if (tclmd->sim_parms->effector_weights) + MEM_freeN(tclmd->sim_parms->effector_weights); + MEM_freeN(tclmd->sim_parms); + } + + if (tclmd->coll_parms) + MEM_freeN(tclmd->coll_parms); + + BKE_ptcache_free_list(&tclmd->ptcaches); + if (flag & LIB_ID_CREATE_NO_MAIN) { + /* Share the cache with the original object's modifier. */ + tclmd->modifier.flag |= eModifierFlag_SharedCaches; + tclmd->ptcaches = clmd->ptcaches; + tclmd->point_cache = clmd->point_cache; + } + else { + tclmd->point_cache = BKE_ptcache_add(&tclmd->ptcaches); + tclmd->point_cache->step = 1; + } + + tclmd->sim_parms = MEM_dupallocN(clmd->sim_parms); + if (clmd->sim_parms->effector_weights) + tclmd->sim_parms->effector_weights = MEM_dupallocN(clmd->sim_parms->effector_weights); + tclmd->coll_parms = MEM_dupallocN(clmd->coll_parms); + tclmd->clothObject = NULL; + tclmd->hairdata = NULL; + tclmd->solver_result = NULL; } static bool dependsOnTime(ModifierData *UNUSED(md)) { - return true; + return true; } static void freeData(ModifierData *md) { - ClothModifierData *clmd = (ClothModifierData *) md; - - if (clmd) { - if (G.debug & G_DEBUG_SIMDATA) { - printf("clothModifier_freeData\n"); - } - - cloth_free_modifier_extern(clmd); - - if (clmd->sim_parms) { - if (clmd->sim_parms->effector_weights) - MEM_freeN(clmd->sim_parms->effector_weights); - MEM_freeN(clmd->sim_parms); - } - if (clmd->coll_parms) - MEM_freeN(clmd->coll_parms); - - if (md->flag & eModifierFlag_SharedCaches) { - BLI_listbase_clear(&clmd->ptcaches); - } - else { - BKE_ptcache_free_list(&clmd->ptcaches); - } - clmd->point_cache = NULL; - - if (clmd->hairdata) - MEM_freeN(clmd->hairdata); - - if (clmd->solver_result) - MEM_freeN(clmd->solver_result); - } + ClothModifierData *clmd = (ClothModifierData *)md; + + if (clmd) { + if (G.debug & G_DEBUG_SIMDATA) { + printf("clothModifier_freeData\n"); + } + + cloth_free_modifier_extern(clmd); + + if (clmd->sim_parms) { + if (clmd->sim_parms->effector_weights) + MEM_freeN(clmd->sim_parms->effector_weights); + MEM_freeN(clmd->sim_parms); + } + if (clmd->coll_parms) + MEM_freeN(clmd->coll_parms); + + if (md->flag & eModifierFlag_SharedCaches) { + BLI_listbase_clear(&clmd->ptcaches); + } + else { + BKE_ptcache_free_list(&clmd->ptcaches); + } + clmd->point_cache = NULL; + + if (clmd->hairdata) + MEM_freeN(clmd->hairdata); + + if (clmd->solver_result) + MEM_freeN(clmd->solver_result); + } } -static void foreachIDLink( - ModifierData *md, Object *ob, - IDWalkFunc walk, void *userData) +static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData) { - ClothModifierData *clmd = (ClothModifierData *) md; + ClothModifierData *clmd = (ClothModifierData *)md; - if (clmd->coll_parms) { - walk(userData, ob, (ID **)&clmd->coll_parms->group, IDWALK_CB_NOP); - } + if (clmd->coll_parms) { + walk(userData, ob, (ID **)&clmd->coll_parms->group, IDWALK_CB_NOP); + } - if (clmd->sim_parms && clmd->sim_parms->effector_weights) { - walk(userData, ob, (ID **)&clmd->sim_parms->effector_weights->group, IDWALK_CB_NOP); - } + if (clmd->sim_parms && clmd->sim_parms->effector_weights) { + walk(userData, ob, (ID **)&clmd->sim_parms->effector_weights->group, IDWALK_CB_NOP); + } } ModifierTypeInfo modifierType_Cloth = { - /* name */ "Cloth", - /* structName */ "ClothModifierData", - /* structSize */ sizeof(ClothModifierData), - /* type */ eModifierTypeType_OnlyDeform, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_UsesPointCache | - eModifierTypeFlag_Single, - - /* copyData */ copyData, - - /* deformVerts */ deformVerts, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ NULL, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ freeData, - /* isDisabled */ NULL, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ dependsOnTime, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ NULL, - /* foreachIDLink */ foreachIDLink, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Cloth", + /* structName */ "ClothModifierData", + /* structSize */ sizeof(ClothModifierData), + /* type */ eModifierTypeType_OnlyDeform, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_UsesPointCache | + eModifierTypeFlag_Single, + + /* copyData */ copyData, + + /* deformVerts */ deformVerts, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ NULL, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ freeData, + /* isDisabled */ NULL, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ dependsOnTime, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ foreachIDLink, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c index 2e56da6f100..59f4a1a93b6 100644 --- a/source/blender/modifiers/intern/MOD_collision.c +++ b/source/blender/modifiers/intern/MOD_collision.c @@ -47,229 +47,223 @@ static void initData(ModifierData *md) { - CollisionModifierData *collmd = (CollisionModifierData *) md; - - collmd->x = NULL; - collmd->xnew = NULL; - collmd->current_x = NULL; - collmd->current_xnew = NULL; - collmd->current_v = NULL; - collmd->time_x = collmd->time_xnew = -1000; - collmd->mvert_num = 0; - collmd->tri_num = 0; - collmd->is_static = false; - collmd->bvhtree = NULL; + CollisionModifierData *collmd = (CollisionModifierData *)md; + + collmd->x = NULL; + collmd->xnew = NULL; + collmd->current_x = NULL; + collmd->current_xnew = NULL; + collmd->current_v = NULL; + collmd->time_x = collmd->time_xnew = -1000; + collmd->mvert_num = 0; + collmd->tri_num = 0; + collmd->is_static = false; + collmd->bvhtree = NULL; } static void freeData(ModifierData *md) { - CollisionModifierData *collmd = (CollisionModifierData *) md; - - if (collmd) { /* Seriously? */ - if (collmd->bvhtree) { - BLI_bvhtree_free(collmd->bvhtree); - collmd->bvhtree = NULL; - } - - MEM_SAFE_FREE(collmd->x); - MEM_SAFE_FREE(collmd->xnew); - MEM_SAFE_FREE(collmd->current_x); - MEM_SAFE_FREE(collmd->current_xnew); - MEM_SAFE_FREE(collmd->current_v); - - MEM_SAFE_FREE(collmd->tri); - - collmd->time_x = collmd->time_xnew = -1000; - collmd->mvert_num = 0; - collmd->tri_num = 0; - collmd->is_static = false; - } + CollisionModifierData *collmd = (CollisionModifierData *)md; + + if (collmd) { /* Seriously? */ + if (collmd->bvhtree) { + BLI_bvhtree_free(collmd->bvhtree); + collmd->bvhtree = NULL; + } + + MEM_SAFE_FREE(collmd->x); + MEM_SAFE_FREE(collmd->xnew); + MEM_SAFE_FREE(collmd->current_x); + MEM_SAFE_FREE(collmd->current_xnew); + MEM_SAFE_FREE(collmd->current_v); + + MEM_SAFE_FREE(collmd->tri); + + collmd->time_x = collmd->time_xnew = -1000; + collmd->mvert_num = 0; + collmd->tri_num = 0; + collmd->is_static = false; + } } static bool dependsOnTime(ModifierData *UNUSED(md)) { - return true; + return true; } -static void deformVerts( - ModifierData *md, const ModifierEvalContext *ctx, - Mesh *mesh, - float (*vertexCos)[3], - int numVerts) +static void deformVerts(ModifierData *md, + const ModifierEvalContext *ctx, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - CollisionModifierData *collmd = (CollisionModifierData *) md; - Mesh *mesh_src; - MVert *tempVert = NULL; - Object *ob = ctx->object; - - if (mesh == NULL) { - mesh_src = MOD_deform_mesh_eval_get(ob, NULL, NULL, NULL, numVerts, false, false); - } - else { - /* Not possible to use get_mesh() in this case as we'll modify its vertices - * and get_mesh() would return 'mesh' directly. */ - BKE_id_copy_ex(NULL, (ID *)mesh, (ID **)&mesh_src, LIB_ID_COPY_LOCALIZE); - } - - if (!ob->pd) { - printf("CollisionModifier deformVerts: Should not happen!\n"); - return; - } - - if (mesh_src) { - float current_time = 0; - unsigned int mvert_num = 0; - - BKE_mesh_apply_vert_coords(mesh_src, vertexCos); - BKE_mesh_calc_normals(mesh_src); - - current_time = DEG_get_ctime(ctx->depsgraph); - - if (G.debug & G_DEBUG_SIMDATA) { - printf("current_time %f, collmd->time_xnew %f\n", current_time, collmd->time_xnew); - } - - mvert_num = mesh_src->totvert; - - if (current_time < collmd->time_xnew) { - freeData((ModifierData *)collmd); - } - else if (current_time == collmd->time_xnew) { - if (mvert_num != collmd->mvert_num) { - freeData((ModifierData *)collmd); - } - } - - /* check if mesh has changed */ - if (collmd->x && (mvert_num != collmd->mvert_num)) - freeData((ModifierData *)collmd); - - if (collmd->time_xnew == -1000) { /* first time */ - - collmd->x = MEM_dupallocN(mesh_src->mvert); /* frame start position */ - - for (uint i = 0; i < mvert_num; i++) { - /* we save global positions */ - mul_m4_v3(ob->obmat, collmd->x[i].co); - } - - collmd->xnew = MEM_dupallocN(collmd->x); // frame end position - collmd->current_x = MEM_dupallocN(collmd->x); // inter-frame - collmd->current_xnew = MEM_dupallocN(collmd->x); // inter-frame - collmd->current_v = MEM_dupallocN(collmd->x); // inter-frame - - collmd->mvert_num = mvert_num; - - { - const MLoop *mloop = mesh_src->mloop; - const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(mesh_src); - collmd->tri_num = BKE_mesh_runtime_looptri_len(mesh_src); - MVertTri *tri = MEM_mallocN(sizeof(*tri) * collmd->tri_num, __func__); - BKE_mesh_runtime_verttri_from_looptri(tri, mloop, looptri, collmd->tri_num); - collmd->tri = tri; - } - - /* create bounding box hierarchy */ - collmd->bvhtree = bvhtree_build_from_mvert( - collmd->x, - collmd->tri, collmd->tri_num, - ob->pd->pdef_sboft); - - collmd->time_x = collmd->time_xnew = current_time; - collmd->is_static = true; - } - else if (mvert_num == collmd->mvert_num) { - /* put positions to old positions */ - tempVert = collmd->x; - collmd->x = collmd->xnew; - collmd->xnew = tempVert; - collmd->time_x = collmd->time_xnew; - - memcpy(collmd->xnew, mesh_src->mvert, mvert_num * sizeof(MVert)); - - bool is_static = true; - - for (uint i = 0; i < mvert_num; i++) { - /* we save global positions */ - mul_m4_v3(ob->obmat, collmd->xnew[i].co); - - /* detect motion */ - is_static = is_static && equals_v3v3(collmd->x[i].co, collmd->xnew[i].co); - } - - memcpy(collmd->current_xnew, collmd->x, mvert_num * sizeof(MVert)); - memcpy(collmd->current_x, collmd->x, mvert_num * sizeof(MVert)); - - /* check if GUI setting has changed for bvh */ - if (collmd->bvhtree) { - if (ob->pd->pdef_sboft != BLI_bvhtree_get_epsilon(collmd->bvhtree)) { - BLI_bvhtree_free(collmd->bvhtree); - collmd->bvhtree = bvhtree_build_from_mvert( - collmd->current_x, - collmd->tri, collmd->tri_num, - ob->pd->pdef_sboft); - } - } - - /* happens on file load (ONLY when i decomment changes in readfile.c) */ - if (!collmd->bvhtree) { - collmd->bvhtree = bvhtree_build_from_mvert( - collmd->current_x, - collmd->tri, collmd->tri_num, - ob->pd->pdef_sboft); - } - else if (!collmd->is_static || !is_static) { - /* recalc static bounding boxes */ - bvhtree_update_from_mvert( - collmd->bvhtree, - collmd->current_x, collmd->current_xnew, - collmd->tri, collmd->tri_num, - true); - } - - collmd->is_static = is_static; - collmd->time_xnew = current_time; - } - else if (mvert_num != collmd->mvert_num) { - freeData((ModifierData *)collmd); - } - } - - if (mesh_src != mesh) { - BKE_id_free(NULL, mesh_src); - } + CollisionModifierData *collmd = (CollisionModifierData *)md; + Mesh *mesh_src; + MVert *tempVert = NULL; + Object *ob = ctx->object; + + if (mesh == NULL) { + mesh_src = MOD_deform_mesh_eval_get(ob, NULL, NULL, NULL, numVerts, false, false); + } + else { + /* Not possible to use get_mesh() in this case as we'll modify its vertices + * and get_mesh() would return 'mesh' directly. */ + BKE_id_copy_ex(NULL, (ID *)mesh, (ID **)&mesh_src, LIB_ID_COPY_LOCALIZE); + } + + if (!ob->pd) { + printf("CollisionModifier deformVerts: Should not happen!\n"); + return; + } + + if (mesh_src) { + float current_time = 0; + unsigned int mvert_num = 0; + + BKE_mesh_apply_vert_coords(mesh_src, vertexCos); + BKE_mesh_calc_normals(mesh_src); + + current_time = DEG_get_ctime(ctx->depsgraph); + + if (G.debug & G_DEBUG_SIMDATA) { + printf("current_time %f, collmd->time_xnew %f\n", current_time, collmd->time_xnew); + } + + mvert_num = mesh_src->totvert; + + if (current_time < collmd->time_xnew) { + freeData((ModifierData *)collmd); + } + else if (current_time == collmd->time_xnew) { + if (mvert_num != collmd->mvert_num) { + freeData((ModifierData *)collmd); + } + } + + /* check if mesh has changed */ + if (collmd->x && (mvert_num != collmd->mvert_num)) + freeData((ModifierData *)collmd); + + if (collmd->time_xnew == -1000) { /* first time */ + + collmd->x = MEM_dupallocN(mesh_src->mvert); /* frame start position */ + + for (uint i = 0; i < mvert_num; i++) { + /* we save global positions */ + mul_m4_v3(ob->obmat, collmd->x[i].co); + } + + collmd->xnew = MEM_dupallocN(collmd->x); // frame end position + collmd->current_x = MEM_dupallocN(collmd->x); // inter-frame + collmd->current_xnew = MEM_dupallocN(collmd->x); // inter-frame + collmd->current_v = MEM_dupallocN(collmd->x); // inter-frame + + collmd->mvert_num = mvert_num; + + { + const MLoop *mloop = mesh_src->mloop; + const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(mesh_src); + collmd->tri_num = BKE_mesh_runtime_looptri_len(mesh_src); + MVertTri *tri = MEM_mallocN(sizeof(*tri) * collmd->tri_num, __func__); + BKE_mesh_runtime_verttri_from_looptri(tri, mloop, looptri, collmd->tri_num); + collmd->tri = tri; + } + + /* create bounding box hierarchy */ + collmd->bvhtree = bvhtree_build_from_mvert( + collmd->x, collmd->tri, collmd->tri_num, ob->pd->pdef_sboft); + + collmd->time_x = collmd->time_xnew = current_time; + collmd->is_static = true; + } + else if (mvert_num == collmd->mvert_num) { + /* put positions to old positions */ + tempVert = collmd->x; + collmd->x = collmd->xnew; + collmd->xnew = tempVert; + collmd->time_x = collmd->time_xnew; + + memcpy(collmd->xnew, mesh_src->mvert, mvert_num * sizeof(MVert)); + + bool is_static = true; + + for (uint i = 0; i < mvert_num; i++) { + /* we save global positions */ + mul_m4_v3(ob->obmat, collmd->xnew[i].co); + + /* detect motion */ + is_static = is_static && equals_v3v3(collmd->x[i].co, collmd->xnew[i].co); + } + + memcpy(collmd->current_xnew, collmd->x, mvert_num * sizeof(MVert)); + memcpy(collmd->current_x, collmd->x, mvert_num * sizeof(MVert)); + + /* check if GUI setting has changed for bvh */ + if (collmd->bvhtree) { + if (ob->pd->pdef_sboft != BLI_bvhtree_get_epsilon(collmd->bvhtree)) { + BLI_bvhtree_free(collmd->bvhtree); + collmd->bvhtree = bvhtree_build_from_mvert( + collmd->current_x, collmd->tri, collmd->tri_num, ob->pd->pdef_sboft); + } + } + + /* happens on file load (ONLY when i decomment changes in readfile.c) */ + if (!collmd->bvhtree) { + collmd->bvhtree = bvhtree_build_from_mvert( + collmd->current_x, collmd->tri, collmd->tri_num, ob->pd->pdef_sboft); + } + else if (!collmd->is_static || !is_static) { + /* recalc static bounding boxes */ + bvhtree_update_from_mvert(collmd->bvhtree, + collmd->current_x, + collmd->current_xnew, + collmd->tri, + collmd->tri_num, + true); + } + + collmd->is_static = is_static; + collmd->time_xnew = current_time; + } + else if (mvert_num != collmd->mvert_num) { + freeData((ModifierData *)collmd); + } + } + + if (mesh_src != mesh) { + BKE_id_free(NULL, mesh_src); + } } static void updateDepsgraph(ModifierData *UNUSED(md), const ModifierUpdateDepsgraphContext *ctx) { - DEG_add_modifier_to_transform_relation(ctx->node, "Collision Modifier"); + DEG_add_modifier_to_transform_relation(ctx->node, "Collision Modifier"); } ModifierTypeInfo modifierType_Collision = { - /* name */ "Collision", - /* structName */ "CollisionModifierData", - /* structSize */ sizeof(CollisionModifierData), - /* type */ eModifierTypeType_OnlyDeform, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_Single, - - /* copyData */ NULL, - - /* deformVerts */ deformVerts, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ NULL, - - /* initData */ initData, - /* requiredDataMask */ NULL, - /* freeData */ freeData, - /* isDisabled */ NULL, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ dependsOnTime, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ NULL, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Collision", + /* structName */ "CollisionModifierData", + /* structSize */ sizeof(CollisionModifierData), + /* type */ eModifierTypeType_OnlyDeform, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_Single, + + /* copyData */ NULL, + + /* deformVerts */ deformVerts, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ NULL, + + /* initData */ initData, + /* requiredDataMask */ NULL, + /* freeData */ freeData, + /* isDisabled */ NULL, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ dependsOnTime, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c index d9e6ed78070..2a332bc9709 100644 --- a/source/blender/modifiers/intern/MOD_correctivesmooth.c +++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c @@ -44,10 +44,8 @@ #include "BLI_strict_flags.h" - #include "DEG_depsgraph_query.h" - // #define DEBUG_TIME #include "PIL_time.h" @@ -60,345 +58,343 @@ static void initData(ModifierData *md) { - CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md; + CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md; - csmd->bind_coords = NULL; - csmd->bind_coords_num = 0; + csmd->bind_coords = NULL; + csmd->bind_coords_num = 0; - csmd->lambda = 0.5f; - csmd->repeat = 5; - csmd->flag = 0; - csmd->smooth_type = MOD_CORRECTIVESMOOTH_SMOOTH_SIMPLE; + csmd->lambda = 0.5f; + csmd->repeat = 5; + csmd->flag = 0; + csmd->smooth_type = MOD_CORRECTIVESMOOTH_SMOOTH_SIMPLE; - csmd->defgrp_name[0] = '\0'; + csmd->defgrp_name[0] = '\0'; - csmd->delta_cache = NULL; + csmd->delta_cache = NULL; } - static void copyData(const ModifierData *md, ModifierData *target, const int flag) { - const CorrectiveSmoothModifierData *csmd = (const CorrectiveSmoothModifierData *)md; - CorrectiveSmoothModifierData *tcsmd = (CorrectiveSmoothModifierData *)target; + const CorrectiveSmoothModifierData *csmd = (const CorrectiveSmoothModifierData *)md; + CorrectiveSmoothModifierData *tcsmd = (CorrectiveSmoothModifierData *)target; - modifier_copyData_generic(md, target, flag); + modifier_copyData_generic(md, target, flag); - if (csmd->bind_coords) { - tcsmd->bind_coords = MEM_dupallocN(csmd->bind_coords); - } + if (csmd->bind_coords) { + tcsmd->bind_coords = MEM_dupallocN(csmd->bind_coords); + } - tcsmd->delta_cache = NULL; - tcsmd->delta_cache_num = 0; + tcsmd->delta_cache = NULL; + tcsmd->delta_cache_num = 0; } - static void freeBind(CorrectiveSmoothModifierData *csmd) { - MEM_SAFE_FREE(csmd->bind_coords); - MEM_SAFE_FREE(csmd->delta_cache); + MEM_SAFE_FREE(csmd->bind_coords); + MEM_SAFE_FREE(csmd->delta_cache); - csmd->bind_coords_num = 0; + csmd->bind_coords_num = 0; } - static void freeData(ModifierData *md) { - CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md; - freeBind(csmd); + CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md; + freeBind(csmd); } - -static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md; + CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md; - /* ask for vertex groups if we need them */ - if (csmd->defgrp_name[0] != '\0') { - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; - } + /* ask for vertex groups if we need them */ + if (csmd->defgrp_name[0] != '\0') { + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + } } - /* check individual weights for changes and cache values */ -static void mesh_get_weights( - MDeformVert *dvert, const int defgrp_index, - const unsigned int numVerts, const bool use_invert_vgroup, - float *smooth_weights) +static void mesh_get_weights(MDeformVert *dvert, + const int defgrp_index, + const unsigned int numVerts, + const bool use_invert_vgroup, + float *smooth_weights) { - unsigned int i; - - for (i = 0; i < numVerts; i++, dvert++) { - const float w = defvert_find_weight(dvert, defgrp_index); - - if (use_invert_vgroup == false) { - smooth_weights[i] = w; - } - else { - smooth_weights[i] = 1.0f - w; - } - } + unsigned int i; + + for (i = 0; i < numVerts; i++, dvert++) { + const float w = defvert_find_weight(dvert, defgrp_index); + + if (use_invert_vgroup == false) { + smooth_weights[i] = w; + } + else { + smooth_weights[i] = 1.0f - w; + } + } } - static void mesh_get_boundaries(Mesh *mesh, float *smooth_weights) { - const MPoly *mpoly = mesh->mpoly; - const MLoop *mloop = mesh->mloop; - const MEdge *medge = mesh->medge; - unsigned int mpoly_num, medge_num, i; - unsigned short *boundaries; - - mpoly_num = (unsigned int)mesh->totpoly; - medge_num = (unsigned int)mesh->totedge; - - boundaries = MEM_calloc_arrayN(medge_num, sizeof(*boundaries), __func__); - - /* count the number of adjacent faces */ - for (i = 0; i < mpoly_num; i++) { - const MPoly *p = &mpoly[i]; - const int totloop = p->totloop; - int j; - for (j = 0; j < totloop; j++) { - boundaries[mloop[p->loopstart + j].e]++; - } - } - - for (i = 0; i < medge_num; i++) { - if (boundaries[i] == 1) { - smooth_weights[medge[i].v1] = 0.0f; - smooth_weights[medge[i].v2] = 0.0f; - } - } - - MEM_freeN(boundaries); + const MPoly *mpoly = mesh->mpoly; + const MLoop *mloop = mesh->mloop; + const MEdge *medge = mesh->medge; + unsigned int mpoly_num, medge_num, i; + unsigned short *boundaries; + + mpoly_num = (unsigned int)mesh->totpoly; + medge_num = (unsigned int)mesh->totedge; + + boundaries = MEM_calloc_arrayN(medge_num, sizeof(*boundaries), __func__); + + /* count the number of adjacent faces */ + for (i = 0; i < mpoly_num; i++) { + const MPoly *p = &mpoly[i]; + const int totloop = p->totloop; + int j; + for (j = 0; j < totloop; j++) { + boundaries[mloop[p->loopstart + j].e]++; + } + } + + for (i = 0; i < medge_num; i++) { + if (boundaries[i] == 1) { + smooth_weights[medge[i].v1] = 0.0f; + smooth_weights[medge[i].v2] = 0.0f; + } + } + + MEM_freeN(boundaries); } - /* -------------------------------------------------------------------- */ /* Simple Weighted Smoothing * * (average of surrounding verts) */ -static void smooth_iter__simple( - CorrectiveSmoothModifierData *csmd, Mesh *mesh, - float (*vertexCos)[3], unsigned int numVerts, - const float *smooth_weights, - unsigned int iterations) +static void smooth_iter__simple(CorrectiveSmoothModifierData *csmd, + Mesh *mesh, + float (*vertexCos)[3], + unsigned int numVerts, + const float *smooth_weights, + unsigned int iterations) { - const float lambda = csmd->lambda; - unsigned int i; - - const unsigned int numEdges = (unsigned int)mesh->totedge; - const MEdge *edges = mesh->medge; - float *vertex_edge_count_div; - - struct SmoothingData_Simple { - float delta[3]; - } *smooth_data = MEM_calloc_arrayN(numVerts, sizeof(*smooth_data), __func__); - - vertex_edge_count_div = MEM_calloc_arrayN(numVerts, sizeof(float), __func__); - - /* calculate as floats to avoid int->float conversion in #smooth_iter */ - for (i = 0; i < numEdges; i++) { - vertex_edge_count_div[edges[i].v1] += 1.0f; - vertex_edge_count_div[edges[i].v2] += 1.0f; - } - - /* a little confusing, but we can include 'lambda' and smoothing weight - * here to avoid multiplying for every iteration */ - if (smooth_weights == NULL) { - for (i = 0; i < numVerts; i++) { - vertex_edge_count_div[i] = - lambda * (vertex_edge_count_div[i] ? (1.0f / vertex_edge_count_div[i]) : 1.0f); - } - } - else { - for (i = 0; i < numVerts; i++) { - vertex_edge_count_div[i] = - smooth_weights[i] * lambda * (vertex_edge_count_div[i] ? (1.0f / vertex_edge_count_div[i]) : 1.0f); - } - } - - /* -------------------------------------------------------------------- */ - /* Main Smoothing Loop */ - - while (iterations--) { - for (i = 0; i < numEdges; i++) { - struct SmoothingData_Simple *sd_v1; - struct SmoothingData_Simple *sd_v2; - float edge_dir[3]; - - sub_v3_v3v3(edge_dir, vertexCos[edges[i].v2], vertexCos[edges[i].v1]); - - sd_v1 = &smooth_data[edges[i].v1]; - sd_v2 = &smooth_data[edges[i].v2]; - - add_v3_v3(sd_v1->delta, edge_dir); - sub_v3_v3(sd_v2->delta, edge_dir); - } - - - for (i = 0; i < numVerts; i++) { - struct SmoothingData_Simple *sd = &smooth_data[i]; - madd_v3_v3fl(vertexCos[i], sd->delta, vertex_edge_count_div[i]); - /* zero for the next iteration (saves memset on entire array) */ - memset(sd, 0, sizeof(*sd)); - } - } - - MEM_freeN(vertex_edge_count_div); - MEM_freeN(smooth_data); + const float lambda = csmd->lambda; + unsigned int i; + + const unsigned int numEdges = (unsigned int)mesh->totedge; + const MEdge *edges = mesh->medge; + float *vertex_edge_count_div; + + struct SmoothingData_Simple { + float delta[3]; + } *smooth_data = MEM_calloc_arrayN(numVerts, sizeof(*smooth_data), __func__); + + vertex_edge_count_div = MEM_calloc_arrayN(numVerts, sizeof(float), __func__); + + /* calculate as floats to avoid int->float conversion in #smooth_iter */ + for (i = 0; i < numEdges; i++) { + vertex_edge_count_div[edges[i].v1] += 1.0f; + vertex_edge_count_div[edges[i].v2] += 1.0f; + } + + /* a little confusing, but we can include 'lambda' and smoothing weight + * here to avoid multiplying for every iteration */ + if (smooth_weights == NULL) { + for (i = 0; i < numVerts; i++) { + vertex_edge_count_div[i] = lambda * (vertex_edge_count_div[i] ? + (1.0f / vertex_edge_count_div[i]) : + 1.0f); + } + } + else { + for (i = 0; i < numVerts; i++) { + vertex_edge_count_div[i] = smooth_weights[i] * lambda * + (vertex_edge_count_div[i] ? (1.0f / vertex_edge_count_div[i]) : + 1.0f); + } + } + + /* -------------------------------------------------------------------- */ + /* Main Smoothing Loop */ + + while (iterations--) { + for (i = 0; i < numEdges; i++) { + struct SmoothingData_Simple *sd_v1; + struct SmoothingData_Simple *sd_v2; + float edge_dir[3]; + + sub_v3_v3v3(edge_dir, vertexCos[edges[i].v2], vertexCos[edges[i].v1]); + + sd_v1 = &smooth_data[edges[i].v1]; + sd_v2 = &smooth_data[edges[i].v2]; + + add_v3_v3(sd_v1->delta, edge_dir); + sub_v3_v3(sd_v2->delta, edge_dir); + } + + for (i = 0; i < numVerts; i++) { + struct SmoothingData_Simple *sd = &smooth_data[i]; + madd_v3_v3fl(vertexCos[i], sd->delta, vertex_edge_count_div[i]); + /* zero for the next iteration (saves memset on entire array) */ + memset(sd, 0, sizeof(*sd)); + } + } + + MEM_freeN(vertex_edge_count_div); + MEM_freeN(smooth_data); } - /* -------------------------------------------------------------------- */ /* Edge-Length Weighted Smoothing */ -static void smooth_iter__length_weight( - CorrectiveSmoothModifierData *csmd, Mesh *mesh, - float (*vertexCos)[3], unsigned int numVerts, - const float *smooth_weights, - unsigned int iterations) +static void smooth_iter__length_weight(CorrectiveSmoothModifierData *csmd, + Mesh *mesh, + float (*vertexCos)[3], + unsigned int numVerts, + const float *smooth_weights, + unsigned int iterations) { - const float eps = FLT_EPSILON * 10.0f; - const unsigned int numEdges = (unsigned int)mesh->totedge; - /* note: the way this smoothing method works, its approx half as strong as the simple-smooth, - * and 2.0 rarely spikes, double the value for consistent behavior. */ - const float lambda = csmd->lambda * 2.0f; - const MEdge *edges = mesh->medge; - float *vertex_edge_count; - unsigned int i; - - struct SmoothingData_Weighted { - float delta[3]; - float edge_length_sum; - } *smooth_data = MEM_calloc_arrayN(numVerts, sizeof(*smooth_data), __func__); - - - /* calculate as floats to avoid int->float conversion in #smooth_iter */ - vertex_edge_count = MEM_calloc_arrayN(numVerts, sizeof(float), __func__); - for (i = 0; i < numEdges; i++) { - vertex_edge_count[edges[i].v1] += 1.0f; - vertex_edge_count[edges[i].v2] += 1.0f; - } - - - /* -------------------------------------------------------------------- */ - /* Main Smoothing Loop */ - - while (iterations--) { - for (i = 0; i < numEdges; i++) { - struct SmoothingData_Weighted *sd_v1; - struct SmoothingData_Weighted *sd_v2; - float edge_dir[3]; - float edge_dist; - - sub_v3_v3v3(edge_dir, vertexCos[edges[i].v2], vertexCos[edges[i].v1]); - edge_dist = len_v3(edge_dir); - - /* weight by distance */ - mul_v3_fl(edge_dir, edge_dist); - - - sd_v1 = &smooth_data[edges[i].v1]; - sd_v2 = &smooth_data[edges[i].v2]; - - add_v3_v3(sd_v1->delta, edge_dir); - sub_v3_v3(sd_v2->delta, edge_dir); - - sd_v1->edge_length_sum += edge_dist; - sd_v2->edge_length_sum += edge_dist; - } - - if (smooth_weights == NULL) { - /* fast-path */ - for (i = 0; i < numVerts; i++) { - struct SmoothingData_Weighted *sd = &smooth_data[i]; - /* divide by sum of all neighbour distances (weighted) and amount of neighbors, (mean average) */ - const float div = sd->edge_length_sum * vertex_edge_count[i]; - if (div > eps) { + const float eps = FLT_EPSILON * 10.0f; + const unsigned int numEdges = (unsigned int)mesh->totedge; + /* note: the way this smoothing method works, its approx half as strong as the simple-smooth, + * and 2.0 rarely spikes, double the value for consistent behavior. */ + const float lambda = csmd->lambda * 2.0f; + const MEdge *edges = mesh->medge; + float *vertex_edge_count; + unsigned int i; + + struct SmoothingData_Weighted { + float delta[3]; + float edge_length_sum; + } *smooth_data = MEM_calloc_arrayN(numVerts, sizeof(*smooth_data), __func__); + + /* calculate as floats to avoid int->float conversion in #smooth_iter */ + vertex_edge_count = MEM_calloc_arrayN(numVerts, sizeof(float), __func__); + for (i = 0; i < numEdges; i++) { + vertex_edge_count[edges[i].v1] += 1.0f; + vertex_edge_count[edges[i].v2] += 1.0f; + } + + /* -------------------------------------------------------------------- */ + /* Main Smoothing Loop */ + + while (iterations--) { + for (i = 0; i < numEdges; i++) { + struct SmoothingData_Weighted *sd_v1; + struct SmoothingData_Weighted *sd_v2; + float edge_dir[3]; + float edge_dist; + + sub_v3_v3v3(edge_dir, vertexCos[edges[i].v2], vertexCos[edges[i].v1]); + edge_dist = len_v3(edge_dir); + + /* weight by distance */ + mul_v3_fl(edge_dir, edge_dist); + + sd_v1 = &smooth_data[edges[i].v1]; + sd_v2 = &smooth_data[edges[i].v2]; + + add_v3_v3(sd_v1->delta, edge_dir); + sub_v3_v3(sd_v2->delta, edge_dir); + + sd_v1->edge_length_sum += edge_dist; + sd_v2->edge_length_sum += edge_dist; + } + + if (smooth_weights == NULL) { + /* fast-path */ + for (i = 0; i < numVerts; i++) { + struct SmoothingData_Weighted *sd = &smooth_data[i]; + /* divide by sum of all neighbour distances (weighted) and amount of neighbors, (mean average) */ + const float div = sd->edge_length_sum * vertex_edge_count[i]; + if (div > eps) { #if 0 - /* first calculate the new location */ - mul_v3_fl(sd->delta, 1.0f / div); - /* then interpolate */ - madd_v3_v3fl(vertexCos[i], sd->delta, lambda); + /* first calculate the new location */ + mul_v3_fl(sd->delta, 1.0f / div); + /* then interpolate */ + madd_v3_v3fl(vertexCos[i], sd->delta, lambda); #else - /* do this in one step */ - madd_v3_v3fl(vertexCos[i], sd->delta, lambda / div); + /* do this in one step */ + madd_v3_v3fl(vertexCos[i], sd->delta, lambda / div); #endif - } - /* zero for the next iteration (saves memset on entire array) */ - memset(sd, 0, sizeof(*sd)); - } - } - else { - for (i = 0; i < numVerts; i++) { - struct SmoothingData_Weighted *sd = &smooth_data[i]; - const float div = sd->edge_length_sum * vertex_edge_count[i]; - if (div > eps) { - const float lambda_w = lambda * smooth_weights[i]; - madd_v3_v3fl(vertexCos[i], sd->delta, lambda_w / div); - } - - memset(sd, 0, sizeof(*sd)); - } - } - } - - MEM_freeN(vertex_edge_count); - MEM_freeN(smooth_data); + } + /* zero for the next iteration (saves memset on entire array) */ + memset(sd, 0, sizeof(*sd)); + } + } + else { + for (i = 0; i < numVerts; i++) { + struct SmoothingData_Weighted *sd = &smooth_data[i]; + const float div = sd->edge_length_sum * vertex_edge_count[i]; + if (div > eps) { + const float lambda_w = lambda * smooth_weights[i]; + madd_v3_v3fl(vertexCos[i], sd->delta, lambda_w / div); + } + + memset(sd, 0, sizeof(*sd)); + } + } + } + + MEM_freeN(vertex_edge_count); + MEM_freeN(smooth_data); } - -static void smooth_iter( - CorrectiveSmoothModifierData *csmd, Mesh *mesh, - float (*vertexCos)[3], unsigned int numVerts, - const float *smooth_weights, - unsigned int iterations) +static void smooth_iter(CorrectiveSmoothModifierData *csmd, + Mesh *mesh, + float (*vertexCos)[3], + unsigned int numVerts, + const float *smooth_weights, + unsigned int iterations) { - switch (csmd->smooth_type) { - case MOD_CORRECTIVESMOOTH_SMOOTH_LENGTH_WEIGHT: - smooth_iter__length_weight(csmd, mesh, vertexCos, numVerts, smooth_weights, iterations); - break; - - /* case MOD_CORRECTIVESMOOTH_SMOOTH_SIMPLE: */ - default: - smooth_iter__simple(csmd, mesh, vertexCos, numVerts, smooth_weights, iterations); - break; - } + switch (csmd->smooth_type) { + case MOD_CORRECTIVESMOOTH_SMOOTH_LENGTH_WEIGHT: + smooth_iter__length_weight(csmd, mesh, vertexCos, numVerts, smooth_weights, iterations); + break; + + /* case MOD_CORRECTIVESMOOTH_SMOOTH_SIMPLE: */ + default: + smooth_iter__simple(csmd, mesh, vertexCos, numVerts, smooth_weights, iterations); + break; + } } -static void smooth_verts( - CorrectiveSmoothModifierData *csmd, Mesh *mesh, - MDeformVert *dvert, const int defgrp_index, - float (*vertexCos)[3], unsigned int numVerts) +static void smooth_verts(CorrectiveSmoothModifierData *csmd, + Mesh *mesh, + MDeformVert *dvert, + const int defgrp_index, + float (*vertexCos)[3], + unsigned int numVerts) { - float *smooth_weights = NULL; + float *smooth_weights = NULL; - if (dvert || (csmd->flag & MOD_CORRECTIVESMOOTH_PIN_BOUNDARY)) { + if (dvert || (csmd->flag & MOD_CORRECTIVESMOOTH_PIN_BOUNDARY)) { - smooth_weights = MEM_malloc_arrayN(numVerts, sizeof(float), __func__); + smooth_weights = MEM_malloc_arrayN(numVerts, sizeof(float), __func__); - if (dvert) { - mesh_get_weights( - dvert, defgrp_index, - numVerts, (csmd->flag & MOD_CORRECTIVESMOOTH_INVERT_VGROUP) != 0, - smooth_weights); - } - else { - copy_vn_fl(smooth_weights, (int)numVerts, 1.0f); - } + if (dvert) { + mesh_get_weights(dvert, + defgrp_index, + numVerts, + (csmd->flag & MOD_CORRECTIVESMOOTH_INVERT_VGROUP) != 0, + smooth_weights); + } + else { + copy_vn_fl(smooth_weights, (int)numVerts, 1.0f); + } - if (csmd->flag & MOD_CORRECTIVESMOOTH_PIN_BOUNDARY) { - mesh_get_boundaries(mesh, smooth_weights); - } - } + if (csmd->flag & MOD_CORRECTIVESMOOTH_PIN_BOUNDARY) { + mesh_get_boundaries(mesh, smooth_weights); + } + } - smooth_iter(csmd, mesh, vertexCos, numVerts, smooth_weights, (unsigned int)csmd->repeat); + smooth_iter(csmd, mesh, vertexCos, numVerts, smooth_weights, (unsigned int)csmd->repeat); - if (smooth_weights) { - MEM_freeN(smooth_weights); - } + if (smooth_weights) { + MEM_freeN(smooth_weights); + } } /** @@ -406,109 +402,102 @@ static void smooth_verts( */ static void calc_tangent_ortho(float ts[3][3]) { - float v_tan_a[3], v_tan_b[3]; - float t_vec_a[3], t_vec_b[3]; + float v_tan_a[3], v_tan_b[3]; + float t_vec_a[3], t_vec_b[3]; - normalize_v3(ts[2]); + normalize_v3(ts[2]); - copy_v3_v3(v_tan_a, ts[0]); - copy_v3_v3(v_tan_b, ts[1]); + copy_v3_v3(v_tan_a, ts[0]); + copy_v3_v3(v_tan_b, ts[1]); - cross_v3_v3v3(ts[1], ts[2], v_tan_a); - mul_v3_fl(ts[1], dot_v3v3(ts[1], v_tan_b) < 0.0f ? -1.0f : 1.0f); + cross_v3_v3v3(ts[1], ts[2], v_tan_a); + mul_v3_fl(ts[1], dot_v3v3(ts[1], v_tan_b) < 0.0f ? -1.0f : 1.0f); - /* orthognalise tangent */ - mul_v3_v3fl(t_vec_a, ts[2], dot_v3v3(ts[2], v_tan_a)); - sub_v3_v3v3(ts[0], v_tan_a, t_vec_a); + /* orthognalise tangent */ + mul_v3_v3fl(t_vec_a, ts[2], dot_v3v3(ts[2], v_tan_a)); + sub_v3_v3v3(ts[0], v_tan_a, t_vec_a); - /* orthognalise bitangent */ - mul_v3_v3fl(t_vec_a, ts[2], dot_v3v3(ts[2], ts[1])); - mul_v3_v3fl(t_vec_b, ts[0], dot_v3v3(ts[0], ts[1]) / dot_v3v3(v_tan_a, v_tan_a)); - sub_v3_v3(ts[1], t_vec_a); - sub_v3_v3(ts[1], t_vec_b); + /* orthognalise bitangent */ + mul_v3_v3fl(t_vec_a, ts[2], dot_v3v3(ts[2], ts[1])); + mul_v3_v3fl(t_vec_b, ts[0], dot_v3v3(ts[0], ts[1]) / dot_v3v3(v_tan_a, v_tan_a)); + sub_v3_v3(ts[1], t_vec_a); + sub_v3_v3(ts[1], t_vec_b); - normalize_v3(ts[0]); - normalize_v3(ts[1]); + normalize_v3(ts[0]); + normalize_v3(ts[1]); } /** * accumulate edge-vectors from all polys. */ -static void calc_tangent_loop_accum( - const float v_dir_prev[3], - const float v_dir_next[3], - float r_tspace[3][3]) +static void calc_tangent_loop_accum(const float v_dir_prev[3], + const float v_dir_next[3], + float r_tspace[3][3]) { - add_v3_v3v3(r_tspace[1], v_dir_prev, v_dir_next); + add_v3_v3v3(r_tspace[1], v_dir_prev, v_dir_next); - if (compare_v3v3(v_dir_prev, v_dir_next, FLT_EPSILON * 10.0f) == false) { - const float weight = fabsf(acosf(dot_v3v3(v_dir_next, v_dir_prev))); - float nor[3]; + if (compare_v3v3(v_dir_prev, v_dir_next, FLT_EPSILON * 10.0f) == false) { + const float weight = fabsf(acosf(dot_v3v3(v_dir_next, v_dir_prev))); + float nor[3]; - cross_v3_v3v3(nor, v_dir_prev, v_dir_next); - normalize_v3(nor); + cross_v3_v3v3(nor, v_dir_prev, v_dir_next); + normalize_v3(nor); - cross_v3_v3v3(r_tspace[0], r_tspace[1], nor); + cross_v3_v3v3(r_tspace[0], r_tspace[1], nor); - mul_v3_fl(nor, weight); - /* accumulate weighted normals */ - add_v3_v3(r_tspace[2], nor); - } + mul_v3_fl(nor, weight); + /* accumulate weighted normals */ + add_v3_v3(r_tspace[2], nor); + } } - -static void calc_tangent_spaces( - Mesh *mesh, float (*vertexCos)[3], - float (*r_tangent_spaces)[3][3]) +static void calc_tangent_spaces(Mesh *mesh, float (*vertexCos)[3], float (*r_tangent_spaces)[3][3]) { - const unsigned int mpoly_num = (unsigned int)mesh->totpoly; + const unsigned int mpoly_num = (unsigned int)mesh->totpoly; #ifndef USE_TANGENT_CALC_INLINE - const unsigned int mvert_num = (unsigned int)dm->getNumVerts(dm); + const unsigned int mvert_num = (unsigned int)dm->getNumVerts(dm); #endif - const MPoly *mpoly = mesh->mpoly; - const MLoop *mloop = mesh->mloop; - unsigned int i; - - for (i = 0; i < mpoly_num; i++) { - const MPoly *mp = &mpoly[i]; - const MLoop *l_next = &mloop[mp->loopstart]; - const MLoop *l_term = l_next + mp->totloop; - const MLoop *l_prev = l_term - 2; - const MLoop *l_curr = l_term - 1; - - /* loop directions */ - float v_dir_prev[3], v_dir_next[3]; - - /* needed entering the loop */ - sub_v3_v3v3(v_dir_prev, vertexCos[l_prev->v], vertexCos[l_curr->v]); - normalize_v3(v_dir_prev); - - for (; - l_next != l_term; - l_prev = l_curr, l_curr = l_next, l_next++) - { - float (*ts)[3] = r_tangent_spaces[l_curr->v]; - - /* re-use the previous value */ + const MPoly *mpoly = mesh->mpoly; + const MLoop *mloop = mesh->mloop; + unsigned int i; + + for (i = 0; i < mpoly_num; i++) { + const MPoly *mp = &mpoly[i]; + const MLoop *l_next = &mloop[mp->loopstart]; + const MLoop *l_term = l_next + mp->totloop; + const MLoop *l_prev = l_term - 2; + const MLoop *l_curr = l_term - 1; + + /* loop directions */ + float v_dir_prev[3], v_dir_next[3]; + + /* needed entering the loop */ + sub_v3_v3v3(v_dir_prev, vertexCos[l_prev->v], vertexCos[l_curr->v]); + normalize_v3(v_dir_prev); + + for (; l_next != l_term; l_prev = l_curr, l_curr = l_next, l_next++) { + float(*ts)[3] = r_tangent_spaces[l_curr->v]; + + /* re-use the previous value */ #if 0 - sub_v3_v3v3(v_dir_prev, vertexCos[l_prev->v], vertexCos[l_curr->v]); - normalize_v3(v_dir_prev); + sub_v3_v3v3(v_dir_prev, vertexCos[l_prev->v], vertexCos[l_curr->v]); + normalize_v3(v_dir_prev); #endif - sub_v3_v3v3(v_dir_next, vertexCos[l_curr->v], vertexCos[l_next->v]); - normalize_v3(v_dir_next); + sub_v3_v3v3(v_dir_next, vertexCos[l_curr->v], vertexCos[l_next->v]); + normalize_v3(v_dir_next); - calc_tangent_loop_accum(v_dir_prev, v_dir_next, ts); + calc_tangent_loop_accum(v_dir_prev, v_dir_next, ts); - copy_v3_v3(v_dir_prev, v_dir_next); - } - } + copy_v3_v3(v_dir_prev, v_dir_next); + } + } - /* do inline */ + /* do inline */ #ifndef USE_TANGENT_CALC_INLINE - for (i = 0; i < mvert_num; i++) { - float (*ts)[3] = r_tangent_spaces[i]; - calc_tangent_ortho(ts); - } + for (i = 0; i < mvert_num; i++) { + float(*ts)[3] = r_tangent_spaces[i]; + calc_tangent_ortho(ts); + } #endif } @@ -516,261 +505,266 @@ static void calc_tangent_spaces( * This calculates #CorrectiveSmoothModifierData.delta_cache * It's not run on every update (during animation for example). */ -static void calc_deltas( - CorrectiveSmoothModifierData *csmd, Mesh *mesh, - MDeformVert *dvert, const int defgrp_index, - const float (*rest_coords)[3], unsigned int numVerts) +static void calc_deltas(CorrectiveSmoothModifierData *csmd, + Mesh *mesh, + MDeformVert *dvert, + const int defgrp_index, + const float (*rest_coords)[3], + unsigned int numVerts) { - float (*smooth_vertex_coords)[3] = MEM_dupallocN(rest_coords); - float (*tangent_spaces)[3][3]; - unsigned int i; + float(*smooth_vertex_coords)[3] = MEM_dupallocN(rest_coords); + float(*tangent_spaces)[3][3]; + unsigned int i; - tangent_spaces = MEM_calloc_arrayN(numVerts, sizeof(float[3][3]), __func__); + tangent_spaces = MEM_calloc_arrayN(numVerts, sizeof(float[3][3]), __func__); - if (csmd->delta_cache_num != numVerts) { - MEM_SAFE_FREE(csmd->delta_cache); - } + if (csmd->delta_cache_num != numVerts) { + MEM_SAFE_FREE(csmd->delta_cache); + } - /* allocate deltas if they have not yet been allocated, otheriwse we will just write over them */ - if (!csmd->delta_cache) { - csmd->delta_cache_num = numVerts; - csmd->delta_cache = MEM_malloc_arrayN(numVerts, sizeof(float[3]), __func__); - } + /* allocate deltas if they have not yet been allocated, otheriwse we will just write over them */ + if (!csmd->delta_cache) { + csmd->delta_cache_num = numVerts; + csmd->delta_cache = MEM_malloc_arrayN(numVerts, sizeof(float[3]), __func__); + } - smooth_verts(csmd, mesh, dvert, defgrp_index, smooth_vertex_coords, numVerts); + smooth_verts(csmd, mesh, dvert, defgrp_index, smooth_vertex_coords, numVerts); - calc_tangent_spaces(mesh, smooth_vertex_coords, tangent_spaces); + calc_tangent_spaces(mesh, smooth_vertex_coords, tangent_spaces); - for (i = 0; i < numVerts; i++) { - float imat[3][3], delta[3]; + for (i = 0; i < numVerts; i++) { + float imat[3][3], delta[3]; #ifdef USE_TANGENT_CALC_INLINE - calc_tangent_ortho(tangent_spaces[i]); + calc_tangent_ortho(tangent_spaces[i]); #endif - sub_v3_v3v3(delta, rest_coords[i], smooth_vertex_coords[i]); - if (UNLIKELY(!invert_m3_m3(imat, tangent_spaces[i]))) { - transpose_m3_m3(imat, tangent_spaces[i]); - } - mul_v3_m3v3(csmd->delta_cache[i], imat, delta); - } + sub_v3_v3v3(delta, rest_coords[i], smooth_vertex_coords[i]); + if (UNLIKELY(!invert_m3_m3(imat, tangent_spaces[i]))) { + transpose_m3_m3(imat, tangent_spaces[i]); + } + mul_v3_m3v3(csmd->delta_cache[i], imat, delta); + } - MEM_freeN(tangent_spaces); - MEM_freeN(smooth_vertex_coords); + MEM_freeN(tangent_spaces); + MEM_freeN(smooth_vertex_coords); } - -static void correctivesmooth_modifier_do( - ModifierData *md, Depsgraph *depsgraph, Object *ob, Mesh *mesh, - float (*vertexCos)[3], unsigned int numVerts, - struct BMEditMesh *em) +static void correctivesmooth_modifier_do(ModifierData *md, + Depsgraph *depsgraph, + Object *ob, + Mesh *mesh, + float (*vertexCos)[3], + unsigned int numVerts, + struct BMEditMesh *em) { - CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md; - - const bool force_delta_cache_update = - /* XXX, take care! if mesh data its self changes we need to forcefully recalculate deltas */ - ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO) && - (((ID *)ob->data)->recalc & ID_RECALC_ALL)); - - bool use_only_smooth = (csmd->flag & MOD_CORRECTIVESMOOTH_ONLY_SMOOTH) != 0; - MDeformVert *dvert = NULL; - int defgrp_index; - - MOD_get_vgroup(ob, mesh, csmd->defgrp_name, &dvert, &defgrp_index); - - /* if rest bind_coords not are defined, set them (only run during bind) */ - if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) && - /* signal to recalculate, whoever sets MUST also free bind coords */ - (csmd->bind_coords_num == (unsigned int)-1)) - { - if (DEG_is_active(depsgraph)) { - BLI_assert(csmd->bind_coords == NULL); - csmd->bind_coords = MEM_dupallocN(vertexCos); - csmd->bind_coords_num = numVerts; - BLI_assert(csmd->bind_coords != NULL); - /* Copy bound data to the original modifier. */ - CorrectiveSmoothModifierData *csmd_orig = - (CorrectiveSmoothModifierData *)modifier_get_original(&csmd->modifier); - csmd_orig->bind_coords = MEM_dupallocN(csmd->bind_coords); - csmd_orig->bind_coords_num = csmd->bind_coords_num; - } - else { - modifier_setError(md, "Attempt to bind from inactive dependency graph"); - } - } - - if (UNLIKELY(use_only_smooth)) { - smooth_verts(csmd, mesh, dvert, defgrp_index, vertexCos, numVerts); - return; - } - - if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) && (csmd->bind_coords == NULL)) { - modifier_setError(md, "Bind data required"); - goto error; - } - - /* If the number of verts has changed, the bind is invalid, so we do nothing */ - if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) { - if (csmd->bind_coords_num != numVerts) { - modifier_setError(md, "Bind vertex count mismatch: %u to %u", csmd->bind_coords_num, numVerts); - goto error; - } - } - else { - /* MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO */ - if (ob->type != OB_MESH) { - modifier_setError(md, "Object is not a mesh"); - goto error; - } - else { - unsigned int me_numVerts = (unsigned int)((em) ? em->bm->totvert : ((Mesh *)ob->data)->totvert); - - if (me_numVerts != numVerts) { - modifier_setError(md, "Original vertex count mismatch: %u to %u", me_numVerts, numVerts); - goto error; - } - } - } - - /* check to see if our deltas are still valid */ - if (!csmd->delta_cache || (csmd->delta_cache_num != numVerts) || force_delta_cache_update) { - const float (*rest_coords)[3]; - bool is_rest_coords_alloc = false; - - if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) { - /* caller needs to do sanity check here */ - csmd->bind_coords_num = numVerts; - rest_coords = (const float (*)[3])csmd->bind_coords; - } - else { - int me_numVerts; - rest_coords = (const float (*)[3]) ((em) ? - BKE_editmesh_vertexCos_get_orco(em, &me_numVerts) : - BKE_mesh_vertexCos_get(ob->data, &me_numVerts)); - - BLI_assert((unsigned int)me_numVerts == numVerts); - is_rest_coords_alloc = true; - } + CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md; + + const bool force_delta_cache_update = + /* XXX, take care! if mesh data its self changes we need to forcefully recalculate deltas */ + ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO) && + (((ID *)ob->data)->recalc & ID_RECALC_ALL)); + + bool use_only_smooth = (csmd->flag & MOD_CORRECTIVESMOOTH_ONLY_SMOOTH) != 0; + MDeformVert *dvert = NULL; + int defgrp_index; + + MOD_get_vgroup(ob, mesh, csmd->defgrp_name, &dvert, &defgrp_index); + + /* if rest bind_coords not are defined, set them (only run during bind) */ + if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) && + /* signal to recalculate, whoever sets MUST also free bind coords */ + (csmd->bind_coords_num == (unsigned int)-1)) { + if (DEG_is_active(depsgraph)) { + BLI_assert(csmd->bind_coords == NULL); + csmd->bind_coords = MEM_dupallocN(vertexCos); + csmd->bind_coords_num = numVerts; + BLI_assert(csmd->bind_coords != NULL); + /* Copy bound data to the original modifier. */ + CorrectiveSmoothModifierData *csmd_orig = (CorrectiveSmoothModifierData *) + modifier_get_original(&csmd->modifier); + csmd_orig->bind_coords = MEM_dupallocN(csmd->bind_coords); + csmd_orig->bind_coords_num = csmd->bind_coords_num; + } + else { + modifier_setError(md, "Attempt to bind from inactive dependency graph"); + } + } + + if (UNLIKELY(use_only_smooth)) { + smooth_verts(csmd, mesh, dvert, defgrp_index, vertexCos, numVerts); + return; + } + + if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) && (csmd->bind_coords == NULL)) { + modifier_setError(md, "Bind data required"); + goto error; + } + + /* If the number of verts has changed, the bind is invalid, so we do nothing */ + if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) { + if (csmd->bind_coords_num != numVerts) { + modifier_setError( + md, "Bind vertex count mismatch: %u to %u", csmd->bind_coords_num, numVerts); + goto error; + } + } + else { + /* MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO */ + if (ob->type != OB_MESH) { + modifier_setError(md, "Object is not a mesh"); + goto error; + } + else { + unsigned int me_numVerts = (unsigned int)((em) ? em->bm->totvert : + ((Mesh *)ob->data)->totvert); + + if (me_numVerts != numVerts) { + modifier_setError(md, "Original vertex count mismatch: %u to %u", me_numVerts, numVerts); + goto error; + } + } + } + + /* check to see if our deltas are still valid */ + if (!csmd->delta_cache || (csmd->delta_cache_num != numVerts) || force_delta_cache_update) { + const float(*rest_coords)[3]; + bool is_rest_coords_alloc = false; + + if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) { + /* caller needs to do sanity check here */ + csmd->bind_coords_num = numVerts; + rest_coords = (const float(*)[3])csmd->bind_coords; + } + else { + int me_numVerts; + rest_coords = (const float(*)[3])((em) ? BKE_editmesh_vertexCos_get_orco(em, &me_numVerts) : + BKE_mesh_vertexCos_get(ob->data, &me_numVerts)); + + BLI_assert((unsigned int)me_numVerts == numVerts); + is_rest_coords_alloc = true; + } #ifdef DEBUG_TIME - TIMEIT_START(corrective_smooth_deltas); + TIMEIT_START(corrective_smooth_deltas); #endif - calc_deltas(csmd, mesh, dvert, defgrp_index, rest_coords, numVerts); + calc_deltas(csmd, mesh, dvert, defgrp_index, rest_coords, numVerts); #ifdef DEBUG_TIME - TIMEIT_END(corrective_smooth_deltas); + 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); - } + 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); + TIMEIT_START(corrective_smooth); #endif - /* do the actual delta mush */ - smooth_verts(csmd, mesh, dvert, defgrp_index, vertexCos, numVerts); + /* do the actual delta mush */ + smooth_verts(csmd, mesh, dvert, defgrp_index, vertexCos, numVerts); - { - unsigned int i; + { + unsigned int i; - float (*tangent_spaces)[3][3]; + float(*tangent_spaces)[3][3]; - /* calloc, since values are accumulated */ - tangent_spaces = MEM_calloc_arrayN(numVerts, sizeof(float[3][3]), __func__); + /* calloc, since values are accumulated */ + tangent_spaces = MEM_calloc_arrayN(numVerts, sizeof(float[3][3]), __func__); - calc_tangent_spaces(mesh, vertexCos, tangent_spaces); + calc_tangent_spaces(mesh, vertexCos, tangent_spaces); - for (i = 0; i < numVerts; i++) { - float delta[3]; + for (i = 0; i < numVerts; i++) { + float delta[3]; #ifdef USE_TANGENT_CALC_INLINE - calc_tangent_ortho(tangent_spaces[i]); + calc_tangent_ortho(tangent_spaces[i]); #endif - mul_v3_m3v3(delta, tangent_spaces[i], csmd->delta_cache[i]); - add_v3_v3(vertexCos[i], delta); - } + mul_v3_m3v3(delta, tangent_spaces[i], csmd->delta_cache[i]); + add_v3_v3(vertexCos[i], delta); + } - MEM_freeN(tangent_spaces); - } + MEM_freeN(tangent_spaces); + } #ifdef DEBUG_TIME - TIMEIT_END(corrective_smooth); + TIMEIT_END(corrective_smooth); #endif - return; + return; - /* when the modifier fails to execute */ + /* when the modifier fails to execute */ error: - MEM_SAFE_FREE( - csmd->delta_cache); - csmd->delta_cache_num = 0; - + MEM_SAFE_FREE(csmd->delta_cache); + csmd->delta_cache_num = 0; } - -static void deformVerts( - ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh, - float (*vertexCos)[3], int numVerts) +static void deformVerts(ModifierData *md, + const ModifierEvalContext *ctx, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); + Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); - correctivesmooth_modifier_do(md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (unsigned int)numVerts, NULL); + correctivesmooth_modifier_do( + md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (unsigned int)numVerts, NULL); - if (mesh_src != mesh) { - BKE_id_free(NULL, mesh_src); - } + if (mesh_src != mesh) { + BKE_id_free(NULL, mesh_src); + } } - -static void deformVertsEM( - ModifierData *md, const ModifierEvalContext *ctx, struct BMEditMesh *editData, - Mesh *mesh, float (*vertexCos)[3], int numVerts) +static void deformVertsEM(ModifierData *md, + const ModifierEvalContext *ctx, + struct BMEditMesh *editData, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false); + Mesh *mesh_src = MOD_deform_mesh_eval_get( + ctx->object, editData, mesh, NULL, numVerts, false, false); - correctivesmooth_modifier_do(md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (unsigned int)numVerts, editData); + correctivesmooth_modifier_do( + md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (unsigned int)numVerts, editData); - if (mesh_src != mesh) { - BKE_id_free(NULL, mesh_src); - } + if (mesh_src != mesh) { + BKE_id_free(NULL, mesh_src); + } } - ModifierTypeInfo modifierType_CorrectiveSmooth = { - /* name */ "CorrectiveSmooth", - /* structName */ "CorrectiveSmoothModifierData", - /* structSize */ sizeof(CorrectiveSmoothModifierData), - /* type */ eModifierTypeType_OnlyDeform, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_SupportsEditmode, - - /* copyData */ copyData, - - /* deformVerts */ deformVerts, - /* deformMatrices */ NULL, - /* deformVertsEM */ deformVertsEM, - /* deformMatricesEM */ NULL, - /* applyModifier */ NULL, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ freeData, - /* isDisabled */ NULL, - /* updateDepsgraph */ NULL, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ NULL, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "CorrectiveSmooth", + /* structName */ "CorrectiveSmoothModifierData", + /* structSize */ sizeof(CorrectiveSmoothModifierData), + /* type */ eModifierTypeType_OnlyDeform, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsEditmode, + + /* copyData */ copyData, + + /* deformVerts */ deformVerts, + /* deformMatrices */ NULL, + /* deformVertsEM */ deformVertsEM, + /* deformMatricesEM */ NULL, + /* applyModifier */ NULL, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ freeData, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c index 91cedda4f48..7a07d9b28eb 100644 --- a/source/blender/modifiers/intern/MOD_curve.c +++ b/source/blender/modifiers/intern/MOD_curve.c @@ -45,128 +45,124 @@ static void initData(ModifierData *md) { - CurveModifierData *cmd = (CurveModifierData *) md; + CurveModifierData *cmd = (CurveModifierData *)md; - cmd->defaxis = MOD_CURVE_POSX; + cmd->defaxis = MOD_CURVE_POSX; } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - CurveModifierData *cmd = (CurveModifierData *)md; + CurveModifierData *cmd = (CurveModifierData *)md; - /* ask for vertexgroups if we need them */ - if (cmd->name[0] != '\0') { - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; - } + /* ask for vertexgroups if we need them */ + if (cmd->name[0] != '\0') { + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + } } static bool isDisabled(const Scene *UNUSED(scene), ModifierData *md, bool UNUSED(userRenderParams)) { - CurveModifierData *cmd = (CurveModifierData *) md; + CurveModifierData *cmd = (CurveModifierData *)md; - return !cmd->object; + return !cmd->object; } -static void foreachObjectLink( - ModifierData *md, Object *ob, - ObjectWalkFunc walk, void *userData) +static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) { - CurveModifierData *cmd = (CurveModifierData *) md; + CurveModifierData *cmd = (CurveModifierData *)md; - walk(userData, ob, &cmd->object, IDWALK_CB_NOP); + walk(userData, ob, &cmd->object, IDWALK_CB_NOP); } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { - CurveModifierData *cmd = (CurveModifierData *)md; - if (cmd->object != NULL) { - /* TODO(sergey): Need to do the same eval_flags trick for path - * as happening in legacy depsgraph callback. - */ - /* TODO(sergey): Currently path is evaluated as a part of modifier stack, - * might be changed in the future. - */ - DEG_add_object_relation(ctx->node, cmd->object, DEG_OB_COMP_TRANSFORM, "Curve Modifier"); - DEG_add_object_relation(ctx->node, cmd->object, DEG_OB_COMP_GEOMETRY, "Curve Modifier"); - DEG_add_special_eval_flag(ctx->node, &cmd->object->id, DAG_EVAL_NEED_CURVE_PATH); - } - - DEG_add_modifier_to_transform_relation(ctx->node, "Curve Modifier"); + CurveModifierData *cmd = (CurveModifierData *)md; + if (cmd->object != NULL) { + /* TODO(sergey): Need to do the same eval_flags trick for path + * as happening in legacy depsgraph callback. + */ + /* TODO(sergey): Currently path is evaluated as a part of modifier stack, + * might be changed in the future. + */ + DEG_add_object_relation(ctx->node, cmd->object, DEG_OB_COMP_TRANSFORM, "Curve Modifier"); + DEG_add_object_relation(ctx->node, cmd->object, DEG_OB_COMP_GEOMETRY, "Curve Modifier"); + DEG_add_special_eval_flag(ctx->node, &cmd->object->id, DAG_EVAL_NEED_CURVE_PATH); + } + + DEG_add_modifier_to_transform_relation(ctx->node, "Curve Modifier"); } -static void deformVerts( - ModifierData *md, - const ModifierEvalContext *ctx, - Mesh *mesh, - float (*vertexCos)[3], - int numVerts) +static void deformVerts(ModifierData *md, + const ModifierEvalContext *ctx, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - CurveModifierData *cmd = (CurveModifierData *) md; - Mesh *mesh_src = NULL; - - if (ctx->object->type == OB_MESH && cmd->name[0] != '\0') { - /* mesh_src is only needed for vgroups. */ - mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); - } - - struct MDeformVert *dvert = NULL; - int defgrp_index = -1; - MOD_get_vgroup(ctx->object, mesh_src, cmd->name, &dvert, &defgrp_index); - - /* silly that defaxis and curve_deform_verts are off by 1 - * but leave for now to save having to call do_versions */ - curve_deform_verts(cmd->object, ctx->object, - vertexCos, numVerts, dvert, defgrp_index, cmd->defaxis - 1); - - if (!ELEM(mesh_src, NULL, mesh)) { - BKE_id_free(NULL, mesh_src); - } + CurveModifierData *cmd = (CurveModifierData *)md; + Mesh *mesh_src = NULL; + + if (ctx->object->type == OB_MESH && cmd->name[0] != '\0') { + /* mesh_src is only needed for vgroups. */ + mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); + } + + struct MDeformVert *dvert = NULL; + int defgrp_index = -1; + MOD_get_vgroup(ctx->object, mesh_src, cmd->name, &dvert, &defgrp_index); + + /* silly that defaxis and curve_deform_verts are off by 1 + * but leave for now to save having to call do_versions */ + curve_deform_verts( + cmd->object, ctx->object, vertexCos, numVerts, dvert, defgrp_index, cmd->defaxis - 1); + + if (!ELEM(mesh_src, NULL, mesh)) { + BKE_id_free(NULL, mesh_src); + } } -static void deformVertsEM( - ModifierData *md, - const ModifierEvalContext *ctx, - struct BMEditMesh *em, - Mesh *mesh, - float (*vertexCos)[3], - int numVerts) +static void deformVertsEM(ModifierData *md, + const ModifierEvalContext *ctx, + struct BMEditMesh *em, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, numVerts, false, false); + Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, numVerts, false, false); - deformVerts(md, ctx, mesh_src, vertexCos, numVerts); + deformVerts(md, ctx, mesh_src, vertexCos, numVerts); - if (!ELEM(mesh_src, NULL, mesh)) { - BKE_id_free(NULL, mesh_src); - } + if (!ELEM(mesh_src, NULL, mesh)) { + BKE_id_free(NULL, mesh_src); + } } - ModifierTypeInfo modifierType_Curve = { - /* name */ "Curve", - /* structName */ "CurveModifierData", - /* structSize */ sizeof(CurveModifierData), - /* type */ eModifierTypeType_OnlyDeform, - /* flags */ eModifierTypeFlag_AcceptsCVs | - eModifierTypeFlag_AcceptsLattice | - eModifierTypeFlag_SupportsEditmode, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ deformVerts, - /* deformMatrices */ NULL, - /* deformVertsEM */ deformVertsEM, - /* deformMatricesEM */ NULL, - /* applyModifier */ NULL, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ NULL, - /* isDisabled */ isDisabled, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ foreachObjectLink, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Curve", + /* structName */ "CurveModifierData", + /* structSize */ sizeof(CurveModifierData), + /* type */ eModifierTypeType_OnlyDeform, + /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice | + eModifierTypeFlag_SupportsEditmode, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ deformVerts, + /* deformMatrices */ NULL, + /* deformVertsEM */ deformVertsEM, + /* deformMatricesEM */ NULL, + /* applyModifier */ NULL, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ NULL, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_datatransfer.c b/source/blender/modifiers/intern/MOD_datatransfer.c index 567af7bae09..4de99ea6fe6 100644 --- a/source/blender/modifiers/intern/MOD_datatransfer.c +++ b/source/blender/modifiers/intern/MOD_datatransfer.c @@ -49,190 +49,212 @@ **************************************/ static void initData(ModifierData *md) { - DataTransferModifierData *dtmd = (DataTransferModifierData *) md; - int i; + DataTransferModifierData *dtmd = (DataTransferModifierData *)md; + int i; - dtmd->ob_source = NULL; - dtmd->data_types = 0; + dtmd->ob_source = NULL; + dtmd->data_types = 0; - dtmd->vmap_mode = MREMAP_MODE_VERT_NEAREST; - dtmd->emap_mode = MREMAP_MODE_EDGE_NEAREST; - dtmd->lmap_mode = MREMAP_MODE_LOOP_NEAREST_POLYNOR; - dtmd->pmap_mode = MREMAP_MODE_POLY_NEAREST; + dtmd->vmap_mode = MREMAP_MODE_VERT_NEAREST; + dtmd->emap_mode = MREMAP_MODE_EDGE_NEAREST; + dtmd->lmap_mode = MREMAP_MODE_LOOP_NEAREST_POLYNOR; + dtmd->pmap_mode = MREMAP_MODE_POLY_NEAREST; - dtmd->map_max_distance = 1.0f; - dtmd->map_ray_radius = 0.0f; + dtmd->map_max_distance = 1.0f; + dtmd->map_ray_radius = 0.0f; - for (i = 0; i < DT_MULTILAYER_INDEX_MAX; i++) { - dtmd->layers_select_src[i] = DT_LAYERS_ALL_SRC; - dtmd->layers_select_dst[i] = DT_LAYERS_NAME_DST; - } + for (i = 0; i < DT_MULTILAYER_INDEX_MAX; i++) { + dtmd->layers_select_src[i] = DT_LAYERS_ALL_SRC; + dtmd->layers_select_dst[i] = DT_LAYERS_NAME_DST; + } - dtmd->mix_mode = CDT_MIX_TRANSFER; - dtmd->mix_factor = 1.0f; - dtmd->defgrp_name[0] = '\0'; + dtmd->mix_mode = CDT_MIX_TRANSFER; + dtmd->mix_factor = 1.0f; + dtmd->defgrp_name[0] = '\0'; - dtmd->flags = MOD_DATATRANSFER_OBSRC_TRANSFORM; + dtmd->flags = MOD_DATATRANSFER_OBSRC_TRANSFORM; } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - DataTransferModifierData *dtmd = (DataTransferModifierData *) md; + DataTransferModifierData *dtmd = (DataTransferModifierData *)md; - if (dtmd->defgrp_name[0] != '\0') { - /* We need vertex groups! */ - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; - } + if (dtmd->defgrp_name[0] != '\0') { + /* We need vertex groups! */ + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + } - BKE_object_data_transfer_dttypes_to_cdmask(dtmd->data_types, r_cddata_masks); + BKE_object_data_transfer_dttypes_to_cdmask(dtmd->data_types, r_cddata_masks); } static bool dependsOnNormals(ModifierData *md) { - DataTransferModifierData *dtmd = (DataTransferModifierData *) md; - int item_types = BKE_object_data_transfer_get_dttypes_item_types(dtmd->data_types); - - if ((item_types & ME_VERT) && (dtmd->vmap_mode & (MREMAP_USE_NORPROJ | MREMAP_USE_NORMAL))) { - return true; - } - if ((item_types & ME_EDGE) && (dtmd->emap_mode & (MREMAP_USE_NORPROJ | MREMAP_USE_NORMAL))) { - return true; - } - if ((item_types & ME_LOOP) && (dtmd->lmap_mode & (MREMAP_USE_NORPROJ | MREMAP_USE_NORMAL))) { - return true; - } - if ((item_types & ME_POLY) && (dtmd->pmap_mode & (MREMAP_USE_NORPROJ | MREMAP_USE_NORMAL))) { - return true; - } - - return false; + DataTransferModifierData *dtmd = (DataTransferModifierData *)md; + int item_types = BKE_object_data_transfer_get_dttypes_item_types(dtmd->data_types); + + if ((item_types & ME_VERT) && (dtmd->vmap_mode & (MREMAP_USE_NORPROJ | MREMAP_USE_NORMAL))) { + return true; + } + if ((item_types & ME_EDGE) && (dtmd->emap_mode & (MREMAP_USE_NORPROJ | MREMAP_USE_NORMAL))) { + return true; + } + if ((item_types & ME_LOOP) && (dtmd->lmap_mode & (MREMAP_USE_NORPROJ | MREMAP_USE_NORMAL))) { + return true; + } + if ((item_types & ME_POLY) && (dtmd->pmap_mode & (MREMAP_USE_NORPROJ | MREMAP_USE_NORMAL))) { + return true; + } + + return false; } -static void foreachObjectLink( - ModifierData *md, Object *ob, - ObjectWalkFunc walk, void *userData) +static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) { - DataTransferModifierData *dtmd = (DataTransferModifierData *) md; - walk(userData, ob, &dtmd->ob_source, IDWALK_CB_NOP); + DataTransferModifierData *dtmd = (DataTransferModifierData *)md; + walk(userData, ob, &dtmd->ob_source, IDWALK_CB_NOP); } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { - DataTransferModifierData *dtmd = (DataTransferModifierData *) md; - if (dtmd->ob_source != NULL) { - CustomData_MeshMasks cddata_masks = {0}; - BKE_object_data_transfer_dttypes_to_cdmask(dtmd->data_types, &cddata_masks); - BKE_mesh_remap_calc_source_cddata_masks_from_map_modes( - dtmd->vmap_mode, dtmd->emap_mode, dtmd->lmap_mode, dtmd->pmap_mode, &cddata_masks); - - DEG_add_object_relation(ctx->node, dtmd->ob_source, DEG_OB_COMP_GEOMETRY, "DataTransfer Modifier"); - DEG_add_customdata_mask(ctx->node, dtmd->ob_source, &cddata_masks); - - if (dtmd->flags & MOD_DATATRANSFER_OBSRC_TRANSFORM) { - DEG_add_object_relation(ctx->node, dtmd->ob_source, DEG_OB_COMP_TRANSFORM, "DataTransfer Modifier"); - DEG_add_modifier_to_transform_relation(ctx->node, "DataTransfer Modifier"); - } - } + DataTransferModifierData *dtmd = (DataTransferModifierData *)md; + if (dtmd->ob_source != NULL) { + CustomData_MeshMasks cddata_masks = {0}; + BKE_object_data_transfer_dttypes_to_cdmask(dtmd->data_types, &cddata_masks); + BKE_mesh_remap_calc_source_cddata_masks_from_map_modes( + dtmd->vmap_mode, dtmd->emap_mode, dtmd->lmap_mode, dtmd->pmap_mode, &cddata_masks); + + DEG_add_object_relation( + ctx->node, dtmd->ob_source, DEG_OB_COMP_GEOMETRY, "DataTransfer Modifier"); + DEG_add_customdata_mask(ctx->node, dtmd->ob_source, &cddata_masks); + + if (dtmd->flags & MOD_DATATRANSFER_OBSRC_TRANSFORM) { + DEG_add_object_relation( + ctx->node, dtmd->ob_source, DEG_OB_COMP_TRANSFORM, "DataTransfer Modifier"); + DEG_add_modifier_to_transform_relation(ctx->node, "DataTransfer Modifier"); + } + } } -static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams)) +static bool isDisabled(const struct Scene *UNUSED(scene), + ModifierData *md, + bool UNUSED(useRenderParams)) { - DataTransferModifierData *dtmd = (DataTransferModifierData *) md; - /* If no source object, bypass. */ - return (dtmd->ob_source == NULL); + DataTransferModifierData *dtmd = (DataTransferModifierData *)md; + /* If no source object, bypass. */ + return (dtmd->ob_source == NULL); } #define HIGH_POLY_WARNING 10000 -#define DT_TYPES_AFFECT_MESH ( \ - DT_TYPE_BWEIGHT_VERT | \ - DT_TYPE_BWEIGHT_EDGE | DT_TYPE_CREASE | DT_TYPE_SHARP_EDGE | \ - DT_TYPE_LNOR | \ - DT_TYPE_SHARP_FACE \ -) +#define DT_TYPES_AFFECT_MESH \ + (DT_TYPE_BWEIGHT_VERT | DT_TYPE_BWEIGHT_EDGE | DT_TYPE_CREASE | DT_TYPE_SHARP_EDGE | \ + DT_TYPE_LNOR | DT_TYPE_SHARP_FACE) static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *me_mod) { - DataTransferModifierData *dtmd = (DataTransferModifierData *) md; - struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); - Mesh *result = me_mod; - ReportList reports; - - /* Only used to check wehther we are operating on org data or not... */ - Mesh *me = ctx->object->data; - - Object *ob_source = dtmd->ob_source; - - 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, ctx->object, ob_source); - } - - if (((result == me) || (me->mvert == result->mvert) || (me->medge == result->medge)) && - (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. */ - BKE_id_copy_ex(NULL, &me_mod->id, (ID **)&result, LIB_ID_COPY_LOCALIZE); - } - - BKE_reports_init(&reports, RPT_STORE); - - /* Note: no islands precision for now here. */ - BKE_object_data_transfer_ex(ctx->depsgraph, scene, ob_source, ctx->object, result, dtmd->data_types, false, - dtmd->vmap_mode, dtmd->emap_mode, dtmd->lmap_mode, dtmd->pmap_mode, - space_transform, false, 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 ((dtmd->data_types & DT_TYPE_LNOR) && !(me->flag & ME_AUTOSMOOTH)) { - modifier_setError((ModifierData *)dtmd, "Enable 'Auto Smooth' option in mesh settings"); - } - else if (result->totvert > HIGH_POLY_WARNING || ((Mesh *)(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 result; + DataTransferModifierData *dtmd = (DataTransferModifierData *)md; + struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); + Mesh *result = me_mod; + ReportList reports; + + /* Only used to check wehther we are operating on org data or not... */ + Mesh *me = ctx->object->data; + + Object *ob_source = dtmd->ob_source; + + 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, ctx->object, ob_source); + } + + if (((result == me) || (me->mvert == result->mvert) || (me->medge == result->medge)) && + (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. */ + BKE_id_copy_ex(NULL, &me_mod->id, (ID **)&result, LIB_ID_COPY_LOCALIZE); + } + + BKE_reports_init(&reports, RPT_STORE); + + /* Note: no islands precision for now here. */ + BKE_object_data_transfer_ex(ctx->depsgraph, + scene, + ob_source, + ctx->object, + result, + dtmd->data_types, + false, + dtmd->vmap_mode, + dtmd->emap_mode, + dtmd->lmap_mode, + dtmd->pmap_mode, + space_transform, + false, + 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 ((dtmd->data_types & DT_TYPE_LNOR) && !(me->flag & ME_AUTOSMOOTH)) { + modifier_setError((ModifierData *)dtmd, "Enable 'Auto Smooth' option in mesh settings"); + } + else if (result->totvert > HIGH_POLY_WARNING || + ((Mesh *)(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 result; } #undef HIGH_POLY_WARNING #undef DT_TYPES_AFFECT_MESH ModifierTypeInfo modifierType_DataTransfer = { - /* name */ "DataTransfer", - /* structName */ "DataTransferModifierData", - /* structSize */ sizeof(DataTransferModifierData), - /* type */ eModifierTypeType_NonGeometrical, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_SupportsMapping | - eModifierTypeFlag_SupportsEditmode | - eModifierTypeFlag_UsesPreview, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ NULL, - /* isDisabled */ isDisabled, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ dependsOnNormals, - /* foreachObjectLink */ foreachObjectLink, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "DataTransfer", + /* structName */ "DataTransferModifierData", + /* structSize */ sizeof(DataTransferModifierData), + /* type */ eModifierTypeType_NonGeometrical, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping | + eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_UsesPreview, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ NULL, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ dependsOnNormals, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c index 40968f1173f..c41abfb6eb2 100644 --- a/source/blender/modifiers/intern/MOD_decimate.c +++ b/source/blender/modifiers/intern/MOD_decimate.c @@ -50,196 +50,195 @@ static void initData(ModifierData *md) { - DecimateModifierData *dmd = (DecimateModifierData *) md; + DecimateModifierData *dmd = (DecimateModifierData *)md; - dmd->percent = 1.0; - dmd->angle = DEG2RADF(5.0f); - dmd->defgrp_factor = 1.0; + dmd->percent = 1.0; + dmd->angle = DEG2RADF(5.0f); + dmd->defgrp_factor = 1.0; } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - DecimateModifierData *dmd = (DecimateModifierData *) md; + DecimateModifierData *dmd = (DecimateModifierData *)md; - /* ask for vertexgroups if we need them */ - if (dmd->defgrp_name[0] != '\0' && (dmd->defgrp_factor > 0.0f)) { - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; - } + /* ask for vertexgroups if we need them */ + if (dmd->defgrp_name[0] != '\0' && (dmd->defgrp_factor > 0.0f)) { + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + } } -static DecimateModifierData *getOriginalModifierData( - const DecimateModifierData *dmd, const ModifierEvalContext *ctx) +static DecimateModifierData *getOriginalModifierData(const DecimateModifierData *dmd, + const ModifierEvalContext *ctx) { - Object *ob_orig = DEG_get_original_object(ctx->object); - return (DecimateModifierData *)modifiers_findByName(ob_orig, dmd->modifier.name); + Object *ob_orig = DEG_get_original_object(ctx->object); + return (DecimateModifierData *)modifiers_findByName(ob_orig, dmd->modifier.name); } -static void updateFaceCount( - const ModifierEvalContext *ctx, DecimateModifierData *dmd, int face_count) +static void updateFaceCount(const ModifierEvalContext *ctx, + DecimateModifierData *dmd, + int face_count) { - dmd->face_count = face_count; + dmd->face_count = face_count; - if (DEG_is_active(ctx->depsgraph)) { - /* update for display only */ - DecimateModifierData *dmd_orig = getOriginalModifierData(dmd, ctx); - dmd_orig->face_count = face_count; - } + if (DEG_is_active(ctx->depsgraph)) { + /* update for display only */ + DecimateModifierData *dmd_orig = getOriginalModifierData(dmd, ctx); + dmd_orig->face_count = face_count; + } } -static Mesh *applyModifier( - ModifierData *md, const ModifierEvalContext *ctx, - Mesh *meshData) +static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *meshData) { - DecimateModifierData *dmd = (DecimateModifierData *) md; - Mesh *mesh = meshData, *result = NULL; - BMesh *bm; - bool calc_face_normal; - float *vweights = NULL; + DecimateModifierData *dmd = (DecimateModifierData *)md; + Mesh *mesh = meshData, *result = NULL; + BMesh *bm; + bool calc_face_normal; + float *vweights = NULL; #ifdef USE_TIMEIT - TIMEIT_START(decim); + TIMEIT_START(decim); #endif - /* set up front so we dont show invalid info in the UI */ - updateFaceCount(ctx, dmd, mesh->totpoly); - - switch (dmd->mode) { - case MOD_DECIM_MODE_COLLAPSE: - if (dmd->percent == 1.0f) { - return mesh; - } - calc_face_normal = true; - break; - case MOD_DECIM_MODE_UNSUBDIV: - if (dmd->iter == 0) { - return mesh; - } - calc_face_normal = false; - break; - case MOD_DECIM_MODE_DISSOLVE: - if (dmd->angle == 0.0f) { - return mesh; - } - calc_face_normal = true; - break; - default: - return mesh; - } - - if (dmd->face_count <= 3) { - modifier_setError(md, "Modifier requires more than 3 input faces"); - return mesh; - } - - if (dmd->mode == MOD_DECIM_MODE_COLLAPSE) { - if (dmd->defgrp_name[0] && (dmd->defgrp_factor > 0.0f)) { - MDeformVert *dvert; - int defgrp_index; - - MOD_get_vgroup(ctx->object, mesh, dmd->defgrp_name, &dvert, &defgrp_index); - - if (dvert) { - const unsigned int vert_tot = mesh->totvert; - unsigned int i; - - vweights = MEM_malloc_arrayN(vert_tot, sizeof(float), __func__); - - if (dmd->flag & MOD_DECIM_FLAG_INVERT_VGROUP) { - for (i = 0; i < vert_tot; i++) { - vweights[i] = 1.0f - defvert_find_weight(&dvert[i], defgrp_index); - } - } - else { - for (i = 0; i < vert_tot; i++) { - vweights[i] = defvert_find_weight(&dvert[i], defgrp_index); - } - } - } - } - } - - bm = BKE_mesh_to_bmesh_ex( - mesh, - &(struct BMeshCreateParams){0}, - &(struct BMeshFromMeshParams){ - .calc_face_normal = calc_face_normal, - .cd_mask_extra = {.vmask = CD_MASK_ORIGINDEX, .emask = CD_MASK_ORIGINDEX, .pmask = CD_MASK_ORIGINDEX}, - }); - - switch (dmd->mode) { - case MOD_DECIM_MODE_COLLAPSE: - { - const bool do_triangulate = (dmd->flag & MOD_DECIM_FLAG_TRIANGULATE) != 0; - const int symmetry_axis = (dmd->flag & MOD_DECIM_FLAG_SYMMETRY) ? dmd->symmetry_axis : -1; - const float symmetry_eps = 0.00002f; - BM_mesh_decimate_collapse( - bm, dmd->percent, vweights, dmd->defgrp_factor, do_triangulate, - symmetry_axis, symmetry_eps); - break; - } - case MOD_DECIM_MODE_UNSUBDIV: - { - BM_mesh_decimate_unsubdivide(bm, dmd->iter); - break; - } - case MOD_DECIM_MODE_DISSOLVE: - { - const bool 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); - } - - updateFaceCount(ctx, dmd, bm->totface); - - result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL); - 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); + /* set up front so we dont show invalid info in the UI */ + updateFaceCount(ctx, dmd, mesh->totpoly); + + switch (dmd->mode) { + case MOD_DECIM_MODE_COLLAPSE: + if (dmd->percent == 1.0f) { + return mesh; + } + calc_face_normal = true; + break; + case MOD_DECIM_MODE_UNSUBDIV: + if (dmd->iter == 0) { + return mesh; + } + calc_face_normal = false; + break; + case MOD_DECIM_MODE_DISSOLVE: + if (dmd->angle == 0.0f) { + return mesh; + } + calc_face_normal = true; + break; + default: + return mesh; + } + + if (dmd->face_count <= 3) { + modifier_setError(md, "Modifier requires more than 3 input faces"); + return mesh; + } + + if (dmd->mode == MOD_DECIM_MODE_COLLAPSE) { + if (dmd->defgrp_name[0] && (dmd->defgrp_factor > 0.0f)) { + MDeformVert *dvert; + int defgrp_index; + + MOD_get_vgroup(ctx->object, mesh, dmd->defgrp_name, &dvert, &defgrp_index); + + if (dvert) { + const unsigned int vert_tot = mesh->totvert; + unsigned int i; + + vweights = MEM_malloc_arrayN(vert_tot, sizeof(float), __func__); + + if (dmd->flag & MOD_DECIM_FLAG_INVERT_VGROUP) { + for (i = 0; i < vert_tot; i++) { + vweights[i] = 1.0f - defvert_find_weight(&dvert[i], defgrp_index); + } + } + else { + for (i = 0; i < vert_tot; i++) { + vweights[i] = defvert_find_weight(&dvert[i], defgrp_index); + } + } + } + } + } + + bm = BKE_mesh_to_bmesh_ex(mesh, + &(struct BMeshCreateParams){0}, + &(struct BMeshFromMeshParams){ + .calc_face_normal = calc_face_normal, + .cd_mask_extra = {.vmask = CD_MASK_ORIGINDEX, + .emask = CD_MASK_ORIGINDEX, + .pmask = CD_MASK_ORIGINDEX}, + }); + + switch (dmd->mode) { + case MOD_DECIM_MODE_COLLAPSE: { + const bool do_triangulate = (dmd->flag & MOD_DECIM_FLAG_TRIANGULATE) != 0; + const int symmetry_axis = (dmd->flag & MOD_DECIM_FLAG_SYMMETRY) ? dmd->symmetry_axis : -1; + const float symmetry_eps = 0.00002f; + BM_mesh_decimate_collapse(bm, + dmd->percent, + vweights, + dmd->defgrp_factor, + do_triangulate, + symmetry_axis, + symmetry_eps); + break; + } + case MOD_DECIM_MODE_UNSUBDIV: { + BM_mesh_decimate_unsubdivide(bm, dmd->iter); + break; + } + case MOD_DECIM_MODE_DISSOLVE: { + const bool 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); + } + + updateFaceCount(ctx, dmd, bm->totface); + + result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL); + 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); + TIMEIT_END(decim); #endif - result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; - return result; + return result; } ModifierTypeInfo modifierType_Decimate = { - /* name */ "Decimate", - /* structName */ "DecimateModifierData", - /* structSize */ sizeof(DecimateModifierData), - /* type */ eModifierTypeType_Nonconstructive, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_AcceptsCVs, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ NULL, - /* isDisabled */ NULL, - /* updateDepsgraph */ NULL, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ NULL, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Decimate", + /* structName */ "DecimateModifierData", + /* structSize */ sizeof(DecimateModifierData), + /* type */ eModifierTypeType_Nonconstructive, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c index 0060639970c..b0c633b1cdd 100644 --- a/source/blender/modifiers/intern/MOD_displace.c +++ b/source/blender/modifiers/intern/MOD_displace.c @@ -21,7 +21,6 @@ * \ingroup modifiers */ - #include "BLI_utildefines.h" #include "BLI_math.h" @@ -51,376 +50,376 @@ #include "RE_shader_ext.h" - /* Displace */ static void initData(ModifierData *md) { - DisplaceModifierData *dmd = (DisplaceModifierData *) md; + DisplaceModifierData *dmd = (DisplaceModifierData *)md; - dmd->texture = NULL; - dmd->strength = 1; - dmd->direction = MOD_DISP_DIR_NOR; - dmd->midlevel = 0.5; - dmd->space = MOD_DISP_SPACE_LOCAL; + dmd->texture = NULL; + dmd->strength = 1; + dmd->direction = MOD_DISP_DIR_NOR; + dmd->midlevel = 0.5; + dmd->space = MOD_DISP_SPACE_LOCAL; } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - DisplaceModifierData *dmd = (DisplaceModifierData *)md; + DisplaceModifierData *dmd = (DisplaceModifierData *)md; - /* ask for vertexgroups if we need them */ - if (dmd->defgrp_name[0] != '\0') { - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; - } + /* ask for vertexgroups if we need them */ + if (dmd->defgrp_name[0] != '\0') { + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + } - /* ask for UV coordinates if we need them */ - if (dmd->texmapping == MOD_DISP_MAP_UV) { - r_cddata_masks->fmask |= CD_MASK_MTFACE; - } + /* ask for UV coordinates if we need them */ + if (dmd->texmapping == MOD_DISP_MAP_UV) { + r_cddata_masks->fmask |= CD_MASK_MTFACE; + } - if (dmd->direction == MOD_DISP_DIR_CLNOR) { - r_cddata_masks->lmask |= CD_MASK_CUSTOMLOOPNORMAL; - } + if (dmd->direction == MOD_DISP_DIR_CLNOR) { + r_cddata_masks->lmask |= CD_MASK_CUSTOMLOOPNORMAL; + } } static bool dependsOnTime(ModifierData *md) { - DisplaceModifierData *dmd = (DisplaceModifierData *)md; - - if (dmd->texture) { - return BKE_texture_dependsOnTime(dmd->texture); - } - else { - return false; - } + DisplaceModifierData *dmd = (DisplaceModifierData *)md; + + if (dmd->texture) { + return BKE_texture_dependsOnTime(dmd->texture); + } + else { + return false; + } } static bool dependsOnNormals(ModifierData *md) { - DisplaceModifierData *dmd = (DisplaceModifierData *)md; - return ELEM(dmd->direction, MOD_DISP_DIR_NOR, MOD_DISP_DIR_CLNOR); + DisplaceModifierData *dmd = (DisplaceModifierData *)md; + return ELEM(dmd->direction, MOD_DISP_DIR_NOR, MOD_DISP_DIR_CLNOR); } -static void foreachObjectLink( - ModifierData *md, Object *ob, - ObjectWalkFunc walk, void *userData) +static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) { - DisplaceModifierData *dmd = (DisplaceModifierData *) md; + DisplaceModifierData *dmd = (DisplaceModifierData *)md; - walk(userData, ob, &dmd->map_object, IDWALK_CB_NOP); + walk(userData, ob, &dmd->map_object, IDWALK_CB_NOP); } -static void foreachIDLink( - ModifierData *md, Object *ob, - IDWalkFunc walk, void *userData) +static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData) { - DisplaceModifierData *dmd = (DisplaceModifierData *) md; + DisplaceModifierData *dmd = (DisplaceModifierData *)md; - walk(userData, ob, (ID **)&dmd->texture, IDWALK_CB_USER); + walk(userData, ob, (ID **)&dmd->texture, IDWALK_CB_USER); - foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData); + foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData); } -static void foreachTexLink( - ModifierData *md, Object *ob, - TexWalkFunc walk, void *userData) +static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void *userData) { - walk(userData, ob, md, "texture"); + walk(userData, ob, md, "texture"); } -static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams)) +static bool isDisabled(const struct Scene *UNUSED(scene), + ModifierData *md, + bool UNUSED(useRenderParams)) { - DisplaceModifierData *dmd = (DisplaceModifierData *) md; - return ((!dmd->texture && dmd->direction == MOD_DISP_DIR_RGB_XYZ) || dmd->strength == 0.0f); + DisplaceModifierData *dmd = (DisplaceModifierData *)md; + return ((!dmd->texture && dmd->direction == MOD_DISP_DIR_RGB_XYZ) || dmd->strength == 0.0f); } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { - DisplaceModifierData *dmd = (DisplaceModifierData *)md; - if (dmd->map_object != NULL && dmd->texmapping == MOD_DISP_MAP_OBJECT) { - DEG_add_modifier_to_transform_relation(ctx->node, "Displace Modifier"); - DEG_add_object_relation(ctx->node, dmd->map_object, DEG_OB_COMP_TRANSFORM, "Displace Modifier"); - } - if (dmd->texmapping == MOD_DISP_MAP_GLOBAL || - (ELEM(dmd->direction, MOD_DISP_DIR_X, MOD_DISP_DIR_Y, MOD_DISP_DIR_Z, MOD_DISP_DIR_RGB_XYZ) && - dmd->space == MOD_DISP_SPACE_GLOBAL)) - { - DEG_add_modifier_to_transform_relation(ctx->node, "Displace Modifier"); - } - if (dmd->texture != NULL) { - DEG_add_generic_id_relation(ctx->node, &dmd->texture->id, "Displace Modifier"); - } + DisplaceModifierData *dmd = (DisplaceModifierData *)md; + if (dmd->map_object != NULL && dmd->texmapping == MOD_DISP_MAP_OBJECT) { + DEG_add_modifier_to_transform_relation(ctx->node, "Displace Modifier"); + DEG_add_object_relation( + ctx->node, dmd->map_object, DEG_OB_COMP_TRANSFORM, "Displace Modifier"); + } + if (dmd->texmapping == MOD_DISP_MAP_GLOBAL || + (ELEM( + dmd->direction, MOD_DISP_DIR_X, MOD_DISP_DIR_Y, MOD_DISP_DIR_Z, MOD_DISP_DIR_RGB_XYZ) && + dmd->space == MOD_DISP_SPACE_GLOBAL)) { + DEG_add_modifier_to_transform_relation(ctx->node, "Displace Modifier"); + } + if (dmd->texture != NULL) { + DEG_add_generic_id_relation(ctx->node, &dmd->texture->id, "Displace Modifier"); + } } typedef struct DisplaceUserdata { - /*const*/ DisplaceModifierData *dmd; - struct Scene *scene; - struct ImagePool *pool; - MDeformVert *dvert; - float weight; - int defgrp_index; - int direction; - bool use_global_direction; - Tex *tex_target; - float (*tex_co)[3]; - float (*vertexCos)[3]; - float local_mat[4][4]; - MVert *mvert; - float (*vert_clnors)[3]; + /*const*/ DisplaceModifierData *dmd; + struct Scene *scene; + struct ImagePool *pool; + MDeformVert *dvert; + float weight; + int defgrp_index; + int direction; + bool use_global_direction; + Tex *tex_target; + float (*tex_co)[3]; + float (*vertexCos)[3]; + float local_mat[4][4]; + MVert *mvert; + float (*vert_clnors)[3]; } DisplaceUserdata; -static void displaceModifier_do_task( - void *__restrict userdata, - const int iter, - const ParallelRangeTLS *__restrict UNUSED(tls)) +static void displaceModifier_do_task(void *__restrict userdata, + const int iter, + const ParallelRangeTLS *__restrict UNUSED(tls)) { - DisplaceUserdata *data = (DisplaceUserdata *)userdata; - DisplaceModifierData *dmd = data->dmd; - MDeformVert *dvert = data->dvert; - float weight = data->weight; - int defgrp_index = data->defgrp_index; - int direction = data->direction; - bool use_global_direction = data->use_global_direction; - float (*tex_co)[3] = data->tex_co; - float (*vertexCos)[3] = data->vertexCos; - MVert *mvert = data->mvert; - float (*vert_clnors)[3] = data->vert_clnors; - - const float delta_fixed = 1.0f - dmd->midlevel; /* when no texture is used, we fallback to white */ - - TexResult texres; - float strength = dmd->strength; - float delta; - float local_vec[3]; - - if (dvert) { - weight = defvert_find_weight(dvert + iter, defgrp_index); - if (weight == 0.0f) { - return; - } - } - - if (data->tex_target) { - texres.nor = NULL; - BKE_texture_get_value_ex(data->scene, data->tex_target, tex_co[iter], &texres, data->pool, false); - delta = texres.tin - dmd->midlevel; - } - else { - delta = delta_fixed; /* (1.0f - dmd->midlevel) */ /* never changes */ - } - - if (dvert) { - strength *= weight; - } - - delta *= strength; - CLAMP(delta, -10000, 10000); - - switch (direction) { - case MOD_DISP_DIR_X: - if (use_global_direction) { - vertexCos[iter][0] += delta * data->local_mat[0][0]; - vertexCos[iter][1] += delta * data->local_mat[1][0]; - vertexCos[iter][2] += delta * data->local_mat[2][0]; - } - else { - vertexCos[iter][0] += delta; - } - break; - case MOD_DISP_DIR_Y: - if (use_global_direction) { - vertexCos[iter][0] += delta * data->local_mat[0][1]; - vertexCos[iter][1] += delta * data->local_mat[1][1]; - vertexCos[iter][2] += delta * data->local_mat[2][1]; - } - else { - vertexCos[iter][1] += delta; - } - break; - case MOD_DISP_DIR_Z: - if (use_global_direction) { - vertexCos[iter][0] += delta * data->local_mat[0][2]; - vertexCos[iter][1] += delta * data->local_mat[1][2]; - vertexCos[iter][2] += delta * data->local_mat[2][2]; - } - else { - vertexCos[iter][2] += delta; - } - break; - case MOD_DISP_DIR_RGB_XYZ: - local_vec[0] = texres.tr - dmd->midlevel; - local_vec[1] = texres.tg - dmd->midlevel; - local_vec[2] = texres.tb - dmd->midlevel; - if (use_global_direction) { - mul_transposed_mat3_m4_v3(data->local_mat, local_vec); - } - mul_v3_fl(local_vec, strength); - add_v3_v3(vertexCos[iter], local_vec); - break; - case MOD_DISP_DIR_NOR: - vertexCos[iter][0] += delta * (mvert[iter].no[0] / 32767.0f); - vertexCos[iter][1] += delta * (mvert[iter].no[1] / 32767.0f); - vertexCos[iter][2] += delta * (mvert[iter].no[2] / 32767.0f); - break; - case MOD_DISP_DIR_CLNOR: - madd_v3_v3fl(vertexCos[iter], vert_clnors[iter], delta); - break; - } + DisplaceUserdata *data = (DisplaceUserdata *)userdata; + DisplaceModifierData *dmd = data->dmd; + MDeformVert *dvert = data->dvert; + float weight = data->weight; + int defgrp_index = data->defgrp_index; + int direction = data->direction; + bool use_global_direction = data->use_global_direction; + float(*tex_co)[3] = data->tex_co; + float(*vertexCos)[3] = data->vertexCos; + MVert *mvert = data->mvert; + float(*vert_clnors)[3] = data->vert_clnors; + + const float delta_fixed = 1.0f - + dmd->midlevel; /* when no texture is used, we fallback to white */ + + TexResult texres; + float strength = dmd->strength; + float delta; + float local_vec[3]; + + if (dvert) { + weight = defvert_find_weight(dvert + iter, defgrp_index); + if (weight == 0.0f) { + return; + } + } + + if (data->tex_target) { + texres.nor = NULL; + BKE_texture_get_value_ex( + data->scene, data->tex_target, tex_co[iter], &texres, data->pool, false); + delta = texres.tin - dmd->midlevel; + } + else { + delta = delta_fixed; /* (1.0f - dmd->midlevel) */ /* never changes */ + } + + if (dvert) { + strength *= weight; + } + + delta *= strength; + CLAMP(delta, -10000, 10000); + + switch (direction) { + case MOD_DISP_DIR_X: + if (use_global_direction) { + vertexCos[iter][0] += delta * data->local_mat[0][0]; + vertexCos[iter][1] += delta * data->local_mat[1][0]; + vertexCos[iter][2] += delta * data->local_mat[2][0]; + } + else { + vertexCos[iter][0] += delta; + } + break; + case MOD_DISP_DIR_Y: + if (use_global_direction) { + vertexCos[iter][0] += delta * data->local_mat[0][1]; + vertexCos[iter][1] += delta * data->local_mat[1][1]; + vertexCos[iter][2] += delta * data->local_mat[2][1]; + } + else { + vertexCos[iter][1] += delta; + } + break; + case MOD_DISP_DIR_Z: + if (use_global_direction) { + vertexCos[iter][0] += delta * data->local_mat[0][2]; + vertexCos[iter][1] += delta * data->local_mat[1][2]; + vertexCos[iter][2] += delta * data->local_mat[2][2]; + } + else { + vertexCos[iter][2] += delta; + } + break; + case MOD_DISP_DIR_RGB_XYZ: + local_vec[0] = texres.tr - dmd->midlevel; + local_vec[1] = texres.tg - dmd->midlevel; + local_vec[2] = texres.tb - dmd->midlevel; + if (use_global_direction) { + mul_transposed_mat3_m4_v3(data->local_mat, local_vec); + } + mul_v3_fl(local_vec, strength); + add_v3_v3(vertexCos[iter], local_vec); + break; + case MOD_DISP_DIR_NOR: + vertexCos[iter][0] += delta * (mvert[iter].no[0] / 32767.0f); + vertexCos[iter][1] += delta * (mvert[iter].no[1] / 32767.0f); + vertexCos[iter][2] += delta * (mvert[iter].no[2] / 32767.0f); + break; + case MOD_DISP_DIR_CLNOR: + madd_v3_v3fl(vertexCos[iter], vert_clnors[iter], delta); + break; + } } -static void displaceModifier_do( - DisplaceModifierData *dmd, const ModifierEvalContext *ctx, - Mesh *mesh, float (*vertexCos)[3], const int numVerts) +static void displaceModifier_do(DisplaceModifierData *dmd, + const ModifierEvalContext *ctx, + Mesh *mesh, + float (*vertexCos)[3], + const int numVerts) { - Object *ob = ctx->object; - MVert *mvert; - MDeformVert *dvert; - int direction = dmd->direction; - int defgrp_index; - float (*tex_co)[3]; - float weight = 1.0f; /* init value unused but some compilers may complain */ - float (*vert_clnors)[3] = NULL; - float local_mat[4][4] = {{0}}; - const bool use_global_direction = dmd->space == MOD_DISP_SPACE_GLOBAL; - - if (dmd->texture == NULL && dmd->direction == MOD_DISP_DIR_RGB_XYZ) return; - if (dmd->strength == 0.0f) return; - - mvert = mesh->mvert; - MOD_get_vgroup(ob, mesh, dmd->defgrp_name, &dvert, &defgrp_index); - - Tex *tex_target = dmd->texture; - if (tex_target != NULL) { - tex_co = MEM_calloc_arrayN((size_t)numVerts, sizeof(*tex_co), - "displaceModifier_do tex_co"); - MOD_get_texture_coords((MappingInfoModifierData *)dmd, ctx, ob, mesh, vertexCos, tex_co); - - MOD_init_texture((MappingInfoModifierData *)dmd, ctx); - } - else { - tex_co = NULL; - } - - if (direction == MOD_DISP_DIR_CLNOR) { - CustomData *ldata = &mesh->ldata; - - if (CustomData_has_layer(ldata, CD_CUSTOMLOOPNORMAL)) { - float (*clnors)[3] = NULL; - - if ((mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) || !CustomData_has_layer(ldata, CD_NORMAL)) { - BKE_mesh_calc_normals_split(mesh); - } - - clnors = CustomData_get_layer(ldata, CD_NORMAL); - vert_clnors = MEM_malloc_arrayN(numVerts, sizeof(*vert_clnors), __func__); - BKE_mesh_normals_loop_to_vertex(numVerts, mesh->mloop, mesh->totloop, - (const float (*)[3])clnors, vert_clnors); - } - else { - direction = MOD_DISP_DIR_NOR; - } - } - else if (ELEM(direction, MOD_DISP_DIR_X, MOD_DISP_DIR_Y, MOD_DISP_DIR_Z, MOD_DISP_DIR_RGB_XYZ) && - use_global_direction) - { - copy_m4_m4(local_mat, ob->obmat); - } - - DisplaceUserdata data = {NULL}; - data.scene = DEG_get_evaluated_scene(ctx->depsgraph); - data.dmd = dmd; - data.dvert = dvert; - data.weight = weight; - data.defgrp_index = defgrp_index; - data.direction = direction; - data.use_global_direction = use_global_direction; - data.tex_target = tex_target; - data.tex_co = tex_co; - data.vertexCos = vertexCos; - copy_m4_m4(data.local_mat, local_mat); - data.mvert = mvert; - data.vert_clnors = vert_clnors; - if (tex_target != NULL) { - data.pool = BKE_image_pool_new(); - BKE_texture_fetch_images_for_pool(tex_target, data.pool); - } - ParallelRangeSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = (numVerts > 512); - BLI_task_parallel_range(0, numVerts, - &data, - displaceModifier_do_task, - &settings); - - if (data.pool != NULL) { - BKE_image_pool_free(data.pool); - } - - if (tex_co) { - MEM_freeN(tex_co); - } - - if (vert_clnors) { - MEM_freeN(vert_clnors); - } + Object *ob = ctx->object; + MVert *mvert; + MDeformVert *dvert; + int direction = dmd->direction; + int defgrp_index; + float(*tex_co)[3]; + float weight = 1.0f; /* init value unused but some compilers may complain */ + float(*vert_clnors)[3] = NULL; + float local_mat[4][4] = {{0}}; + const bool use_global_direction = dmd->space == MOD_DISP_SPACE_GLOBAL; + + if (dmd->texture == NULL && dmd->direction == MOD_DISP_DIR_RGB_XYZ) + return; + if (dmd->strength == 0.0f) + return; + + mvert = mesh->mvert; + MOD_get_vgroup(ob, mesh, dmd->defgrp_name, &dvert, &defgrp_index); + + Tex *tex_target = dmd->texture; + if (tex_target != NULL) { + tex_co = MEM_calloc_arrayN((size_t)numVerts, sizeof(*tex_co), "displaceModifier_do tex_co"); + MOD_get_texture_coords((MappingInfoModifierData *)dmd, ctx, ob, mesh, vertexCos, tex_co); + + MOD_init_texture((MappingInfoModifierData *)dmd, ctx); + } + else { + tex_co = NULL; + } + + if (direction == MOD_DISP_DIR_CLNOR) { + CustomData *ldata = &mesh->ldata; + + if (CustomData_has_layer(ldata, CD_CUSTOMLOOPNORMAL)) { + float(*clnors)[3] = NULL; + + if ((mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) || + !CustomData_has_layer(ldata, CD_NORMAL)) { + BKE_mesh_calc_normals_split(mesh); + } + + clnors = CustomData_get_layer(ldata, CD_NORMAL); + vert_clnors = MEM_malloc_arrayN(numVerts, sizeof(*vert_clnors), __func__); + BKE_mesh_normals_loop_to_vertex( + numVerts, mesh->mloop, mesh->totloop, (const float(*)[3])clnors, vert_clnors); + } + else { + direction = MOD_DISP_DIR_NOR; + } + } + else if (ELEM(direction, MOD_DISP_DIR_X, MOD_DISP_DIR_Y, MOD_DISP_DIR_Z, MOD_DISP_DIR_RGB_XYZ) && + use_global_direction) { + copy_m4_m4(local_mat, ob->obmat); + } + + DisplaceUserdata data = {NULL}; + data.scene = DEG_get_evaluated_scene(ctx->depsgraph); + data.dmd = dmd; + data.dvert = dvert; + data.weight = weight; + data.defgrp_index = defgrp_index; + data.direction = direction; + data.use_global_direction = use_global_direction; + data.tex_target = tex_target; + data.tex_co = tex_co; + data.vertexCos = vertexCos; + copy_m4_m4(data.local_mat, local_mat); + data.mvert = mvert; + data.vert_clnors = vert_clnors; + if (tex_target != NULL) { + data.pool = BKE_image_pool_new(); + BKE_texture_fetch_images_for_pool(tex_target, data.pool); + } + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (numVerts > 512); + BLI_task_parallel_range(0, numVerts, &data, displaceModifier_do_task, &settings); + + if (data.pool != NULL) { + BKE_image_pool_free(data.pool); + } + + if (tex_co) { + MEM_freeN(tex_co); + } + + if (vert_clnors) { + MEM_freeN(vert_clnors); + } } -static void deformVerts( - ModifierData *md, - const ModifierEvalContext *ctx, - Mesh *mesh, - float (*vertexCos)[3], - int numVerts) +static void deformVerts(ModifierData *md, + const ModifierEvalContext *ctx, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); + Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); - displaceModifier_do((DisplaceModifierData *)md, ctx, mesh_src, vertexCos, numVerts); + displaceModifier_do((DisplaceModifierData *)md, ctx, mesh_src, vertexCos, numVerts); - if (!ELEM(mesh_src, NULL, mesh)) { - BKE_id_free(NULL, mesh_src); - } + if (!ELEM(mesh_src, NULL, mesh)) { + BKE_id_free(NULL, mesh_src); + } } -static void deformVertsEM( - ModifierData *md, const ModifierEvalContext *ctx, struct BMEditMesh *editData, - Mesh *mesh, float (*vertexCos)[3], int numVerts) +static void deformVertsEM(ModifierData *md, + const ModifierEvalContext *ctx, + struct BMEditMesh *editData, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false); + Mesh *mesh_src = MOD_deform_mesh_eval_get( + ctx->object, editData, mesh, NULL, numVerts, false, false); - displaceModifier_do((DisplaceModifierData *)md, ctx, mesh_src, vertexCos, numVerts); + displaceModifier_do((DisplaceModifierData *)md, ctx, mesh_src, vertexCos, numVerts); - if (!ELEM(mesh_src, NULL, mesh)) { - BKE_id_free(NULL, mesh_src); - } + if (!ELEM(mesh_src, NULL, mesh)) { + BKE_id_free(NULL, mesh_src); + } } - ModifierTypeInfo modifierType_Displace = { - /* name */ "Displace", - /* structName */ "DisplaceModifierData", - /* structSize */ sizeof(DisplaceModifierData), - /* type */ eModifierTypeType_OnlyDeform, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_SupportsEditmode, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ deformVerts, - /* deformMatrices */ NULL, - /* deformVertsEM */ deformVertsEM, - /* deformMatricesEM */ NULL, - /* applyModifier */ NULL, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ NULL, - /* isDisabled */ isDisabled, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ dependsOnTime, - /* dependsOnNormals */ dependsOnNormals, - /* foreachObjectLink */ foreachObjectLink, - /* foreachIDLink */ foreachIDLink, - /* foreachTexLink */ foreachTexLink, - /* freeRuntimeData */ NULL, + /* name */ "Displace", + /* structName */ "DisplaceModifierData", + /* structSize */ sizeof(DisplaceModifierData), + /* type */ eModifierTypeType_OnlyDeform, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsEditmode, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ deformVerts, + /* deformMatrices */ NULL, + /* deformVertsEM */ deformVertsEM, + /* deformMatricesEM */ NULL, + /* applyModifier */ NULL, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ NULL, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ dependsOnTime, + /* dependsOnNormals */ dependsOnNormals, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ foreachIDLink, + /* foreachTexLink */ foreachTexLink, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_dynamicpaint.c b/source/blender/modifiers/intern/MOD_dynamicpaint.c index badf3df6b1d..ccd71455b21 100644 --- a/source/blender/modifiers/intern/MOD_dynamicpaint.c +++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c @@ -43,157 +43,160 @@ static void initData(ModifierData *md) { - DynamicPaintModifierData *pmd = (DynamicPaintModifierData *) md; + DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md; - pmd->canvas = NULL; - pmd->brush = NULL; - pmd->type = MOD_DYNAMICPAINT_TYPE_CANVAS; + pmd->canvas = NULL; + pmd->brush = NULL; + pmd->type = MOD_DYNAMICPAINT_TYPE_CANVAS; } static void copyData(const ModifierData *md, ModifierData *target, const int flag) { - const DynamicPaintModifierData *pmd = (const DynamicPaintModifierData *)md; - DynamicPaintModifierData *tpmd = (DynamicPaintModifierData *)target; + const DynamicPaintModifierData *pmd = (const DynamicPaintModifierData *)md; + DynamicPaintModifierData *tpmd = (DynamicPaintModifierData *)target; - dynamicPaint_Modifier_copy(pmd, tpmd, flag); + dynamicPaint_Modifier_copy(pmd, tpmd, flag); } static void freeRuntimeData(void *runtime_data_v) { - if (runtime_data_v == NULL) { - return; - } - DynamicPaintRuntime *runtime_data = (DynamicPaintRuntime *)runtime_data_v; - dynamicPaint_Modifier_free_runtime(runtime_data); + if (runtime_data_v == NULL) { + return; + } + DynamicPaintRuntime *runtime_data = (DynamicPaintRuntime *)runtime_data_v; + dynamicPaint_Modifier_free_runtime(runtime_data); } static void freeData(ModifierData *md) { - DynamicPaintModifierData *pmd = (DynamicPaintModifierData *) md; - dynamicPaint_Modifier_free(pmd); + DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md; + dynamicPaint_Modifier_free(pmd); } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md; - - if (pmd->canvas) { - DynamicPaintSurface *surface = pmd->canvas->surfaces.first; - for (; surface; surface = surface->next) { - /* tface */ - if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ || - surface->init_color_type == MOD_DPAINT_INITIAL_TEXTURE) - { - r_cddata_masks->lmask |= CD_MASK_MLOOPUV; - } - /* mcol */ - if (surface->type == MOD_DPAINT_SURFACE_T_PAINT || - surface->init_color_type == MOD_DPAINT_INITIAL_VERTEXCOLOR) - { - r_cddata_masks->lmask |= CD_MASK_MLOOPCOL; - } - /* CD_MDEFORMVERT */ - if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) { - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; - } - } - } + DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md; + + if (pmd->canvas) { + DynamicPaintSurface *surface = pmd->canvas->surfaces.first; + for (; surface; surface = surface->next) { + /* tface */ + if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ || + surface->init_color_type == MOD_DPAINT_INITIAL_TEXTURE) { + r_cddata_masks->lmask |= CD_MASK_MLOOPUV; + } + /* mcol */ + if (surface->type == MOD_DPAINT_SURFACE_T_PAINT || + surface->init_color_type == MOD_DPAINT_INITIAL_VERTEXCOLOR) { + r_cddata_masks->lmask |= CD_MASK_MLOOPCOL; + } + /* CD_MDEFORMVERT */ + if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) { + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + } + } + } } -static Mesh *applyModifier( - ModifierData *md, const ModifierEvalContext *ctx, - Mesh *mesh) +static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) { - DynamicPaintModifierData *pmd = (DynamicPaintModifierData *) md; - - /* dont apply dynamic paint on orco mesh stack */ - if (!(ctx->flag & MOD_APPLY_ORCO)) { - Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); - return dynamicPaint_Modifier_do(pmd, ctx->depsgraph, scene, ctx->object, mesh); - } - return mesh; + DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md; + + /* dont apply dynamic paint on orco mesh stack */ + if (!(ctx->flag & MOD_APPLY_ORCO)) { + Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); + return dynamicPaint_Modifier_do(pmd, ctx->depsgraph, scene, ctx->object, mesh); + } + return mesh; } static bool is_brush_cb(Object *UNUSED(ob), ModifierData *pmd) { - return ((DynamicPaintModifierData *)pmd)->brush != NULL; + return ((DynamicPaintModifierData *)pmd)->brush != NULL; } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { - DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md; - /* Add relation from canvases to all brush objects. */ - if (pmd->canvas != NULL) { - for (DynamicPaintSurface *surface = pmd->canvas->surfaces.first; surface; surface = surface->next) { - if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) { - DEG_add_forcefield_relations(ctx->node, ctx->object, surface->effector_weights, true, 0, "Dynamic Paint Field"); - } - - /* Actual code uses custom loop over group/scene without layer checks in dynamicPaint_doStep */ - DEG_add_collision_relations(ctx->node, ctx->object, surface->brush_group, eModifierType_DynamicPaint, is_brush_cb, "Dynamic Paint Brush"); - } - } + DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md; + /* Add relation from canvases to all brush objects. */ + if (pmd->canvas != NULL) { + for (DynamicPaintSurface *surface = pmd->canvas->surfaces.first; surface; + surface = surface->next) { + if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) { + DEG_add_forcefield_relations( + ctx->node, ctx->object, surface->effector_weights, true, 0, "Dynamic Paint Field"); + } + + /* Actual code uses custom loop over group/scene without layer checks in dynamicPaint_doStep */ + DEG_add_collision_relations(ctx->node, + ctx->object, + surface->brush_group, + eModifierType_DynamicPaint, + is_brush_cb, + "Dynamic Paint Brush"); + } + } } static bool dependsOnTime(ModifierData *UNUSED(md)) { - return true; + return true; } -static void foreachIDLink( - ModifierData *md, Object *ob, - IDWalkFunc walk, void *userData) +static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData) { - DynamicPaintModifierData *pmd = (DynamicPaintModifierData *) md; - - if (pmd->canvas) { - DynamicPaintSurface *surface = pmd->canvas->surfaces.first; - - for (; surface; surface = surface->next) { - walk(userData, ob, (ID **)&surface->brush_group, IDWALK_CB_NOP); - walk(userData, ob, (ID **)&surface->init_texture, IDWALK_CB_USER); - if (surface->effector_weights) { - walk(userData, ob, (ID **)&surface->effector_weights->group, IDWALK_CB_NOP); - } - } - } + DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md; + + if (pmd->canvas) { + DynamicPaintSurface *surface = pmd->canvas->surfaces.first; + + for (; surface; surface = surface->next) { + walk(userData, ob, (ID **)&surface->brush_group, IDWALK_CB_NOP); + walk(userData, ob, (ID **)&surface->init_texture, IDWALK_CB_USER); + if (surface->effector_weights) { + walk(userData, ob, (ID **)&surface->effector_weights->group, IDWALK_CB_NOP); + } + } + } } -static void foreachTexLink( - ModifierData *UNUSED(md), Object *UNUSED(ob), - TexWalkFunc UNUSED(walk), void *UNUSED(userData)) +static void foreachTexLink(ModifierData *UNUSED(md), + Object *UNUSED(ob), + TexWalkFunc UNUSED(walk), + void *UNUSED(userData)) { - //walk(userData, ob, md, ""); /* re-enable when possible */ + //walk(userData, ob, md, ""); /* re-enable when possible */ } ModifierTypeInfo modifierType_DynamicPaint = { - /* name */ "Dynamic Paint", - /* structName */ "DynamicPaintModifierData", - /* structSize */ sizeof(DynamicPaintModifierData), - /* type */ eModifierTypeType_Constructive, - /* flags */ eModifierTypeFlag_AcceptsMesh | -/* eModifierTypeFlag_SupportsMapping |*/ - eModifierTypeFlag_UsesPointCache | - eModifierTypeFlag_Single | - eModifierTypeFlag_UsesPreview, - - /* copyData */ copyData, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ freeData, - /* isDisabled */ NULL, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ dependsOnTime, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ NULL, - /* foreachIDLink */ foreachIDLink, - /* foreachTexLink */ foreachTexLink, - /* freeRuntimeData */ freeRuntimeData, + /* name */ "Dynamic Paint", + /* structName */ "DynamicPaintModifierData", + /* structSize */ sizeof(DynamicPaintModifierData), + /* type */ eModifierTypeType_Constructive, + /* flags */ eModifierTypeFlag_AcceptsMesh | + /* eModifierTypeFlag_SupportsMapping |*/ + eModifierTypeFlag_UsesPointCache | eModifierTypeFlag_Single | + eModifierTypeFlag_UsesPreview, + + /* copyData */ copyData, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ freeData, + /* isDisabled */ NULL, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ dependsOnTime, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ foreachIDLink, + /* foreachTexLink */ foreachTexLink, + /* freeRuntimeData */ freeRuntimeData, }; diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c index 751a70916ab..9c2ad13db94 100644 --- a/source/blender/modifiers/intern/MOD_edgesplit.c +++ b/source/blender/modifiers/intern/MOD_edgesplit.c @@ -43,124 +43,115 @@ static Mesh *doEdgeSplit(Mesh *mesh, EdgeSplitModifierData *emd) { - Mesh *result; - BMesh *bm; - BMIter iter; - BMEdge *e; - const float threshold = cosf(emd->split_angle + 0.000000175f); - const bool do_split_angle = (emd->flags & MOD_EDGESPLIT_FROMANGLE) != 0 && emd->split_angle < (float)M_PI; - const bool do_split_all = do_split_angle && emd->split_angle < FLT_EPSILON; - const bool calc_face_normals = do_split_angle && !do_split_all; - - bm = BKE_mesh_to_bmesh_ex( - mesh, - &(struct BMeshCreateParams){0}, - &(struct BMeshFromMeshParams){ - .calc_face_normal = calc_face_normals, - .add_key_index = false, - .use_shapekey = false, - .active_shapekey = 0, - .cd_mask_extra = {.vmask = CD_MASK_ORIGINDEX, .emask = CD_MASK_ORIGINDEX, .pmask = CD_MASK_ORIGINDEX}, - }); - - if (do_split_angle) { - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - /* check for 1 edge having 2 face users */ - BMLoop *l1, *l2; - if ((l1 = e->l) && - (l2 = e->l->radial_next) != l1) - { - if (/* 3+ faces on this edge, always split */ - UNLIKELY(l1 != l2->radial_next) || - /* O° angle setting, we want to split on all edges. */ - do_split_all || - /* 2 face edge - check angle*/ - (dot_v3v3(l1->f->no, l2->f->no) < threshold)) - { - BM_elem_flag_enable(e, BM_ELEM_TAG); - } - } - } - } - - if (emd->flags & MOD_EDGESPLIT_FROMFLAG) { - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - /* check for 2 or more edge users */ - if ((e->l) && - (e->l->next != e->l)) - { - if (!BM_elem_flag_test(e, BM_ELEM_SMOOTH)) { - BM_elem_flag_enable(e, BM_ELEM_TAG); - } - } - } - } - - BM_mesh_edgesplit(bm, false, true, false); - - /* BM_mesh_validate(bm); */ /* for troubleshooting */ - - result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL); - BM_mesh_free(bm); - - result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; - return result; + Mesh *result; + BMesh *bm; + BMIter iter; + BMEdge *e; + const float threshold = cosf(emd->split_angle + 0.000000175f); + const bool do_split_angle = (emd->flags & MOD_EDGESPLIT_FROMANGLE) != 0 && + emd->split_angle < (float)M_PI; + const bool do_split_all = do_split_angle && emd->split_angle < FLT_EPSILON; + const bool calc_face_normals = do_split_angle && !do_split_all; + + bm = BKE_mesh_to_bmesh_ex(mesh, + &(struct BMeshCreateParams){0}, + &(struct BMeshFromMeshParams){ + .calc_face_normal = calc_face_normals, + .add_key_index = false, + .use_shapekey = false, + .active_shapekey = 0, + .cd_mask_extra = {.vmask = CD_MASK_ORIGINDEX, + .emask = CD_MASK_ORIGINDEX, + .pmask = CD_MASK_ORIGINDEX}, + }); + + if (do_split_angle) { + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + /* check for 1 edge having 2 face users */ + BMLoop *l1, *l2; + if ((l1 = e->l) && (l2 = e->l->radial_next) != l1) { + if (/* 3+ faces on this edge, always split */ + UNLIKELY(l1 != l2->radial_next) || + /* O° angle setting, we want to split on all edges. */ + do_split_all || + /* 2 face edge - check angle*/ + (dot_v3v3(l1->f->no, l2->f->no) < threshold)) { + BM_elem_flag_enable(e, BM_ELEM_TAG); + } + } + } + } + + if (emd->flags & MOD_EDGESPLIT_FROMFLAG) { + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + /* check for 2 or more edge users */ + if ((e->l) && (e->l->next != e->l)) { + if (!BM_elem_flag_test(e, BM_ELEM_SMOOTH)) { + BM_elem_flag_enable(e, BM_ELEM_TAG); + } + } + } + } + + BM_mesh_edgesplit(bm, false, true, false); + + /* BM_mesh_validate(bm); */ /* for troubleshooting */ + + result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL); + BM_mesh_free(bm); + + result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + return result; } static void initData(ModifierData *md) { - EdgeSplitModifierData *emd = (EdgeSplitModifierData *) md; + EdgeSplitModifierData *emd = (EdgeSplitModifierData *)md; - /* default to 30-degree split angle, sharpness from both angle & flag */ - emd->split_angle = DEG2RADF(30.0f); - emd->flags = MOD_EDGESPLIT_FROMANGLE | MOD_EDGESPLIT_FROMFLAG; + /* default to 30-degree split angle, sharpness from both angle & flag */ + emd->split_angle = DEG2RADF(30.0f); + emd->flags = MOD_EDGESPLIT_FROMANGLE | MOD_EDGESPLIT_FROMFLAG; } -static Mesh *applyModifier( - ModifierData *md, - const ModifierEvalContext *UNUSED(ctx), - Mesh *mesh) +static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *UNUSED(ctx), Mesh *mesh) { - Mesh *result; - EdgeSplitModifierData *emd = (EdgeSplitModifierData *) md; + Mesh *result; + EdgeSplitModifierData *emd = (EdgeSplitModifierData *)md; - if (!(emd->flags & (MOD_EDGESPLIT_FROMANGLE | MOD_EDGESPLIT_FROMFLAG))) - return mesh; + if (!(emd->flags & (MOD_EDGESPLIT_FROMANGLE | MOD_EDGESPLIT_FROMFLAG))) + return mesh; - result = doEdgeSplit(mesh, emd); + result = doEdgeSplit(mesh, emd); - return result; + return result; } - ModifierTypeInfo modifierType_EdgeSplit = { - /* name */ "EdgeSplit", - /* structName */ "EdgeSplitModifierData", - /* structSize */ sizeof(EdgeSplitModifierData), - /* type */ eModifierTypeType_Constructive, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_AcceptsCVs | - eModifierTypeFlag_SupportsMapping | - eModifierTypeFlag_SupportsEditmode | - eModifierTypeFlag_EnableInEditmode, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ initData, - /* requiredDataMask */ NULL, - /* freeData */ NULL, - /* isDisabled */ NULL, - /* updateDepsgraph */ NULL, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ NULL, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "EdgeSplit", + /* structName */ "EdgeSplitModifierData", + /* structSize */ sizeof(EdgeSplitModifierData), + /* type */ eModifierTypeType_Constructive, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs | + eModifierTypeFlag_SupportsMapping | eModifierTypeFlag_SupportsEditmode | + eModifierTypeFlag_EnableInEditmode, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ initData, + /* requiredDataMask */ NULL, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c index a8a0b963bd8..f126adbaafd 100644 --- a/source/blender/modifiers/intern/MOD_explode.c +++ b/source/blender/modifiers/intern/MOD_explode.c @@ -21,7 +21,6 @@ * \ingroup modifiers */ - #include "BLI_utildefines.h" #include "BLI_edgehash.h" @@ -50,1055 +49,1137 @@ static void initData(ModifierData *md) { - ExplodeModifierData *emd = (ExplodeModifierData *) md; + ExplodeModifierData *emd = (ExplodeModifierData *)md; - emd->facepa = NULL; - emd->flag |= eExplodeFlag_Unborn + eExplodeFlag_Alive + eExplodeFlag_Dead; + emd->facepa = NULL; + emd->flag |= eExplodeFlag_Unborn + eExplodeFlag_Alive + eExplodeFlag_Dead; } static void freeData(ModifierData *md) { - ExplodeModifierData *emd = (ExplodeModifierData *) md; + ExplodeModifierData *emd = (ExplodeModifierData *)md; - MEM_SAFE_FREE(emd->facepa); + MEM_SAFE_FREE(emd->facepa); } static void copyData(const ModifierData *md, ModifierData *target, const int flag) { #if 0 - const ExplodeModifierData *emd = (const ExplodeModifierData *) md; + const ExplodeModifierData *emd = (const ExplodeModifierData *) md; #endif - ExplodeModifierData *temd = (ExplodeModifierData *) target; + ExplodeModifierData *temd = (ExplodeModifierData *)target; - modifier_copyData_generic(md, target, flag); + modifier_copyData_generic(md, target, flag); - temd->facepa = NULL; + temd->facepa = NULL; } static bool dependsOnTime(ModifierData *UNUSED(md)) { - return true; + return true; } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - ExplodeModifierData *emd = (ExplodeModifierData *) md; + ExplodeModifierData *emd = (ExplodeModifierData *)md; - if (emd->vgroup) { - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; - } + if (emd->vgroup) { + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + } } -static void createFacepa( - ExplodeModifierData *emd, - ParticleSystemModifierData *psmd, - Mesh *mesh) +static void createFacepa(ExplodeModifierData *emd, ParticleSystemModifierData *psmd, Mesh *mesh) { - ParticleSystem *psys = psmd->psys; - MFace *fa = NULL, *mface = NULL; - MVert *mvert = NULL; - ParticleData *pa; - KDTree_3d *tree; - RNG *rng; - float center[3], co[3]; - int *facepa = NULL, *vertpa = NULL, totvert = 0, totface = 0, totpart = 0; - int i, p, v1, v2, v3, v4 = 0; - - mvert = mesh->mvert; - mface = mesh->mface; - totvert = mesh->totvert; - totface = mesh->totface; - totpart = psmd->psys->totpart; - - rng = BLI_rng_new_srandom(psys->seed); - - if (emd->facepa) { - MEM_freeN(emd->facepa); - } - facepa = emd->facepa = MEM_calloc_arrayN(totface, sizeof(int), "explode_facepa"); - - vertpa = MEM_calloc_arrayN(totvert, sizeof(int), "explode_vertpa"); - - /* initialize all faces & verts to no particle */ - for (i = 0; i < totface; i++) { - facepa[i] = totpart; - } - for (i = 0; i < totvert; i++) { - vertpa[i] = totpart; - } - - /* set protected verts */ - if (emd->vgroup) { - MDeformVert *dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT); - if (dvert) { - const int defgrp_index = emd->vgroup - 1; - for (i = 0; i < totvert; i++, dvert++) { - float val = BLI_rng_get_float(rng); - val = (1.0f - emd->protect) * val + emd->protect * 0.5f; - if (val < defvert_find_weight(dvert, defgrp_index)) - vertpa[i] = -1; - } - } - } - - /* make tree of emitter locations */ - tree = BLI_kdtree_3d_new(totpart); - for (p = 0, pa = psys->particles; p < totpart; p++, pa++) { - psys_particle_on_emitter(psmd, psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co, NULL, NULL, NULL, NULL); - BLI_kdtree_3d_insert(tree, p, co); - } - BLI_kdtree_3d_balance(tree); - - /* set face-particle-indexes to nearest particle to face center */ - for (i = 0, fa = mface; i < totface; i++, fa++) { - add_v3_v3v3(center, mvert[fa->v1].co, mvert[fa->v2].co); - add_v3_v3(center, mvert[fa->v3].co); - if (fa->v4) { - add_v3_v3(center, mvert[fa->v4].co); - mul_v3_fl(center, 0.25); - } - else { - mul_v3_fl(center, 1.0f / 3.0f); - } - - p = BLI_kdtree_3d_find_nearest(tree, center, NULL); - - v1 = vertpa[fa->v1]; - v2 = vertpa[fa->v2]; - v3 = vertpa[fa->v3]; - if (fa->v4) { - v4 = vertpa[fa->v4]; - } - - if (v1 >= 0 && v2 >= 0 && v3 >= 0 && (fa->v4 == 0 || v4 >= 0)) { - facepa[i] = p; - } - - if (v1 >= 0) { - vertpa[fa->v1] = p; - } - if (v2 >= 0) { - vertpa[fa->v2] = p; - } - if (v3 >= 0) { - vertpa[fa->v3] = p; - } - if (fa->v4 && v4 >= 0) { - vertpa[fa->v4] = p; - } - } - - if (vertpa) { - MEM_freeN(vertpa); - } - BLI_kdtree_3d_free(tree); - - BLI_rng_free(rng); + ParticleSystem *psys = psmd->psys; + MFace *fa = NULL, *mface = NULL; + MVert *mvert = NULL; + ParticleData *pa; + KDTree_3d *tree; + RNG *rng; + float center[3], co[3]; + int *facepa = NULL, *vertpa = NULL, totvert = 0, totface = 0, totpart = 0; + int i, p, v1, v2, v3, v4 = 0; + + mvert = mesh->mvert; + mface = mesh->mface; + totvert = mesh->totvert; + totface = mesh->totface; + totpart = psmd->psys->totpart; + + rng = BLI_rng_new_srandom(psys->seed); + + if (emd->facepa) { + MEM_freeN(emd->facepa); + } + facepa = emd->facepa = MEM_calloc_arrayN(totface, sizeof(int), "explode_facepa"); + + vertpa = MEM_calloc_arrayN(totvert, sizeof(int), "explode_vertpa"); + + /* initialize all faces & verts to no particle */ + for (i = 0; i < totface; i++) { + facepa[i] = totpart; + } + for (i = 0; i < totvert; i++) { + vertpa[i] = totpart; + } + + /* set protected verts */ + if (emd->vgroup) { + MDeformVert *dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT); + if (dvert) { + const int defgrp_index = emd->vgroup - 1; + for (i = 0; i < totvert; i++, dvert++) { + float val = BLI_rng_get_float(rng); + val = (1.0f - emd->protect) * val + emd->protect * 0.5f; + if (val < defvert_find_weight(dvert, defgrp_index)) + vertpa[i] = -1; + } + } + } + + /* make tree of emitter locations */ + tree = BLI_kdtree_3d_new(totpart); + for (p = 0, pa = psys->particles; p < totpart; p++, pa++) { + psys_particle_on_emitter(psmd, + psys->part->from, + pa->num, + pa->num_dmcache, + pa->fuv, + pa->foffset, + co, + NULL, + NULL, + NULL, + NULL); + BLI_kdtree_3d_insert(tree, p, co); + } + BLI_kdtree_3d_balance(tree); + + /* set face-particle-indexes to nearest particle to face center */ + for (i = 0, fa = mface; i < totface; i++, fa++) { + add_v3_v3v3(center, mvert[fa->v1].co, mvert[fa->v2].co); + add_v3_v3(center, mvert[fa->v3].co); + if (fa->v4) { + add_v3_v3(center, mvert[fa->v4].co); + mul_v3_fl(center, 0.25); + } + else { + mul_v3_fl(center, 1.0f / 3.0f); + } + + p = BLI_kdtree_3d_find_nearest(tree, center, NULL); + + v1 = vertpa[fa->v1]; + v2 = vertpa[fa->v2]; + v3 = vertpa[fa->v3]; + if (fa->v4) { + v4 = vertpa[fa->v4]; + } + + if (v1 >= 0 && v2 >= 0 && v3 >= 0 && (fa->v4 == 0 || v4 >= 0)) { + facepa[i] = p; + } + + if (v1 >= 0) { + vertpa[fa->v1] = p; + } + if (v2 >= 0) { + vertpa[fa->v2] = p; + } + if (v3 >= 0) { + vertpa[fa->v3] = p; + } + if (fa->v4 && v4 >= 0) { + vertpa[fa->v4] = p; + } + } + + if (vertpa) { + MEM_freeN(vertpa); + } + BLI_kdtree_3d_free(tree); + + BLI_rng_free(rng); } static int edgecut_get(EdgeHash *edgehash, unsigned int v1, unsigned int v2) { - return POINTER_AS_INT(BLI_edgehash_lookup(edgehash, v1, v2)); + return POINTER_AS_INT(BLI_edgehash_lookup(edgehash, v1, v2)); } - static const short add_faces[24] = { - 0, - 0, 0, 2, 0, 1, 2, 2, 0, 2, 1, - 2, 2, 2, 2, 3, 0, 0, 0, 1, 0, - 1, 1, 2, + 0, 0, 0, 2, 0, 1, 2, 2, 0, 2, 1, 2, 2, 2, 2, 3, 0, 0, 0, 1, 0, 1, 1, 2, }; static MFace *get_dface(Mesh *mesh, Mesh *split, int cur, int i, MFace *mf) { - MFace *df = &split->mface[cur]; - CustomData_copy_data(&mesh->fdata, &split->fdata, i, cur, 1); - *df = *mf; - return df; + MFace *df = &split->mface[cur]; + CustomData_copy_data(&mesh->fdata, &split->fdata, i, cur, 1); + *df = *mf; + return df; } -#define SET_VERTS(a, b, c, d) \ - { \ - v[0] = mf->v##a; uv[0] = a - 1; \ - v[1] = mf->v##b; uv[1] = b - 1; \ - v[2] = mf->v##c; uv[2] = c - 1; \ - v[3] = mf->v##d; uv[3] = d - 1; \ - } (void)0 +#define SET_VERTS(a, b, c, d) \ + { \ + v[0] = mf->v##a; \ + uv[0] = a - 1; \ + v[1] = mf->v##b; \ + uv[1] = b - 1; \ + v[2] = mf->v##c; \ + uv[2] = c - 1; \ + v[3] = mf->v##d; \ + uv[3] = d - 1; \ + } \ + (void)0 #define GET_ES(v1, v2) edgecut_get(eh, v1, v2) #define INT_UV(uvf, c0, c1) mid_v2_v2v2(uvf, mf->uv[c0], mf->uv[c1]) -static void remap_faces_3_6_9_12(Mesh *mesh, Mesh *split, MFace *mf, int *facepa, int *vertpa, int i, EdgeHash *eh, int cur, int v1, int v2, int v3, int v4) +static void remap_faces_3_6_9_12(Mesh *mesh, + Mesh *split, + MFace *mf, + int *facepa, + int *vertpa, + int i, + EdgeHash *eh, + int cur, + int v1, + int v2, + int v3, + int v4) { - MFace *df1 = get_dface(mesh, split, cur, i, mf); - MFace *df2 = get_dface(mesh, split, cur + 1, i, mf); - MFace *df3 = get_dface(mesh, split, cur + 2, i, mf); - - facepa[cur] = vertpa[v1]; - df1->v1 = v1; - df1->v2 = GET_ES(v1, v2); - df1->v3 = GET_ES(v2, v3); - df1->v4 = v3; - df1->flag |= ME_FACE_SEL; - - facepa[cur + 1] = vertpa[v2]; - df2->v1 = GET_ES(v1, v2); - df2->v2 = v2; - df2->v3 = GET_ES(v2, v3); - df2->v4 = 0; - df2->flag &= ~ME_FACE_SEL; - - facepa[cur + 2] = vertpa[v1]; - df3->v1 = v1; - df3->v2 = v3; - df3->v3 = v4; - df3->v4 = 0; - df3->flag &= ~ME_FACE_SEL; + MFace *df1 = get_dface(mesh, split, cur, i, mf); + MFace *df2 = get_dface(mesh, split, cur + 1, i, mf); + MFace *df3 = get_dface(mesh, split, cur + 2, i, mf); + + facepa[cur] = vertpa[v1]; + df1->v1 = v1; + df1->v2 = GET_ES(v1, v2); + df1->v3 = GET_ES(v2, v3); + df1->v4 = v3; + df1->flag |= ME_FACE_SEL; + + facepa[cur + 1] = vertpa[v2]; + df2->v1 = GET_ES(v1, v2); + df2->v2 = v2; + df2->v3 = GET_ES(v2, v3); + df2->v4 = 0; + df2->flag &= ~ME_FACE_SEL; + + facepa[cur + 2] = vertpa[v1]; + df3->v1 = v1; + df3->v2 = v3; + df3->v3 = v4; + df3->v4 = 0; + df3->flag &= ~ME_FACE_SEL; } -static void remap_uvs_3_6_9_12(Mesh *mesh, Mesh *split, int numlayer, int i, int cur, int c0, int c1, int c2, int c3) +static void remap_uvs_3_6_9_12( + Mesh *mesh, Mesh *split, int numlayer, int i, int cur, int c0, int c1, int c2, int c3) { - MTFace *mf, *df1, *df2, *df3; - int l; - - for (l = 0; l < numlayer; l++) { - mf = CustomData_get_layer_n(&split->fdata, CD_MTFACE, l); - df1 = mf + cur; - df2 = df1 + 1; - df3 = df1 + 2; - mf = CustomData_get_layer_n(&mesh->fdata, CD_MTFACE, l); - mf += i; - - copy_v2_v2(df1->uv[0], mf->uv[c0]); - INT_UV(df1->uv[1], c0, c1); - INT_UV(df1->uv[2], c1, c2); - copy_v2_v2(df1->uv[3], mf->uv[c2]); - - INT_UV(df2->uv[0], c0, c1); - copy_v2_v2(df2->uv[1], mf->uv[c1]); - INT_UV(df2->uv[2], c1, c2); - - copy_v2_v2(df3->uv[0], mf->uv[c0]); - copy_v2_v2(df3->uv[1], mf->uv[c2]); - copy_v2_v2(df3->uv[2], mf->uv[c3]); - } + MTFace *mf, *df1, *df2, *df3; + int l; + + for (l = 0; l < numlayer; l++) { + mf = CustomData_get_layer_n(&split->fdata, CD_MTFACE, l); + df1 = mf + cur; + df2 = df1 + 1; + df3 = df1 + 2; + mf = CustomData_get_layer_n(&mesh->fdata, CD_MTFACE, l); + mf += i; + + copy_v2_v2(df1->uv[0], mf->uv[c0]); + INT_UV(df1->uv[1], c0, c1); + INT_UV(df1->uv[2], c1, c2); + copy_v2_v2(df1->uv[3], mf->uv[c2]); + + INT_UV(df2->uv[0], c0, c1); + copy_v2_v2(df2->uv[1], mf->uv[c1]); + INT_UV(df2->uv[2], c1, c2); + + copy_v2_v2(df3->uv[0], mf->uv[c0]); + copy_v2_v2(df3->uv[1], mf->uv[c2]); + copy_v2_v2(df3->uv[2], mf->uv[c3]); + } } -static void remap_faces_5_10(Mesh *mesh, Mesh *split, MFace *mf, int *facepa, int *vertpa, int i, EdgeHash *eh, int cur, int v1, int v2, int v3, int v4) +static void remap_faces_5_10(Mesh *mesh, + Mesh *split, + MFace *mf, + int *facepa, + int *vertpa, + int i, + EdgeHash *eh, + int cur, + int v1, + int v2, + int v3, + int v4) { - MFace *df1 = get_dface(mesh, split, cur, i, mf); - MFace *df2 = get_dface(mesh, split, cur + 1, i, mf); - - facepa[cur] = vertpa[v1]; - df1->v1 = v1; - df1->v2 = v2; - df1->v3 = GET_ES(v2, v3); - df1->v4 = GET_ES(v1, v4); - df1->flag |= ME_FACE_SEL; - - facepa[cur + 1] = vertpa[v3]; - df2->v1 = GET_ES(v1, v4); - df2->v2 = GET_ES(v2, v3); - df2->v3 = v3; - df2->v4 = v4; - df2->flag |= ME_FACE_SEL; + MFace *df1 = get_dface(mesh, split, cur, i, mf); + MFace *df2 = get_dface(mesh, split, cur + 1, i, mf); + + facepa[cur] = vertpa[v1]; + df1->v1 = v1; + df1->v2 = v2; + df1->v3 = GET_ES(v2, v3); + df1->v4 = GET_ES(v1, v4); + df1->flag |= ME_FACE_SEL; + + facepa[cur + 1] = vertpa[v3]; + df2->v1 = GET_ES(v1, v4); + df2->v2 = GET_ES(v2, v3); + df2->v3 = v3; + df2->v4 = v4; + df2->flag |= ME_FACE_SEL; } -static void remap_uvs_5_10(Mesh *mesh, Mesh *split, int numlayer, int i, int cur, int c0, int c1, int c2, int c3) +static void remap_uvs_5_10( + Mesh *mesh, Mesh *split, int numlayer, int i, int cur, int c0, int c1, int c2, int c3) { - MTFace *mf, *df1, *df2; - int l; - - for (l = 0; l < numlayer; l++) { - mf = CustomData_get_layer_n(&split->fdata, CD_MTFACE, l); - df1 = mf + cur; - df2 = df1 + 1; - mf = CustomData_get_layer_n(&mesh->fdata, CD_MTFACE, l); - mf += i; - - copy_v2_v2(df1->uv[0], mf->uv[c0]); - copy_v2_v2(df1->uv[1], mf->uv[c1]); - INT_UV(df1->uv[2], c1, c2); - INT_UV(df1->uv[3], c0, c3); - - INT_UV(df2->uv[0], c0, c3); - INT_UV(df2->uv[1], c1, c2); - copy_v2_v2(df2->uv[2], mf->uv[c2]); - copy_v2_v2(df2->uv[3], mf->uv[c3]); - - } + MTFace *mf, *df1, *df2; + int l; + + for (l = 0; l < numlayer; l++) { + mf = CustomData_get_layer_n(&split->fdata, CD_MTFACE, l); + df1 = mf + cur; + df2 = df1 + 1; + mf = CustomData_get_layer_n(&mesh->fdata, CD_MTFACE, l); + mf += i; + + copy_v2_v2(df1->uv[0], mf->uv[c0]); + copy_v2_v2(df1->uv[1], mf->uv[c1]); + INT_UV(df1->uv[2], c1, c2); + INT_UV(df1->uv[3], c0, c3); + + INT_UV(df2->uv[0], c0, c3); + INT_UV(df2->uv[1], c1, c2); + copy_v2_v2(df2->uv[2], mf->uv[c2]); + copy_v2_v2(df2->uv[3], mf->uv[c3]); + } } -static void remap_faces_15(Mesh *mesh, Mesh *split, MFace *mf, int *facepa, int *vertpa, int i, EdgeHash *eh, int cur, int v1, int v2, int v3, int v4) +static void remap_faces_15(Mesh *mesh, + Mesh *split, + MFace *mf, + int *facepa, + int *vertpa, + int i, + EdgeHash *eh, + int cur, + int v1, + int v2, + int v3, + int v4) { - MFace *df1 = get_dface(mesh, split, cur, i, mf); - MFace *df2 = get_dface(mesh, split, cur + 1, i, mf); - MFace *df3 = get_dface(mesh, split, cur + 2, i, mf); - MFace *df4 = get_dface(mesh, split, cur + 3, i, mf); - - facepa[cur] = vertpa[v1]; - df1->v1 = v1; - df1->v2 = GET_ES(v1, v2); - df1->v3 = GET_ES(v1, v3); - df1->v4 = GET_ES(v1, v4); - df1->flag |= ME_FACE_SEL; - - facepa[cur + 1] = vertpa[v2]; - df2->v1 = GET_ES(v1, v2); - df2->v2 = v2; - df2->v3 = GET_ES(v2, v3); - df2->v4 = GET_ES(v1, v3); - df2->flag |= ME_FACE_SEL; - - facepa[cur + 2] = vertpa[v3]; - df3->v1 = GET_ES(v1, v3); - df3->v2 = GET_ES(v2, v3); - df3->v3 = v3; - df3->v4 = GET_ES(v3, v4); - df3->flag |= ME_FACE_SEL; - - facepa[cur + 3] = vertpa[v4]; - df4->v1 = GET_ES(v1, v4); - df4->v2 = GET_ES(v1, v3); - df4->v3 = GET_ES(v3, v4); - df4->v4 = v4; - df4->flag |= ME_FACE_SEL; + MFace *df1 = get_dface(mesh, split, cur, i, mf); + MFace *df2 = get_dface(mesh, split, cur + 1, i, mf); + MFace *df3 = get_dface(mesh, split, cur + 2, i, mf); + MFace *df4 = get_dface(mesh, split, cur + 3, i, mf); + + facepa[cur] = vertpa[v1]; + df1->v1 = v1; + df1->v2 = GET_ES(v1, v2); + df1->v3 = GET_ES(v1, v3); + df1->v4 = GET_ES(v1, v4); + df1->flag |= ME_FACE_SEL; + + facepa[cur + 1] = vertpa[v2]; + df2->v1 = GET_ES(v1, v2); + df2->v2 = v2; + df2->v3 = GET_ES(v2, v3); + df2->v4 = GET_ES(v1, v3); + df2->flag |= ME_FACE_SEL; + + facepa[cur + 2] = vertpa[v3]; + df3->v1 = GET_ES(v1, v3); + df3->v2 = GET_ES(v2, v3); + df3->v3 = v3; + df3->v4 = GET_ES(v3, v4); + df3->flag |= ME_FACE_SEL; + + facepa[cur + 3] = vertpa[v4]; + df4->v1 = GET_ES(v1, v4); + df4->v2 = GET_ES(v1, v3); + df4->v3 = GET_ES(v3, v4); + df4->v4 = v4; + df4->flag |= ME_FACE_SEL; } -static void remap_uvs_15(Mesh *mesh, Mesh *split, int numlayer, int i, int cur, int c0, int c1, int c2, int c3) +static void remap_uvs_15( + Mesh *mesh, Mesh *split, int numlayer, int i, int cur, int c0, int c1, int c2, int c3) { - MTFace *mf, *df1, *df2, *df3, *df4; - int l; - - for (l = 0; l < numlayer; l++) { - mf = CustomData_get_layer_n(&split->fdata, CD_MTFACE, l); - df1 = mf + cur; - df2 = df1 + 1; - df3 = df1 + 2; - df4 = df1 + 3; - mf = CustomData_get_layer_n(&mesh->fdata, CD_MTFACE, l); - mf += i; - - copy_v2_v2(df1->uv[0], mf->uv[c0]); - INT_UV(df1->uv[1], c0, c1); - INT_UV(df1->uv[2], c0, c2); - INT_UV(df1->uv[3], c0, c3); - - INT_UV(df2->uv[0], c0, c1); - copy_v2_v2(df2->uv[1], mf->uv[c1]); - INT_UV(df2->uv[2], c1, c2); - INT_UV(df2->uv[3], c0, c2); - - INT_UV(df3->uv[0], c0, c2); - INT_UV(df3->uv[1], c1, c2); - copy_v2_v2(df3->uv[2], mf->uv[c2]); - INT_UV(df3->uv[3], c2, c3); - - INT_UV(df4->uv[0], c0, c3); - INT_UV(df4->uv[1], c0, c2); - INT_UV(df4->uv[2], c2, c3); - copy_v2_v2(df4->uv[3], mf->uv[c3]); - } + MTFace *mf, *df1, *df2, *df3, *df4; + int l; + + for (l = 0; l < numlayer; l++) { + mf = CustomData_get_layer_n(&split->fdata, CD_MTFACE, l); + df1 = mf + cur; + df2 = df1 + 1; + df3 = df1 + 2; + df4 = df1 + 3; + mf = CustomData_get_layer_n(&mesh->fdata, CD_MTFACE, l); + mf += i; + + copy_v2_v2(df1->uv[0], mf->uv[c0]); + INT_UV(df1->uv[1], c0, c1); + INT_UV(df1->uv[2], c0, c2); + INT_UV(df1->uv[3], c0, c3); + + INT_UV(df2->uv[0], c0, c1); + copy_v2_v2(df2->uv[1], mf->uv[c1]); + INT_UV(df2->uv[2], c1, c2); + INT_UV(df2->uv[3], c0, c2); + + INT_UV(df3->uv[0], c0, c2); + INT_UV(df3->uv[1], c1, c2); + copy_v2_v2(df3->uv[2], mf->uv[c2]); + INT_UV(df3->uv[3], c2, c3); + + INT_UV(df4->uv[0], c0, c3); + INT_UV(df4->uv[1], c0, c2); + INT_UV(df4->uv[2], c2, c3); + copy_v2_v2(df4->uv[3], mf->uv[c3]); + } } -static void remap_faces_7_11_13_14(Mesh *mesh, Mesh *split, MFace *mf, int *facepa, int *vertpa, int i, EdgeHash *eh, int cur, int v1, int v2, int v3, int v4) +static void remap_faces_7_11_13_14(Mesh *mesh, + Mesh *split, + MFace *mf, + int *facepa, + int *vertpa, + int i, + EdgeHash *eh, + int cur, + int v1, + int v2, + int v3, + int v4) { - MFace *df1 = get_dface(mesh, split, cur, i, mf); - MFace *df2 = get_dface(mesh, split, cur + 1, i, mf); - MFace *df3 = get_dface(mesh, split, cur + 2, i, mf); - - facepa[cur] = vertpa[v1]; - df1->v1 = v1; - df1->v2 = GET_ES(v1, v2); - df1->v3 = GET_ES(v2, v3); - df1->v4 = GET_ES(v1, v4); - df1->flag |= ME_FACE_SEL; - - facepa[cur + 1] = vertpa[v2]; - df2->v1 = GET_ES(v1, v2); - df2->v2 = v2; - df2->v3 = GET_ES(v2, v3); - df2->v4 = 0; - df2->flag &= ~ME_FACE_SEL; - - facepa[cur + 2] = vertpa[v4]; - df3->v1 = GET_ES(v1, v4); - df3->v2 = GET_ES(v2, v3); - df3->v3 = v3; - df3->v4 = v4; - df3->flag |= ME_FACE_SEL; + MFace *df1 = get_dface(mesh, split, cur, i, mf); + MFace *df2 = get_dface(mesh, split, cur + 1, i, mf); + MFace *df3 = get_dface(mesh, split, cur + 2, i, mf); + + facepa[cur] = vertpa[v1]; + df1->v1 = v1; + df1->v2 = GET_ES(v1, v2); + df1->v3 = GET_ES(v2, v3); + df1->v4 = GET_ES(v1, v4); + df1->flag |= ME_FACE_SEL; + + facepa[cur + 1] = vertpa[v2]; + df2->v1 = GET_ES(v1, v2); + df2->v2 = v2; + df2->v3 = GET_ES(v2, v3); + df2->v4 = 0; + df2->flag &= ~ME_FACE_SEL; + + facepa[cur + 2] = vertpa[v4]; + df3->v1 = GET_ES(v1, v4); + df3->v2 = GET_ES(v2, v3); + df3->v3 = v3; + df3->v4 = v4; + df3->flag |= ME_FACE_SEL; } -static void remap_uvs_7_11_13_14(Mesh *mesh, Mesh *split, int numlayer, int i, int cur, int c0, int c1, int c2, int c3) +static void remap_uvs_7_11_13_14( + Mesh *mesh, Mesh *split, int numlayer, int i, int cur, int c0, int c1, int c2, int c3) { - MTFace *mf, *df1, *df2, *df3; - int l; - - for (l = 0; l < numlayer; l++) { - mf = CustomData_get_layer_n(&split->fdata, CD_MTFACE, l); - df1 = mf + cur; - df2 = df1 + 1; - df3 = df1 + 2; - mf = CustomData_get_layer_n(&mesh->fdata, CD_MTFACE, l); - mf += i; - - copy_v2_v2(df1->uv[0], mf->uv[c0]); - INT_UV(df1->uv[1], c0, c1); - INT_UV(df1->uv[2], c1, c2); - INT_UV(df1->uv[3], c0, c3); - - INT_UV(df2->uv[0], c0, c1); - copy_v2_v2(df2->uv[1], mf->uv[c1]); - INT_UV(df2->uv[2], c1, c2); - - INT_UV(df3->uv[0], c0, c3); - INT_UV(df3->uv[1], c1, c2); - copy_v2_v2(df3->uv[2], mf->uv[c2]); - copy_v2_v2(df3->uv[3], mf->uv[c3]); - } + MTFace *mf, *df1, *df2, *df3; + int l; + + for (l = 0; l < numlayer; l++) { + mf = CustomData_get_layer_n(&split->fdata, CD_MTFACE, l); + df1 = mf + cur; + df2 = df1 + 1; + df3 = df1 + 2; + mf = CustomData_get_layer_n(&mesh->fdata, CD_MTFACE, l); + mf += i; + + copy_v2_v2(df1->uv[0], mf->uv[c0]); + INT_UV(df1->uv[1], c0, c1); + INT_UV(df1->uv[2], c1, c2); + INT_UV(df1->uv[3], c0, c3); + + INT_UV(df2->uv[0], c0, c1); + copy_v2_v2(df2->uv[1], mf->uv[c1]); + INT_UV(df2->uv[2], c1, c2); + + INT_UV(df3->uv[0], c0, c3); + INT_UV(df3->uv[1], c1, c2); + copy_v2_v2(df3->uv[2], mf->uv[c2]); + copy_v2_v2(df3->uv[3], mf->uv[c3]); + } } -static void remap_faces_19_21_22(Mesh *mesh, Mesh *split, MFace *mf, int *facepa, int *vertpa, int i, EdgeHash *eh, int cur, int v1, int v2, int v3) +static void remap_faces_19_21_22(Mesh *mesh, + Mesh *split, + MFace *mf, + int *facepa, + int *vertpa, + int i, + EdgeHash *eh, + int cur, + int v1, + int v2, + int v3) { - MFace *df1 = get_dface(mesh, split, cur, i, mf); - MFace *df2 = get_dface(mesh, split, cur + 1, i, mf); - - facepa[cur] = vertpa[v1]; - df1->v1 = v1; - df1->v2 = GET_ES(v1, v2); - df1->v3 = GET_ES(v1, v3); - df1->v4 = 0; - df1->flag &= ~ME_FACE_SEL; - - facepa[cur + 1] = vertpa[v2]; - df2->v1 = GET_ES(v1, v2); - df2->v2 = v2; - df2->v3 = v3; - df2->v4 = GET_ES(v1, v3); - df2->flag |= ME_FACE_SEL; + MFace *df1 = get_dface(mesh, split, cur, i, mf); + MFace *df2 = get_dface(mesh, split, cur + 1, i, mf); + + facepa[cur] = vertpa[v1]; + df1->v1 = v1; + df1->v2 = GET_ES(v1, v2); + df1->v3 = GET_ES(v1, v3); + df1->v4 = 0; + df1->flag &= ~ME_FACE_SEL; + + facepa[cur + 1] = vertpa[v2]; + df2->v1 = GET_ES(v1, v2); + df2->v2 = v2; + df2->v3 = v3; + df2->v4 = GET_ES(v1, v3); + df2->flag |= ME_FACE_SEL; } -static void remap_uvs_19_21_22(Mesh *mesh, Mesh *split, int numlayer, int i, int cur, int c0, int c1, int c2) +static void remap_uvs_19_21_22( + Mesh *mesh, Mesh *split, int numlayer, int i, int cur, int c0, int c1, int c2) { - MTFace *mf, *df1, *df2; - int l; - - for (l = 0; l < numlayer; l++) { - mf = CustomData_get_layer_n(&split->fdata, CD_MTFACE, l); - df1 = mf + cur; - df2 = df1 + 1; - mf = CustomData_get_layer_n(&mesh->fdata, CD_MTFACE, l); - mf += i; - - copy_v2_v2(df1->uv[0], mf->uv[c0]); - INT_UV(df1->uv[1], c0, c1); - INT_UV(df1->uv[2], c0, c2); - - INT_UV(df2->uv[0], c0, c1); - copy_v2_v2(df2->uv[1], mf->uv[c1]); - copy_v2_v2(df2->uv[2], mf->uv[c2]); - INT_UV(df2->uv[3], c0, c2); - } + MTFace *mf, *df1, *df2; + int l; + + for (l = 0; l < numlayer; l++) { + mf = CustomData_get_layer_n(&split->fdata, CD_MTFACE, l); + df1 = mf + cur; + df2 = df1 + 1; + mf = CustomData_get_layer_n(&mesh->fdata, CD_MTFACE, l); + mf += i; + + copy_v2_v2(df1->uv[0], mf->uv[c0]); + INT_UV(df1->uv[1], c0, c1); + INT_UV(df1->uv[2], c0, c2); + + INT_UV(df2->uv[0], c0, c1); + copy_v2_v2(df2->uv[1], mf->uv[c1]); + copy_v2_v2(df2->uv[2], mf->uv[c2]); + INT_UV(df2->uv[3], c0, c2); + } } -static void remap_faces_23(Mesh *mesh, Mesh *split, MFace *mf, int *facepa, int *vertpa, int i, EdgeHash *eh, int cur, int v1, int v2, int v3) +static void remap_faces_23(Mesh *mesh, + Mesh *split, + MFace *mf, + int *facepa, + int *vertpa, + int i, + EdgeHash *eh, + int cur, + int v1, + int v2, + int v3) { - MFace *df1 = get_dface(mesh, split, cur, i, mf); - MFace *df2 = get_dface(mesh, split, cur + 1, i, mf); - MFace *df3 = get_dface(mesh, split, cur + 2, i, mf); - - facepa[cur] = vertpa[v1]; - df1->v1 = v1; - df1->v2 = GET_ES(v1, v2); - df1->v3 = GET_ES(v2, v3); - df1->v4 = GET_ES(v1, v3); - df1->flag |= ME_FACE_SEL; - - facepa[cur + 1] = vertpa[v2]; - df2->v1 = GET_ES(v1, v2); - df2->v2 = v2; - df2->v3 = GET_ES(v2, v3); - df2->v4 = 0; - df2->flag &= ~ME_FACE_SEL; - - facepa[cur + 2] = vertpa[v3]; - df3->v1 = GET_ES(v1, v3); - df3->v2 = GET_ES(v2, v3); - df3->v3 = v3; - df3->v4 = 0; - df3->flag &= ~ME_FACE_SEL; + MFace *df1 = get_dface(mesh, split, cur, i, mf); + MFace *df2 = get_dface(mesh, split, cur + 1, i, mf); + MFace *df3 = get_dface(mesh, split, cur + 2, i, mf); + + facepa[cur] = vertpa[v1]; + df1->v1 = v1; + df1->v2 = GET_ES(v1, v2); + df1->v3 = GET_ES(v2, v3); + df1->v4 = GET_ES(v1, v3); + df1->flag |= ME_FACE_SEL; + + facepa[cur + 1] = vertpa[v2]; + df2->v1 = GET_ES(v1, v2); + df2->v2 = v2; + df2->v3 = GET_ES(v2, v3); + df2->v4 = 0; + df2->flag &= ~ME_FACE_SEL; + + facepa[cur + 2] = vertpa[v3]; + df3->v1 = GET_ES(v1, v3); + df3->v2 = GET_ES(v2, v3); + df3->v3 = v3; + df3->v4 = 0; + df3->flag &= ~ME_FACE_SEL; } -static void remap_uvs_23(Mesh *mesh, Mesh *split, int numlayer, int i, int cur, int c0, int c1, int c2) +static void remap_uvs_23( + Mesh *mesh, Mesh *split, int numlayer, int i, int cur, int c0, int c1, int c2) { - MTFace *mf, *df1, *df2; - int l; - - for (l = 0; l < numlayer; l++) { - mf = CustomData_get_layer_n(&split->fdata, CD_MTFACE, l); - df1 = mf + cur; - df2 = df1 + 1; - mf = CustomData_get_layer_n(&mesh->fdata, CD_MTFACE, l); - mf += i; - - copy_v2_v2(df1->uv[0], mf->uv[c0]); - INT_UV(df1->uv[1], c0, c1); - INT_UV(df1->uv[2], c1, c2); - INT_UV(df1->uv[3], c0, c2); - - INT_UV(df2->uv[0], c0, c1); - copy_v2_v2(df2->uv[1], mf->uv[c1]); - INT_UV(df2->uv[2], c1, c2); - - INT_UV(df2->uv[0], c0, c2); - INT_UV(df2->uv[1], c1, c2); - copy_v2_v2(df2->uv[2], mf->uv[c2]); - } + MTFace *mf, *df1, *df2; + int l; + + for (l = 0; l < numlayer; l++) { + mf = CustomData_get_layer_n(&split->fdata, CD_MTFACE, l); + df1 = mf + cur; + df2 = df1 + 1; + mf = CustomData_get_layer_n(&mesh->fdata, CD_MTFACE, l); + mf += i; + + copy_v2_v2(df1->uv[0], mf->uv[c0]); + INT_UV(df1->uv[1], c0, c1); + INT_UV(df1->uv[2], c1, c2); + INT_UV(df1->uv[3], c0, c2); + + INT_UV(df2->uv[0], c0, c1); + copy_v2_v2(df2->uv[1], mf->uv[c1]); + INT_UV(df2->uv[2], c1, c2); + + INT_UV(df2->uv[0], c0, c2); + INT_UV(df2->uv[1], c1, c2); + copy_v2_v2(df2->uv[2], mf->uv[c2]); + } } static Mesh *cutEdges(ExplodeModifierData *emd, Mesh *mesh) { - Mesh *split_m; - MFace *mf = NULL, *df1 = NULL; - MFace *mface = mesh->mface; - MVert *dupve, *mv; - EdgeHash *edgehash; - EdgeHashIterator *ehi; - int totvert = mesh->totvert; - int totface = mesh->totface; - - int *facesplit = MEM_calloc_arrayN(totface, sizeof(int), "explode_facesplit"); - int *vertpa = MEM_calloc_arrayN(totvert, sizeof(int), "explode_vertpa2"); - int *facepa = emd->facepa; - int *fs, totesplit = 0, totfsplit = 0, curdupface = 0; - int i, v1, v2, v3, v4, esplit, - v[4] = {0, 0, 0, 0}, /* To quite gcc barking... */ - uv[4] = {0, 0, 0, 0}; /* To quite gcc barking... */ - int numlayer; - unsigned int ed_v1, ed_v2; - - edgehash = BLI_edgehash_new(__func__); - - /* recreate vertpa from facepa calculation */ - for (i = 0, mf = mface; i < totface; i++, mf++) { - vertpa[mf->v1] = facepa[i]; - vertpa[mf->v2] = facepa[i]; - vertpa[mf->v3] = facepa[i]; - if (mf->v4) { - vertpa[mf->v4] = facepa[i]; - } - } - - /* mark edges for splitting and how to split faces */ - for (i = 0, mf = mface, fs = facesplit; i < totface; i++, mf++, fs++) { - v1 = vertpa[mf->v1]; - v2 = vertpa[mf->v2]; - v3 = vertpa[mf->v3]; - - if (v1 != v2) { - BLI_edgehash_reinsert(edgehash, mf->v1, mf->v2, NULL); - (*fs) |= 1; - } - - if (v2 != v3) { - BLI_edgehash_reinsert(edgehash, mf->v2, mf->v3, NULL); - (*fs) |= 2; - } - - if (mf->v4) { - v4 = vertpa[mf->v4]; - - if (v3 != v4) { - BLI_edgehash_reinsert(edgehash, mf->v3, mf->v4, NULL); - (*fs) |= 4; - } - - if (v1 != v4) { - BLI_edgehash_reinsert(edgehash, mf->v1, mf->v4, NULL); - (*fs) |= 8; - } - - /* mark center vertex as a fake edge split */ - if (*fs == 15) { - BLI_edgehash_reinsert(edgehash, mf->v1, mf->v3, NULL); - } - } - else { - (*fs) |= 16; /* mark face as tri */ - - if (v1 != v3) { - BLI_edgehash_reinsert(edgehash, mf->v1, mf->v3, NULL); - (*fs) |= 4; - } - } - } - - /* count splits & create indexes for new verts */ - ehi = BLI_edgehashIterator_new(edgehash); - totesplit = totvert; - for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) { - BLI_edgehashIterator_setValue(ehi, POINTER_FROM_INT(totesplit)); - totesplit++; - } - BLI_edgehashIterator_free(ehi); - - /* count new faces due to splitting */ - for (i = 0, fs = facesplit; i < totface; i++, fs++) - totfsplit += add_faces[*fs]; - - split_m = BKE_mesh_new_nomain_from_template( - mesh, totesplit, 0, totface + totfsplit, 0, 0); - - numlayer = CustomData_number_of_layers(&split_m->fdata, CD_MTFACE); - - /* copy new faces & verts (is it really this painful with custom data??) */ - for (i = 0; i < totvert; i++) { - MVert source; - MVert *dest; - source = mesh->mvert[i]; - dest = &split_m->mvert[i]; - - CustomData_copy_data(&mesh->vdata, &split_m->vdata, i, i, 1); - *dest = source; - } - - /* override original facepa (original pointer is saved in caller function) */ - - /* BMESH_TODO, (totfsplit * 2) over allocation is used since the quads are - * later interpreted as tri's, for this to work right I think we probably - * have to stop using tessface - campbell */ - - facepa = MEM_calloc_arrayN((totface + (totfsplit * 2)), sizeof(int), "explode_facepa"); - //memcpy(facepa, emd->facepa, totface*sizeof(int)); - emd->facepa = facepa; - - /* create new verts */ - ehi = BLI_edgehashIterator_new(edgehash); - for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) { - BLI_edgehashIterator_getKey(ehi, &ed_v1, &ed_v2); - esplit = POINTER_AS_INT(BLI_edgehashIterator_getValue(ehi)); - mv = &split_m->mvert[ed_v2]; - dupve = &split_m->mvert[esplit]; - - CustomData_copy_data(&split_m->vdata, &split_m->vdata, ed_v2, esplit, 1); - - *dupve = *mv; - - mv = &split_m->mvert[ed_v1]; - - mid_v3_v3v3(dupve->co, dupve->co, mv->co); - } - BLI_edgehashIterator_free(ehi); - - /* create new faces */ - curdupface = 0; //=totface; - //curdupin=totesplit; - for (i = 0, fs = facesplit; i < totface; i++, fs++) { - mf = &mesh->mface[i]; - - switch (*fs) { - case 3: - case 10: - case 11: - case 15: - SET_VERTS(1, 2, 3, 4); - break; - case 5: - case 6: - case 7: - SET_VERTS(2, 3, 4, 1); - break; - case 9: - case 13: - SET_VERTS(4, 1, 2, 3); - break; - case 12: - case 14: - SET_VERTS(3, 4, 1, 2); - break; - case 21: - case 23: - SET_VERTS(1, 2, 3, 4); - break; - case 19: - SET_VERTS(2, 3, 1, 4); - break; - case 22: - SET_VERTS(3, 1, 2, 4); - break; - } - - switch (*fs) { - case 3: - case 6: - case 9: - case 12: - remap_faces_3_6_9_12(mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]); - if (numlayer) { - remap_uvs_3_6_9_12(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]); - } - break; - case 5: - case 10: - remap_faces_5_10(mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]); - if (numlayer) { - remap_uvs_5_10(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]); - } - break; - case 15: - remap_faces_15(mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]); - if (numlayer) { - remap_uvs_15(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]); - } - break; - case 7: - case 11: - case 13: - case 14: - remap_faces_7_11_13_14(mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]); - if (numlayer) { - remap_uvs_7_11_13_14(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]); - } - break; - case 19: - case 21: - case 22: - remap_faces_19_21_22(mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2]); - if (numlayer) { - remap_uvs_19_21_22(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2]); - } - break; - case 23: - remap_faces_23(mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2]); - if (numlayer) { - remap_uvs_23(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2]); - } - break; - case 0: - case 16: - df1 = get_dface(mesh, split_m, curdupface, i, mf); - facepa[curdupface] = vertpa[mf->v1]; - - if (df1->v4) { - df1->flag |= ME_FACE_SEL; - } - else { - df1->flag &= ~ME_FACE_SEL; - } - break; - } - - curdupface += add_faces[*fs] + 1; - } - - for (i = 0; i < curdupface; i++) { - mf = &split_m->mface[i]; - test_index_face(mf, &split_m->fdata, i, ((mf->flag & ME_FACE_SEL) ? 4 : 3)); - } - - BLI_edgehash_free(edgehash, NULL); - MEM_freeN(facesplit); - MEM_freeN(vertpa); - - BKE_mesh_calc_edges_tessface(split_m); - BKE_mesh_convert_mfaces_to_mpolys(split_m); - - return split_m; + Mesh *split_m; + MFace *mf = NULL, *df1 = NULL; + MFace *mface = mesh->mface; + MVert *dupve, *mv; + EdgeHash *edgehash; + EdgeHashIterator *ehi; + int totvert = mesh->totvert; + int totface = mesh->totface; + + int *facesplit = MEM_calloc_arrayN(totface, sizeof(int), "explode_facesplit"); + int *vertpa = MEM_calloc_arrayN(totvert, sizeof(int), "explode_vertpa2"); + int *facepa = emd->facepa; + int *fs, totesplit = 0, totfsplit = 0, curdupface = 0; + int i, v1, v2, v3, v4, esplit, v[4] = {0, 0, 0, 0}, /* To quite gcc barking... */ + uv[4] = {0, 0, 0, 0}; /* To quite gcc barking... */ + int numlayer; + unsigned int ed_v1, ed_v2; + + edgehash = BLI_edgehash_new(__func__); + + /* recreate vertpa from facepa calculation */ + for (i = 0, mf = mface; i < totface; i++, mf++) { + vertpa[mf->v1] = facepa[i]; + vertpa[mf->v2] = facepa[i]; + vertpa[mf->v3] = facepa[i]; + if (mf->v4) { + vertpa[mf->v4] = facepa[i]; + } + } + + /* mark edges for splitting and how to split faces */ + for (i = 0, mf = mface, fs = facesplit; i < totface; i++, mf++, fs++) { + v1 = vertpa[mf->v1]; + v2 = vertpa[mf->v2]; + v3 = vertpa[mf->v3]; + + if (v1 != v2) { + BLI_edgehash_reinsert(edgehash, mf->v1, mf->v2, NULL); + (*fs) |= 1; + } + + if (v2 != v3) { + BLI_edgehash_reinsert(edgehash, mf->v2, mf->v3, NULL); + (*fs) |= 2; + } + + if (mf->v4) { + v4 = vertpa[mf->v4]; + + if (v3 != v4) { + BLI_edgehash_reinsert(edgehash, mf->v3, mf->v4, NULL); + (*fs) |= 4; + } + + if (v1 != v4) { + BLI_edgehash_reinsert(edgehash, mf->v1, mf->v4, NULL); + (*fs) |= 8; + } + + /* mark center vertex as a fake edge split */ + if (*fs == 15) { + BLI_edgehash_reinsert(edgehash, mf->v1, mf->v3, NULL); + } + } + else { + (*fs) |= 16; /* mark face as tri */ + + if (v1 != v3) { + BLI_edgehash_reinsert(edgehash, mf->v1, mf->v3, NULL); + (*fs) |= 4; + } + } + } + + /* count splits & create indexes for new verts */ + ehi = BLI_edgehashIterator_new(edgehash); + totesplit = totvert; + for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) { + BLI_edgehashIterator_setValue(ehi, POINTER_FROM_INT(totesplit)); + totesplit++; + } + BLI_edgehashIterator_free(ehi); + + /* count new faces due to splitting */ + for (i = 0, fs = facesplit; i < totface; i++, fs++) + totfsplit += add_faces[*fs]; + + split_m = BKE_mesh_new_nomain_from_template(mesh, totesplit, 0, totface + totfsplit, 0, 0); + + numlayer = CustomData_number_of_layers(&split_m->fdata, CD_MTFACE); + + /* copy new faces & verts (is it really this painful with custom data??) */ + for (i = 0; i < totvert; i++) { + MVert source; + MVert *dest; + source = mesh->mvert[i]; + dest = &split_m->mvert[i]; + + CustomData_copy_data(&mesh->vdata, &split_m->vdata, i, i, 1); + *dest = source; + } + + /* override original facepa (original pointer is saved in caller function) */ + + /* BMESH_TODO, (totfsplit * 2) over allocation is used since the quads are + * later interpreted as tri's, for this to work right I think we probably + * have to stop using tessface - campbell */ + + facepa = MEM_calloc_arrayN((totface + (totfsplit * 2)), sizeof(int), "explode_facepa"); + //memcpy(facepa, emd->facepa, totface*sizeof(int)); + emd->facepa = facepa; + + /* create new verts */ + ehi = BLI_edgehashIterator_new(edgehash); + for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) { + BLI_edgehashIterator_getKey(ehi, &ed_v1, &ed_v2); + esplit = POINTER_AS_INT(BLI_edgehashIterator_getValue(ehi)); + mv = &split_m->mvert[ed_v2]; + dupve = &split_m->mvert[esplit]; + + CustomData_copy_data(&split_m->vdata, &split_m->vdata, ed_v2, esplit, 1); + + *dupve = *mv; + + mv = &split_m->mvert[ed_v1]; + + mid_v3_v3v3(dupve->co, dupve->co, mv->co); + } + BLI_edgehashIterator_free(ehi); + + /* create new faces */ + curdupface = 0; //=totface; + //curdupin=totesplit; + for (i = 0, fs = facesplit; i < totface; i++, fs++) { + mf = &mesh->mface[i]; + + switch (*fs) { + case 3: + case 10: + case 11: + case 15: + SET_VERTS(1, 2, 3, 4); + break; + case 5: + case 6: + case 7: + SET_VERTS(2, 3, 4, 1); + break; + case 9: + case 13: + SET_VERTS(4, 1, 2, 3); + break; + case 12: + case 14: + SET_VERTS(3, 4, 1, 2); + break; + case 21: + case 23: + SET_VERTS(1, 2, 3, 4); + break; + case 19: + SET_VERTS(2, 3, 1, 4); + break; + case 22: + SET_VERTS(3, 1, 2, 4); + break; + } + + switch (*fs) { + case 3: + case 6: + case 9: + case 12: + remap_faces_3_6_9_12( + mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]); + if (numlayer) { + remap_uvs_3_6_9_12(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]); + } + break; + case 5: + case 10: + remap_faces_5_10( + mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]); + if (numlayer) { + remap_uvs_5_10(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]); + } + break; + case 15: + remap_faces_15( + mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]); + if (numlayer) { + remap_uvs_15(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]); + } + break; + case 7: + case 11: + case 13: + case 14: + remap_faces_7_11_13_14( + mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]); + if (numlayer) { + remap_uvs_7_11_13_14(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]); + } + break; + case 19: + case 21: + case 22: + remap_faces_19_21_22( + mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2]); + if (numlayer) { + remap_uvs_19_21_22(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2]); + } + break; + case 23: + remap_faces_23( + mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2]); + if (numlayer) { + remap_uvs_23(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2]); + } + break; + case 0: + case 16: + df1 = get_dface(mesh, split_m, curdupface, i, mf); + facepa[curdupface] = vertpa[mf->v1]; + + if (df1->v4) { + df1->flag |= ME_FACE_SEL; + } + else { + df1->flag &= ~ME_FACE_SEL; + } + break; + } + + curdupface += add_faces[*fs] + 1; + } + + for (i = 0; i < curdupface; i++) { + mf = &split_m->mface[i]; + test_index_face(mf, &split_m->fdata, i, ((mf->flag & ME_FACE_SEL) ? 4 : 3)); + } + + BLI_edgehash_free(edgehash, NULL); + MEM_freeN(facesplit); + MEM_freeN(vertpa); + + BKE_mesh_calc_edges_tessface(split_m); + BKE_mesh_convert_mfaces_to_mpolys(split_m); + + return split_m; } -static Mesh *explodeMesh( - ExplodeModifierData *emd, - ParticleSystemModifierData *psmd, const ModifierEvalContext *ctx, Scene *scene, - Mesh *to_explode) +static Mesh *explodeMesh(ExplodeModifierData *emd, + ParticleSystemModifierData *psmd, + const ModifierEvalContext *ctx, + Scene *scene, + Mesh *to_explode) { - Mesh *explode, *mesh = to_explode; - MFace *mf = NULL, *mface; - /* ParticleSettings *part=psmd->psys->part; */ /* UNUSED */ - ParticleSimulationData sim = {NULL}; - ParticleData *pa = NULL, *pars = psmd->psys->particles; - ParticleKey state, birth; - EdgeHash *vertpahash; - EdgeHashIterator *ehi; - float *vertco = NULL, imat[4][4]; - float rot[4]; - float cfra; - /* float timestep; */ - const int *facepa = emd->facepa; - int totdup = 0, totvert = 0, totface = 0, totpart = 0, delface = 0; - int i, v, u; - unsigned int ed_v1, ed_v2, mindex = 0; - MTFace *mtface = NULL, *mtf; - - totface = mesh->totface; - totvert = mesh->totvert; - mface = mesh->mface; - totpart = psmd->psys->totpart; - - sim.depsgraph = ctx->depsgraph; - sim.scene = scene; - sim.ob = ctx->object; - sim.psys = psmd->psys; - sim.psmd = psmd; - - /* timestep = psys_get_timestep(&sim); */ - - cfra = BKE_scene_frame_get(scene); - - /* hash table for vertice <-> particle relations */ - vertpahash = BLI_edgehash_new(__func__); - - for (i = 0; i < totface; i++) { - if (facepa[i] != totpart) { - pa = pars + facepa[i]; - - if ((pa->alive == PARS_UNBORN && (emd->flag & eExplodeFlag_Unborn) == 0) || - (pa->alive == PARS_ALIVE && (emd->flag & eExplodeFlag_Alive) == 0) || - (pa->alive == PARS_DEAD && (emd->flag & eExplodeFlag_Dead) == 0)) - { - delface++; - continue; - } - } - - /* do mindex + totvert to ensure the vertex index to be the first - * with BLI_edgehashIterator_getKey */ - if (facepa[i] == totpart || cfra < (pars + facepa[i])->time) { - mindex = totvert + totpart; - } - else { - mindex = totvert + facepa[i]; - } - - mf = &mface[i]; - - /* set face vertices to exist in particle group */ - BLI_edgehash_reinsert(vertpahash, mf->v1, mindex, NULL); - BLI_edgehash_reinsert(vertpahash, mf->v2, mindex, NULL); - BLI_edgehash_reinsert(vertpahash, mf->v3, mindex, NULL); - if (mf->v4) { - BLI_edgehash_reinsert(vertpahash, mf->v4, mindex, NULL); - } - } - - /* make new vertice indexes & count total vertices after duplication */ - ehi = BLI_edgehashIterator_new(vertpahash); - for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) { - BLI_edgehashIterator_setValue(ehi, POINTER_FROM_INT(totdup)); - totdup++; - } - BLI_edgehashIterator_free(ehi); - - /* the final duplicated vertices */ - explode = BKE_mesh_new_nomain_from_template(mesh, totdup, 0, totface - delface, 0, 0); - - mtface = CustomData_get_layer_named(&explode->fdata, CD_MTFACE, emd->uvname); - /*dupvert = CDDM_get_verts(explode);*/ - - /* getting back to object space */ - invert_m4_m4(imat, ctx->object->obmat); - - psmd->psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); - - /* duplicate & displace vertices */ - ehi = BLI_edgehashIterator_new(vertpahash); - for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) { - MVert source; - MVert *dest; - - /* get particle + vertex from hash */ - BLI_edgehashIterator_getKey(ehi, &ed_v1, &ed_v2); - ed_v2 -= totvert; - v = POINTER_AS_INT(BLI_edgehashIterator_getValue(ehi)); - - source = mesh->mvert[ed_v1]; - dest = &explode->mvert[v]; - - CustomData_copy_data(&mesh->vdata, &explode->vdata, ed_v1, v, 1); - - *dest = source; - - if (ed_v2 != totpart) { - /* get particle */ - pa = pars + ed_v2; - - psys_get_birth_coords(&sim, pa, &birth, 0, 0); - - state.time = cfra; - psys_get_particle_state(&sim, ed_v2, &state, 1); - - vertco = explode->mvert[v].co; - mul_m4_v3(ctx->object->obmat, vertco); - - sub_v3_v3(vertco, birth.co); - - /* apply rotation, size & location */ - sub_qt_qtqt(rot, state.rot, birth.rot); - mul_qt_v3(rot, vertco); - - if (emd->flag & eExplodeFlag_PaSize) { - mul_v3_fl(vertco, pa->size); - } - - add_v3_v3(vertco, state.co); + Mesh *explode, *mesh = to_explode; + MFace *mf = NULL, *mface; + /* ParticleSettings *part=psmd->psys->part; */ /* UNUSED */ + ParticleSimulationData sim = {NULL}; + ParticleData *pa = NULL, *pars = psmd->psys->particles; + ParticleKey state, birth; + EdgeHash *vertpahash; + EdgeHashIterator *ehi; + float *vertco = NULL, imat[4][4]; + float rot[4]; + float cfra; + /* float timestep; */ + const int *facepa = emd->facepa; + int totdup = 0, totvert = 0, totface = 0, totpart = 0, delface = 0; + int i, v, u; + unsigned int ed_v1, ed_v2, mindex = 0; + MTFace *mtface = NULL, *mtf; + + totface = mesh->totface; + totvert = mesh->totvert; + mface = mesh->mface; + totpart = psmd->psys->totpart; + + sim.depsgraph = ctx->depsgraph; + sim.scene = scene; + sim.ob = ctx->object; + sim.psys = psmd->psys; + sim.psmd = psmd; + + /* timestep = psys_get_timestep(&sim); */ + + cfra = BKE_scene_frame_get(scene); + + /* hash table for vertice <-> particle relations */ + vertpahash = BLI_edgehash_new(__func__); + + for (i = 0; i < totface; i++) { + if (facepa[i] != totpart) { + pa = pars + facepa[i]; + + if ((pa->alive == PARS_UNBORN && (emd->flag & eExplodeFlag_Unborn) == 0) || + (pa->alive == PARS_ALIVE && (emd->flag & eExplodeFlag_Alive) == 0) || + (pa->alive == PARS_DEAD && (emd->flag & eExplodeFlag_Dead) == 0)) { + delface++; + continue; + } + } + + /* do mindex + totvert to ensure the vertex index to be the first + * with BLI_edgehashIterator_getKey */ + if (facepa[i] == totpart || cfra < (pars + facepa[i])->time) { + mindex = totvert + totpart; + } + else { + mindex = totvert + facepa[i]; + } + + mf = &mface[i]; + + /* set face vertices to exist in particle group */ + BLI_edgehash_reinsert(vertpahash, mf->v1, mindex, NULL); + BLI_edgehash_reinsert(vertpahash, mf->v2, mindex, NULL); + BLI_edgehash_reinsert(vertpahash, mf->v3, mindex, NULL); + if (mf->v4) { + BLI_edgehash_reinsert(vertpahash, mf->v4, mindex, NULL); + } + } + + /* make new vertice indexes & count total vertices after duplication */ + ehi = BLI_edgehashIterator_new(vertpahash); + for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) { + BLI_edgehashIterator_setValue(ehi, POINTER_FROM_INT(totdup)); + totdup++; + } + BLI_edgehashIterator_free(ehi); + + /* the final duplicated vertices */ + explode = BKE_mesh_new_nomain_from_template(mesh, totdup, 0, totface - delface, 0, 0); + + mtface = CustomData_get_layer_named(&explode->fdata, CD_MTFACE, emd->uvname); + /*dupvert = CDDM_get_verts(explode);*/ + + /* getting back to object space */ + invert_m4_m4(imat, ctx->object->obmat); + + psmd->psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); + + /* duplicate & displace vertices */ + ehi = BLI_edgehashIterator_new(vertpahash); + for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) { + MVert source; + MVert *dest; + + /* get particle + vertex from hash */ + BLI_edgehashIterator_getKey(ehi, &ed_v1, &ed_v2); + ed_v2 -= totvert; + v = POINTER_AS_INT(BLI_edgehashIterator_getValue(ehi)); + + source = mesh->mvert[ed_v1]; + dest = &explode->mvert[v]; + + CustomData_copy_data(&mesh->vdata, &explode->vdata, ed_v1, v, 1); + + *dest = source; + + if (ed_v2 != totpart) { + /* get particle */ + pa = pars + ed_v2; + + psys_get_birth_coords(&sim, pa, &birth, 0, 0); + + state.time = cfra; + psys_get_particle_state(&sim, ed_v2, &state, 1); + + vertco = explode->mvert[v].co; + mul_m4_v3(ctx->object->obmat, vertco); - mul_m4_v3(imat, vertco); - } - } - BLI_edgehashIterator_free(ehi); + sub_v3_v3(vertco, birth.co); + + /* apply rotation, size & location */ + sub_qt_qtqt(rot, state.rot, birth.rot); + mul_qt_v3(rot, vertco); - /*map new vertices to faces*/ - for (i = 0, u = 0; i < totface; i++) { - MFace source; - int orig_v4; + if (emd->flag & eExplodeFlag_PaSize) { + mul_v3_fl(vertco, pa->size); + } - if (facepa[i] != totpart) { - pa = pars + facepa[i]; + add_v3_v3(vertco, state.co); - if (pa->alive == PARS_UNBORN && (emd->flag & eExplodeFlag_Unborn) == 0) continue; - if (pa->alive == PARS_ALIVE && (emd->flag & eExplodeFlag_Alive) == 0) continue; - if (pa->alive == PARS_DEAD && (emd->flag & eExplodeFlag_Dead) == 0) continue; - } + mul_m4_v3(imat, vertco); + } + } + BLI_edgehashIterator_free(ehi); + + /*map new vertices to faces*/ + for (i = 0, u = 0; i < totface; i++) { + MFace source; + int orig_v4; + + if (facepa[i] != totpart) { + pa = pars + facepa[i]; + + if (pa->alive == PARS_UNBORN && (emd->flag & eExplodeFlag_Unborn) == 0) + continue; + if (pa->alive == PARS_ALIVE && (emd->flag & eExplodeFlag_Alive) == 0) + continue; + if (pa->alive == PARS_DEAD && (emd->flag & eExplodeFlag_Dead) == 0) + continue; + } - source = mesh->mface[i]; - mf = &explode->mface[u]; + source = mesh->mface[i]; + mf = &explode->mface[u]; - orig_v4 = source.v4; + orig_v4 = source.v4; - if (facepa[i] != totpart && cfra < pa->time) { - mindex = totvert + totpart; - } - else { - mindex = totvert + facepa[i]; - } + if (facepa[i] != totpart && cfra < pa->time) { + mindex = totvert + totpart; + } + else { + mindex = totvert + facepa[i]; + } - source.v1 = edgecut_get(vertpahash, source.v1, mindex); - source.v2 = edgecut_get(vertpahash, source.v2, mindex); - source.v3 = edgecut_get(vertpahash, source.v3, mindex); - if (source.v4) { - source.v4 = edgecut_get(vertpahash, source.v4, mindex); - } + source.v1 = edgecut_get(vertpahash, source.v1, mindex); + source.v2 = edgecut_get(vertpahash, source.v2, mindex); + source.v3 = edgecut_get(vertpahash, source.v3, mindex); + if (source.v4) { + source.v4 = edgecut_get(vertpahash, source.v4, mindex); + } - CustomData_copy_data(&mesh->fdata, &explode->fdata, i, u, 1); + CustomData_copy_data(&mesh->fdata, &explode->fdata, i, u, 1); - *mf = source; + *mf = source; - /* override uv channel for particle age */ - if (mtface) { - float age = (cfra - pa->time) / pa->lifetime; - /* Clamp to this range to avoid flipping to the other side of the coordinates. */ - CLAMP(age, 0.001f, 0.999f); + /* override uv channel for particle age */ + if (mtface) { + float age = (cfra - pa->time) / pa->lifetime; + /* Clamp to this range to avoid flipping to the other side of the coordinates. */ + CLAMP(age, 0.001f, 0.999f); - mtf = mtface + u; + mtf = mtface + u; - mtf->uv[0][0] = mtf->uv[1][0] = mtf->uv[2][0] = mtf->uv[3][0] = age; - mtf->uv[0][1] = mtf->uv[1][1] = mtf->uv[2][1] = mtf->uv[3][1] = 0.5f; - } + mtf->uv[0][0] = mtf->uv[1][0] = mtf->uv[2][0] = mtf->uv[3][0] = age; + mtf->uv[0][1] = mtf->uv[1][1] = mtf->uv[2][1] = mtf->uv[3][1] = 0.5f; + } - test_index_face(mf, &explode->fdata, u, (orig_v4 ? 4 : 3)); - u++; - } + test_index_face(mf, &explode->fdata, u, (orig_v4 ? 4 : 3)); + u++; + } - /* cleanup */ - BLI_edgehash_free(vertpahash, NULL); + /* cleanup */ + BLI_edgehash_free(vertpahash, NULL); - /* finalization */ - BKE_mesh_calc_edges_tessface(explode); - BKE_mesh_convert_mfaces_to_mpolys(explode); - explode->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + /* finalization */ + BKE_mesh_calc_edges_tessface(explode); + BKE_mesh_convert_mfaces_to_mpolys(explode); + explode->runtime.cd_dirty_vert |= CD_MASK_NORMAL; - if (psmd->psys->lattice_deform_data) { - end_latt_deform(psmd->psys->lattice_deform_data); - psmd->psys->lattice_deform_data = NULL; - } + if (psmd->psys->lattice_deform_data) { + end_latt_deform(psmd->psys->lattice_deform_data); + psmd->psys->lattice_deform_data = NULL; + } - return explode; + return explode; } static ParticleSystemModifierData *findPrecedingParticlesystem(Object *ob, ModifierData *emd) { - ModifierData *md; - ParticleSystemModifierData *psmd = NULL; - - for (md = ob->modifiers.first; emd != md; md = md->next) { - if (md->type == eModifierType_ParticleSystem) { - psmd = (ParticleSystemModifierData *) md; - } - } - return psmd; + ModifierData *md; + ParticleSystemModifierData *psmd = NULL; + + for (md = ob->modifiers.first; emd != md; md = md->next) { + if (md->type == eModifierType_ParticleSystem) { + psmd = (ParticleSystemModifierData *)md; + } + } + return psmd; } -static Mesh *applyModifier( - ModifierData *md, const ModifierEvalContext *ctx, - Mesh *mesh) +static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) { - ExplodeModifierData *emd = (ExplodeModifierData *) md; - ParticleSystemModifierData *psmd = findPrecedingParticlesystem(ctx->object, md); - - if (psmd) { - ParticleSystem *psys = psmd->psys; - - if (psys == NULL || psys->totpart == 0) { - return mesh; - } - if (psys->part == NULL || psys->particles == NULL) { - return mesh; - } - if (psmd->mesh_final == NULL) { - return mesh; - } - - BKE_mesh_tessface_ensure(mesh); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */ - - /* 1. find faces to be exploded if needed */ - if (emd->facepa == NULL || - psmd->flag & eParticleSystemFlag_Pars || - emd->flag & eExplodeFlag_CalcFaces || - MEM_allocN_len(emd->facepa) / sizeof(int) != mesh->totface) - { - if (psmd->flag & eParticleSystemFlag_Pars) { - psmd->flag &= ~eParticleSystemFlag_Pars; - } - if (emd->flag & eExplodeFlag_CalcFaces) { - emd->flag &= ~eExplodeFlag_CalcFaces; - } - createFacepa(emd, psmd, mesh); - } - /* 2. create new mesh */ - Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); - if (emd->flag & eExplodeFlag_EdgeCut) { - int *facepa = emd->facepa; - Mesh *split_m = cutEdges(emd, mesh); - Mesh *explode = explodeMesh(emd, psmd, ctx, scene, split_m); - - MEM_freeN(emd->facepa); - emd->facepa = facepa; - BKE_id_free(NULL, split_m); - return explode; - } - else { - return explodeMesh(emd, psmd, ctx, scene, mesh); - } - } - return mesh; + ExplodeModifierData *emd = (ExplodeModifierData *)md; + ParticleSystemModifierData *psmd = findPrecedingParticlesystem(ctx->object, md); + + if (psmd) { + ParticleSystem *psys = psmd->psys; + + if (psys == NULL || psys->totpart == 0) { + return mesh; + } + if (psys->part == NULL || psys->particles == NULL) { + return mesh; + } + if (psmd->mesh_final == NULL) { + return mesh; + } + + BKE_mesh_tessface_ensure(mesh); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */ + + /* 1. find faces to be exploded if needed */ + if (emd->facepa == NULL || psmd->flag & eParticleSystemFlag_Pars || + emd->flag & eExplodeFlag_CalcFaces || + MEM_allocN_len(emd->facepa) / sizeof(int) != mesh->totface) { + if (psmd->flag & eParticleSystemFlag_Pars) { + psmd->flag &= ~eParticleSystemFlag_Pars; + } + if (emd->flag & eExplodeFlag_CalcFaces) { + emd->flag &= ~eExplodeFlag_CalcFaces; + } + createFacepa(emd, psmd, mesh); + } + /* 2. create new mesh */ + Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); + if (emd->flag & eExplodeFlag_EdgeCut) { + int *facepa = emd->facepa; + Mesh *split_m = cutEdges(emd, mesh); + Mesh *explode = explodeMesh(emd, psmd, ctx, scene, split_m); + + MEM_freeN(emd->facepa); + emd->facepa = facepa; + BKE_id_free(NULL, split_m); + return explode; + } + else { + return explodeMesh(emd, psmd, ctx, scene, mesh); + } + } + return mesh; } ModifierTypeInfo modifierType_Explode = { - /* name */ "Explode", - /* structName */ "ExplodeModifierData", - /* structSize */ sizeof(ExplodeModifierData), - /* type */ eModifierTypeType_Constructive, - /* flags */ eModifierTypeFlag_AcceptsMesh, - /* copyData */ copyData, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ freeData, - /* isDisabled */ NULL, - /* updateDepsgraph */ NULL, - /* dependsOnTime */ dependsOnTime, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ NULL, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Explode", + /* structName */ "ExplodeModifierData", + /* structSize */ sizeof(ExplodeModifierData), + /* type */ eModifierTypeType_Constructive, + /* flags */ eModifierTypeFlag_AcceptsMesh, + /* copyData */ copyData, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ freeData, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ dependsOnTime, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_fluidsim.c b/source/blender/modifiers/intern/MOD_fluidsim.c index 4377e04db84..620b21f3e0c 100644 --- a/source/blender/modifiers/intern/MOD_fluidsim.c +++ b/source/blender/modifiers/intern/MOD_fluidsim.c @@ -21,7 +21,6 @@ * \ingroup modifiers */ - #include "BLI_utildefines.h" #include "DNA_mesh_types.h" @@ -42,117 +41,110 @@ /* Fluidsim */ static void initData(ModifierData *md) { - FluidsimModifierData *fluidmd = (FluidsimModifierData *) md; + FluidsimModifierData *fluidmd = (FluidsimModifierData *)md; - fluidsim_init(fluidmd); + fluidsim_init(fluidmd); } static void freeData(ModifierData *md) { - FluidsimModifierData *fluidmd = (FluidsimModifierData *) md; + FluidsimModifierData *fluidmd = (FluidsimModifierData *)md; - fluidsim_free(fluidmd); + fluidsim_free(fluidmd); } static void copyData(const ModifierData *md, ModifierData *target, const int UNUSED(flag)) { - const FluidsimModifierData *fluidmd = (const FluidsimModifierData *) md; - FluidsimModifierData *tfluidmd = (FluidsimModifierData *) target; - - /* Free any FSS that was allocated in initData() */ - if (tfluidmd->fss) { - MEM_SAFE_FREE(tfluidmd->fss->meshVelocities); - MEM_freeN(tfluidmd->fss); - } - - if (fluidmd->fss == NULL) { - tfluidmd->fss = NULL; - return; - } - - tfluidmd->fss = MEM_dupallocN(fluidmd->fss); - if (tfluidmd->fss->meshVelocities != NULL) { - tfluidmd->fss->meshVelocities = MEM_dupallocN(tfluidmd->fss->meshVelocities); - } + const FluidsimModifierData *fluidmd = (const FluidsimModifierData *)md; + FluidsimModifierData *tfluidmd = (FluidsimModifierData *)target; + + /* Free any FSS that was allocated in initData() */ + if (tfluidmd->fss) { + MEM_SAFE_FREE(tfluidmd->fss->meshVelocities); + MEM_freeN(tfluidmd->fss); + } + + if (fluidmd->fss == NULL) { + tfluidmd->fss = NULL; + return; + } + + tfluidmd->fss = MEM_dupallocN(fluidmd->fss); + if (tfluidmd->fss->meshVelocities != NULL) { + tfluidmd->fss->meshVelocities = MEM_dupallocN(tfluidmd->fss->meshVelocities); + } } - - -static Mesh *applyModifier( - ModifierData *md, const ModifierEvalContext *ctx, - Mesh *mesh) +static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) { - FluidsimModifierData *fluidmd = (FluidsimModifierData *) md; - Mesh *result = NULL; + FluidsimModifierData *fluidmd = (FluidsimModifierData *)md; + Mesh *result = NULL; - /* check for alloc failing */ - if (!fluidmd->fss) { - initData(md); + /* check for alloc failing */ + if (!fluidmd->fss) { + initData(md); - if (!fluidmd->fss) { - return mesh; - } - } + if (!fluidmd->fss) { + return mesh; + } + } - result = fluidsimModifier_do(fluidmd, ctx, mesh); + result = fluidsimModifier_do(fluidmd, ctx, mesh); - return result ? result : mesh; + return result ? result : mesh; } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { - FluidsimModifierData *fluidmd = (FluidsimModifierData *) md; - if (fluidmd && fluidmd->fss) { - if (fluidmd->fss->type == OB_FLUIDSIM_DOMAIN) { - FOREACH_SCENE_OBJECT_BEGIN(ctx->scene, ob1) - { - if (ob1 != ctx->object) { - FluidsimModifierData *fluidmdtmp = - (FluidsimModifierData *)modifiers_findByType(ob1, eModifierType_Fluidsim); - - /* Only put dependencies from NON-DOMAIN fluids in here. */ - if (fluidmdtmp && fluidmdtmp->fss && (fluidmdtmp->fss->type != OB_FLUIDSIM_DOMAIN)) { - DEG_add_object_relation(ctx->node, ob1, DEG_OB_COMP_TRANSFORM, "Fluidsim Object"); - } - } - } - FOREACH_SCENE_OBJECT_END; - } - } + FluidsimModifierData *fluidmd = (FluidsimModifierData *)md; + if (fluidmd && fluidmd->fss) { + if (fluidmd->fss->type == OB_FLUIDSIM_DOMAIN) { + FOREACH_SCENE_OBJECT_BEGIN (ctx->scene, ob1) { + if (ob1 != ctx->object) { + FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType( + ob1, eModifierType_Fluidsim); + + /* Only put dependencies from NON-DOMAIN fluids in here. */ + if (fluidmdtmp && fluidmdtmp->fss && (fluidmdtmp->fss->type != OB_FLUIDSIM_DOMAIN)) { + DEG_add_object_relation(ctx->node, ob1, DEG_OB_COMP_TRANSFORM, "Fluidsim Object"); + } + } + } + FOREACH_SCENE_OBJECT_END; + } + } } static bool dependsOnTime(ModifierData *UNUSED(md)) { - return true; + return true; } - ModifierTypeInfo modifierType_Fluidsim = { - /* name */ "Fluidsim", - /* structName */ "FluidsimModifierData", - /* structSize */ sizeof(FluidsimModifierData), - /* type */ eModifierTypeType_Nonconstructive, - - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_RequiresOriginalData | - eModifierTypeFlag_Single, - - /* copyData */ copyData, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ initData, - /* requiredDataMask */ NULL, - /* freeData */ freeData, - /* isDisabled */ NULL, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ dependsOnTime, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ NULL, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Fluidsim", + /* structName */ "FluidsimModifierData", + /* structSize */ sizeof(FluidsimModifierData), + /* type */ eModifierTypeType_Nonconstructive, + + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_RequiresOriginalData | + eModifierTypeFlag_Single, + + /* copyData */ copyData, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ initData, + /* requiredDataMask */ NULL, + /* freeData */ freeData, + /* isDisabled */ NULL, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ dependsOnTime, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_fluidsim_util.c b/source/blender/modifiers/intern/MOD_fluidsim_util.c index f548eb78abd..3744c527983 100644 --- a/source/blender/modifiers/intern/MOD_fluidsim_util.c +++ b/source/blender/modifiers/intern/MOD_fluidsim_util.c @@ -21,7 +21,6 @@ * \ingroup modifiers */ - #include #include @@ -56,288 +55,301 @@ // headers for fluidsim bobj meshes #include "LBM_fluidsim.h" - void fluidsim_init(FluidsimModifierData *fluidmd) { #ifdef WITH_MOD_FLUID - if (fluidmd) { - FluidsimSettings *fss = MEM_callocN(sizeof(FluidsimSettings), "fluidsimsettings"); - - fluidmd->fss = fss; - - if (!fss) - return; - - fss->fmd = fluidmd; - fss->type = OB_FLUIDSIM_ENABLE; - fss->threads = 0; - fss->show_advancedoptions = 0; - - fss->resolutionxyz = 65; - fss->previewresxyz = 45; - fss->realsize = 0.5; - fss->guiDisplayMode = OB_FSDOM_PREVIEW; - fss->renderDisplayMode = OB_FSDOM_FINAL; - - fss->viscosityValue = 1.0; - fss->viscosityExponent = 6; - - fss->grav[0] = 0.0; - fss->grav[1] = 0.0; - fss->grav[2] = -9.81; - - fss->animStart = 0.0; - fss->animEnd = 4.0; - fss->animRate = 1.0; - fss->gstar = 0.005; // used as normgstar - fss->maxRefine = -1; - /* maxRefine is set according to resolutionxyz during bake */ - - /* fluid/inflow settings - * fss->iniVel --> automatically set to 0 */ - - modifier_path_init(fss->surfdataPath, sizeof(fss->surfdataPath), OB_FLUIDSIM_SURF_DIR_DEFAULT); - - /* first init of bounding box */ - /* no bounding box needed */ - - /* todo - reuse default init from elbeem! */ - fss->typeFlags = OB_FSBND_PARTSLIP | OB_FSSG_NOOBS; - fss->domainNovecgen = 0; - fss->volumeInitType = 1; /* volume */ - fss->partSlipValue = 0.2; - - fss->generateTracers = 0; - fss->generateParticles = 0.0; - fss->surfaceSmoothing = 1.0; - fss->surfaceSubdivs = 0.0; - fss->particleInfSize = 0.0; - fss->particleInfAlpha = 0.0; - - /* init fluid control settings */ - fss->attractforceStrength = 0.2; - fss->attractforceRadius = 0.75; - fss->velocityforceStrength = 0.2; - fss->velocityforceRadius = 0.75; - fss->cpsTimeStart = fss->animStart; - fss->cpsTimeEnd = fss->animEnd; - fss->cpsQuality = 10.0; // 1.0 / 10.0 => means 0.1 width - - /* - * BAD TODO: this is done in buttons_object.c in the moment - * Mesh *mesh = ob->data; - * // calculate bounding box - * fluid_get_bb(mesh->mvert, mesh->totvert, ob->obmat, fss->bbStart, fss->bbSize); - */ - - fss->meshVelocities = NULL; - - fss->lastgoodframe = -1; - - fss->flag |= OB_FLUIDSIM_ACTIVE; - - } + if (fluidmd) { + FluidsimSettings *fss = MEM_callocN(sizeof(FluidsimSettings), "fluidsimsettings"); + + fluidmd->fss = fss; + + if (!fss) + return; + + fss->fmd = fluidmd; + fss->type = OB_FLUIDSIM_ENABLE; + fss->threads = 0; + fss->show_advancedoptions = 0; + + fss->resolutionxyz = 65; + fss->previewresxyz = 45; + fss->realsize = 0.5; + fss->guiDisplayMode = OB_FSDOM_PREVIEW; + fss->renderDisplayMode = OB_FSDOM_FINAL; + + fss->viscosityValue = 1.0; + fss->viscosityExponent = 6; + + fss->grav[0] = 0.0; + fss->grav[1] = 0.0; + fss->grav[2] = -9.81; + + fss->animStart = 0.0; + fss->animEnd = 4.0; + fss->animRate = 1.0; + fss->gstar = 0.005; // used as normgstar + fss->maxRefine = -1; + /* maxRefine is set according to resolutionxyz during bake */ + + /* fluid/inflow settings + * fss->iniVel --> automatically set to 0 */ + + modifier_path_init(fss->surfdataPath, sizeof(fss->surfdataPath), OB_FLUIDSIM_SURF_DIR_DEFAULT); + + /* first init of bounding box */ + /* no bounding box needed */ + + /* todo - reuse default init from elbeem! */ + fss->typeFlags = OB_FSBND_PARTSLIP | OB_FSSG_NOOBS; + fss->domainNovecgen = 0; + fss->volumeInitType = 1; /* volume */ + fss->partSlipValue = 0.2; + + fss->generateTracers = 0; + fss->generateParticles = 0.0; + fss->surfaceSmoothing = 1.0; + fss->surfaceSubdivs = 0.0; + fss->particleInfSize = 0.0; + fss->particleInfAlpha = 0.0; + + /* init fluid control settings */ + fss->attractforceStrength = 0.2; + fss->attractforceRadius = 0.75; + fss->velocityforceStrength = 0.2; + fss->velocityforceRadius = 0.75; + fss->cpsTimeStart = fss->animStart; + fss->cpsTimeEnd = fss->animEnd; + fss->cpsQuality = 10.0; // 1.0 / 10.0 => means 0.1 width + + /* + * BAD TODO: this is done in buttons_object.c in the moment + * Mesh *mesh = ob->data; + * // calculate bounding box + * fluid_get_bb(mesh->mvert, mesh->totvert, ob->obmat, fss->bbStart, fss->bbSize); + */ + + fss->meshVelocities = NULL; + + fss->lastgoodframe = -1; + + fss->flag |= OB_FLUIDSIM_ACTIVE; + } #else - (void)fluidmd; /* unused */ + (void)fluidmd; /* unused */ #endif - return; + return; } void fluidsim_free(FluidsimModifierData *fluidmd) { - if (fluidmd && fluidmd->fss) { - if (fluidmd->fss->meshVelocities) { - MEM_freeN(fluidmd->fss->meshVelocities); - } - MEM_SAFE_FREE(fluidmd->fss); - } - - return; + if (fluidmd && fluidmd->fss) { + if (fluidmd->fss->meshVelocities) { + MEM_freeN(fluidmd->fss->meshVelocities); + } + MEM_SAFE_FREE(fluidmd->fss); + } + + return; } #ifdef WITH_MOD_FLUID /* read .bobj.gz file into a fluidsimMesh struct */ static Mesh *fluidsim_read_obj(const char *filename, const MPoly *mp_example) { - int wri = 0, i; - int gotBytes; - gzFile gzf; - int numverts = 0, numfaces = 0; - Mesh *mesh = NULL; - MPoly *mp; - MLoop *ml; - MVert *mv; - short *normals, *no_s; - float no[3]; - - const short mp_mat_nr = mp_example->mat_nr; - const char mp_flag = mp_example->flag; - - /* ------------------------------------------------ - * get numverts + numfaces first - * ------------------------------------------------ */ - gzf = BLI_gzopen(filename, "rb"); - if (!gzf) { - return NULL; - } - - /* read numverts */ - gotBytes = gzread(gzf, &wri, sizeof(wri)); - numverts = wri; - - /* skip verts */ - gotBytes = gzseek(gzf, numverts * 3 * sizeof(float), SEEK_CUR) != -1; - - - /* read number of normals */ - if (gotBytes) - gotBytes = gzread(gzf, &wri, sizeof(wri)); - - /* skip normals */ - gotBytes = gzseek(gzf, numverts * 3 * sizeof(float), SEEK_CUR) != -1; - - /* get no. of triangles */ - if (gotBytes) - gotBytes = gzread(gzf, &wri, sizeof(wri)); - numfaces = wri; - - gzclose(gzf); - /* ------------------------------------------------ */ - - if (!numfaces || !numverts || !gotBytes) - return NULL; - - gzf = BLI_gzopen(filename, "rb"); - if (!gzf) { - return NULL; - } - - mesh = BKE_mesh_new_nomain(numverts, 0, 0, numfaces * 3, numfaces); - - if (!mesh) { - gzclose(gzf); - return NULL; - } - - /* read numverts */ - gotBytes = gzread(gzf, &wri, sizeof(wri)); - - /* read vertex position from file */ - mv = mesh->mvert; - - for (i = 0; i < numverts; i++, mv++) - gotBytes = gzread(gzf, mv->co, sizeof(float) * 3); - - /* should be the same as numverts */ - gotBytes = gzread(gzf, &wri, sizeof(wri)); - if (wri != numverts) { - if (mesh) - BKE_id_free(NULL, mesh); - gzclose(gzf); - return NULL; - } - - normals = MEM_calloc_arrayN(numverts, 3 * sizeof(short), "fluid_tmp_normals"); - if (!normals) { - if (mesh) - BKE_id_free(NULL, mesh); - gzclose(gzf); - return NULL; - } - - /* read normals from file (but don't save them yet) */ - for (i = numverts, no_s = normals; i > 0; i--, no_s += 3) { - gotBytes = gzread(gzf, no, sizeof(float) * 3); - normal_float_to_short_v3(no_s, no); - } - - /* read no. of triangles */ - gotBytes = gzread(gzf, &wri, sizeof(wri)); - - if (wri != numfaces) { - printf("Fluidsim: error in reading data from file.\n"); - if (mesh) - BKE_id_free(NULL, mesh); - gzclose(gzf); - MEM_freeN(normals); - return NULL; - } - - /* read triangles from file */ - mp = mesh->mpoly; - ml = mesh->mloop; - for (i = 0; i < numfaces; i++, mp++, ml += 3) { - int face[3]; - - gotBytes = gzread(gzf, face, sizeof(int) * 3); - - /* initialize from existing face */ - mp->mat_nr = mp_mat_nr; - mp->flag = mp_flag; - - mp->loopstart = i * 3; - mp->totloop = 3; - - ml[0].v = face[0]; - ml[1].v = face[1]; - ml[2].v = face[2]; - - } - - gzclose(gzf); - - BKE_mesh_calc_edges(mesh, false, false); - BKE_mesh_apply_vert_normals(mesh, (short (*)[3])normals); - MEM_freeN(normals); - - // CDDM_calc_normals(result); - return mesh; + int wri = 0, i; + int gotBytes; + gzFile gzf; + int numverts = 0, numfaces = 0; + Mesh *mesh = NULL; + MPoly *mp; + MLoop *ml; + MVert *mv; + short *normals, *no_s; + float no[3]; + + const short mp_mat_nr = mp_example->mat_nr; + const char mp_flag = mp_example->flag; + + /* ------------------------------------------------ + * get numverts + numfaces first + * ------------------------------------------------ */ + gzf = BLI_gzopen(filename, "rb"); + if (!gzf) { + return NULL; + } + + /* read numverts */ + gotBytes = gzread(gzf, &wri, sizeof(wri)); + numverts = wri; + + /* skip verts */ + gotBytes = gzseek(gzf, numverts * 3 * sizeof(float), SEEK_CUR) != -1; + + /* read number of normals */ + if (gotBytes) + gotBytes = gzread(gzf, &wri, sizeof(wri)); + + /* skip normals */ + gotBytes = gzseek(gzf, numverts * 3 * sizeof(float), SEEK_CUR) != -1; + + /* get no. of triangles */ + if (gotBytes) + gotBytes = gzread(gzf, &wri, sizeof(wri)); + numfaces = wri; + + gzclose(gzf); + /* ------------------------------------------------ */ + + if (!numfaces || !numverts || !gotBytes) + return NULL; + + gzf = BLI_gzopen(filename, "rb"); + if (!gzf) { + return NULL; + } + + mesh = BKE_mesh_new_nomain(numverts, 0, 0, numfaces * 3, numfaces); + + if (!mesh) { + gzclose(gzf); + return NULL; + } + + /* read numverts */ + gotBytes = gzread(gzf, &wri, sizeof(wri)); + + /* read vertex position from file */ + mv = mesh->mvert; + + for (i = 0; i < numverts; i++, mv++) + gotBytes = gzread(gzf, mv->co, sizeof(float) * 3); + + /* should be the same as numverts */ + gotBytes = gzread(gzf, &wri, sizeof(wri)); + if (wri != numverts) { + if (mesh) + BKE_id_free(NULL, mesh); + gzclose(gzf); + return NULL; + } + + normals = MEM_calloc_arrayN(numverts, 3 * sizeof(short), "fluid_tmp_normals"); + if (!normals) { + if (mesh) + BKE_id_free(NULL, mesh); + gzclose(gzf); + return NULL; + } + + /* read normals from file (but don't save them yet) */ + for (i = numverts, no_s = normals; i > 0; i--, no_s += 3) { + gotBytes = gzread(gzf, no, sizeof(float) * 3); + normal_float_to_short_v3(no_s, no); + } + + /* read no. of triangles */ + gotBytes = gzread(gzf, &wri, sizeof(wri)); + + if (wri != numfaces) { + printf("Fluidsim: error in reading data from file.\n"); + if (mesh) + BKE_id_free(NULL, mesh); + gzclose(gzf); + MEM_freeN(normals); + return NULL; + } + + /* read triangles from file */ + mp = mesh->mpoly; + ml = mesh->mloop; + for (i = 0; i < numfaces; i++, mp++, ml += 3) { + int face[3]; + + gotBytes = gzread(gzf, face, sizeof(int) * 3); + + /* initialize from existing face */ + mp->mat_nr = mp_mat_nr; + mp->flag = mp_flag; + + mp->loopstart = i * 3; + mp->totloop = 3; + + ml[0].v = face[0]; + ml[1].v = face[1]; + ml[2].v = face[2]; + } + + gzclose(gzf); + + BKE_mesh_calc_edges(mesh, false, false); + BKE_mesh_apply_vert_normals(mesh, (short(*)[3])normals); + MEM_freeN(normals); + + // CDDM_calc_normals(result); + return mesh; } - -void fluid_get_bb( - MVert *mvert, int totvert, float obmat[4][4], - /*RET*/ float start[3], /*RET*/ float size[3]) +void fluid_get_bb(MVert *mvert, + int totvert, + float obmat[4][4], + /*RET*/ float start[3], + /*RET*/ float size[3]) { - float bbsx = 0.0, bbsy = 0.0, bbsz = 0.0; - float bbex = 1.0, bbey = 1.0, bbez = 1.0; - int i; - float vec[3]; - - if (totvert == 0) { - zero_v3(start); - zero_v3(size); - return; - } - - copy_v3_v3(vec, mvert[0].co); - mul_m4_v3(obmat, vec); - bbsx = vec[0]; bbsy = vec[1]; bbsz = vec[2]; - bbex = vec[0]; bbey = vec[1]; bbez = vec[2]; - - for (i = 1; i < totvert; i++) { - copy_v3_v3(vec, mvert[i].co); - mul_m4_v3(obmat, vec); - - if (vec[0] < bbsx) { bbsx = vec[0]; } - if (vec[1] < bbsy) { bbsy = vec[1]; } - if (vec[2] < bbsz) { bbsz = vec[2]; } - if (vec[0] > bbex) { bbex = vec[0]; } - if (vec[1] > bbey) { bbey = vec[1]; } - if (vec[2] > bbez) { bbez = vec[2]; } - } - - /* return values... */ - if (start) { - start[0] = bbsx; - start[1] = bbsy; - start[2] = bbsz; - } - if (size) { - size[0] = bbex - bbsx; - size[1] = bbey - bbsy; - size[2] = bbez - bbsz; - } + float bbsx = 0.0, bbsy = 0.0, bbsz = 0.0; + float bbex = 1.0, bbey = 1.0, bbez = 1.0; + int i; + float vec[3]; + + if (totvert == 0) { + zero_v3(start); + zero_v3(size); + return; + } + + copy_v3_v3(vec, mvert[0].co); + mul_m4_v3(obmat, vec); + bbsx = vec[0]; + bbsy = vec[1]; + bbsz = vec[2]; + bbex = vec[0]; + bbey = vec[1]; + bbez = vec[2]; + + for (i = 1; i < totvert; i++) { + copy_v3_v3(vec, mvert[i].co); + mul_m4_v3(obmat, vec); + + if (vec[0] < bbsx) { + bbsx = vec[0]; + } + if (vec[1] < bbsy) { + bbsy = vec[1]; + } + if (vec[2] < bbsz) { + bbsz = vec[2]; + } + if (vec[0] > bbex) { + bbex = vec[0]; + } + if (vec[1] > bbey) { + bbey = vec[1]; + } + if (vec[2] > bbez) { + bbez = vec[2]; + } + } + + /* return values... */ + if (start) { + start[0] = bbsx; + start[1] = bbsy; + start[2] = bbsz; + } + if (size) { + size[0] = bbex - bbsx; + size[1] = bbey - bbsy; + size[2] = bbez - bbsz; + } } //------------------------------------------------------------------------------- @@ -346,206 +358,209 @@ void fluid_get_bb( void fluid_estimate_memory(Object *ob, FluidsimSettings *fss, char *value) { - Mesh *mesh; + Mesh *mesh; - value[0] = '\0'; + value[0] = '\0'; - if (ob->type == OB_MESH) { - /* use mesh bounding box and object scaling */ - mesh = ob->data; + if (ob->type == OB_MESH) { + /* use mesh bounding box and object scaling */ + mesh = ob->data; - fluid_get_bb(mesh->mvert, mesh->totvert, ob->obmat, fss->bbStart, fss->bbSize); - elbeemEstimateMemreq(fss->resolutionxyz, fss->bbSize[0], fss->bbSize[1], fss->bbSize[2], fss->maxRefine, value); - } + fluid_get_bb(mesh->mvert, mesh->totvert, ob->obmat, fss->bbStart, fss->bbSize); + elbeemEstimateMemreq( + fss->resolutionxyz, fss->bbSize[0], fss->bbSize[1], fss->bbSize[2], fss->maxRefine, value); + } } - /* read zipped fluidsim velocities into the co's of the fluidsimsettings normals struct */ static void fluidsim_read_vel_cache(FluidsimModifierData *fluidmd, Mesh *mesh, char *filename) { - int wri, i, j; - float wrf; - gzFile gzf; - FluidsimSettings *fss = fluidmd->fss; - int len = strlen(filename); - int totvert = mesh->totvert; - FluidVertexVelocity *velarray = NULL; - - /* mesh and vverts have to be valid from loading... */ - - if (fss->meshVelocities) - MEM_freeN(fss->meshVelocities); - - if (len < 7) { - return; - } - - if (fss->domainNovecgen > 0) return; - - fss->meshVelocities = MEM_calloc_arrayN(mesh->totvert, sizeof(FluidVertexVelocity), "Fluidsim_velocities"); - fss->totvert = totvert; - - velarray = fss->meshVelocities; - - /* .bobj.gz, correct filename - * 87654321 */ - filename[len - 6] = 'v'; - filename[len - 5] = 'e'; - filename[len - 4] = 'l'; - - gzf = BLI_gzopen(filename, "rb"); - if (!gzf) { - MEM_freeN(fss->meshVelocities); - fss->meshVelocities = NULL; - return; - } - - gzread(gzf, &wri, sizeof(wri)); - if (wri != totvert) { - MEM_freeN(fss->meshVelocities); - fss->meshVelocities = NULL; - return; - } - - for (i = 0; i < totvert; i++) { - for (j = 0; j < 3; j++) { - gzread(gzf, &wrf, sizeof(wrf)); - velarray[i].vel[j] = wrf; - } - } - - gzclose(gzf); + int wri, i, j; + float wrf; + gzFile gzf; + FluidsimSettings *fss = fluidmd->fss; + int len = strlen(filename); + int totvert = mesh->totvert; + FluidVertexVelocity *velarray = NULL; + + /* mesh and vverts have to be valid from loading... */ + + if (fss->meshVelocities) + MEM_freeN(fss->meshVelocities); + + if (len < 7) { + return; + } + + if (fss->domainNovecgen > 0) + return; + + fss->meshVelocities = MEM_calloc_arrayN( + mesh->totvert, sizeof(FluidVertexVelocity), "Fluidsim_velocities"); + fss->totvert = totvert; + + velarray = fss->meshVelocities; + + /* .bobj.gz, correct filename + * 87654321 */ + filename[len - 6] = 'v'; + filename[len - 5] = 'e'; + filename[len - 4] = 'l'; + + gzf = BLI_gzopen(filename, "rb"); + if (!gzf) { + MEM_freeN(fss->meshVelocities); + fss->meshVelocities = NULL; + return; + } + + gzread(gzf, &wri, sizeof(wri)); + if (wri != totvert) { + MEM_freeN(fss->meshVelocities); + fss->meshVelocities = NULL; + return; + } + + for (i = 0; i < totvert; i++) { + for (j = 0; j < 3; j++) { + gzread(gzf, &wrf, sizeof(wrf)); + velarray[i].vel[j] = wrf; + } + } + + gzclose(gzf); } static Mesh *fluidsim_read_cache( - Object *ob, Mesh *orgmesh, - FluidsimModifierData *fluidmd, int framenr, int useRenderParams) + Object *ob, Mesh *orgmesh, FluidsimModifierData *fluidmd, int framenr, int useRenderParams) { - int curFrame = framenr /* - 1 */ /*scene->r.sfra*/; /* start with 0 at start frame */ - /* why start with 0 as start frame?? Animations + time are frozen for frame 0 anyway. (See physics_fluid.c for that. - DG */ - /* If we start with frame 0, we need to remap all animation channels, too, because they will all be 1 frame late if using frame-1! - DG */ - - char targetFile[FILE_MAX]; - FluidsimSettings *fss = fluidmd->fss; - Mesh *newmesh = NULL; - MPoly *mpoly; - MPoly mp_example = {0}; - - const int displaymode = useRenderParams ? fss->renderDisplayMode : fss->guiDisplayMode; - - switch (displaymode) { - case OB_FSDOM_GEOM: - /* just display original object */ - return NULL; - case OB_FSDOM_PREVIEW: - /* use preview mesh */ - BLI_join_dirfile(targetFile, sizeof(targetFile), fss->surfdataPath, OB_FLUIDSIM_SURF_PREVIEW_OBJ_FNAME); - break; - case OB_FSDOM_FINAL: - /* use final mesh */ - BLI_join_dirfile(targetFile, sizeof(targetFile), fss->surfdataPath, OB_FLUIDSIM_SURF_FINAL_OBJ_FNAME); - break; - default: - BLI_assert(!"Wrong fluidsim display type"); - return NULL; - } - - /* offset baked frame */ - curFrame += fss->frameOffset; - - BLI_path_abs(targetFile, modifier_path_relbase_from_global(ob)); - BLI_path_frame(targetFile, curFrame, 0); // fixed #frame-no - - /* assign material + flags to new mesh. - * if there's no faces in original mesh, keep materials and flags unchanged */ - mpoly = orgmesh->mpoly; - if (mpoly) { - mp_example = *mpoly; - } - /* else leave NULL'd */ - - newmesh = fluidsim_read_obj(targetFile, &mp_example); - - if (!newmesh) { - /* switch, abort background rendering when fluidsim mesh is missing */ - const char *strEnvName2 = "BLENDER_ELBEEMBOBJABORT"; // from blendercall.cpp - - if (G.background == 1) { - if (BLI_getenv(strEnvName2)) { - int elevel = atoi(BLI_getenv(strEnvName2)); - if (elevel > 0) { - printf("Env. var %s set, fluid sim mesh '%s' not found, aborting render...\n", - strEnvName2, targetFile); - exit(1); - } - } - } - - /* display org. object upon failure which is in new mesh */ - return NULL; - } - - /* load vertex velocities, if they exist... - * TODO? use generate flag as loading flag as well? - * warning, needs original .bobj.gz mesh loading filename */ - if (displaymode == OB_FSDOM_FINAL) { - fluidsim_read_vel_cache(fluidmd, newmesh, targetFile); - } - else { - if (fss->meshVelocities) - MEM_freeN(fss->meshVelocities); - - fss->meshVelocities = NULL; - } - - return newmesh; + int curFrame = framenr /* - 1 */ /*scene->r.sfra*/; /* start with 0 at start frame */ + /* why start with 0 as start frame?? Animations + time are frozen for frame 0 anyway. (See physics_fluid.c for that. - DG */ + /* If we start with frame 0, we need to remap all animation channels, too, because they will all be 1 frame late if using frame-1! - DG */ + + char targetFile[FILE_MAX]; + FluidsimSettings *fss = fluidmd->fss; + Mesh *newmesh = NULL; + MPoly *mpoly; + MPoly mp_example = {0}; + + const int displaymode = useRenderParams ? fss->renderDisplayMode : fss->guiDisplayMode; + + switch (displaymode) { + case OB_FSDOM_GEOM: + /* just display original object */ + return NULL; + case OB_FSDOM_PREVIEW: + /* use preview mesh */ + BLI_join_dirfile( + targetFile, sizeof(targetFile), fss->surfdataPath, OB_FLUIDSIM_SURF_PREVIEW_OBJ_FNAME); + break; + case OB_FSDOM_FINAL: + /* use final mesh */ + BLI_join_dirfile( + targetFile, sizeof(targetFile), fss->surfdataPath, OB_FLUIDSIM_SURF_FINAL_OBJ_FNAME); + break; + default: + BLI_assert(!"Wrong fluidsim display type"); + return NULL; + } + + /* offset baked frame */ + curFrame += fss->frameOffset; + + BLI_path_abs(targetFile, modifier_path_relbase_from_global(ob)); + BLI_path_frame(targetFile, curFrame, 0); // fixed #frame-no + + /* assign material + flags to new mesh. + * if there's no faces in original mesh, keep materials and flags unchanged */ + mpoly = orgmesh->mpoly; + if (mpoly) { + mp_example = *mpoly; + } + /* else leave NULL'd */ + + newmesh = fluidsim_read_obj(targetFile, &mp_example); + + if (!newmesh) { + /* switch, abort background rendering when fluidsim mesh is missing */ + const char *strEnvName2 = "BLENDER_ELBEEMBOBJABORT"; // from blendercall.cpp + + if (G.background == 1) { + if (BLI_getenv(strEnvName2)) { + int elevel = atoi(BLI_getenv(strEnvName2)); + if (elevel > 0) { + printf("Env. var %s set, fluid sim mesh '%s' not found, aborting render...\n", + strEnvName2, + targetFile); + exit(1); + } + } + } + + /* display org. object upon failure which is in new mesh */ + return NULL; + } + + /* load vertex velocities, if they exist... + * TODO? use generate flag as loading flag as well? + * warning, needs original .bobj.gz mesh loading filename */ + if (displaymode == OB_FSDOM_FINAL) { + fluidsim_read_vel_cache(fluidmd, newmesh, targetFile); + } + else { + if (fss->meshVelocities) + MEM_freeN(fss->meshVelocities); + + fss->meshVelocities = NULL; + } + + return newmesh; } -#endif // WITH_MOD_FLUID +#endif // WITH_MOD_FLUID -Mesh *fluidsimModifier_do( - FluidsimModifierData *fluidmd, - const ModifierEvalContext *ctx, - Mesh *mesh) +Mesh *fluidsimModifier_do(FluidsimModifierData *fluidmd, + const ModifierEvalContext *ctx, + Mesh *mesh) { #ifdef WITH_MOD_FLUID - Object *ob = ctx->object; - Depsgraph *depsgraph = ctx->depsgraph; - const bool useRenderParams = (ctx->flag & MOD_APPLY_RENDER) != 0; -// const bool isFinalCalc = (ctx->flag & MOD_APPLY_USECACHE) != 0; - Mesh *result = NULL; - int framenr; - FluidsimSettings *fss = NULL; + Object *ob = ctx->object; + Depsgraph *depsgraph = ctx->depsgraph; + const bool useRenderParams = (ctx->flag & MOD_APPLY_RENDER) != 0; + // const bool isFinalCalc = (ctx->flag & MOD_APPLY_USECACHE) != 0; + Mesh *result = NULL; + int framenr; + FluidsimSettings *fss = NULL; - framenr = (int)DEG_get_ctime(depsgraph); + framenr = (int)DEG_get_ctime(depsgraph); - /* only handle fluidsim domains */ - if (fluidmd && fluidmd->fss && (fluidmd->fss->type != OB_FLUIDSIM_DOMAIN)) - return mesh; + /* only handle fluidsim domains */ + if (fluidmd && fluidmd->fss && (fluidmd->fss->type != OB_FLUIDSIM_DOMAIN)) + return mesh; - /* sanity check */ - if (!fluidmd || !fluidmd->fss) - return mesh; + /* sanity check */ + if (!fluidmd || !fluidmd->fss) + return mesh; - fss = fluidmd->fss; + fss = fluidmd->fss; - /* timescale not supported yet - * clmd->sim_parms->timescale = timescale; */ + /* timescale not supported yet + * clmd->sim_parms->timescale = timescale; */ - /* support reversing of baked fluid frames here */ - if ((fss->flag & OB_FLUIDSIM_REVERSE) && (fss->lastgoodframe >= 0)) { - framenr = fss->lastgoodframe - framenr + 1; - CLAMP(framenr, 1, fss->lastgoodframe); - } + /* support reversing of baked fluid frames here */ + if ((fss->flag & OB_FLUIDSIM_REVERSE) && (fss->lastgoodframe >= 0)) { + framenr = fss->lastgoodframe - framenr + 1; + CLAMP(framenr, 1, fss->lastgoodframe); + } - /* try to read from cache */ - /* if the frame is there, fine, otherwise don't do anything */ - if ((result = fluidsim_read_cache(ob, mesh, fluidmd, framenr, useRenderParams))) - return result; + /* try to read from cache */ + /* if the frame is there, fine, otherwise don't do anything */ + if ((result = fluidsim_read_cache(ob, mesh, fluidmd, framenr, useRenderParams))) + return result; - return mesh; + return mesh; #else - /* unused */ - UNUSED_VARS(fluidmd, ctx, mesh); - return NULL; + /* unused */ + UNUSED_VARS(fluidmd, ctx, mesh); + return NULL; #endif } diff --git a/source/blender/modifiers/intern/MOD_fluidsim_util.h b/source/blender/modifiers/intern/MOD_fluidsim_util.h index 7673ec7f6b0..0d2be3e7074 100644 --- a/source/blender/modifiers/intern/MOD_fluidsim_util.h +++ b/source/blender/modifiers/intern/MOD_fluidsim_util.h @@ -21,7 +21,6 @@ * \ingroup modifiers */ - #ifndef __MOD_FLUIDSIM_UTIL_H__ #define __MOD_FLUIDSIM_UTIL_H__ @@ -35,9 +34,8 @@ struct Scene; void fluidsim_init(struct FluidsimModifierData *fluidmd); void fluidsim_free(struct FluidsimModifierData *fluidmd); -struct Mesh *fluidsimModifier_do( - struct FluidsimModifierData *fluidmd, - const struct ModifierEvalContext *ctx, - struct Mesh *me); +struct Mesh *fluidsimModifier_do(struct FluidsimModifierData *fluidmd, + const struct ModifierEvalContext *ctx, + struct Mesh *me); #endif diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c index 0c15f4caa23..c12fb9c1bd8 100644 --- a/source/blender/modifiers/intern/MOD_hook.c +++ b/source/blender/modifiers/intern/MOD_hook.c @@ -21,7 +21,6 @@ * \ingroup modifiers */ - #include "BLI_utildefines.h" #include "BLI_math.h" @@ -47,360 +46,366 @@ static void initData(ModifierData *md) { - HookModifierData *hmd = (HookModifierData *) md; + HookModifierData *hmd = (HookModifierData *)md; - hmd->force = 1.0; - hmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); - hmd->falloff_type = eHook_Falloff_Smooth; - hmd->flag = 0; + hmd->force = 1.0; + hmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + hmd->falloff_type = eHook_Falloff_Smooth; + hmd->flag = 0; } static void copyData(const ModifierData *md, ModifierData *target, const int flag) { - const HookModifierData *hmd = (const HookModifierData *) md; - HookModifierData *thmd = (HookModifierData *) target; + const HookModifierData *hmd = (const HookModifierData *)md; + HookModifierData *thmd = (HookModifierData *)target; - modifier_copyData_generic(md, target, flag); + modifier_copyData_generic(md, target, flag); - thmd->curfalloff = curvemapping_copy(hmd->curfalloff); + thmd->curfalloff = curvemapping_copy(hmd->curfalloff); - thmd->indexar = MEM_dupallocN(hmd->indexar); + thmd->indexar = MEM_dupallocN(hmd->indexar); } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - HookModifierData *hmd = (HookModifierData *)md; - - /* ask for vertexgroups if we need them */ - if (hmd->name[0] != '\0') { - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; - } - if (hmd->indexar != NULL) { - /* TODO check which origindex are actually needed? */ - r_cddata_masks->vmask |= CD_MASK_ORIGINDEX; - r_cddata_masks->emask |= CD_MASK_ORIGINDEX; - r_cddata_masks->pmask |= CD_MASK_ORIGINDEX; - } + HookModifierData *hmd = (HookModifierData *)md; + + /* ask for vertexgroups if we need them */ + if (hmd->name[0] != '\0') { + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + } + if (hmd->indexar != NULL) { + /* TODO check which origindex are actually needed? */ + r_cddata_masks->vmask |= CD_MASK_ORIGINDEX; + r_cddata_masks->emask |= CD_MASK_ORIGINDEX; + r_cddata_masks->pmask |= CD_MASK_ORIGINDEX; + } } static void freeData(ModifierData *md) { - HookModifierData *hmd = (HookModifierData *) md; + HookModifierData *hmd = (HookModifierData *)md; - curvemapping_free(hmd->curfalloff); + curvemapping_free(hmd->curfalloff); - MEM_SAFE_FREE(hmd->indexar); + MEM_SAFE_FREE(hmd->indexar); } -static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams)) +static bool isDisabled(const struct Scene *UNUSED(scene), + ModifierData *md, + bool UNUSED(useRenderParams)) { - HookModifierData *hmd = (HookModifierData *) md; + HookModifierData *hmd = (HookModifierData *)md; - return !hmd->object; + return !hmd->object; } -static void foreachObjectLink( - ModifierData *md, Object *ob, - ObjectWalkFunc walk, void *userData) +static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) { - HookModifierData *hmd = (HookModifierData *) md; + HookModifierData *hmd = (HookModifierData *)md; - walk(userData, ob, &hmd->object, IDWALK_CB_NOP); + walk(userData, ob, &hmd->object, IDWALK_CB_NOP); } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { - HookModifierData *hmd = (HookModifierData *)md; - if (hmd->object != NULL) { - if (hmd->subtarget[0]) { - DEG_add_bone_relation(ctx->node, hmd->object, hmd->subtarget, DEG_OB_COMP_BONE, "Hook Modifier"); - } - DEG_add_object_relation(ctx->node, hmd->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier"); - } - /* We need own transformation as well. */ - DEG_add_modifier_to_transform_relation(ctx->node, "Hook Modifier"); + HookModifierData *hmd = (HookModifierData *)md; + if (hmd->object != NULL) { + if (hmd->subtarget[0]) { + DEG_add_bone_relation( + ctx->node, hmd->object, hmd->subtarget, DEG_OB_COMP_BONE, "Hook Modifier"); + } + DEG_add_object_relation(ctx->node, hmd->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier"); + } + /* We need own transformation as well. */ + DEG_add_modifier_to_transform_relation(ctx->node, "Hook Modifier"); } struct HookData_cb { - float (*vertexCos)[3]; + float (*vertexCos)[3]; - MDeformVert *dvert; - int defgrp_index; + MDeformVert *dvert; + int defgrp_index; - struct CurveMapping *curfalloff; + struct CurveMapping *curfalloff; - char falloff_type; - float falloff; - float falloff_sq; - float fac_orig; + char falloff_type; + float falloff; + float falloff_sq; + float fac_orig; - unsigned int use_falloff : 1; - unsigned int use_uniform : 1; + unsigned int use_falloff : 1; + unsigned int use_uniform : 1; - float cent[3]; + float cent[3]; - float mat_uniform[3][3]; - float mat[4][4]; + float mat_uniform[3][3]; + float mat[4][4]; }; -static float hook_falloff( - const struct HookData_cb *hd, - const float len_sq) +static float hook_falloff(const struct HookData_cb *hd, const float len_sq) { - BLI_assert(hd->falloff_sq); - if (len_sq > hd->falloff_sq) { - return 0.0f; - } - else if (len_sq > 0.0f) { - float fac; - - if (hd->falloff_type == eHook_Falloff_Const) { - fac = 1.0f; - goto finally; - } - else if (hd->falloff_type == eHook_Falloff_InvSquare) { - /* avoid sqrt below */ - fac = 1.0f - (len_sq / hd->falloff_sq); - goto finally; - } - - fac = 1.0f - (sqrtf(len_sq) / hd->falloff); - - /* closely match PROP_SMOOTH and similar */ - switch (hd->falloff_type) { + BLI_assert(hd->falloff_sq); + if (len_sq > hd->falloff_sq) { + return 0.0f; + } + else if (len_sq > 0.0f) { + float fac; + + if (hd->falloff_type == eHook_Falloff_Const) { + fac = 1.0f; + goto finally; + } + else if (hd->falloff_type == eHook_Falloff_InvSquare) { + /* avoid sqrt below */ + fac = 1.0f - (len_sq / hd->falloff_sq); + goto finally; + } + + fac = 1.0f - (sqrtf(len_sq) / hd->falloff); + + /* closely match PROP_SMOOTH and similar */ + switch (hd->falloff_type) { #if 0 - case eHook_Falloff_None: - fac = 1.0f; - break; + case eHook_Falloff_None: + fac = 1.0f; + break; #endif - case eHook_Falloff_Curve: - fac = curvemapping_evaluateF(hd->curfalloff, 0, fac); - break; - case eHook_Falloff_Sharp: - fac = fac * fac; - break; - case eHook_Falloff_Smooth: - fac = 3.0f * fac * fac - 2.0f * fac * fac * fac; - break; - case eHook_Falloff_Root: - fac = sqrtf(fac); - break; - case eHook_Falloff_Linear: - /* pass */ - break; + case eHook_Falloff_Curve: + fac = curvemapping_evaluateF(hd->curfalloff, 0, fac); + break; + case eHook_Falloff_Sharp: + fac = fac * fac; + break; + case eHook_Falloff_Smooth: + fac = 3.0f * fac * fac - 2.0f * fac * fac * fac; + break; + case eHook_Falloff_Root: + fac = sqrtf(fac); + break; + case eHook_Falloff_Linear: + /* pass */ + break; #if 0 - case eHook_Falloff_Const: - fac = 1.0f; - break; + case eHook_Falloff_Const: + fac = 1.0f; + break; #endif - case eHook_Falloff_Sphere: - fac = sqrtf(2 * fac - fac * fac); - break; + case eHook_Falloff_Sphere: + fac = sqrtf(2 * fac - fac * fac); + break; #if 0 - case eHook_Falloff_InvSquare: - fac = fac * (2.0f - fac); - break; + case eHook_Falloff_InvSquare: + fac = fac * (2.0f - fac); + break; #endif - } - -finally: - return fac * hd->fac_orig; - } - else { - return hd->fac_orig; - } + } + + finally: + return fac * hd->fac_orig; + } + else { + return hd->fac_orig; + } } static void hook_co_apply(struct HookData_cb *hd, const int j) { - float *co = hd->vertexCos[j]; - float fac; - - if (hd->use_falloff) { - float len_sq; - - if (hd->use_uniform) { - float co_uniform[3]; - mul_v3_m3v3(co_uniform, hd->mat_uniform, co); - len_sq = len_squared_v3v3(hd->cent, co_uniform); - } - else { - len_sq = len_squared_v3v3(hd->cent, co); - } - - fac = hook_falloff(hd, len_sq); - } - else { - fac = hd->fac_orig; - } - - if (fac) { - if (hd->dvert) { - fac *= defvert_find_weight(&hd->dvert[j], hd->defgrp_index); - } - - if (fac) { - float co_tmp[3]; - mul_v3_m4v3(co_tmp, hd->mat, co); - interp_v3_v3v3(co, co, co_tmp, fac); - } - } + float *co = hd->vertexCos[j]; + float fac; + + if (hd->use_falloff) { + float len_sq; + + if (hd->use_uniform) { + float co_uniform[3]; + mul_v3_m3v3(co_uniform, hd->mat_uniform, co); + len_sq = len_squared_v3v3(hd->cent, co_uniform); + } + else { + len_sq = len_squared_v3v3(hd->cent, co); + } + + fac = hook_falloff(hd, len_sq); + } + else { + fac = hd->fac_orig; + } + + if (fac) { + if (hd->dvert) { + fac *= defvert_find_weight(&hd->dvert[j], hd->defgrp_index); + } + + if (fac) { + float co_tmp[3]; + mul_v3_m4v3(co_tmp, hd->mat, co); + interp_v3_v3v3(co, co, co_tmp, fac); + } + } } -static void deformVerts_do( - HookModifierData *hmd, const ModifierEvalContext *UNUSED(ctx), - Object *ob, Mesh *mesh, - float (*vertexCos)[3], int numVerts) +static void deformVerts_do(HookModifierData *hmd, + const ModifierEvalContext *UNUSED(ctx), + Object *ob, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - Object *ob_target = hmd->object; - bPoseChannel *pchan = BKE_pose_channel_find_name(ob_target->pose, hmd->subtarget); - float dmat[4][4]; - int i, *index_pt; - struct HookData_cb hd; - - if (hmd->curfalloff == NULL) { - /* should never happen, but bad lib linking could cause it */ - hmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); - } - - if (hmd->curfalloff) { - curvemapping_initialize(hmd->curfalloff); - } - - /* Generic data needed for applying per-vertex calculations (initialize all members) */ - hd.vertexCos = vertexCos; - MOD_get_vgroup(ob, mesh, hmd->name, &hd.dvert, &hd.defgrp_index); - - hd.curfalloff = hmd->curfalloff; - - hd.falloff_type = hmd->falloff_type; - hd.falloff = (hmd->falloff_type == eHook_Falloff_None) ? 0.0f : hmd->falloff; - hd.falloff_sq = SQUARE(hd.falloff); - hd.fac_orig = hmd->force; - - hd.use_falloff = (hd.falloff_sq != 0.0f); - hd.use_uniform = (hmd->flag & MOD_HOOK_UNIFORM_SPACE) != 0; - - if (hd.use_uniform) { - copy_m3_m4(hd.mat_uniform, hmd->parentinv); - mul_v3_m3v3(hd.cent, hd.mat_uniform, hmd->cent); - } - else { - unit_m3(hd.mat_uniform); /* unused */ - copy_v3_v3(hd.cent, hmd->cent); - } - - /* get world-space matrix of target, corrected for the space the verts are in */ - if (hmd->subtarget[0] && pchan) { - /* bone target if there's a matching pose-channel */ - mul_m4_m4m4(dmat, ob_target->obmat, pchan->pose_mat); - } - else { - /* just object target */ - copy_m4_m4(dmat, ob_target->obmat); - } - invert_m4_m4(ob->imat, ob->obmat); - mul_m4_series(hd.mat, ob->imat, dmat, hmd->parentinv); - /* --- done with 'hd' init --- */ - - - /* Regarding index range checking below. - * - * This should always be true and I don't generally like - * "paranoid" style code like this, but old files can have - * indices that are out of range because old blender did - * not correct them on exit editmode. - zr - */ - - if (hmd->force == 0.0f) { - /* do nothing, avoid annoying checks in the loop */ - } - else if (hmd->indexar) { /* vertex indices? */ - const int *origindex_ar; - - /* if mesh is present and has original index data, use it */ - if (mesh && (origindex_ar = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX))) { - for (i = 0, index_pt = hmd->indexar; i < hmd->totindex; i++, index_pt++) { - if (*index_pt < numVerts) { - int j; - - for (j = 0; j < numVerts; j++) { - if (origindex_ar[j] == *index_pt) { - hook_co_apply(&hd, j); - } - } - } - } - } - else { /* missing mesh or ORIGINDEX */ - for (i = 0, index_pt = hmd->indexar; i < hmd->totindex; i++, index_pt++) { - if (*index_pt < numVerts) { - hook_co_apply(&hd, *index_pt); - } - } - } - } - else if (hd.dvert) { /* vertex group hook */ - for (i = 0; i < numVerts; i++) { - hook_co_apply(&hd, i); - } - } + Object *ob_target = hmd->object; + bPoseChannel *pchan = BKE_pose_channel_find_name(ob_target->pose, hmd->subtarget); + float dmat[4][4]; + int i, *index_pt; + struct HookData_cb hd; + + if (hmd->curfalloff == NULL) { + /* should never happen, but bad lib linking could cause it */ + hmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + } + + if (hmd->curfalloff) { + curvemapping_initialize(hmd->curfalloff); + } + + /* Generic data needed for applying per-vertex calculations (initialize all members) */ + hd.vertexCos = vertexCos; + MOD_get_vgroup(ob, mesh, hmd->name, &hd.dvert, &hd.defgrp_index); + + hd.curfalloff = hmd->curfalloff; + + hd.falloff_type = hmd->falloff_type; + hd.falloff = (hmd->falloff_type == eHook_Falloff_None) ? 0.0f : hmd->falloff; + hd.falloff_sq = SQUARE(hd.falloff); + hd.fac_orig = hmd->force; + + hd.use_falloff = (hd.falloff_sq != 0.0f); + hd.use_uniform = (hmd->flag & MOD_HOOK_UNIFORM_SPACE) != 0; + + if (hd.use_uniform) { + copy_m3_m4(hd.mat_uniform, hmd->parentinv); + mul_v3_m3v3(hd.cent, hd.mat_uniform, hmd->cent); + } + else { + unit_m3(hd.mat_uniform); /* unused */ + copy_v3_v3(hd.cent, hmd->cent); + } + + /* get world-space matrix of target, corrected for the space the verts are in */ + if (hmd->subtarget[0] && pchan) { + /* bone target if there's a matching pose-channel */ + mul_m4_m4m4(dmat, ob_target->obmat, pchan->pose_mat); + } + else { + /* just object target */ + copy_m4_m4(dmat, ob_target->obmat); + } + invert_m4_m4(ob->imat, ob->obmat); + mul_m4_series(hd.mat, ob->imat, dmat, hmd->parentinv); + /* --- done with 'hd' init --- */ + + /* Regarding index range checking below. + * + * This should always be true and I don't generally like + * "paranoid" style code like this, but old files can have + * indices that are out of range because old blender did + * not correct them on exit editmode. - zr + */ + + if (hmd->force == 0.0f) { + /* do nothing, avoid annoying checks in the loop */ + } + else if (hmd->indexar) { /* vertex indices? */ + const int *origindex_ar; + + /* if mesh is present and has original index data, use it */ + if (mesh && (origindex_ar = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX))) { + for (i = 0, index_pt = hmd->indexar; i < hmd->totindex; i++, index_pt++) { + if (*index_pt < numVerts) { + int j; + + for (j = 0; j < numVerts; j++) { + if (origindex_ar[j] == *index_pt) { + hook_co_apply(&hd, j); + } + } + } + } + } + else { /* missing mesh or ORIGINDEX */ + for (i = 0, index_pt = hmd->indexar; i < hmd->totindex; i++, index_pt++) { + if (*index_pt < numVerts) { + hook_co_apply(&hd, *index_pt); + } + } + } + } + else if (hd.dvert) { /* vertex group hook */ + for (i = 0; i < numVerts; i++) { + hook_co_apply(&hd, i); + } + } } -static void deformVerts( - struct ModifierData *md, const struct ModifierEvalContext *ctx, struct Mesh *mesh, - float (*vertexCos)[3], int numVerts) +static void deformVerts(struct ModifierData *md, + const struct ModifierEvalContext *ctx, + struct Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - HookModifierData *hmd = (HookModifierData *)md; - Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); + HookModifierData *hmd = (HookModifierData *)md; + Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); - deformVerts_do(hmd, ctx, ctx->object, mesh_src, vertexCos, numVerts); + deformVerts_do(hmd, ctx, ctx->object, mesh_src, vertexCos, numVerts); - if (!ELEM(mesh_src, NULL, mesh)) { - BKE_id_free(NULL, mesh_src); - } + if (!ELEM(mesh_src, NULL, mesh)) { + BKE_id_free(NULL, mesh_src); + } } -static void deformVertsEM( - struct ModifierData *md, const struct ModifierEvalContext *ctx, - struct BMEditMesh *editData, - struct Mesh *mesh, float (*vertexCos)[3], int numVerts) +static void deformVertsEM(struct ModifierData *md, + const struct ModifierEvalContext *ctx, + struct BMEditMesh *editData, + struct Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - HookModifierData *hmd = (HookModifierData *)md; - Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false); + HookModifierData *hmd = (HookModifierData *)md; + Mesh *mesh_src = MOD_deform_mesh_eval_get( + ctx->object, editData, mesh, NULL, numVerts, false, false); - deformVerts_do(hmd, ctx, ctx->object, mesh_src, vertexCos, numVerts); + deformVerts_do(hmd, ctx, ctx->object, mesh_src, vertexCos, numVerts); - if (!ELEM(mesh_src, NULL, mesh)) { - BKE_id_free(NULL, mesh_src); - } + if (!ELEM(mesh_src, NULL, mesh)) { + BKE_id_free(NULL, mesh_src); + } } ModifierTypeInfo modifierType_Hook = { - /* name */ "Hook", - /* structName */ "HookModifierData", - /* structSize */ sizeof(HookModifierData), - /* type */ eModifierTypeType_OnlyDeform, - /* flags */ eModifierTypeFlag_AcceptsCVs | - eModifierTypeFlag_AcceptsLattice | - eModifierTypeFlag_SupportsEditmode, - /* copyData */ copyData, - - /* deformVerts */ deformVerts, - /* deformMatrices */ NULL, - /* deformVertsEM */ deformVertsEM, - /* deformMatricesEM */ NULL, - /* applyModifier */ NULL, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ freeData, - /* isDisabled */ isDisabled, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ foreachObjectLink, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Hook", + /* structName */ "HookModifierData", + /* structSize */ sizeof(HookModifierData), + /* type */ eModifierTypeType_OnlyDeform, + /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice | + eModifierTypeFlag_SupportsEditmode, + /* copyData */ copyData, + + /* deformVerts */ deformVerts, + /* deformMatrices */ NULL, + /* deformVertsEM */ deformVertsEM, + /* deformMatricesEM */ NULL, + /* applyModifier */ NULL, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ freeData, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.c b/source/blender/modifiers/intern/MOD_laplaciandeform.c index df0ef4a7404..02682b23490 100644 --- a/source/blender/modifiers/intern/MOD_laplaciandeform.c +++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c @@ -44,165 +44,173 @@ #include "eigen_capi.h" enum { - LAPDEFORM_SYSTEM_NOT_CHANGE = 0, - LAPDEFORM_SYSTEM_IS_DIFFERENT, - LAPDEFORM_SYSTEM_ONLY_CHANGE_ANCHORS, - LAPDEFORM_SYSTEM_ONLY_CHANGE_GROUP, - LAPDEFORM_SYSTEM_ONLY_CHANGE_MESH, - LAPDEFORM_SYSTEM_CHANGE_VERTEXES, - LAPDEFORM_SYSTEM_CHANGE_EDGES, - LAPDEFORM_SYSTEM_CHANGE_NOT_VALID_GROUP, + LAPDEFORM_SYSTEM_NOT_CHANGE = 0, + LAPDEFORM_SYSTEM_IS_DIFFERENT, + LAPDEFORM_SYSTEM_ONLY_CHANGE_ANCHORS, + LAPDEFORM_SYSTEM_ONLY_CHANGE_GROUP, + LAPDEFORM_SYSTEM_ONLY_CHANGE_MESH, + LAPDEFORM_SYSTEM_CHANGE_VERTEXES, + LAPDEFORM_SYSTEM_CHANGE_EDGES, + LAPDEFORM_SYSTEM_CHANGE_NOT_VALID_GROUP, }; typedef struct LaplacianSystem { - bool is_matrix_computed; - bool has_solution; - int total_verts; - int total_edges; - int total_tris; - int total_anchors; - int repeat; - char anchor_grp_name[64]; /* Vertex Group name */ - float (*co)[3]; /* Original vertex coordinates */ - float (*no)[3]; /* Original vertex normal */ - float (*delta)[3]; /* Differential Coordinates */ - unsigned int (*tris)[3]; /* Copy of MLoopTri (tessellation triangle) v1-v3 */ - int *index_anchors; /* Static vertex index list */ - int *unit_verts; /* Unit vectors of projected edges onto the plane orthogonal to n */ - int *ringf_indices; /* Indices of faces per vertex */ - int *ringv_indices; /* Indices of neighbors(vertex) per vertex */ - LinearSolver *context; /* System for solve general implicit rotations */ - MeshElemMap *ringf_map; /* Map of faces per vertex */ - MeshElemMap *ringv_map; /* Map of vertex per vertex */ + bool is_matrix_computed; + bool has_solution; + int total_verts; + int total_edges; + int total_tris; + int total_anchors; + int repeat; + char anchor_grp_name[64]; /* Vertex Group name */ + float (*co)[3]; /* Original vertex coordinates */ + float (*no)[3]; /* Original vertex normal */ + float (*delta)[3]; /* Differential Coordinates */ + unsigned int (*tris)[3]; /* Copy of MLoopTri (tessellation triangle) v1-v3 */ + int *index_anchors; /* Static vertex index list */ + int *unit_verts; /* Unit vectors of projected edges onto the plane orthogonal to n */ + int *ringf_indices; /* Indices of faces per vertex */ + int *ringv_indices; /* Indices of neighbors(vertex) per vertex */ + LinearSolver *context; /* System for solve general implicit rotations */ + MeshElemMap *ringf_map; /* Map of faces per vertex */ + MeshElemMap *ringv_map; /* Map of vertex per vertex */ } LaplacianSystem; static LaplacianSystem *newLaplacianSystem(void) { - LaplacianSystem *sys; - sys = MEM_callocN(sizeof(LaplacianSystem), "DeformCache"); - - sys->is_matrix_computed = false; - sys->has_solution = false; - sys->total_verts = 0; - sys->total_edges = 0; - sys->total_anchors = 0; - sys->total_tris = 0; - sys->repeat = 1; - sys->anchor_grp_name[0] = '\0'; - - return sys; + LaplacianSystem *sys; + sys = MEM_callocN(sizeof(LaplacianSystem), "DeformCache"); + + sys->is_matrix_computed = false; + sys->has_solution = false; + sys->total_verts = 0; + sys->total_edges = 0; + sys->total_anchors = 0; + sys->total_tris = 0; + sys->repeat = 1; + sys->anchor_grp_name[0] = '\0'; + + return sys; } -static LaplacianSystem *initLaplacianSystem( - int totalVerts, int totalEdges, int totalTris, int totalAnchors, - const char defgrpName[64], int iterations) +static LaplacianSystem *initLaplacianSystem(int totalVerts, + int totalEdges, + int totalTris, + int totalAnchors, + const char defgrpName[64], + int iterations) { - LaplacianSystem *sys = newLaplacianSystem(); - - sys->is_matrix_computed = false; - sys->has_solution = false; - sys->total_verts = totalVerts; - sys->total_edges = totalEdges; - sys->total_tris = totalTris; - sys->total_anchors = totalAnchors; - sys->repeat = iterations; - BLI_strncpy(sys->anchor_grp_name, defgrpName, sizeof(sys->anchor_grp_name)); - sys->co = MEM_malloc_arrayN(totalVerts, sizeof(float[3]), "DeformCoordinates"); - sys->no = MEM_calloc_arrayN(totalVerts, sizeof(float[3]), "DeformNormals"); - sys->delta = MEM_calloc_arrayN(totalVerts, sizeof(float[3]), "DeformDeltas"); - sys->tris = MEM_malloc_arrayN(totalTris, sizeof(int[3]), "DeformFaces"); - sys->index_anchors = MEM_malloc_arrayN((totalAnchors), sizeof(int), "DeformAnchors"); - sys->unit_verts = MEM_calloc_arrayN(totalVerts, sizeof(int), "DeformUnitVerts"); - return sys; + LaplacianSystem *sys = newLaplacianSystem(); + + sys->is_matrix_computed = false; + sys->has_solution = false; + sys->total_verts = totalVerts; + sys->total_edges = totalEdges; + sys->total_tris = totalTris; + sys->total_anchors = totalAnchors; + sys->repeat = iterations; + BLI_strncpy(sys->anchor_grp_name, defgrpName, sizeof(sys->anchor_grp_name)); + sys->co = MEM_malloc_arrayN(totalVerts, sizeof(float[3]), "DeformCoordinates"); + sys->no = MEM_calloc_arrayN(totalVerts, sizeof(float[3]), "DeformNormals"); + sys->delta = MEM_calloc_arrayN(totalVerts, sizeof(float[3]), "DeformDeltas"); + sys->tris = MEM_malloc_arrayN(totalTris, sizeof(int[3]), "DeformFaces"); + sys->index_anchors = MEM_malloc_arrayN((totalAnchors), sizeof(int), "DeformAnchors"); + sys->unit_verts = MEM_calloc_arrayN(totalVerts, sizeof(int), "DeformUnitVerts"); + return sys; } static void deleteLaplacianSystem(LaplacianSystem *sys) { - MEM_SAFE_FREE(sys->co); - MEM_SAFE_FREE(sys->no); - MEM_SAFE_FREE(sys->delta); - MEM_SAFE_FREE(sys->tris); - MEM_SAFE_FREE(sys->index_anchors); - MEM_SAFE_FREE(sys->unit_verts); - MEM_SAFE_FREE(sys->ringf_indices); - MEM_SAFE_FREE(sys->ringv_indices); - MEM_SAFE_FREE(sys->ringf_map); - MEM_SAFE_FREE(sys->ringv_map); - - if (sys->context) { - EIG_linear_solver_delete(sys->context); - } - MEM_SAFE_FREE(sys); + MEM_SAFE_FREE(sys->co); + MEM_SAFE_FREE(sys->no); + MEM_SAFE_FREE(sys->delta); + MEM_SAFE_FREE(sys->tris); + MEM_SAFE_FREE(sys->index_anchors); + MEM_SAFE_FREE(sys->unit_verts); + MEM_SAFE_FREE(sys->ringf_indices); + MEM_SAFE_FREE(sys->ringv_indices); + MEM_SAFE_FREE(sys->ringf_map); + MEM_SAFE_FREE(sys->ringv_map); + + if (sys->context) { + EIG_linear_solver_delete(sys->context); + } + MEM_SAFE_FREE(sys); } -static void createFaceRingMap( - const int mvert_tot, const MLoopTri *mlooptri, const int mtri_tot, - const MLoop *mloop, MeshElemMap **r_map, int **r_indices) +static void createFaceRingMap(const int mvert_tot, + const MLoopTri *mlooptri, + const int mtri_tot, + const MLoop *mloop, + MeshElemMap **r_map, + int **r_indices) { - int i, j, totalr = 0; - int *indices, *index_iter; - MeshElemMap *map = MEM_calloc_arrayN(mvert_tot, sizeof(MeshElemMap), "DeformRingMap"); - const MLoopTri *mlt; - - for (i = 0, mlt = mlooptri; i < mtri_tot; i++, mlt++) { - - for (j = 0; j < 3; j++) { - const unsigned int v_index = mloop[mlt->tri[j]].v; - map[v_index].count++; - totalr++; - } - } - indices = MEM_calloc_arrayN(totalr, sizeof(int), "DeformRingIndex"); - index_iter = indices; - for (i = 0; i < mvert_tot; i++) { - map[i].indices = index_iter; - index_iter += map[i].count; - map[i].count = 0; - } - for (i = 0, mlt = mlooptri; i < mtri_tot; i++, mlt++) { - for (j = 0; j < 3; j++) { - const unsigned int v_index = mloop[mlt->tri[j]].v; - map[v_index].indices[map[v_index].count] = i; - map[v_index].count++; - } - } - *r_map = map; - *r_indices = indices; + int i, j, totalr = 0; + int *indices, *index_iter; + MeshElemMap *map = MEM_calloc_arrayN(mvert_tot, sizeof(MeshElemMap), "DeformRingMap"); + const MLoopTri *mlt; + + for (i = 0, mlt = mlooptri; i < mtri_tot; i++, mlt++) { + + for (j = 0; j < 3; j++) { + const unsigned int v_index = mloop[mlt->tri[j]].v; + map[v_index].count++; + totalr++; + } + } + indices = MEM_calloc_arrayN(totalr, sizeof(int), "DeformRingIndex"); + index_iter = indices; + for (i = 0; i < mvert_tot; i++) { + map[i].indices = index_iter; + index_iter += map[i].count; + map[i].count = 0; + } + for (i = 0, mlt = mlooptri; i < mtri_tot; i++, mlt++) { + for (j = 0; j < 3; j++) { + const unsigned int v_index = mloop[mlt->tri[j]].v; + map[v_index].indices[map[v_index].count] = i; + map[v_index].count++; + } + } + *r_map = map; + *r_indices = indices; } -static void createVertRingMap( - const int mvert_tot, const MEdge *medge, const int medge_tot, - MeshElemMap **r_map, int **r_indices) +static void createVertRingMap(const int mvert_tot, + const MEdge *medge, + const int medge_tot, + MeshElemMap **r_map, + int **r_indices) { - MeshElemMap *map = MEM_calloc_arrayN(mvert_tot, sizeof(MeshElemMap), "DeformNeighborsMap"); - int i, vid[2], totalr = 0; - int *indices, *index_iter; - const MEdge *me; - - for (i = 0, me = medge; i < medge_tot; i++, me++) { - vid[0] = me->v1; - vid[1] = me->v2; - map[vid[0]].count++; - map[vid[1]].count++; - totalr += 2; - } - indices = MEM_calloc_arrayN(totalr, sizeof(int), "DeformNeighborsIndex"); - index_iter = indices; - for (i = 0; i < mvert_tot; i++) { - map[i].indices = index_iter; - index_iter += map[i].count; - map[i].count = 0; - } - for (i = 0, me = medge; i < medge_tot; i++, me++) { - vid[0] = me->v1; - vid[1] = me->v2; - map[vid[0]].indices[map[vid[0]].count] = vid[1]; - map[vid[0]].count++; - map[vid[1]].indices[map[vid[1]].count] = vid[0]; - map[vid[1]].count++; - } - *r_map = map; - *r_indices = indices; + MeshElemMap *map = MEM_calloc_arrayN(mvert_tot, sizeof(MeshElemMap), "DeformNeighborsMap"); + int i, vid[2], totalr = 0; + int *indices, *index_iter; + const MEdge *me; + + for (i = 0, me = medge; i < medge_tot; i++, me++) { + vid[0] = me->v1; + vid[1] = me->v2; + map[vid[0]].count++; + map[vid[1]].count++; + totalr += 2; + } + indices = MEM_calloc_arrayN(totalr, sizeof(int), "DeformNeighborsIndex"); + index_iter = indices; + for (i = 0; i < mvert_tot; i++) { + map[i].indices = index_iter; + index_iter += map[i].count; + map[i].count = 0; + } + for (i = 0, me = medge; i < medge_tot; i++, me++) { + vid[0] = me->v1; + vid[1] = me->v2; + map[vid[0]].indices[map[vid[0]].count] = vid[1]; + map[vid[0]].count++; + map[vid[1]].indices[map[vid[1]].count] = vid[0]; + map[vid[1]].count++; + } + *r_map = map; + *r_indices = indices; } /** @@ -235,557 +243,577 @@ static void createVertRingMap( */ static void initLaplacianMatrix(LaplacianSystem *sys) { - float no[3]; - float w2, w3; - int i = 3, j, ti; - int idv[3]; - - for (ti = 0; ti < sys->total_tris; ti++) { - const unsigned int *vidt = sys->tris[ti]; - const float *co[3]; - - co[0] = sys->co[vidt[0]]; - co[1] = sys->co[vidt[1]]; - co[2] = sys->co[vidt[2]]; - - normal_tri_v3(no, UNPACK3(co)); - add_v3_v3(sys->no[vidt[0]], no); - add_v3_v3(sys->no[vidt[1]], no); - add_v3_v3(sys->no[vidt[2]], no); - - for (j = 0; j < 3; j++) { - const float *v1, *v2, *v3; - - idv[0] = vidt[j]; - idv[1] = vidt[(j + 1) % i]; - idv[2] = vidt[(j + 2) % i]; - - v1 = sys->co[idv[0]]; - v2 = sys->co[idv[1]]; - v3 = sys->co[idv[2]]; - - w2 = cotangent_tri_weight_v3(v3, v1, v2); - w3 = cotangent_tri_weight_v3(v2, v3, v1); - - sys->delta[idv[0]][0] += v1[0] * (w2 + w3); - sys->delta[idv[0]][1] += v1[1] * (w2 + w3); - sys->delta[idv[0]][2] += v1[2] * (w2 + w3); - - sys->delta[idv[0]][0] -= v2[0] * w2; - sys->delta[idv[0]][1] -= v2[1] * w2; - sys->delta[idv[0]][2] -= v2[2] * w2; - - sys->delta[idv[0]][0] -= v3[0] * w3; - sys->delta[idv[0]][1] -= v3[1] * w3; - sys->delta[idv[0]][2] -= v3[2] * w3; - - EIG_linear_solver_matrix_add(sys->context, idv[0], idv[1], -w2); - EIG_linear_solver_matrix_add(sys->context, idv[0], idv[2], -w3); - EIG_linear_solver_matrix_add(sys->context, idv[0], idv[0], w2 + w3); - } - } + float no[3]; + float w2, w3; + int i = 3, j, ti; + int idv[3]; + + for (ti = 0; ti < sys->total_tris; ti++) { + const unsigned int *vidt = sys->tris[ti]; + const float *co[3]; + + co[0] = sys->co[vidt[0]]; + co[1] = sys->co[vidt[1]]; + co[2] = sys->co[vidt[2]]; + + normal_tri_v3(no, UNPACK3(co)); + add_v3_v3(sys->no[vidt[0]], no); + add_v3_v3(sys->no[vidt[1]], no); + add_v3_v3(sys->no[vidt[2]], no); + + for (j = 0; j < 3; j++) { + const float *v1, *v2, *v3; + + idv[0] = vidt[j]; + idv[1] = vidt[(j + 1) % i]; + idv[2] = vidt[(j + 2) % i]; + + v1 = sys->co[idv[0]]; + v2 = sys->co[idv[1]]; + v3 = sys->co[idv[2]]; + + w2 = cotangent_tri_weight_v3(v3, v1, v2); + w3 = cotangent_tri_weight_v3(v2, v3, v1); + + sys->delta[idv[0]][0] += v1[0] * (w2 + w3); + sys->delta[idv[0]][1] += v1[1] * (w2 + w3); + sys->delta[idv[0]][2] += v1[2] * (w2 + w3); + + sys->delta[idv[0]][0] -= v2[0] * w2; + sys->delta[idv[0]][1] -= v2[1] * w2; + sys->delta[idv[0]][2] -= v2[2] * w2; + + sys->delta[idv[0]][0] -= v3[0] * w3; + sys->delta[idv[0]][1] -= v3[1] * w3; + sys->delta[idv[0]][2] -= v3[2] * w3; + + EIG_linear_solver_matrix_add(sys->context, idv[0], idv[1], -w2); + EIG_linear_solver_matrix_add(sys->context, idv[0], idv[2], -w3); + EIG_linear_solver_matrix_add(sys->context, idv[0], idv[0], w2 + w3); + } + } } static void computeImplictRotations(LaplacianSystem *sys) { - int vid, *vidn = NULL; - float minj, mjt, qj[3], vj[3]; - int i, j, ln; - - for (i = 0; i < sys->total_verts; i++) { - normalize_v3(sys->no[i]); - vidn = sys->ringv_map[i].indices; - ln = sys->ringv_map[i].count; - minj = 1000000.0f; - for (j = 0; j < ln; j++) { - vid = vidn[j]; - copy_v3_v3(qj, sys->co[vid]); - sub_v3_v3v3(vj, qj, sys->co[i]); - normalize_v3(vj); - mjt = fabsf(dot_v3v3(vj, sys->no[i])); - if (mjt < minj) { - minj = mjt; - sys->unit_verts[i] = vidn[j]; - } - } - } + int vid, *vidn = NULL; + float minj, mjt, qj[3], vj[3]; + int i, j, ln; + + for (i = 0; i < sys->total_verts; i++) { + normalize_v3(sys->no[i]); + vidn = sys->ringv_map[i].indices; + ln = sys->ringv_map[i].count; + minj = 1000000.0f; + for (j = 0; j < ln; j++) { + vid = vidn[j]; + copy_v3_v3(qj, sys->co[vid]); + sub_v3_v3v3(vj, qj, sys->co[i]); + normalize_v3(vj); + mjt = fabsf(dot_v3v3(vj, sys->no[i])); + if (mjt < minj) { + minj = mjt; + sys->unit_verts[i] = vidn[j]; + } + } + } } static void rotateDifferentialCoordinates(LaplacianSystem *sys) { - float alpha, beta, gamma; - float pj[3], ni[3], di[3]; - float uij[3], dun[3], e2[3], pi[3], fni[3], vn[3][3]; - int i, j, num_fni, k, fi; - int *fidn; - - for (i = 0; i < sys->total_verts; i++) { - copy_v3_v3(pi, sys->co[i]); - copy_v3_v3(ni, sys->no[i]); - k = sys->unit_verts[i]; - copy_v3_v3(pj, sys->co[k]); - sub_v3_v3v3(uij, pj, pi); - mul_v3_v3fl(dun, ni, dot_v3v3(uij, ni)); - sub_v3_v3(uij, dun); - normalize_v3(uij); - cross_v3_v3v3(e2, ni, uij); - copy_v3_v3(di, sys->delta[i]); - alpha = dot_v3v3(ni, di); - beta = dot_v3v3(uij, di); - gamma = dot_v3v3(e2, di); - - pi[0] = EIG_linear_solver_variable_get(sys->context, 0, i); - pi[1] = EIG_linear_solver_variable_get(sys->context, 1, i); - pi[2] = EIG_linear_solver_variable_get(sys->context, 2, i); - zero_v3(ni); - num_fni = sys->ringf_map[i].count; - for (fi = 0; fi < num_fni; fi++) { - const unsigned int *vin; - fidn = sys->ringf_map[i].indices; - vin = sys->tris[fidn[fi]]; - for (j = 0; j < 3; j++) { - vn[j][0] = EIG_linear_solver_variable_get(sys->context, 0, vin[j]); - vn[j][1] = EIG_linear_solver_variable_get(sys->context, 1, vin[j]); - vn[j][2] = EIG_linear_solver_variable_get(sys->context, 2, vin[j]); - if (vin[j] == sys->unit_verts[i]) { - copy_v3_v3(pj, vn[j]); - } - } - - normal_tri_v3(fni, UNPACK3(vn)); - add_v3_v3(ni, fni); - } - - normalize_v3(ni); - sub_v3_v3v3(uij, pj, pi); - mul_v3_v3fl(dun, ni, dot_v3v3(uij, ni)); - sub_v3_v3(uij, dun); - normalize_v3(uij); - cross_v3_v3v3(e2, ni, uij); - fni[0] = alpha * ni[0] + beta * uij[0] + gamma * e2[0]; - fni[1] = alpha * ni[1] + beta * uij[1] + gamma * e2[1]; - fni[2] = alpha * ni[2] + beta * uij[2] + gamma * e2[2]; - - if (len_squared_v3(fni) > FLT_EPSILON) { - EIG_linear_solver_right_hand_side_add(sys->context, 0, i, fni[0]); - EIG_linear_solver_right_hand_side_add(sys->context, 1, i, fni[1]); - EIG_linear_solver_right_hand_side_add(sys->context, 2, i, fni[2]); - } - else { - EIG_linear_solver_right_hand_side_add(sys->context, 0, i, sys->delta[i][0]); - EIG_linear_solver_right_hand_side_add(sys->context, 1, i, sys->delta[i][1]); - EIG_linear_solver_right_hand_side_add(sys->context, 2, i, sys->delta[i][2]); - } - } + float alpha, beta, gamma; + float pj[3], ni[3], di[3]; + float uij[3], dun[3], e2[3], pi[3], fni[3], vn[3][3]; + int i, j, num_fni, k, fi; + int *fidn; + + for (i = 0; i < sys->total_verts; i++) { + copy_v3_v3(pi, sys->co[i]); + copy_v3_v3(ni, sys->no[i]); + k = sys->unit_verts[i]; + copy_v3_v3(pj, sys->co[k]); + sub_v3_v3v3(uij, pj, pi); + mul_v3_v3fl(dun, ni, dot_v3v3(uij, ni)); + sub_v3_v3(uij, dun); + normalize_v3(uij); + cross_v3_v3v3(e2, ni, uij); + copy_v3_v3(di, sys->delta[i]); + alpha = dot_v3v3(ni, di); + beta = dot_v3v3(uij, di); + gamma = dot_v3v3(e2, di); + + pi[0] = EIG_linear_solver_variable_get(sys->context, 0, i); + pi[1] = EIG_linear_solver_variable_get(sys->context, 1, i); + pi[2] = EIG_linear_solver_variable_get(sys->context, 2, i); + zero_v3(ni); + num_fni = sys->ringf_map[i].count; + for (fi = 0; fi < num_fni; fi++) { + const unsigned int *vin; + fidn = sys->ringf_map[i].indices; + vin = sys->tris[fidn[fi]]; + for (j = 0; j < 3; j++) { + vn[j][0] = EIG_linear_solver_variable_get(sys->context, 0, vin[j]); + vn[j][1] = EIG_linear_solver_variable_get(sys->context, 1, vin[j]); + vn[j][2] = EIG_linear_solver_variable_get(sys->context, 2, vin[j]); + if (vin[j] == sys->unit_verts[i]) { + copy_v3_v3(pj, vn[j]); + } + } + + normal_tri_v3(fni, UNPACK3(vn)); + add_v3_v3(ni, fni); + } + + normalize_v3(ni); + sub_v3_v3v3(uij, pj, pi); + mul_v3_v3fl(dun, ni, dot_v3v3(uij, ni)); + sub_v3_v3(uij, dun); + normalize_v3(uij); + cross_v3_v3v3(e2, ni, uij); + fni[0] = alpha * ni[0] + beta * uij[0] + gamma * e2[0]; + fni[1] = alpha * ni[1] + beta * uij[1] + gamma * e2[1]; + fni[2] = alpha * ni[2] + beta * uij[2] + gamma * e2[2]; + + if (len_squared_v3(fni) > FLT_EPSILON) { + EIG_linear_solver_right_hand_side_add(sys->context, 0, i, fni[0]); + EIG_linear_solver_right_hand_side_add(sys->context, 1, i, fni[1]); + EIG_linear_solver_right_hand_side_add(sys->context, 2, i, fni[2]); + } + else { + EIG_linear_solver_right_hand_side_add(sys->context, 0, i, sys->delta[i][0]); + EIG_linear_solver_right_hand_side_add(sys->context, 1, i, sys->delta[i][1]); + EIG_linear_solver_right_hand_side_add(sys->context, 2, i, sys->delta[i][2]); + } + } } static void laplacianDeformPreview(LaplacianSystem *sys, float (*vertexCos)[3]) { - int vid, i, j, n, na; - n = sys->total_verts; - na = sys->total_anchors; - - if (!sys->is_matrix_computed) { - sys->context = EIG_linear_least_squares_solver_new(n + na, n, 3); - - for (i = 0; i < n; i++) { - EIG_linear_solver_variable_set(sys->context, 0, i, sys->co[i][0]); - EIG_linear_solver_variable_set(sys->context, 1, i, sys->co[i][1]); - EIG_linear_solver_variable_set(sys->context, 2, i, sys->co[i][2]); - } - for (i = 0; i < na; i++) { - vid = sys->index_anchors[i]; - EIG_linear_solver_variable_set(sys->context, 0, vid, vertexCos[vid][0]); - EIG_linear_solver_variable_set(sys->context, 1, vid, vertexCos[vid][1]); - EIG_linear_solver_variable_set(sys->context, 2, vid, vertexCos[vid][2]); - } - - initLaplacianMatrix(sys); - computeImplictRotations(sys); - - for (i = 0; i < n; i++) { - EIG_linear_solver_right_hand_side_add(sys->context, 0, i, sys->delta[i][0]); - EIG_linear_solver_right_hand_side_add(sys->context, 1, i, sys->delta[i][1]); - EIG_linear_solver_right_hand_side_add(sys->context, 2, i, sys->delta[i][2]); - } - for (i = 0; i < na; i++) { - vid = sys->index_anchors[i]; - EIG_linear_solver_right_hand_side_add(sys->context, 0, n + i, vertexCos[vid][0]); - EIG_linear_solver_right_hand_side_add(sys->context, 1, n + i, vertexCos[vid][1]); - EIG_linear_solver_right_hand_side_add(sys->context, 2, n + i, vertexCos[vid][2]); - EIG_linear_solver_matrix_add(sys->context, n + i, vid, 1.0f); - } - if (EIG_linear_solver_solve(sys->context)) { - sys->has_solution = true; - - for (j = 1; j <= sys->repeat; j++) { - rotateDifferentialCoordinates(sys); - - for (i = 0; i < na; i++) { - vid = sys->index_anchors[i]; - EIG_linear_solver_right_hand_side_add(sys->context, 0, n + i, vertexCos[vid][0]); - EIG_linear_solver_right_hand_side_add(sys->context, 1, n + i, vertexCos[vid][1]); - EIG_linear_solver_right_hand_side_add(sys->context, 2, n + i, vertexCos[vid][2]); - } - - if (!EIG_linear_solver_solve(sys->context)) { - sys->has_solution = false; - break; - } - } - if (sys->has_solution) { - for (vid = 0; vid < sys->total_verts; vid++) { - vertexCos[vid][0] = EIG_linear_solver_variable_get(sys->context, 0, vid); - vertexCos[vid][1] = EIG_linear_solver_variable_get(sys->context, 1, vid); - vertexCos[vid][2] = EIG_linear_solver_variable_get(sys->context, 2, vid); - } - } - else { - sys->has_solution = false; - } - - } - else { - sys->has_solution = false; - } - sys->is_matrix_computed = true; - - } - else if (sys->has_solution) { - for (i = 0; i < n; i++) { - EIG_linear_solver_right_hand_side_add(sys->context, 0, i, sys->delta[i][0]); - EIG_linear_solver_right_hand_side_add(sys->context, 1, i, sys->delta[i][1]); - EIG_linear_solver_right_hand_side_add(sys->context, 2, i, sys->delta[i][2]); - } - for (i = 0; i < na; i++) { - vid = sys->index_anchors[i]; - EIG_linear_solver_right_hand_side_add(sys->context, 0, n + i, vertexCos[vid][0]); - EIG_linear_solver_right_hand_side_add(sys->context, 1, n + i, vertexCos[vid][1]); - EIG_linear_solver_right_hand_side_add(sys->context, 2, n + i, vertexCos[vid][2]); - EIG_linear_solver_matrix_add(sys->context, n + i, vid, 1.0f); - } - - if (EIG_linear_solver_solve(sys->context)) { - sys->has_solution = true; - for (j = 1; j <= sys->repeat; j++) { - rotateDifferentialCoordinates(sys); - - for (i = 0; i < na; i++) { - vid = sys->index_anchors[i]; - EIG_linear_solver_right_hand_side_add(sys->context, 0, n + i, vertexCos[vid][0]); - EIG_linear_solver_right_hand_side_add(sys->context, 1, n + i, vertexCos[vid][1]); - EIG_linear_solver_right_hand_side_add(sys->context, 2, n + i, vertexCos[vid][2]); - } - if (!EIG_linear_solver_solve(sys->context)) { - sys->has_solution = false; - break; - } - } - if (sys->has_solution) { - for (vid = 0; vid < sys->total_verts; vid++) { - vertexCos[vid][0] = EIG_linear_solver_variable_get(sys->context, 0, vid); - vertexCos[vid][1] = EIG_linear_solver_variable_get(sys->context, 1, vid); - vertexCos[vid][2] = EIG_linear_solver_variable_get(sys->context, 2, vid); - } - } - else { - sys->has_solution = false; - } - } - else { - sys->has_solution = false; - } - } + int vid, i, j, n, na; + n = sys->total_verts; + na = sys->total_anchors; + + if (!sys->is_matrix_computed) { + sys->context = EIG_linear_least_squares_solver_new(n + na, n, 3); + + for (i = 0; i < n; i++) { + EIG_linear_solver_variable_set(sys->context, 0, i, sys->co[i][0]); + EIG_linear_solver_variable_set(sys->context, 1, i, sys->co[i][1]); + EIG_linear_solver_variable_set(sys->context, 2, i, sys->co[i][2]); + } + for (i = 0; i < na; i++) { + vid = sys->index_anchors[i]; + EIG_linear_solver_variable_set(sys->context, 0, vid, vertexCos[vid][0]); + EIG_linear_solver_variable_set(sys->context, 1, vid, vertexCos[vid][1]); + EIG_linear_solver_variable_set(sys->context, 2, vid, vertexCos[vid][2]); + } + + initLaplacianMatrix(sys); + computeImplictRotations(sys); + + for (i = 0; i < n; i++) { + EIG_linear_solver_right_hand_side_add(sys->context, 0, i, sys->delta[i][0]); + EIG_linear_solver_right_hand_side_add(sys->context, 1, i, sys->delta[i][1]); + EIG_linear_solver_right_hand_side_add(sys->context, 2, i, sys->delta[i][2]); + } + for (i = 0; i < na; i++) { + vid = sys->index_anchors[i]; + EIG_linear_solver_right_hand_side_add(sys->context, 0, n + i, vertexCos[vid][0]); + EIG_linear_solver_right_hand_side_add(sys->context, 1, n + i, vertexCos[vid][1]); + EIG_linear_solver_right_hand_side_add(sys->context, 2, n + i, vertexCos[vid][2]); + EIG_linear_solver_matrix_add(sys->context, n + i, vid, 1.0f); + } + if (EIG_linear_solver_solve(sys->context)) { + sys->has_solution = true; + + for (j = 1; j <= sys->repeat; j++) { + rotateDifferentialCoordinates(sys); + + for (i = 0; i < na; i++) { + vid = sys->index_anchors[i]; + EIG_linear_solver_right_hand_side_add(sys->context, 0, n + i, vertexCos[vid][0]); + EIG_linear_solver_right_hand_side_add(sys->context, 1, n + i, vertexCos[vid][1]); + EIG_linear_solver_right_hand_side_add(sys->context, 2, n + i, vertexCos[vid][2]); + } + + if (!EIG_linear_solver_solve(sys->context)) { + sys->has_solution = false; + break; + } + } + if (sys->has_solution) { + for (vid = 0; vid < sys->total_verts; vid++) { + vertexCos[vid][0] = EIG_linear_solver_variable_get(sys->context, 0, vid); + vertexCos[vid][1] = EIG_linear_solver_variable_get(sys->context, 1, vid); + vertexCos[vid][2] = EIG_linear_solver_variable_get(sys->context, 2, vid); + } + } + else { + sys->has_solution = false; + } + } + else { + sys->has_solution = false; + } + sys->is_matrix_computed = true; + } + else if (sys->has_solution) { + for (i = 0; i < n; i++) { + EIG_linear_solver_right_hand_side_add(sys->context, 0, i, sys->delta[i][0]); + EIG_linear_solver_right_hand_side_add(sys->context, 1, i, sys->delta[i][1]); + EIG_linear_solver_right_hand_side_add(sys->context, 2, i, sys->delta[i][2]); + } + for (i = 0; i < na; i++) { + vid = sys->index_anchors[i]; + EIG_linear_solver_right_hand_side_add(sys->context, 0, n + i, vertexCos[vid][0]); + EIG_linear_solver_right_hand_side_add(sys->context, 1, n + i, vertexCos[vid][1]); + EIG_linear_solver_right_hand_side_add(sys->context, 2, n + i, vertexCos[vid][2]); + EIG_linear_solver_matrix_add(sys->context, n + i, vid, 1.0f); + } + + if (EIG_linear_solver_solve(sys->context)) { + sys->has_solution = true; + for (j = 1; j <= sys->repeat; j++) { + rotateDifferentialCoordinates(sys); + + for (i = 0; i < na; i++) { + vid = sys->index_anchors[i]; + EIG_linear_solver_right_hand_side_add(sys->context, 0, n + i, vertexCos[vid][0]); + EIG_linear_solver_right_hand_side_add(sys->context, 1, n + i, vertexCos[vid][1]); + EIG_linear_solver_right_hand_side_add(sys->context, 2, n + i, vertexCos[vid][2]); + } + if (!EIG_linear_solver_solve(sys->context)) { + sys->has_solution = false; + break; + } + } + if (sys->has_solution) { + for (vid = 0; vid < sys->total_verts; vid++) { + vertexCos[vid][0] = EIG_linear_solver_variable_get(sys->context, 0, vid); + vertexCos[vid][1] = EIG_linear_solver_variable_get(sys->context, 1, vid); + vertexCos[vid][2] = EIG_linear_solver_variable_get(sys->context, 2, vid); + } + } + else { + sys->has_solution = false; + } + } + else { + sys->has_solution = false; + } + } } static bool isValidVertexGroup(LaplacianDeformModifierData *lmd, Object *ob, Mesh *mesh) { - int defgrp_index; - MDeformVert *dvert = NULL; + int defgrp_index; + MDeformVert *dvert = NULL; - MOD_get_vgroup(ob, mesh, lmd->anchor_grp_name, &dvert, &defgrp_index); + MOD_get_vgroup(ob, mesh, lmd->anchor_grp_name, &dvert, &defgrp_index); - return (dvert != NULL); + return (dvert != NULL); } static void initSystem( - LaplacianDeformModifierData *lmd, Object *ob, Mesh *mesh, - float (*vertexCos)[3], int numVerts) + LaplacianDeformModifierData *lmd, Object *ob, Mesh *mesh, float (*vertexCos)[3], int numVerts) { - int i; - int defgrp_index; - int total_anchors; - float wpaint; - MDeformVert *dvert = NULL; - MDeformVert *dv = NULL; - LaplacianSystem *sys; - - if (isValidVertexGroup(lmd, ob, mesh)) { - int *index_anchors = MEM_malloc_arrayN(numVerts, sizeof(int), __func__); /* over-alloc */ - const MLoopTri *mlooptri; - const MLoop *mloop; - - STACK_DECLARE(index_anchors); - - STACK_INIT(index_anchors, numVerts); - - MOD_get_vgroup(ob, mesh, lmd->anchor_grp_name, &dvert, &defgrp_index); - BLI_assert(dvert != NULL); - dv = dvert; - for (i = 0; i < numVerts; i++) { - wpaint = defvert_find_weight(dv, defgrp_index); - dv++; - if (wpaint > 0.0f) { - STACK_PUSH(index_anchors, i); - } - } - - total_anchors = STACK_SIZE(index_anchors); - lmd->cache_system = initLaplacianSystem(numVerts, mesh->totedge, BKE_mesh_runtime_looptri_len(mesh), - total_anchors, lmd->anchor_grp_name, lmd->repeat); - sys = (LaplacianSystem *)lmd->cache_system; - memcpy(sys->index_anchors, index_anchors, sizeof(int) * total_anchors); - memcpy(sys->co, vertexCos, sizeof(float[3]) * numVerts); - MEM_freeN(index_anchors); - lmd->vertexco = MEM_malloc_arrayN(numVerts, sizeof(float[3]), "ModDeformCoordinates"); - memcpy(lmd->vertexco, vertexCos, sizeof(float[3]) * numVerts); - lmd->total_verts = numVerts; - - createFaceRingMap( - mesh->totvert, BKE_mesh_runtime_looptri_ensure(mesh), BKE_mesh_runtime_looptri_len(mesh), - mesh->mloop, &sys->ringf_map, &sys->ringf_indices); - createVertRingMap( - mesh->totvert, mesh->medge, mesh->totedge, - &sys->ringv_map, &sys->ringv_indices); - - - mlooptri = BKE_mesh_runtime_looptri_ensure(mesh); - mloop = mesh->mloop; - - for (i = 0; i < sys->total_tris; i++) { - sys->tris[i][0] = mloop[mlooptri[i].tri[0]].v; - sys->tris[i][1] = mloop[mlooptri[i].tri[1]].v; - sys->tris[i][2] = mloop[mlooptri[i].tri[2]].v; - } - } + int i; + int defgrp_index; + int total_anchors; + float wpaint; + MDeformVert *dvert = NULL; + MDeformVert *dv = NULL; + LaplacianSystem *sys; + + if (isValidVertexGroup(lmd, ob, mesh)) { + int *index_anchors = MEM_malloc_arrayN(numVerts, sizeof(int), __func__); /* over-alloc */ + const MLoopTri *mlooptri; + const MLoop *mloop; + + STACK_DECLARE(index_anchors); + + STACK_INIT(index_anchors, numVerts); + + MOD_get_vgroup(ob, mesh, lmd->anchor_grp_name, &dvert, &defgrp_index); + BLI_assert(dvert != NULL); + dv = dvert; + for (i = 0; i < numVerts; i++) { + wpaint = defvert_find_weight(dv, defgrp_index); + dv++; + if (wpaint > 0.0f) { + STACK_PUSH(index_anchors, i); + } + } + + total_anchors = STACK_SIZE(index_anchors); + lmd->cache_system = initLaplacianSystem(numVerts, + mesh->totedge, + BKE_mesh_runtime_looptri_len(mesh), + total_anchors, + lmd->anchor_grp_name, + lmd->repeat); + sys = (LaplacianSystem *)lmd->cache_system; + memcpy(sys->index_anchors, index_anchors, sizeof(int) * total_anchors); + memcpy(sys->co, vertexCos, sizeof(float[3]) * numVerts); + MEM_freeN(index_anchors); + lmd->vertexco = MEM_malloc_arrayN(numVerts, sizeof(float[3]), "ModDeformCoordinates"); + memcpy(lmd->vertexco, vertexCos, sizeof(float[3]) * numVerts); + lmd->total_verts = numVerts; + + createFaceRingMap(mesh->totvert, + BKE_mesh_runtime_looptri_ensure(mesh), + BKE_mesh_runtime_looptri_len(mesh), + mesh->mloop, + &sys->ringf_map, + &sys->ringf_indices); + createVertRingMap( + mesh->totvert, mesh->medge, mesh->totedge, &sys->ringv_map, &sys->ringv_indices); + + mlooptri = BKE_mesh_runtime_looptri_ensure(mesh); + mloop = mesh->mloop; + + for (i = 0; i < sys->total_tris; i++) { + sys->tris[i][0] = mloop[mlooptri[i].tri[0]].v; + sys->tris[i][1] = mloop[mlooptri[i].tri[1]].v; + sys->tris[i][2] = mloop[mlooptri[i].tri[2]].v; + } + } } -static int isSystemDifferent(LaplacianDeformModifierData *lmd, Object *ob, Mesh *mesh, int numVerts) +static int isSystemDifferent(LaplacianDeformModifierData *lmd, + Object *ob, + Mesh *mesh, + int numVerts) { - int i; - int defgrp_index; - int total_anchors = 0; - float wpaint; - MDeformVert *dvert = NULL; - MDeformVert *dv = NULL; - LaplacianSystem *sys = (LaplacianSystem *)lmd->cache_system; - - if (sys->total_verts != numVerts) { - return LAPDEFORM_SYSTEM_CHANGE_VERTEXES; - } - if (sys->total_edges != mesh->totedge) { - return LAPDEFORM_SYSTEM_CHANGE_EDGES; - } - if (!STREQ(lmd->anchor_grp_name, sys->anchor_grp_name)) { - return LAPDEFORM_SYSTEM_ONLY_CHANGE_GROUP; - } - MOD_get_vgroup(ob, mesh, lmd->anchor_grp_name, &dvert, &defgrp_index); - if (!dvert) { - return LAPDEFORM_SYSTEM_CHANGE_NOT_VALID_GROUP; - } - dv = dvert; - for (i = 0; i < numVerts; i++) { - wpaint = defvert_find_weight(dv, defgrp_index); - dv++; - if (wpaint > 0.0f) { - total_anchors++; - } - } - if (sys->total_anchors != total_anchors) { - return LAPDEFORM_SYSTEM_ONLY_CHANGE_ANCHORS; - } - - return LAPDEFORM_SYSTEM_NOT_CHANGE; + int i; + int defgrp_index; + int total_anchors = 0; + float wpaint; + MDeformVert *dvert = NULL; + MDeformVert *dv = NULL; + LaplacianSystem *sys = (LaplacianSystem *)lmd->cache_system; + + if (sys->total_verts != numVerts) { + return LAPDEFORM_SYSTEM_CHANGE_VERTEXES; + } + if (sys->total_edges != mesh->totedge) { + return LAPDEFORM_SYSTEM_CHANGE_EDGES; + } + if (!STREQ(lmd->anchor_grp_name, sys->anchor_grp_name)) { + return LAPDEFORM_SYSTEM_ONLY_CHANGE_GROUP; + } + MOD_get_vgroup(ob, mesh, lmd->anchor_grp_name, &dvert, &defgrp_index); + if (!dvert) { + return LAPDEFORM_SYSTEM_CHANGE_NOT_VALID_GROUP; + } + dv = dvert; + for (i = 0; i < numVerts; i++) { + wpaint = defvert_find_weight(dv, defgrp_index); + dv++; + if (wpaint > 0.0f) { + total_anchors++; + } + } + if (sys->total_anchors != total_anchors) { + return LAPDEFORM_SYSTEM_ONLY_CHANGE_ANCHORS; + } + + return LAPDEFORM_SYSTEM_NOT_CHANGE; } static void LaplacianDeformModifier_do( - LaplacianDeformModifierData *lmd, Object *ob, Mesh *mesh, - float (*vertexCos)[3], int numVerts) + LaplacianDeformModifierData *lmd, Object *ob, Mesh *mesh, 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, mesh, numVerts); - sys = lmd->cache_system; - if (sysdif) { - if (sysdif == LAPDEFORM_SYSTEM_ONLY_CHANGE_ANCHORS || sysdif == LAPDEFORM_SYSTEM_ONLY_CHANGE_GROUP) { - filevertexCos = MEM_malloc_arrayN(numVerts, sizeof(float[3]), "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, mesh, 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, mesh->totedge); - } - 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 (!isValidVertexGroup(lmd, ob, mesh)) { - modifier_setError(&lmd->modifier, "Vertex group '%s' is not valid", lmd->anchor_grp_name); - lmd->flag &= ~MOD_LAPLACIANDEFORM_BIND; - } - else if (lmd->total_verts > 0 && lmd->total_verts == numVerts) { - filevertexCos = MEM_malloc_arrayN(numVerts, sizeof(float[3]), "TempDeformCoordinates"); - memcpy(filevertexCos, lmd->vertexco, sizeof(float[3]) * numVerts); - MEM_SAFE_FREE(lmd->vertexco); - lmd->total_verts = 0; - initSystem(lmd, ob, mesh, filevertexCos, numVerts); - sys = lmd->cache_system; - MEM_SAFE_FREE(filevertexCos); - laplacianDeformPreview(sys, vertexCos); - } - else { - initSystem(lmd, ob, mesh, vertexCos, numVerts); - sys = lmd->cache_system; - laplacianDeformPreview(sys, vertexCos); - } - } - if (sys && sys->is_matrix_computed && !sys->has_solution) { - modifier_setError(&lmd->modifier, "The system did not find a solution"); - } + 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, mesh, numVerts); + sys = lmd->cache_system; + if (sysdif) { + if (sysdif == LAPDEFORM_SYSTEM_ONLY_CHANGE_ANCHORS || + sysdif == LAPDEFORM_SYSTEM_ONLY_CHANGE_GROUP) { + filevertexCos = MEM_malloc_arrayN(numVerts, sizeof(float[3]), "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, mesh, 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, mesh->totedge); + } + 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 (!isValidVertexGroup(lmd, ob, mesh)) { + modifier_setError(&lmd->modifier, "Vertex group '%s' is not valid", lmd->anchor_grp_name); + lmd->flag &= ~MOD_LAPLACIANDEFORM_BIND; + } + else if (lmd->total_verts > 0 && lmd->total_verts == numVerts) { + filevertexCos = MEM_malloc_arrayN(numVerts, sizeof(float[3]), "TempDeformCoordinates"); + memcpy(filevertexCos, lmd->vertexco, sizeof(float[3]) * numVerts); + MEM_SAFE_FREE(lmd->vertexco); + lmd->total_verts = 0; + initSystem(lmd, ob, mesh, filevertexCos, numVerts); + sys = lmd->cache_system; + MEM_SAFE_FREE(filevertexCos); + laplacianDeformPreview(sys, vertexCos); + } + else { + initSystem(lmd, ob, mesh, vertexCos, numVerts); + sys = lmd->cache_system; + laplacianDeformPreview(sys, vertexCos); + } + } + if (sys && sys->is_matrix_computed && !sys->has_solution) { + modifier_setError(&lmd->modifier, "The system did not find a solution"); + } } static void initData(ModifierData *md) { - LaplacianDeformModifierData *lmd = (LaplacianDeformModifierData *)md; - lmd->anchor_grp_name[0] = '\0'; - lmd->total_verts = 0; - lmd->repeat = 1; - lmd->vertexco = NULL; - lmd->cache_system = NULL; - lmd->flag = 0; + LaplacianDeformModifierData *lmd = (LaplacianDeformModifierData *)md; + lmd->anchor_grp_name[0] = '\0'; + lmd->total_verts = 0; + lmd->repeat = 1; + lmd->vertexco = NULL; + lmd->cache_system = NULL; + lmd->flag = 0; } static void copyData(const ModifierData *md, ModifierData *target, const int flag) { - const LaplacianDeformModifierData *lmd = (const LaplacianDeformModifierData *)md; - LaplacianDeformModifierData *tlmd = (LaplacianDeformModifierData *)target; + const LaplacianDeformModifierData *lmd = (const LaplacianDeformModifierData *)md; + LaplacianDeformModifierData *tlmd = (LaplacianDeformModifierData *)target; - modifier_copyData_generic(md, target, flag); + modifier_copyData_generic(md, target, flag); - tlmd->vertexco = MEM_dupallocN(lmd->vertexco); - tlmd->cache_system = NULL; + tlmd->vertexco = MEM_dupallocN(lmd->vertexco); + tlmd->cache_system = NULL; } -static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams)) +static bool isDisabled(const struct Scene *UNUSED(scene), + ModifierData *md, + bool UNUSED(useRenderParams)) { - LaplacianDeformModifierData *lmd = (LaplacianDeformModifierData *)md; - if (lmd->anchor_grp_name[0]) return 0; - return 1; + LaplacianDeformModifierData *lmd = (LaplacianDeformModifierData *)md; + if (lmd->anchor_grp_name[0]) + return 0; + return 1; } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - LaplacianDeformModifierData *lmd = (LaplacianDeformModifierData *)md; + LaplacianDeformModifierData *lmd = (LaplacianDeformModifierData *)md; - if (lmd->anchor_grp_name[0] != '\0') { - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; - } + if (lmd->anchor_grp_name[0] != '\0') { + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + } } -static void deformVerts( - ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh, - float (*vertexCos)[3], int numVerts) +static void deformVerts(ModifierData *md, + const ModifierEvalContext *ctx, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); + Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); - LaplacianDeformModifier_do((LaplacianDeformModifierData *)md, ctx->object, mesh_src, vertexCos, numVerts); + LaplacianDeformModifier_do( + (LaplacianDeformModifierData *)md, ctx->object, mesh_src, vertexCos, numVerts); - if (!ELEM(mesh_src, NULL, mesh)) { - BKE_id_free(NULL, mesh_src); - } + if (!ELEM(mesh_src, NULL, mesh)) { + BKE_id_free(NULL, mesh_src); + } } -static void deformVertsEM( - ModifierData *md, const ModifierEvalContext *ctx, struct BMEditMesh *editData, - Mesh *mesh, float (*vertexCos)[3], int numVerts) +static void deformVertsEM(ModifierData *md, + const ModifierEvalContext *ctx, + struct BMEditMesh *editData, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false); + Mesh *mesh_src = MOD_deform_mesh_eval_get( + ctx->object, editData, mesh, NULL, numVerts, false, false); - LaplacianDeformModifier_do((LaplacianDeformModifierData *)md, ctx->object, mesh_src, - vertexCos, numVerts); + LaplacianDeformModifier_do( + (LaplacianDeformModifierData *)md, ctx->object, mesh_src, vertexCos, numVerts); - if (!ELEM(mesh_src, NULL, mesh)) { - BKE_id_free(NULL, mesh_src); - } + if (!ELEM(mesh_src, NULL, mesh)) { + BKE_id_free(NULL, mesh_src); + } } static void freeData(ModifierData *md) { - LaplacianDeformModifierData *lmd = (LaplacianDeformModifierData *)md; - LaplacianSystem *sys = (LaplacianSystem *)lmd->cache_system; - if (sys) { - deleteLaplacianSystem(sys); - } - MEM_SAFE_FREE(lmd->vertexco); - lmd->total_verts = 0; + LaplacianDeformModifierData *lmd = (LaplacianDeformModifierData *)md; + LaplacianSystem *sys = (LaplacianSystem *)lmd->cache_system; + if (sys) { + deleteLaplacianSystem(sys); + } + MEM_SAFE_FREE(lmd->vertexco); + lmd->total_verts = 0; } ModifierTypeInfo modifierType_LaplacianDeform = { - /* name */ "LaplacianDeform", - /* structName */ "LaplacianDeformModifierData", - /* structSize */ sizeof(LaplacianDeformModifierData), - /* type */ eModifierTypeType_OnlyDeform, - /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsEditmode, - /* copyData */ copyData, - - /* deformVerts */ deformVerts, - /* deformMatrices */ NULL, - /* deformVertsEM */ deformVertsEM, - /* deformMatricesEM */ NULL, - /* applyModifier */ NULL, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ freeData, - /* isDisabled */ isDisabled, - /* updateDepsgraph */ NULL, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ NULL, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "LaplacianDeform", + /* structName */ "LaplacianDeformModifierData", + /* structSize */ sizeof(LaplacianDeformModifierData), + /* type */ eModifierTypeType_OnlyDeform, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsEditmode, + /* copyData */ copyData, + + /* deformVerts */ deformVerts, + /* deformMatrices */ NULL, + /* deformVertsEM */ deformVertsEM, + /* deformMatricesEM */ NULL, + /* applyModifier */ NULL, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ freeData, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_laplaciansmooth.c b/source/blender/modifiers/intern/MOD_laplaciansmooth.c index 321dfd5dae1..0dfe5f49393 100644 --- a/source/blender/modifiers/intern/MOD_laplaciansmooth.c +++ b/source/blender/modifiers/intern/MOD_laplaciansmooth.c @@ -21,7 +21,6 @@ * \ingroup modifiers */ - #include "BLI_utildefines.h" #include "BLI_math.h" @@ -43,36 +42,43 @@ #include "eigen_capi.h" struct BLaplacianSystem { - float *eweights; /* Length weights per Edge */ - float (*fweights)[3]; /* Cotangent weights per face */ - float *ring_areas; /* Total area per ring*/ - float *vlengths; /* Total sum of lengths(edges) per vertice*/ - float *vweights; /* Total sum of weights per vertice*/ - int numEdges; /* Number of edges*/ - int numLoops; /* Number of edges*/ - int numPolys; /* Number of faces*/ - int numVerts; /* Number of verts*/ - short *numNeFa; /* Number of neighbors faces around vertice*/ - short *numNeEd; /* Number of neighbors Edges around vertice*/ - short *zerola; /* Is zero area or length*/ - - /* Pointers to data*/ - float (*vertexCos)[3]; - const MPoly *mpoly; - const MLoop *mloop; - const MEdge *medges; - LinearSolver *context; - - /*Data*/ - float min_area; - float vert_centroid[3]; + float *eweights; /* Length weights per Edge */ + float (*fweights)[3]; /* Cotangent weights per face */ + float *ring_areas; /* Total area per ring*/ + float *vlengths; /* Total sum of lengths(edges) per vertice*/ + float *vweights; /* Total sum of weights per vertice*/ + int numEdges; /* Number of edges*/ + int numLoops; /* Number of edges*/ + int numPolys; /* Number of faces*/ + int numVerts; /* Number of verts*/ + short *numNeFa; /* Number of neighbors faces around vertice*/ + short *numNeEd; /* Number of neighbors Edges around vertice*/ + short *zerola; /* Is zero area or length*/ + + /* Pointers to data*/ + float (*vertexCos)[3]; + const MPoly *mpoly; + const MLoop *mloop; + const MEdge *medges; + LinearSolver *context; + + /*Data*/ + float min_area; + float vert_centroid[3]; }; typedef struct BLaplacianSystem LaplacianSystem; static void required_data_mask(Object *ob, ModifierData *md, CustomData_MeshMasks *r_cddata_masks); static bool is_disabled(const struct Scene *UNUSED(scene), ModifierData *md, bool useRenderParams); -static float compute_volume(const float center[3], float (*vertexCos)[3], const MPoly *mpoly, int numPolys, const MLoop *mloop); -static LaplacianSystem *init_laplacian_system(int a_numEdges, int a_numPolys, int a_numLoops, int a_numVerts); +static float compute_volume(const float center[3], + float (*vertexCos)[3], + const MPoly *mpoly, + int numPolys, + const MLoop *mloop); +static LaplacianSystem *init_laplacian_system(int a_numEdges, + int a_numPolys, + int a_numLoops, + int a_numVerts); static void delete_laplacian_system(LaplacianSystem *sys); static void fill_laplacian_matrix(LaplacianSystem *sys); static void init_data(ModifierData *md); @@ -83,473 +89,503 @@ static void validate_solution(LaplacianSystem *sys, short flag, float lambda, fl static void delete_laplacian_system(LaplacianSystem *sys) { - MEM_SAFE_FREE(sys->eweights); - MEM_SAFE_FREE(sys->fweights); - MEM_SAFE_FREE(sys->numNeEd); - MEM_SAFE_FREE(sys->numNeFa); - MEM_SAFE_FREE(sys->ring_areas); - MEM_SAFE_FREE(sys->vlengths); - MEM_SAFE_FREE(sys->vweights); - MEM_SAFE_FREE(sys->zerola); - - if (sys->context) { - EIG_linear_solver_delete(sys->context); - } - sys->vertexCos = NULL; - sys->mpoly = NULL; - sys->mloop = NULL; - sys->medges = NULL; - MEM_freeN(sys); + MEM_SAFE_FREE(sys->eweights); + MEM_SAFE_FREE(sys->fweights); + MEM_SAFE_FREE(sys->numNeEd); + MEM_SAFE_FREE(sys->numNeFa); + MEM_SAFE_FREE(sys->ring_areas); + MEM_SAFE_FREE(sys->vlengths); + MEM_SAFE_FREE(sys->vweights); + MEM_SAFE_FREE(sys->zerola); + + if (sys->context) { + EIG_linear_solver_delete(sys->context); + } + sys->vertexCos = NULL; + sys->mpoly = NULL; + sys->mloop = NULL; + sys->medges = NULL; + MEM_freeN(sys); } static void memset_laplacian_system(LaplacianSystem *sys, int val) { - memset(sys->eweights, val, sizeof(float) * sys->numEdges); - memset(sys->fweights, val, sizeof(float[3]) * sys->numLoops); - memset(sys->numNeEd, val, sizeof(short) * sys->numVerts); - memset(sys->numNeFa, val, sizeof(short) * sys->numVerts); - memset(sys->ring_areas, val, sizeof(float) * sys->numVerts); - memset(sys->vlengths, val, sizeof(float) * sys->numVerts); - memset(sys->vweights, val, sizeof(float) * sys->numVerts); - memset(sys->zerola, val, sizeof(short) * sys->numVerts); + memset(sys->eweights, val, sizeof(float) * sys->numEdges); + memset(sys->fweights, val, sizeof(float[3]) * sys->numLoops); + memset(sys->numNeEd, val, sizeof(short) * sys->numVerts); + memset(sys->numNeFa, val, sizeof(short) * sys->numVerts); + memset(sys->ring_areas, val, sizeof(float) * sys->numVerts); + memset(sys->vlengths, val, sizeof(float) * sys->numVerts); + memset(sys->vweights, val, sizeof(float) * sys->numVerts); + memset(sys->zerola, val, sizeof(short) * sys->numVerts); } -static LaplacianSystem *init_laplacian_system(int a_numEdges, int a_numPolys, int a_numLoops, int a_numVerts) +static LaplacianSystem *init_laplacian_system(int a_numEdges, + int a_numPolys, + int a_numLoops, + int a_numVerts) { - LaplacianSystem *sys; - sys = MEM_callocN(sizeof(LaplacianSystem), "ModLaplSmoothSystem"); - sys->numEdges = a_numEdges; - sys->numPolys = a_numPolys; - sys->numLoops = a_numLoops; - sys->numVerts = a_numVerts; - - sys->eweights = MEM_calloc_arrayN(sys->numEdges, sizeof(float), __func__); - sys->fweights = MEM_calloc_arrayN(sys->numLoops, sizeof(float[3]), __func__); - sys->numNeEd = MEM_calloc_arrayN(sys->numVerts, sizeof(short), __func__); - sys->numNeFa = MEM_calloc_arrayN(sys->numVerts, sizeof(short), __func__); - sys->ring_areas = MEM_calloc_arrayN(sys->numVerts, sizeof(float), __func__); - sys->vlengths = MEM_calloc_arrayN(sys->numVerts, sizeof(float), __func__); - sys->vweights = MEM_calloc_arrayN(sys->numVerts, sizeof(float), __func__); - sys->zerola = MEM_calloc_arrayN(sys->numVerts, sizeof(short), __func__); - - return sys; + LaplacianSystem *sys; + sys = MEM_callocN(sizeof(LaplacianSystem), "ModLaplSmoothSystem"); + sys->numEdges = a_numEdges; + sys->numPolys = a_numPolys; + sys->numLoops = a_numLoops; + sys->numVerts = a_numVerts; + + sys->eweights = MEM_calloc_arrayN(sys->numEdges, sizeof(float), __func__); + sys->fweights = MEM_calloc_arrayN(sys->numLoops, sizeof(float[3]), __func__); + sys->numNeEd = MEM_calloc_arrayN(sys->numVerts, sizeof(short), __func__); + sys->numNeFa = MEM_calloc_arrayN(sys->numVerts, sizeof(short), __func__); + sys->ring_areas = MEM_calloc_arrayN(sys->numVerts, sizeof(float), __func__); + sys->vlengths = MEM_calloc_arrayN(sys->numVerts, sizeof(float), __func__); + sys->vweights = MEM_calloc_arrayN(sys->numVerts, sizeof(float), __func__); + sys->zerola = MEM_calloc_arrayN(sys->numVerts, sizeof(short), __func__); + + return sys; } -static float compute_volume( - const float center[3], float (*vertexCos)[3], - const MPoly *mpoly, int numPolys, const MLoop *mloop) +static float compute_volume(const float center[3], + float (*vertexCos)[3], + const MPoly *mpoly, + int numPolys, + const MLoop *mloop) { - int i; - float vol = 0.0f; - - for (i = 0; i < numPolys; i++) { - const MPoly *mp = &mpoly[i]; - const MLoop *l_first = &mloop[mp->loopstart]; - const MLoop *l_prev = l_first + 1; - const MLoop *l_curr = l_first + 2; - const MLoop *l_term = l_first + mp->totloop; - - - for (; - l_curr != l_term; - l_prev = l_curr, l_curr++) - { - vol += volume_tetrahedron_signed_v3( - center, - vertexCos[l_first->v], - vertexCos[l_prev->v], - vertexCos[l_curr->v]); - } - } - - return fabsf(vol); + int i; + float vol = 0.0f; + + for (i = 0; i < numPolys; i++) { + const MPoly *mp = &mpoly[i]; + const MLoop *l_first = &mloop[mp->loopstart]; + const MLoop *l_prev = l_first + 1; + const MLoop *l_curr = l_first + 2; + const MLoop *l_term = l_first + mp->totloop; + + for (; l_curr != l_term; l_prev = l_curr, l_curr++) { + vol += volume_tetrahedron_signed_v3( + center, vertexCos[l_first->v], vertexCos[l_prev->v], vertexCos[l_curr->v]); + } + } + + return fabsf(vol); } static void volume_preservation(LaplacianSystem *sys, float vini, float vend, short flag) { - float beta; - int i; - - if (vend != 0.0f) { - beta = pow(vini / vend, 1.0f / 3.0f); - for (i = 0; i < sys->numVerts; i++) { - if (flag & MOD_LAPLACIANSMOOTH_X) { - sys->vertexCos[i][0] = (sys->vertexCos[i][0] - sys->vert_centroid[0]) * beta + sys->vert_centroid[0]; - } - if (flag & MOD_LAPLACIANSMOOTH_Y) { - sys->vertexCos[i][1] = (sys->vertexCos[i][1] - sys->vert_centroid[1]) * beta + sys->vert_centroid[1]; - } - if (flag & MOD_LAPLACIANSMOOTH_Z) { - sys->vertexCos[i][2] = (sys->vertexCos[i][2] - sys->vert_centroid[2]) * beta + sys->vert_centroid[2]; - } - - } - } + float beta; + int i; + + if (vend != 0.0f) { + beta = pow(vini / vend, 1.0f / 3.0f); + for (i = 0; i < sys->numVerts; i++) { + if (flag & MOD_LAPLACIANSMOOTH_X) { + sys->vertexCos[i][0] = (sys->vertexCos[i][0] - sys->vert_centroid[0]) * beta + + sys->vert_centroid[0]; + } + if (flag & MOD_LAPLACIANSMOOTH_Y) { + sys->vertexCos[i][1] = (sys->vertexCos[i][1] - sys->vert_centroid[1]) * beta + + sys->vert_centroid[1]; + } + if (flag & MOD_LAPLACIANSMOOTH_Z) { + sys->vertexCos[i][2] = (sys->vertexCos[i][2] - sys->vert_centroid[2]) * beta + + sys->vert_centroid[2]; + } + } + } } static void init_laplacian_matrix(LaplacianSystem *sys) { - float *v1, *v2; - float w1, w2, w3; - float areaf; - int i; - unsigned int idv1, idv2; - - for (i = 0; i < sys->numEdges; i++) { - idv1 = sys->medges[i].v1; - idv2 = sys->medges[i].v2; - - v1 = sys->vertexCos[idv1]; - v2 = sys->vertexCos[idv2]; - - sys->numNeEd[idv1] = sys->numNeEd[idv1] + 1; - sys->numNeEd[idv2] = sys->numNeEd[idv2] + 1; - w1 = len_v3v3(v1, v2); - if (w1 < sys->min_area) { - sys->zerola[idv1] = 1; - sys->zerola[idv2] = 1; - } - else { - w1 = 1.0f / w1; - } - - sys->eweights[i] = w1; - } - - for (i = 0; i < sys->numPolys; i++) { - const MPoly *mp = &sys->mpoly[i]; - const MLoop *l_next = &sys->mloop[mp->loopstart]; - const MLoop *l_term = l_next + mp->totloop; - const MLoop *l_prev = l_term - 2; - const MLoop *l_curr = l_term - 1; - - for (; - l_next != l_term; - l_prev = l_curr, l_curr = l_next, l_next++) - { - const float *v_prev = sys->vertexCos[l_prev->v]; - const float *v_curr = sys->vertexCos[l_curr->v]; - const float *v_next = sys->vertexCos[l_next->v]; - const unsigned int l_curr_index = l_curr - sys->mloop; - - sys->numNeFa[l_curr->v] += 1; - - areaf = area_tri_v3(v_prev, v_curr, v_next); - - if (areaf < sys->min_area) { - sys->zerola[l_curr->v] = 1; - } - - sys->ring_areas[l_prev->v] += areaf; - sys->ring_areas[l_curr->v] += areaf; - sys->ring_areas[l_next->v] += areaf; - - w1 = cotangent_tri_weight_v3(v_curr, v_next, v_prev) / 2.0f; - w2 = cotangent_tri_weight_v3(v_next, v_prev, v_curr) / 2.0f; - w3 = cotangent_tri_weight_v3(v_prev, v_curr, v_next) / 2.0f; - - sys->fweights[l_curr_index][0] += w1; - sys->fweights[l_curr_index][1] += w2; - sys->fweights[l_curr_index][2] += w3; - - sys->vweights[l_curr->v] += w2 + w3; - sys->vweights[l_next->v] += w1 + w3; - sys->vweights[l_prev->v] += w1 + w2; - } - } - for (i = 0; i < sys->numEdges; i++) { - idv1 = sys->medges[i].v1; - idv2 = sys->medges[i].v2; - /* if is boundary, apply scale-dependent umbrella operator only with neighbors in boundary */ - if (sys->numNeEd[idv1] != sys->numNeFa[idv1] && sys->numNeEd[idv2] != sys->numNeFa[idv2]) { - sys->vlengths[idv1] += sys->eweights[i]; - sys->vlengths[idv2] += sys->eweights[i]; - } - } - + float *v1, *v2; + float w1, w2, w3; + float areaf; + int i; + unsigned int idv1, idv2; + + for (i = 0; i < sys->numEdges; i++) { + idv1 = sys->medges[i].v1; + idv2 = sys->medges[i].v2; + + v1 = sys->vertexCos[idv1]; + v2 = sys->vertexCos[idv2]; + + sys->numNeEd[idv1] = sys->numNeEd[idv1] + 1; + sys->numNeEd[idv2] = sys->numNeEd[idv2] + 1; + w1 = len_v3v3(v1, v2); + if (w1 < sys->min_area) { + sys->zerola[idv1] = 1; + sys->zerola[idv2] = 1; + } + else { + w1 = 1.0f / w1; + } + + sys->eweights[i] = w1; + } + + for (i = 0; i < sys->numPolys; i++) { + const MPoly *mp = &sys->mpoly[i]; + const MLoop *l_next = &sys->mloop[mp->loopstart]; + const MLoop *l_term = l_next + mp->totloop; + const MLoop *l_prev = l_term - 2; + const MLoop *l_curr = l_term - 1; + + for (; l_next != l_term; l_prev = l_curr, l_curr = l_next, l_next++) { + const float *v_prev = sys->vertexCos[l_prev->v]; + const float *v_curr = sys->vertexCos[l_curr->v]; + const float *v_next = sys->vertexCos[l_next->v]; + const unsigned int l_curr_index = l_curr - sys->mloop; + + sys->numNeFa[l_curr->v] += 1; + + areaf = area_tri_v3(v_prev, v_curr, v_next); + + if (areaf < sys->min_area) { + sys->zerola[l_curr->v] = 1; + } + + sys->ring_areas[l_prev->v] += areaf; + sys->ring_areas[l_curr->v] += areaf; + sys->ring_areas[l_next->v] += areaf; + + w1 = cotangent_tri_weight_v3(v_curr, v_next, v_prev) / 2.0f; + w2 = cotangent_tri_weight_v3(v_next, v_prev, v_curr) / 2.0f; + w3 = cotangent_tri_weight_v3(v_prev, v_curr, v_next) / 2.0f; + + sys->fweights[l_curr_index][0] += w1; + sys->fweights[l_curr_index][1] += w2; + sys->fweights[l_curr_index][2] += w3; + + sys->vweights[l_curr->v] += w2 + w3; + sys->vweights[l_next->v] += w1 + w3; + sys->vweights[l_prev->v] += w1 + w2; + } + } + for (i = 0; i < sys->numEdges; i++) { + idv1 = sys->medges[i].v1; + idv2 = sys->medges[i].v2; + /* if is boundary, apply scale-dependent umbrella operator only with neighbors in boundary */ + if (sys->numNeEd[idv1] != sys->numNeFa[idv1] && sys->numNeEd[idv2] != sys->numNeFa[idv2]) { + sys->vlengths[idv1] += sys->eweights[i]; + sys->vlengths[idv2] += sys->eweights[i]; + } + } } static void fill_laplacian_matrix(LaplacianSystem *sys) { - int i; - unsigned int idv1, idv2; - - for (i = 0; i < sys->numPolys; i++) { - const MPoly *mp = &sys->mpoly[i]; - const MLoop *l_next = &sys->mloop[mp->loopstart]; - const MLoop *l_term = l_next + mp->totloop; - const MLoop *l_prev = l_term - 2; - const MLoop *l_curr = l_term - 1; - - for (; - l_next != l_term; - l_prev = l_curr, l_curr = l_next, l_next++) - { - const unsigned int l_curr_index = l_curr - sys->mloop; - - /* Is ring if number of faces == number of edges around vertice*/ - if (sys->numNeEd[l_curr->v] == sys->numNeFa[l_curr->v] && sys->zerola[l_curr->v] == 0) { - EIG_linear_solver_matrix_add(sys->context, l_curr->v, l_next->v, sys->fweights[l_curr_index][2] * sys->vweights[l_curr->v]); - EIG_linear_solver_matrix_add(sys->context, l_curr->v, l_prev->v, sys->fweights[l_curr_index][1] * sys->vweights[l_curr->v]); - } - if (sys->numNeEd[l_next->v] == sys->numNeFa[l_next->v] && sys->zerola[l_next->v] == 0) { - EIG_linear_solver_matrix_add(sys->context, l_next->v, l_curr->v, sys->fweights[l_curr_index][2] * sys->vweights[l_next->v]); - EIG_linear_solver_matrix_add(sys->context, l_next->v, l_prev->v, sys->fweights[l_curr_index][0] * sys->vweights[l_next->v]); - } - if (sys->numNeEd[l_prev->v] == sys->numNeFa[l_prev->v] && sys->zerola[l_prev->v] == 0) { - EIG_linear_solver_matrix_add(sys->context, l_prev->v, l_curr->v, sys->fweights[l_curr_index][1] * sys->vweights[l_prev->v]); - EIG_linear_solver_matrix_add(sys->context, l_prev->v, l_next->v, sys->fweights[l_curr_index][0] * sys->vweights[l_prev->v]); - } - } - } - - for (i = 0; i < sys->numEdges; i++) { - idv1 = sys->medges[i].v1; - idv2 = sys->medges[i].v2; - /* Is boundary */ - if (sys->numNeEd[idv1] != sys->numNeFa[idv1] && - sys->numNeEd[idv2] != sys->numNeFa[idv2] && - sys->zerola[idv1] == 0 && - sys->zerola[idv2] == 0) - { - EIG_linear_solver_matrix_add(sys->context, idv1, idv2, sys->eweights[i] * sys->vlengths[idv1]); - EIG_linear_solver_matrix_add(sys->context, idv2, idv1, sys->eweights[i] * sys->vlengths[idv2]); - } - } + int i; + unsigned int idv1, idv2; + + for (i = 0; i < sys->numPolys; i++) { + const MPoly *mp = &sys->mpoly[i]; + const MLoop *l_next = &sys->mloop[mp->loopstart]; + const MLoop *l_term = l_next + mp->totloop; + const MLoop *l_prev = l_term - 2; + const MLoop *l_curr = l_term - 1; + + for (; l_next != l_term; l_prev = l_curr, l_curr = l_next, l_next++) { + const unsigned int l_curr_index = l_curr - sys->mloop; + + /* Is ring if number of faces == number of edges around vertice*/ + if (sys->numNeEd[l_curr->v] == sys->numNeFa[l_curr->v] && sys->zerola[l_curr->v] == 0) { + EIG_linear_solver_matrix_add(sys->context, + l_curr->v, + l_next->v, + sys->fweights[l_curr_index][2] * sys->vweights[l_curr->v]); + EIG_linear_solver_matrix_add(sys->context, + l_curr->v, + l_prev->v, + sys->fweights[l_curr_index][1] * sys->vweights[l_curr->v]); + } + if (sys->numNeEd[l_next->v] == sys->numNeFa[l_next->v] && sys->zerola[l_next->v] == 0) { + EIG_linear_solver_matrix_add(sys->context, + l_next->v, + l_curr->v, + sys->fweights[l_curr_index][2] * sys->vweights[l_next->v]); + EIG_linear_solver_matrix_add(sys->context, + l_next->v, + l_prev->v, + sys->fweights[l_curr_index][0] * sys->vweights[l_next->v]); + } + if (sys->numNeEd[l_prev->v] == sys->numNeFa[l_prev->v] && sys->zerola[l_prev->v] == 0) { + EIG_linear_solver_matrix_add(sys->context, + l_prev->v, + l_curr->v, + sys->fweights[l_curr_index][1] * sys->vweights[l_prev->v]); + EIG_linear_solver_matrix_add(sys->context, + l_prev->v, + l_next->v, + sys->fweights[l_curr_index][0] * sys->vweights[l_prev->v]); + } + } + } + + for (i = 0; i < sys->numEdges; i++) { + idv1 = sys->medges[i].v1; + idv2 = sys->medges[i].v2; + /* Is boundary */ + if (sys->numNeEd[idv1] != sys->numNeFa[idv1] && sys->numNeEd[idv2] != sys->numNeFa[idv2] && + sys->zerola[idv1] == 0 && sys->zerola[idv2] == 0) { + EIG_linear_solver_matrix_add( + sys->context, idv1, idv2, sys->eweights[i] * sys->vlengths[idv1]); + EIG_linear_solver_matrix_add( + sys->context, idv2, idv1, sys->eweights[i] * sys->vlengths[idv2]); + } + } } static void validate_solution(LaplacianSystem *sys, short flag, float lambda, float lambda_border) { - int i; - float lam; - float vini = 0.0f, vend = 0.0f; - - if (flag & MOD_LAPLACIANSMOOTH_PRESERVE_VOLUME) { - vini = compute_volume(sys->vert_centroid, sys->vertexCos, sys->mpoly, sys->numPolys, sys->mloop); - } - for (i = 0; i < sys->numVerts; i++) { - if (sys->zerola[i] == 0) { - lam = sys->numNeEd[i] == sys->numNeFa[i] ? (lambda >= 0.0f ? 1.0f : -1.0f) : (lambda_border >= 0.0f ? 1.0f : -1.0f); - if (flag & MOD_LAPLACIANSMOOTH_X) { - sys->vertexCos[i][0] += lam * ((float)EIG_linear_solver_variable_get(sys->context, 0, i) - sys->vertexCos[i][0]); - } - if (flag & MOD_LAPLACIANSMOOTH_Y) { - sys->vertexCos[i][1] += lam * ((float)EIG_linear_solver_variable_get(sys->context, 1, i) - sys->vertexCos[i][1]); - } - if (flag & MOD_LAPLACIANSMOOTH_Z) { - sys->vertexCos[i][2] += lam * ((float)EIG_linear_solver_variable_get(sys->context, 2, i) - sys->vertexCos[i][2]); - } - } - } - if (flag & MOD_LAPLACIANSMOOTH_PRESERVE_VOLUME) { - vend = compute_volume(sys->vert_centroid, sys->vertexCos, sys->mpoly, sys->numPolys, sys->mloop); - volume_preservation(sys, vini, vend, flag); - } + int i; + float lam; + float vini = 0.0f, vend = 0.0f; + + if (flag & MOD_LAPLACIANSMOOTH_PRESERVE_VOLUME) { + vini = compute_volume( + sys->vert_centroid, sys->vertexCos, sys->mpoly, sys->numPolys, sys->mloop); + } + for (i = 0; i < sys->numVerts; i++) { + if (sys->zerola[i] == 0) { + lam = sys->numNeEd[i] == sys->numNeFa[i] ? (lambda >= 0.0f ? 1.0f : -1.0f) : + (lambda_border >= 0.0f ? 1.0f : -1.0f); + if (flag & MOD_LAPLACIANSMOOTH_X) { + sys->vertexCos[i][0] += lam * ((float)EIG_linear_solver_variable_get(sys->context, 0, i) - + sys->vertexCos[i][0]); + } + if (flag & MOD_LAPLACIANSMOOTH_Y) { + sys->vertexCos[i][1] += lam * ((float)EIG_linear_solver_variable_get(sys->context, 1, i) - + sys->vertexCos[i][1]); + } + if (flag & MOD_LAPLACIANSMOOTH_Z) { + sys->vertexCos[i][2] += lam * ((float)EIG_linear_solver_variable_get(sys->context, 2, i) - + sys->vertexCos[i][2]); + } + } + } + if (flag & MOD_LAPLACIANSMOOTH_PRESERVE_VOLUME) { + vend = compute_volume( + sys->vert_centroid, sys->vertexCos, sys->mpoly, sys->numPolys, sys->mloop); + volume_preservation(sys, vini, vend, flag); + } } static void laplaciansmoothModifier_do( - LaplacianSmoothModifierData *smd, Object *ob, Mesh *mesh, - float (*vertexCos)[3], int numVerts) + LaplacianSmoothModifierData *smd, Object *ob, Mesh *mesh, float (*vertexCos)[3], int numVerts) { - LaplacianSystem *sys; - MDeformVert *dvert = NULL; - MDeformVert *dv = NULL; - float w, wpaint; - int i, iter; - int defgrp_index; - - sys = init_laplacian_system(mesh->totedge, mesh->totpoly, mesh->totloop, numVerts); - if (!sys) { - return; - } - - sys->mpoly = mesh->mpoly; - sys->mloop = mesh->mloop; - sys->medges = mesh->medge; - sys->vertexCos = vertexCos; - sys->min_area = 0.00001f; - MOD_get_vgroup(ob, mesh, smd->defgrp_name, &dvert, &defgrp_index); - - sys->vert_centroid[0] = 0.0f; - sys->vert_centroid[1] = 0.0f; - sys->vert_centroid[2] = 0.0f; - memset_laplacian_system(sys, 0); - - sys->context = EIG_linear_least_squares_solver_new(numVerts, numVerts, 3); - - init_laplacian_matrix(sys); - - for (iter = 0; iter < smd->repeat; iter++) { - for (i = 0; i < numVerts; i++) { - EIG_linear_solver_variable_set(sys->context, 0, i, vertexCos[i][0]); - EIG_linear_solver_variable_set(sys->context, 1, i, vertexCos[i][1]); - EIG_linear_solver_variable_set(sys->context, 2, i, vertexCos[i][2]); - if (iter == 0) { - add_v3_v3(sys->vert_centroid, vertexCos[i]); - } - } - if (iter == 0 && numVerts > 0) { - mul_v3_fl(sys->vert_centroid, 1.0f / (float)numVerts); - } - - dv = dvert; - for (i = 0; i < numVerts; i++) { - EIG_linear_solver_right_hand_side_add(sys->context, 0, i, vertexCos[i][0]); - EIG_linear_solver_right_hand_side_add(sys->context, 1, i, vertexCos[i][1]); - EIG_linear_solver_right_hand_side_add(sys->context, 2, i, vertexCos[i][2]); - if (iter == 0) { - if (dv) { - wpaint = defvert_find_weight(dv, defgrp_index); - dv++; - } - else { - wpaint = 1.0f; - } - - if (sys->zerola[i] == 0) { - if (smd->flag & MOD_LAPLACIANSMOOTH_NORMALIZED) { - w = sys->vweights[i]; - sys->vweights[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda) * wpaint / w; - w = sys->vlengths[i]; - sys->vlengths[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda_border) * wpaint * 2.0f / w; - if (sys->numNeEd[i] == sys->numNeFa[i]) { - EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f + fabsf(smd->lambda) * wpaint); - } - else { - EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f + fabsf(smd->lambda_border) * wpaint * 2.0f); - } - } - else { - w = sys->vweights[i] * sys->ring_areas[i]; - sys->vweights[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda) * wpaint / (4.0f * w); - w = sys->vlengths[i]; - sys->vlengths[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda_border) * wpaint * 2.0f / w; - - if (sys->numNeEd[i] == sys->numNeFa[i]) { - EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f + fabsf(smd->lambda) * wpaint / (4.0f * sys->ring_areas[i])); - } - else { - EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f + fabsf(smd->lambda_border) * wpaint * 2.0f); - } - } - } - else { - EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f); - } - } - } - - if (iter == 0) { - fill_laplacian_matrix(sys); - } - - if (EIG_linear_solver_solve(sys->context)) { - validate_solution(sys, smd->flag, smd->lambda, smd->lambda_border); - } - } - EIG_linear_solver_delete(sys->context); - sys->context = NULL; - - delete_laplacian_system(sys); + LaplacianSystem *sys; + MDeformVert *dvert = NULL; + MDeformVert *dv = NULL; + float w, wpaint; + int i, iter; + int defgrp_index; + + sys = init_laplacian_system(mesh->totedge, mesh->totpoly, mesh->totloop, numVerts); + if (!sys) { + return; + } + + sys->mpoly = mesh->mpoly; + sys->mloop = mesh->mloop; + sys->medges = mesh->medge; + sys->vertexCos = vertexCos; + sys->min_area = 0.00001f; + MOD_get_vgroup(ob, mesh, smd->defgrp_name, &dvert, &defgrp_index); + + sys->vert_centroid[0] = 0.0f; + sys->vert_centroid[1] = 0.0f; + sys->vert_centroid[2] = 0.0f; + memset_laplacian_system(sys, 0); + + sys->context = EIG_linear_least_squares_solver_new(numVerts, numVerts, 3); + + init_laplacian_matrix(sys); + + for (iter = 0; iter < smd->repeat; iter++) { + for (i = 0; i < numVerts; i++) { + EIG_linear_solver_variable_set(sys->context, 0, i, vertexCos[i][0]); + EIG_linear_solver_variable_set(sys->context, 1, i, vertexCos[i][1]); + EIG_linear_solver_variable_set(sys->context, 2, i, vertexCos[i][2]); + if (iter == 0) { + add_v3_v3(sys->vert_centroid, vertexCos[i]); + } + } + if (iter == 0 && numVerts > 0) { + mul_v3_fl(sys->vert_centroid, 1.0f / (float)numVerts); + } + + dv = dvert; + for (i = 0; i < numVerts; i++) { + EIG_linear_solver_right_hand_side_add(sys->context, 0, i, vertexCos[i][0]); + EIG_linear_solver_right_hand_side_add(sys->context, 1, i, vertexCos[i][1]); + EIG_linear_solver_right_hand_side_add(sys->context, 2, i, vertexCos[i][2]); + if (iter == 0) { + if (dv) { + wpaint = defvert_find_weight(dv, defgrp_index); + dv++; + } + else { + wpaint = 1.0f; + } + + if (sys->zerola[i] == 0) { + if (smd->flag & MOD_LAPLACIANSMOOTH_NORMALIZED) { + w = sys->vweights[i]; + sys->vweights[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda) * wpaint / w; + w = sys->vlengths[i]; + sys->vlengths[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda_border) * wpaint * 2.0f / w; + if (sys->numNeEd[i] == sys->numNeFa[i]) { + EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f + fabsf(smd->lambda) * wpaint); + } + else { + EIG_linear_solver_matrix_add( + sys->context, i, i, 1.0f + fabsf(smd->lambda_border) * wpaint * 2.0f); + } + } + else { + w = sys->vweights[i] * sys->ring_areas[i]; + sys->vweights[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda) * wpaint / (4.0f * w); + w = sys->vlengths[i]; + sys->vlengths[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda_border) * wpaint * 2.0f / w; + + if (sys->numNeEd[i] == sys->numNeFa[i]) { + EIG_linear_solver_matrix_add(sys->context, + i, + i, + 1.0f + fabsf(smd->lambda) * wpaint / + (4.0f * sys->ring_areas[i])); + } + else { + EIG_linear_solver_matrix_add( + sys->context, i, i, 1.0f + fabsf(smd->lambda_border) * wpaint * 2.0f); + } + } + } + else { + EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f); + } + } + } + + if (iter == 0) { + fill_laplacian_matrix(sys); + } + + if (EIG_linear_solver_solve(sys->context)) { + validate_solution(sys, smd->flag, smd->lambda, smd->lambda_border); + } + } + EIG_linear_solver_delete(sys->context); + sys->context = NULL; + + delete_laplacian_system(sys); } static void init_data(ModifierData *md) { - LaplacianSmoothModifierData *smd = (LaplacianSmoothModifierData *) md; - smd->lambda = 0.01f; - smd->lambda_border = 0.01f; - smd->repeat = 1; - smd->flag = MOD_LAPLACIANSMOOTH_X | MOD_LAPLACIANSMOOTH_Y | MOD_LAPLACIANSMOOTH_Z | MOD_LAPLACIANSMOOTH_PRESERVE_VOLUME | MOD_LAPLACIANSMOOTH_NORMALIZED; - smd->defgrp_name[0] = '\0'; + LaplacianSmoothModifierData *smd = (LaplacianSmoothModifierData *)md; + smd->lambda = 0.01f; + smd->lambda_border = 0.01f; + smd->repeat = 1; + smd->flag = MOD_LAPLACIANSMOOTH_X | MOD_LAPLACIANSMOOTH_Y | MOD_LAPLACIANSMOOTH_Z | + MOD_LAPLACIANSMOOTH_PRESERVE_VOLUME | MOD_LAPLACIANSMOOTH_NORMALIZED; + smd->defgrp_name[0] = '\0'; } -static bool is_disabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams)) +static bool is_disabled(const struct Scene *UNUSED(scene), + ModifierData *md, + bool UNUSED(useRenderParams)) { - LaplacianSmoothModifierData *smd = (LaplacianSmoothModifierData *) md; - short flag; + LaplacianSmoothModifierData *smd = (LaplacianSmoothModifierData *)md; + short flag; - flag = smd->flag & (MOD_LAPLACIANSMOOTH_X | MOD_LAPLACIANSMOOTH_Y | MOD_LAPLACIANSMOOTH_Z); + flag = smd->flag & (MOD_LAPLACIANSMOOTH_X | MOD_LAPLACIANSMOOTH_Y | MOD_LAPLACIANSMOOTH_Z); - /* disable if modifier is off for X, Y and Z or if factor is 0 */ - if (flag == 0) return 1; + /* disable if modifier is off for X, Y and Z or if factor is 0 */ + if (flag == 0) + return 1; - return 0; + return 0; } -static void required_data_mask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void required_data_mask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - LaplacianSmoothModifierData *smd = (LaplacianSmoothModifierData *)md; + LaplacianSmoothModifierData *smd = (LaplacianSmoothModifierData *)md; - /* ask for vertexgroups if we need them */ - if (smd->defgrp_name[0] != '\0') { - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; - } + /* ask for vertexgroups if we need them */ + if (smd->defgrp_name[0] != '\0') { + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + } } -static void deformVerts( - ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh, - float (*vertexCos)[3], int numVerts) +static void deformVerts(ModifierData *md, + const ModifierEvalContext *ctx, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - Mesh *mesh_src; + Mesh *mesh_src; - if (numVerts == 0) - return; + if (numVerts == 0) + return; - mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); + mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); - laplaciansmoothModifier_do((LaplacianSmoothModifierData *)md, ctx->object, mesh_src, - vertexCos, numVerts); + laplaciansmoothModifier_do( + (LaplacianSmoothModifierData *)md, ctx->object, mesh_src, vertexCos, numVerts); - if (!ELEM(mesh_src, NULL, mesh)) { - BKE_id_free(NULL, mesh_src); - } + if (!ELEM(mesh_src, NULL, mesh)) { + BKE_id_free(NULL, mesh_src); + } } -static void deformVertsEM( - ModifierData *md, const ModifierEvalContext *ctx, struct BMEditMesh *editData, - Mesh *mesh, float (*vertexCos)[3], int numVerts) +static void deformVertsEM(ModifierData *md, + const ModifierEvalContext *ctx, + struct BMEditMesh *editData, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - Mesh *mesh_src; + Mesh *mesh_src; - if (numVerts == 0) - return; + if (numVerts == 0) + return; - mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false); + mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false); - laplaciansmoothModifier_do((LaplacianSmoothModifierData *)md, ctx->object, mesh_src, - vertexCos, numVerts); + laplaciansmoothModifier_do( + (LaplacianSmoothModifierData *)md, ctx->object, mesh_src, vertexCos, numVerts); - if (!ELEM(mesh_src, NULL, mesh)) { - BKE_id_free(NULL, mesh_src); - } + if (!ELEM(mesh_src, NULL, mesh)) { + BKE_id_free(NULL, mesh_src); + } } - ModifierTypeInfo modifierType_LaplacianSmooth = { - /* name */ "Laplacian Smooth", - /* structName */ "LaplacianSmoothModifierData", - /* structSize */ sizeof(LaplacianSmoothModifierData), - /* type */ eModifierTypeType_OnlyDeform, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_SupportsEditmode, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ deformVerts, - /* deformMatrices */ NULL, - /* deformVertsEM */ deformVertsEM, - /* deformMatricesEM */ NULL, - /* applyModifier */ NULL, - - /* initData */ init_data, - /* requiredDataMask */ required_data_mask, - /* freeData */ NULL, - /* isDisabled */ is_disabled, - /* updateDepsgraph */ NULL, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ NULL, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Laplacian Smooth", + /* structName */ "LaplacianSmoothModifierData", + /* structSize */ sizeof(LaplacianSmoothModifierData), + /* type */ eModifierTypeType_OnlyDeform, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsEditmode, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ deformVerts, + /* deformMatrices */ NULL, + /* deformVertsEM */ deformVertsEM, + /* deformMatricesEM */ NULL, + /* applyModifier */ NULL, + + /* initData */ init_data, + /* requiredDataMask */ required_data_mask, + /* freeData */ NULL, + /* isDisabled */ is_disabled, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_lattice.c b/source/blender/modifiers/intern/MOD_lattice.c index 4715d2ab073..b639e874a88 100644 --- a/source/blender/modifiers/intern/MOD_lattice.c +++ b/source/blender/modifiers/intern/MOD_lattice.c @@ -21,7 +21,6 @@ * \ingroup modifiers */ - #include #include "BLI_utildefines.h" @@ -43,105 +42,110 @@ static void initData(ModifierData *md) { - LatticeModifierData *lmd = (LatticeModifierData *) md; - lmd->strength = 1.0f; + LatticeModifierData *lmd = (LatticeModifierData *)md; + lmd->strength = 1.0f; } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - LatticeModifierData *lmd = (LatticeModifierData *)md; + LatticeModifierData *lmd = (LatticeModifierData *)md; - /* ask for vertexgroups if we need them */ - if (lmd->name[0] != '\0') { - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; - } + /* ask for vertexgroups if we need them */ + if (lmd->name[0] != '\0') { + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + } } -static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(userRenderParams)) +static bool isDisabled(const struct Scene *UNUSED(scene), + ModifierData *md, + bool UNUSED(userRenderParams)) { - LatticeModifierData *lmd = (LatticeModifierData *) md; + LatticeModifierData *lmd = (LatticeModifierData *)md; - return !lmd->object; + return !lmd->object; } -static void foreachObjectLink( - ModifierData *md, Object *ob, - ObjectWalkFunc walk, void *userData) +static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) { - LatticeModifierData *lmd = (LatticeModifierData *) md; + LatticeModifierData *lmd = (LatticeModifierData *)md; - walk(userData, ob, &lmd->object, IDWALK_CB_NOP); + walk(userData, ob, &lmd->object, IDWALK_CB_NOP); } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { - LatticeModifierData *lmd = (LatticeModifierData *)md; - if (lmd->object != NULL) { - DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_GEOMETRY, "Lattice Modifier"); - DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_TRANSFORM, "Lattice Modifier"); - } - DEG_add_modifier_to_transform_relation(ctx->node, "Lattice Modifier"); + LatticeModifierData *lmd = (LatticeModifierData *)md; + if (lmd->object != NULL) { + DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_GEOMETRY, "Lattice Modifier"); + DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_TRANSFORM, "Lattice Modifier"); + } + DEG_add_modifier_to_transform_relation(ctx->node, "Lattice Modifier"); } -static void deformVerts( - ModifierData *md, const ModifierEvalContext *ctx, - struct Mesh *mesh, - float (*vertexCos)[3], - int numVerts) +static void deformVerts(ModifierData *md, + const ModifierEvalContext *ctx, + struct Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - LatticeModifierData *lmd = (LatticeModifierData *) md; - struct Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); + LatticeModifierData *lmd = (LatticeModifierData *)md; + struct Mesh *mesh_src = MOD_deform_mesh_eval_get( + ctx->object, NULL, mesh, NULL, numVerts, false, false); - MOD_previous_vcos_store(md, vertexCos); /* if next modifier needs original vertices */ + MOD_previous_vcos_store(md, vertexCos); /* if next modifier needs original vertices */ - lattice_deform_verts(lmd->object, ctx->object, mesh_src, - vertexCos, numVerts, lmd->name, lmd->strength); + lattice_deform_verts( + lmd->object, ctx->object, mesh_src, vertexCos, numVerts, lmd->name, lmd->strength); - if (!ELEM(mesh_src, NULL, mesh)) { - BKE_id_free(NULL, mesh_src); - } + if (!ELEM(mesh_src, NULL, mesh)) { + BKE_id_free(NULL, mesh_src); + } } -static void deformVertsEM( - ModifierData *md, const ModifierEvalContext *ctx, struct BMEditMesh *em, - struct Mesh *mesh, float (*vertexCos)[3], int numVerts) +static void deformVertsEM(ModifierData *md, + const ModifierEvalContext *ctx, + struct BMEditMesh *em, + struct Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - struct Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, numVerts, false, false); + struct Mesh *mesh_src = MOD_deform_mesh_eval_get( + ctx->object, em, mesh, NULL, numVerts, false, false); - deformVerts(md, ctx, mesh_src, vertexCos, numVerts); + deformVerts(md, ctx, mesh_src, vertexCos, numVerts); - if (!ELEM(mesh_src, NULL, mesh)) { - BKE_id_free(NULL, mesh_src); - } + if (!ELEM(mesh_src, NULL, mesh)) { + BKE_id_free(NULL, mesh_src); + } } - ModifierTypeInfo modifierType_Lattice = { - /* name */ "Lattice", - /* structName */ "LatticeModifierData", - /* structSize */ sizeof(LatticeModifierData), - /* type */ eModifierTypeType_OnlyDeform, - /* flags */ eModifierTypeFlag_AcceptsCVs | - eModifierTypeFlag_AcceptsLattice | - eModifierTypeFlag_SupportsEditmode, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ deformVerts, - /* deformMatrices */ NULL, - /* deformVertsEM */ deformVertsEM, - /* deformMatricesEM */ NULL, - /* applyModifier */ NULL, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ NULL, - /* isDisabled */ isDisabled, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ foreachObjectLink, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Lattice", + /* structName */ "LatticeModifierData", + /* structSize */ sizeof(LatticeModifierData), + /* type */ eModifierTypeType_OnlyDeform, + /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice | + eModifierTypeFlag_SupportsEditmode, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ deformVerts, + /* deformMatrices */ NULL, + /* deformVertsEM */ deformVertsEM, + /* deformMatricesEM */ NULL, + /* applyModifier */ NULL, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ NULL, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_mask.c b/source/blender/modifiers/intern/MOD_mask.c index efb299773ef..a13e75c76de 100644 --- a/source/blender/modifiers/intern/MOD_mask.c +++ b/source/blender/modifiers/intern/MOD_mask.c @@ -21,7 +21,6 @@ * \ingroup modifiers */ - #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" @@ -49,329 +48,324 @@ #include "BLI_strict_flags.h" -static void requiredDataMask(Object *UNUSED(ob), ModifierData *UNUSED(md), CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *UNUSED(md), + CustomData_MeshMasks *r_cddata_masks) { - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; } -static void foreachObjectLink( - ModifierData *md, Object *ob, - ObjectWalkFunc walk, void *userData) +static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) { - MaskModifierData *mmd = (MaskModifierData *)md; - walk(userData, ob, &mmd->ob_arm, IDWALK_CB_NOP); + MaskModifierData *mmd = (MaskModifierData *)md; + walk(userData, ob, &mmd->ob_arm, IDWALK_CB_NOP); } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { - MaskModifierData *mmd = (MaskModifierData *)md; - if (mmd->ob_arm) { - bArmature *arm = (bArmature *)mmd->ob_arm->data; - /* Tag relationship in depsgraph, but also on the armature. */ - /* TODO(sergey): Is it a proper relation here? */ - DEG_add_object_relation(ctx->node, mmd->ob_arm, DEG_OB_COMP_TRANSFORM, "Mask Modifier"); - arm->flag |= ARM_HAS_VIZ_DEPS; - DEG_add_modifier_to_transform_relation(ctx->node, "Mask Modifier"); - } + MaskModifierData *mmd = (MaskModifierData *)md; + if (mmd->ob_arm) { + bArmature *arm = (bArmature *)mmd->ob_arm->data; + /* Tag relationship in depsgraph, but also on the armature. */ + /* TODO(sergey): Is it a proper relation here? */ + DEG_add_object_relation(ctx->node, mmd->ob_arm, DEG_OB_COMP_TRANSFORM, "Mask Modifier"); + arm->flag |= ARM_HAS_VIZ_DEPS; + DEG_add_modifier_to_transform_relation(ctx->node, "Mask Modifier"); + } } static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) { - MaskModifierData *mmd = (MaskModifierData *)md; - Object *ob = ctx->object; - const bool found_test = (mmd->flag & MOD_MASK_INV) == 0; - Mesh *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 = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT); - if (dvert == NULL) { - return found_test ? BKE_mesh_new_nomain_from_template(mesh, 0, 0, 0, 0, 0) : mesh; - } - - /* 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 = mesh->totvert; - maxEdges = mesh->totedge; - maxPolys = mesh->totpoly; - - /* 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 mesh; - } - - /* 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 mesh; - } - - /* 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 > mmd->threshold) { - found = true; - break; - } - } - } - } - - if (found_test != found) { - continue; - } - - /* add to ghash for verts (numVerts acts as counter for mapping) */ - BLI_ghash_insert(vertHash, POINTER_FROM_INT(i), POINTER_FROM_INT(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 mesh; - } - - /* 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) > mmd->threshold; - if (found_test != found) { - continue; - } - - /* add to ghash for verts (numVerts acts as counter for mapping) */ - BLI_ghash_insert(vertHash, POINTER_FROM_INT(i), POINTER_FROM_INT(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 = mesh->mvert; - medge_src = mesh->medge; - mpoly_src = mesh->mpoly; - mloop_src = mesh->mloop; - - /* 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, POINTER_FROM_INT(me->v1)) && - BLI_ghash_haskey(vertHash, POINTER_FROM_INT(me->v2))) - { - BLI_ghash_insert(edgeHash, POINTER_FROM_INT(i), POINTER_FROM_INT(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, POINTER_FROM_INT(ml_src->v))) { - ok = false; - break; - } - } - - /* all verts must be available */ - if (ok) { - BLI_ghash_insert(polyHash, POINTER_FROM_INT(i), POINTER_FROM_INT(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 = BKE_mesh_new_nomain_from_template(mesh, numVerts, numEdges, 0, numLoops, numPolys); - - mpoly_dst = result->mpoly; - mloop_dst = result->mloop; - medge_dst = result->medge; - mvert_dst = result->mvert; - - /* 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 = POINTER_AS_INT(BLI_ghashIterator_getKey(&gh_iter)); - const int i_dst = POINTER_AS_INT(BLI_ghashIterator_getValue(&gh_iter)); - - v_src = &mvert_src[i_src]; - v_dst = &mvert_dst[i_dst]; - - *v_dst = *v_src; - CustomData_copy_data(&mesh->vdata, &result->vdata, i_src, i_dst, 1); - } - - /* edges */ - GHASH_ITER (gh_iter, edgeHash) { - const MEdge *e_src; - MEdge *e_dst; - const int i_src = POINTER_AS_INT(BLI_ghashIterator_getKey(&gh_iter)); - const int i_dst = POINTER_AS_INT(BLI_ghashIterator_getValue(&gh_iter)); - - e_src = &medge_src[i_src]; - e_dst = &medge_dst[i_dst]; - - CustomData_copy_data(&mesh->edata, &result->edata, i_src, i_dst, 1); - *e_dst = *e_src; - e_dst->v1 = POINTER_AS_UINT(BLI_ghash_lookup(vertHash, POINTER_FROM_UINT(e_src->v1))); - e_dst->v2 = POINTER_AS_UINT(BLI_ghash_lookup(vertHash, POINTER_FROM_UINT(e_src->v2))); - } - - /* faces */ - GHASH_ITER (gh_iter, polyHash) { - const int i_src = POINTER_AS_INT(BLI_ghashIterator_getKey(&gh_iter)); - const int i_dst = POINTER_AS_INT(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]; - - CustomData_copy_data(&mesh->pdata, &result->pdata, i_src, i_dst, 1); - CustomData_copy_data(&mesh->ldata, &result->ldata, 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 = POINTER_AS_UINT(BLI_ghash_lookup(vertHash, POINTER_FROM_UINT(ml_src[i].v))); - ml_dst[i].e = POINTER_AS_UINT(BLI_ghash_lookup(edgeHash, POINTER_FROM_UINT(ml_src[i].e))); - } - } - - MEM_freeN(loop_mapping); - - /* why is this needed? - campbell */ - /* recalculate normals */ - result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; - - /* 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; + MaskModifierData *mmd = (MaskModifierData *)md; + Object *ob = ctx->object; + const bool found_test = (mmd->flag & MOD_MASK_INV) == 0; + Mesh *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 = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT); + if (dvert == NULL) { + return found_test ? BKE_mesh_new_nomain_from_template(mesh, 0, 0, 0, 0, 0) : mesh; + } + + /* 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 = mesh->totvert; + maxEdges = mesh->totedge; + maxPolys = mesh->totpoly; + + /* 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 mesh; + } + + /* 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 mesh; + } + + /* 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 > mmd->threshold) { + found = true; + break; + } + } + } + } + + if (found_test != found) { + continue; + } + + /* add to ghash for verts (numVerts acts as counter for mapping) */ + BLI_ghash_insert(vertHash, POINTER_FROM_INT(i), POINTER_FROM_INT(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 mesh; + } + + /* 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) > mmd->threshold; + if (found_test != found) { + continue; + } + + /* add to ghash for verts (numVerts acts as counter for mapping) */ + BLI_ghash_insert(vertHash, POINTER_FROM_INT(i), POINTER_FROM_INT(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 = mesh->mvert; + medge_src = mesh->medge; + mpoly_src = mesh->mpoly; + mloop_src = mesh->mloop; + + /* 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, POINTER_FROM_INT(me->v1)) && + BLI_ghash_haskey(vertHash, POINTER_FROM_INT(me->v2))) { + BLI_ghash_insert(edgeHash, POINTER_FROM_INT(i), POINTER_FROM_INT(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, POINTER_FROM_INT(ml_src->v))) { + ok = false; + break; + } + } + + /* all verts must be available */ + if (ok) { + BLI_ghash_insert(polyHash, POINTER_FROM_INT(i), POINTER_FROM_INT(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 = BKE_mesh_new_nomain_from_template(mesh, numVerts, numEdges, 0, numLoops, numPolys); + + mpoly_dst = result->mpoly; + mloop_dst = result->mloop; + medge_dst = result->medge; + mvert_dst = result->mvert; + + /* 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 = POINTER_AS_INT(BLI_ghashIterator_getKey(&gh_iter)); + const int i_dst = POINTER_AS_INT(BLI_ghashIterator_getValue(&gh_iter)); + + v_src = &mvert_src[i_src]; + v_dst = &mvert_dst[i_dst]; + + *v_dst = *v_src; + CustomData_copy_data(&mesh->vdata, &result->vdata, i_src, i_dst, 1); + } + + /* edges */ + GHASH_ITER (gh_iter, edgeHash) { + const MEdge *e_src; + MEdge *e_dst; + const int i_src = POINTER_AS_INT(BLI_ghashIterator_getKey(&gh_iter)); + const int i_dst = POINTER_AS_INT(BLI_ghashIterator_getValue(&gh_iter)); + + e_src = &medge_src[i_src]; + e_dst = &medge_dst[i_dst]; + + CustomData_copy_data(&mesh->edata, &result->edata, i_src, i_dst, 1); + *e_dst = *e_src; + e_dst->v1 = POINTER_AS_UINT(BLI_ghash_lookup(vertHash, POINTER_FROM_UINT(e_src->v1))); + e_dst->v2 = POINTER_AS_UINT(BLI_ghash_lookup(vertHash, POINTER_FROM_UINT(e_src->v2))); + } + + /* faces */ + GHASH_ITER (gh_iter, polyHash) { + const int i_src = POINTER_AS_INT(BLI_ghashIterator_getKey(&gh_iter)); + const int i_dst = POINTER_AS_INT(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]; + + CustomData_copy_data(&mesh->pdata, &result->pdata, i_src, i_dst, 1); + CustomData_copy_data(&mesh->ldata, &result->ldata, 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 = POINTER_AS_UINT(BLI_ghash_lookup(vertHash, POINTER_FROM_UINT(ml_src[i].v))); + ml_dst[i].e = POINTER_AS_UINT(BLI_ghash_lookup(edgeHash, POINTER_FROM_UINT(ml_src[i].e))); + } + } + + MEM_freeN(loop_mapping); + + /* why is this needed? - campbell */ + /* recalculate normals */ + result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + + /* 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; } - ModifierTypeInfo modifierType_Mask = { - /* name */ "Mask", - /* structName */ "MaskModifierData", - /* structSize */ sizeof(MaskModifierData), - /* type */ eModifierTypeType_Nonconstructive, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_SupportsMapping | - eModifierTypeFlag_SupportsEditmode, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ NULL, - /* requiredDataMask */ requiredDataMask, - /* freeData */ NULL, - /* isDisabled */ NULL, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ foreachObjectLink, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Mask", + /* structName */ "MaskModifierData", + /* structSize */ sizeof(MaskModifierData), + /* type */ eModifierTypeType_Nonconstructive, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping | + eModifierTypeFlag_SupportsEditmode, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ NULL, + /* requiredDataMask */ requiredDataMask, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_meshcache.c b/source/blender/modifiers/intern/MOD_meshcache.c index 74172927c9d..cf1b2daa9cd 100644 --- a/source/blender/modifiers/intern/MOD_meshcache.c +++ b/source/blender/modifiers/intern/MOD_meshcache.c @@ -39,276 +39,276 @@ #include "MEM_guardedalloc.h" -#include "MOD_meshcache_util.h" /* utility functions */ +#include "MOD_meshcache_util.h" /* utility functions */ #include "MOD_modifiertypes.h" static void initData(ModifierData *md) { - MeshCacheModifierData *mcmd = (MeshCacheModifierData *)md; + MeshCacheModifierData *mcmd = (MeshCacheModifierData *)md; - mcmd->flag = 0; - mcmd->type = MOD_MESHCACHE_TYPE_MDD; - mcmd->interp = MOD_MESHCACHE_INTERP_LINEAR; - mcmd->frame_scale = 1.0f; + mcmd->flag = 0; + mcmd->type = MOD_MESHCACHE_TYPE_MDD; + mcmd->interp = MOD_MESHCACHE_INTERP_LINEAR; + mcmd->frame_scale = 1.0f; - mcmd->factor = 1.0f; + mcmd->factor = 1.0f; - /* (Y, Z). Blender default */ - mcmd->forward_axis = 1; - mcmd->up_axis = 2; + /* (Y, Z). Blender default */ + mcmd->forward_axis = 1; + mcmd->up_axis = 2; } static bool dependsOnTime(ModifierData *md) { - MeshCacheModifierData *mcmd = (MeshCacheModifierData *)md; - return (mcmd->play_mode == MOD_MESHCACHE_PLAY_CFEA); + MeshCacheModifierData *mcmd = (MeshCacheModifierData *)md; + return (mcmd->play_mode == MOD_MESHCACHE_PLAY_CFEA); } -static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams)) +static bool isDisabled(const struct Scene *UNUSED(scene), + ModifierData *md, + bool UNUSED(useRenderParams)) { - MeshCacheModifierData *mcmd = (MeshCacheModifierData *) md; + MeshCacheModifierData *mcmd = (MeshCacheModifierData *)md; - /* leave it up to the modifier to check the file is valid on calculation */ - return (mcmd->factor <= 0.0f) || (mcmd->filepath[0] == '\0'); + /* leave it up to the modifier to check the file is valid on calculation */ + return (mcmd->factor <= 0.0f) || (mcmd->filepath[0] == '\0'); } - -static void meshcache_do( - MeshCacheModifierData *mcmd, Scene *scene, Object *ob, - float (*vertexCos_Real)[3], int numVerts) +static void meshcache_do(MeshCacheModifierData *mcmd, + Scene *scene, + Object *ob, + 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_malloc_arrayN(numVerts, sizeof(*vertexCos_Store), __func__) : NULL; - float (*vertexCos)[3] = vertexCos_Store ? vertexCos_Store : vertexCos_Real; - - 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_FROM_GLOBAL((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_malloc_arrayN(numVerts, sizeof(*vertexCos_Source), __func__); - float (*vertexCos_New)[3] = MEM_malloc_arrayN(numVerts, sizeof(*vertexCos_New), __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); - } + const bool use_factor = mcmd->factor < 1.0f; + float(*vertexCos_Store)[3] = (use_factor || + (mcmd->deform_mode == MOD_MESHCACHE_DEFORM_INTEGRATE)) ? + MEM_malloc_arrayN( + numVerts, sizeof(*vertexCos_Store), __func__) : + NULL; + float(*vertexCos)[3] = vertexCos_Store ? vertexCos_Store : vertexCos_Real; + + 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_FROM_GLOBAL((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_malloc_arrayN( + numVerts, sizeof(*vertexCos_Source), __func__); + float(*vertexCos_New)[3] = MEM_malloc_arrayN(numVerts, sizeof(*vertexCos_New), __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 void deformVerts( - ModifierData *md, const ModifierEvalContext *ctx, - Mesh *UNUSED(mesh), - float (*vertexCos)[3], - int numVerts) +static void deformVerts(ModifierData *md, + const ModifierEvalContext *ctx, + Mesh *UNUSED(mesh), + float (*vertexCos)[3], + int numVerts) { - MeshCacheModifierData *mcmd = (MeshCacheModifierData *)md; - Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); + MeshCacheModifierData *mcmd = (MeshCacheModifierData *)md; + Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); - meshcache_do(mcmd, scene, ctx->object, vertexCos, numVerts); + meshcache_do(mcmd, scene, ctx->object, vertexCos, numVerts); } -static void deformVertsEM( - ModifierData *md, const ModifierEvalContext *ctx, - struct BMEditMesh *UNUSED(editData), - Mesh *UNUSED(mesh), - float (*vertexCos)[3], - int numVerts) +static void deformVertsEM(ModifierData *md, + const ModifierEvalContext *ctx, + struct BMEditMesh *UNUSED(editData), + Mesh *UNUSED(mesh), + float (*vertexCos)[3], + int numVerts) { - MeshCacheModifierData *mcmd = (MeshCacheModifierData *)md; - Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); + MeshCacheModifierData *mcmd = (MeshCacheModifierData *)md; + Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); - meshcache_do(mcmd, scene, ctx->object, vertexCos, numVerts); + meshcache_do(mcmd, scene, ctx->object, vertexCos, numVerts); } - ModifierTypeInfo modifierType_MeshCache = { - /* name */ "Mesh Cache", - /* structName */ "MeshCacheModifierData", - /* structSize */ sizeof(MeshCacheModifierData), - /* type */ eModifierTypeType_OnlyDeform, - /* flags */ eModifierTypeFlag_AcceptsCVs | - eModifierTypeFlag_AcceptsLattice | - eModifierTypeFlag_SupportsEditmode, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ deformVerts, - /* deformMatrices */ NULL, - /* deformVertsEM */ deformVertsEM, - /* deformMatricesEM */ NULL, - /* applyModifier */ NULL, - - /* initData */ initData, - /* requiredDataMask */ NULL, - /* freeData */ NULL, - /* isDisabled */ isDisabled, - /* updateDepsgraph */ NULL, - /* dependsOnTime */ dependsOnTime, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ NULL, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Mesh Cache", + /* structName */ "MeshCacheModifierData", + /* structSize */ sizeof(MeshCacheModifierData), + /* type */ eModifierTypeType_OnlyDeform, + /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice | + eModifierTypeFlag_SupportsEditmode, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ deformVerts, + /* deformMatrices */ NULL, + /* deformVertsEM */ deformVertsEM, + /* deformMatricesEM */ NULL, + /* applyModifier */ NULL, + + /* initData */ initData, + /* requiredDataMask */ NULL, + /* freeData */ NULL, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ dependsOnTime, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_meshcache_mdd.c b/source/blender/modifiers/intern/MOD_meshcache_mdd.c index bd99248eec4..16a118522c5 100644 --- a/source/blender/modifiers/intern/MOD_meshcache_mdd.c +++ b/source/blender/modifiers/intern/MOD_meshcache_mdd.c @@ -35,272 +35,276 @@ #include "DNA_modifier_types.h" -#include "MOD_meshcache_util.h" /* own include */ +#include "MOD_meshcache_util.h" /* own include */ typedef struct MDDHead { - int frame_tot; - int verts_tot; -} MDDHead; /* frames, verts */ - -static bool meshcache_read_mdd_head( - FILE *fp, const int verts_tot, - MDDHead *mdd_head, - const char **err_str) + int frame_tot; + int verts_tot; +} MDDHead; /* frames, verts */ + +static bool meshcache_read_mdd_head(FILE *fp, + const int verts_tot, + MDDHead *mdd_head, + const char **err_str) { - if (!fread(mdd_head, sizeof(*mdd_head), 1, fp)) { - *err_str = "Missing header"; - return false; - } + if (!fread(mdd_head, sizeof(*mdd_head), 1, fp)) { + *err_str = "Missing header"; + return false; + } #ifdef __LITTLE_ENDIAN__ - BLI_endian_switch_int32_array((int *)mdd_head, 2); + BLI_endian_switch_int32_array((int *)mdd_head, 2); #endif - if (mdd_head->verts_tot != verts_tot) { - *err_str = "Vertex count mismatch"; - return false; - } + if (mdd_head->verts_tot != verts_tot) { + *err_str = "Vertex count mismatch"; + return false; + } - if (mdd_head->frame_tot <= 0) { - *err_str = "Invalid frame total"; - return false; - } - /* intentionally dont seek back */ + if (mdd_head->frame_tot <= 0) { + *err_str = "Invalid frame total"; + return false; + } + /* intentionally dont seek back */ - return true; + return true; } /** * Gets the index frange and factor */ -static bool meshcache_read_mdd_range( - FILE *fp, - const int verts_tot, - const float frame, const char interp, - int r_index_range[2], float *r_factor, - const char **err_str) +static bool meshcache_read_mdd_range(FILE *fp, + const int verts_tot, + const float frame, + const char interp, + int r_index_range[2], + float *r_factor, + const char **err_str) { - MDDHead mdd_head; + MDDHead mdd_head; - /* first check interpolation and get the vert locations */ + /* first check interpolation and get the vert locations */ - if (meshcache_read_mdd_head(fp, verts_tot, &mdd_head, err_str) == false) { - return false; - } + if (meshcache_read_mdd_head(fp, verts_tot, &mdd_head, err_str) == false) { + return false; + } - MOD_meshcache_calc_range(frame, interp, mdd_head.frame_tot, r_index_range, r_factor); + MOD_meshcache_calc_range(frame, interp, mdd_head.frame_tot, r_index_range, r_factor); - return true; + return true; } -static bool meshcache_read_mdd_range_from_time( - FILE *fp, - const int verts_tot, - const float time, const float UNUSED(fps), - float *r_frame, - const char **err_str) +static bool meshcache_read_mdd_range_from_time(FILE *fp, + const int verts_tot, + const float time, + const float UNUSED(fps), + float *r_frame, + const char **err_str) { - MDDHead mdd_head; - int i; - float f_time, f_time_prev = FLT_MAX; - float frame; + MDDHead mdd_head; + int i; + float f_time, f_time_prev = FLT_MAX; + float frame; - if (meshcache_read_mdd_head(fp, verts_tot, &mdd_head, err_str) == false) { - return false; - } + if (meshcache_read_mdd_head(fp, verts_tot, &mdd_head, err_str) == false) { + return false; + } - for (i = 0; i < mdd_head.frame_tot; i++) { - fread(&f_time, sizeof(float), 1, fp); + for (i = 0; i < mdd_head.frame_tot; i++) { + fread(&f_time, sizeof(float), 1, fp); #ifdef __LITTLE_ENDIAN__ - BLI_endian_switch_float(&f_time); + BLI_endian_switch_float(&f_time); #endif - if (f_time >= time) { - break; - } - f_time_prev = f_time; - } - - if (i == mdd_head.frame_tot) { - frame = (float)(mdd_head.frame_tot - 1); - } - if (UNLIKELY(f_time_prev == FLT_MAX)) { - frame = 0.0f; - } - else { - const float range = f_time - f_time_prev; - - if (range <= FRAME_SNAP_EPS) { - frame = (float)i; - } - else { - frame = (float)(i - 1) + ((time - f_time_prev) / range); - } - } - - *r_frame = frame; - return true; + if (f_time >= time) { + break; + } + f_time_prev = f_time; + } + + if (i == mdd_head.frame_tot) { + frame = (float)(mdd_head.frame_tot - 1); + } + if (UNLIKELY(f_time_prev == FLT_MAX)) { + frame = 0.0f; + } + else { + const float range = f_time - f_time_prev; + + if (range <= FRAME_SNAP_EPS) { + frame = (float)i; + } + else { + frame = (float)(i - 1) + ((time - f_time_prev) / range); + } + } + + *r_frame = frame; + return true; } -bool MOD_meshcache_read_mdd_index( - FILE *fp, - float (*vertexCos)[3], const int verts_tot, - const int index, const float factor, - const char **err_str) +bool MOD_meshcache_read_mdd_index(FILE *fp, + float (*vertexCos)[3], + const int verts_tot, + const int index, + const float factor, + const char **err_str) { - MDDHead mdd_head; + MDDHead mdd_head; - if (meshcache_read_mdd_head(fp, verts_tot, &mdd_head, err_str) == false) { - return false; - } + if (meshcache_read_mdd_head(fp, verts_tot, &mdd_head, err_str) == false) { + return false; + } - if (fseek(fp, mdd_head.frame_tot * sizeof(int), SEEK_CUR) != 0) { - *err_str = "Header seek failed"; - return false; - } + if (fseek(fp, mdd_head.frame_tot * sizeof(int), SEEK_CUR) != 0) { + *err_str = "Header seek failed"; + return false; + } - if (fseek(fp, sizeof(float) * 3 * index * mdd_head.verts_tot, SEEK_CUR) != 0) { - *err_str = "Failed to seek frame"; - return false; - } + if (fseek(fp, sizeof(float) * 3 * index * mdd_head.verts_tot, SEEK_CUR) != 0) { + *err_str = "Failed to seek frame"; + return false; + } - if (factor >= 1.0f) { + if (factor >= 1.0f) { #if 1 - float *vco = *vertexCos; - unsigned int i; - for (i = mdd_head.verts_tot; i != 0 ; i--, vco += 3) { - fread(vco, sizeof(float) * 3, 1, fp); + float *vco = *vertexCos; + unsigned int i; + for (i = mdd_head.verts_tot; i != 0; i--, vco += 3) { + fread(vco, sizeof(float) * 3, 1, fp); # ifdef __LITTLE_ENDIAN__ - BLI_endian_switch_float(vco + 0); - BLI_endian_switch_float(vco + 1); - BLI_endian_switch_float(vco + 2); -# endif /* __LITTLE_ENDIAN__ */ - } + BLI_endian_switch_float(vco + 0); + BLI_endian_switch_float(vco + 1); + BLI_endian_switch_float(vco + 2); +# endif /* __LITTLE_ENDIAN__ */ + } #else - /* no blending */ - if (!fread(vertexCos, sizeof(float) * 3, mdd_head.verts_tot, f)) { - *err_str = errno ? strerror(errno) : "Failed to read frame"; - return false; - } + /* no blending */ + if (!fread(vertexCos, sizeof(float) * 3, mdd_head.verts_tot, f)) { + *err_str = errno ? strerror(errno) : "Failed to read frame"; + return false; + } # ifdef __LITTLE_ENDIAN__ - BLI_endian_switch_float_array(vertexCos[0], mdd_head.verts_tot * 3); + BLI_endian_switch_float_array(vertexCos[0], mdd_head.verts_tot * 3); # endif #endif - } - else { - const float ifactor = 1.0f - factor; - float *vco = *vertexCos; - unsigned int i; - for (i = mdd_head.verts_tot; i != 0 ; i--, vco += 3) { - float tvec[3]; - fread(tvec, sizeof(float) * 3, 1, fp); + } + else { + const float ifactor = 1.0f - factor; + float *vco = *vertexCos; + unsigned int i; + for (i = mdd_head.verts_tot; i != 0; i--, vco += 3) { + float tvec[3]; + fread(tvec, sizeof(float) * 3, 1, fp); #ifdef __LITTLE_ENDIAN__ - BLI_endian_switch_float(tvec + 0); - BLI_endian_switch_float(tvec + 1); - BLI_endian_switch_float(tvec + 2); + BLI_endian_switch_float(tvec + 0); + BLI_endian_switch_float(tvec + 1); + BLI_endian_switch_float(tvec + 2); #endif - vco[0] = (vco[0] * ifactor) + (tvec[0] * factor); - vco[1] = (vco[1] * ifactor) + (tvec[1] * factor); - vco[2] = (vco[2] * ifactor) + (tvec[2] * factor); - } - } + vco[0] = (vco[0] * ifactor) + (tvec[0] * factor); + vco[1] = (vco[1] * ifactor) + (tvec[1] * factor); + vco[2] = (vco[2] * ifactor) + (tvec[2] * factor); + } + } - return true; + return true; } -bool MOD_meshcache_read_mdd_frame( - FILE *fp, - float (*vertexCos)[3], const int verts_tot, const char interp, - const float frame, - const char **err_str) +bool MOD_meshcache_read_mdd_frame(FILE *fp, + float (*vertexCos)[3], + const int verts_tot, + const char interp, + const float frame, + const char **err_str) { - int index_range[2]; - float factor; - - if (meshcache_read_mdd_range(fp, verts_tot, frame, interp, - index_range, &factor, /* read into these values */ - err_str) == false) - { - return false; - } - - if (index_range[0] == index_range[1]) { - /* read single */ - if ((fseek(fp, 0, SEEK_SET) == 0) && - MOD_meshcache_read_mdd_index(fp, vertexCos, verts_tot, index_range[0], 1.0f, err_str)) - { - return true; - } - else { - return false; - } - } - else { - /* read both and interpolate */ - if ((fseek(fp, 0, SEEK_SET) == 0) && - MOD_meshcache_read_mdd_index(fp, vertexCos, verts_tot, index_range[0], 1.0f, err_str) && - (fseek(fp, 0, SEEK_SET) == 0) && - MOD_meshcache_read_mdd_index(fp, vertexCos, verts_tot, index_range[1], factor, err_str)) - { - return true; - } - else { - return false; - } - } + int index_range[2]; + float factor; + + if (meshcache_read_mdd_range(fp, + verts_tot, + frame, + interp, + index_range, + &factor, /* read into these values */ + err_str) == false) { + return false; + } + + if (index_range[0] == index_range[1]) { + /* read single */ + if ((fseek(fp, 0, SEEK_SET) == 0) && + MOD_meshcache_read_mdd_index(fp, vertexCos, verts_tot, index_range[0], 1.0f, err_str)) { + return true; + } + else { + return false; + } + } + else { + /* read both and interpolate */ + if ((fseek(fp, 0, SEEK_SET) == 0) && + MOD_meshcache_read_mdd_index(fp, vertexCos, verts_tot, index_range[0], 1.0f, err_str) && + (fseek(fp, 0, SEEK_SET) == 0) && + MOD_meshcache_read_mdd_index(fp, vertexCos, verts_tot, index_range[1], factor, err_str)) { + return true; + } + else { + return false; + } + } } -bool MOD_meshcache_read_mdd_times( - const char *filepath, - float (*vertexCos)[3], const int verts_tot, const char interp, - const float time, const float fps, const char time_mode, - const char **err_str) +bool MOD_meshcache_read_mdd_times(const char *filepath, + float (*vertexCos)[3], + const int verts_tot, + const char interp, + const float time, + const float fps, + const char time_mode, + const char **err_str) { - float frame; - - FILE *fp = BLI_fopen(filepath, "rb"); - bool ok; - - if (fp == NULL) { - *err_str = errno ? strerror(errno) : "Unknown error opening file"; - return false; - } - - switch (time_mode) { - case MOD_MESHCACHE_TIME_FRAME: - { - frame = time; - break; - } - case MOD_MESHCACHE_TIME_SECONDS: - { - /* we need to find the closest time */ - if (meshcache_read_mdd_range_from_time(fp, verts_tot, time, fps, &frame, err_str) == false) { - fclose(fp); - return false; - } - rewind(fp); - break; - } - case MOD_MESHCACHE_TIME_FACTOR: - default: - { - MDDHead mdd_head; - if (meshcache_read_mdd_head(fp, verts_tot, &mdd_head, err_str) == false) { - fclose(fp); - return false; - } - - frame = CLAMPIS(time, 0.0f, 1.0f) * (float)mdd_head.frame_tot; - rewind(fp); - break; - } - } - - ok = MOD_meshcache_read_mdd_frame(fp, vertexCos, verts_tot, interp, frame, err_str); - - fclose(fp); - return ok; + float frame; + + FILE *fp = BLI_fopen(filepath, "rb"); + bool ok; + + if (fp == NULL) { + *err_str = errno ? strerror(errno) : "Unknown error opening file"; + return false; + } + + switch (time_mode) { + case MOD_MESHCACHE_TIME_FRAME: { + frame = time; + break; + } + case MOD_MESHCACHE_TIME_SECONDS: { + /* we need to find the closest time */ + if (meshcache_read_mdd_range_from_time(fp, verts_tot, time, fps, &frame, err_str) == false) { + fclose(fp); + return false; + } + rewind(fp); + break; + } + case MOD_MESHCACHE_TIME_FACTOR: + default: { + MDDHead mdd_head; + if (meshcache_read_mdd_head(fp, verts_tot, &mdd_head, err_str) == false) { + fclose(fp); + return false; + } + + frame = CLAMPIS(time, 0.0f, 1.0f) * (float)mdd_head.frame_tot; + rewind(fp); + break; + } + } + + ok = MOD_meshcache_read_mdd_frame(fp, vertexCos, verts_tot, interp, frame, err_str); + + fclose(fp); + return ok; } diff --git a/source/blender/modifiers/intern/MOD_meshcache_pc2.c b/source/blender/modifiers/intern/MOD_meshcache_pc2.c index e19a967cca7..97a8635ac9e 100644 --- a/source/blender/modifiers/intern/MOD_meshcache_pc2.c +++ b/source/blender/modifiers/intern/MOD_meshcache_pc2.c @@ -35,248 +35,251 @@ #include "DNA_modifier_types.h" -#include "MOD_meshcache_util.h" /* own include */ +#include "MOD_meshcache_util.h" /* own include */ typedef struct PC2Head { - char header[12]; /* 'POINTCACHE2\0' */ - int file_version; /* unused - should be 1 */ - int verts_tot; - float start; - float sampling; - int frame_tot; -} PC2Head; /* frames, verts */ - -static bool meshcache_read_pc2_head( - FILE *fp, const int verts_tot, - PC2Head *pc2_head, - const char **err_str) + char header[12]; /* 'POINTCACHE2\0' */ + int file_version; /* unused - should be 1 */ + int verts_tot; + float start; + float sampling; + int frame_tot; +} PC2Head; /* frames, verts */ + +static bool meshcache_read_pc2_head(FILE *fp, + const int verts_tot, + PC2Head *pc2_head, + const char **err_str) { - if (!fread(pc2_head, sizeof(*pc2_head), 1, fp)) { - *err_str = "Missing header"; - return false; - } + if (!fread(pc2_head, sizeof(*pc2_head), 1, fp)) { + *err_str = "Missing header"; + return false; + } - if (!STREQ(pc2_head->header, "POINTCACHE2")) { - *err_str = "Invalid header"; - return false; - } + if (!STREQ(pc2_head->header, "POINTCACHE2")) { + *err_str = "Invalid header"; + return false; + } #ifdef __BIG_ENDIAN__ - BLI_endian_switch_int32_array(&pc2_head->file_version, (sizeof(*pc2_head) - sizeof(pc2_head->header)) / sizeof(int)); + BLI_endian_switch_int32_array(&pc2_head->file_version, + (sizeof(*pc2_head) - sizeof(pc2_head->header)) / sizeof(int)); #endif - if (pc2_head->verts_tot != verts_tot) { - *err_str = "Vertex count mismatch"; - return false; - } + if (pc2_head->verts_tot != verts_tot) { + *err_str = "Vertex count mismatch"; + return false; + } - if (pc2_head->frame_tot <= 0) { - *err_str = "Invalid frame total"; - return false; - } - /* intentionally dont seek back */ + if (pc2_head->frame_tot <= 0) { + *err_str = "Invalid frame total"; + return false; + } + /* intentionally dont seek back */ - return true; + return true; } - /** * Gets the index frange and factor * * currently same as for MDD */ -static bool meshcache_read_pc2_range( - FILE *fp, - const int verts_tot, - const float frame, const char interp, - int r_index_range[2], float *r_factor, - const char **err_str) +static bool meshcache_read_pc2_range(FILE *fp, + const int verts_tot, + const float frame, + const char interp, + int r_index_range[2], + float *r_factor, + const char **err_str) { - PC2Head pc2_head; + PC2Head pc2_head; - /* first check interpolation and get the vert locations */ + /* first check interpolation and get the vert locations */ - if (meshcache_read_pc2_head(fp, verts_tot, &pc2_head, err_str) == false) { - return false; - } + if (meshcache_read_pc2_head(fp, verts_tot, &pc2_head, err_str) == false) { + return false; + } - MOD_meshcache_calc_range(frame, interp, pc2_head.frame_tot, r_index_range, r_factor); + MOD_meshcache_calc_range(frame, interp, pc2_head.frame_tot, r_index_range, r_factor); - return true; + return true; } -static bool meshcache_read_pc2_range_from_time( - FILE *fp, - const int verts_tot, - const float time, const float fps, - float *r_frame, - const char **err_str) +static bool meshcache_read_pc2_range_from_time(FILE *fp, + const int verts_tot, + const float time, + const float fps, + float *r_frame, + const char **err_str) { - PC2Head pc2_head; - float frame; + PC2Head pc2_head; + float frame; - if (meshcache_read_pc2_head(fp, verts_tot, &pc2_head, err_str) == false) { - return false; - } + if (meshcache_read_pc2_head(fp, verts_tot, &pc2_head, err_str) == false) { + return false; + } - frame = ((time / fps) - pc2_head.start) / pc2_head.sampling; + frame = ((time / fps) - pc2_head.start) / pc2_head.sampling; - if (frame >= pc2_head.frame_tot) { - frame = (float)(pc2_head.frame_tot - 1); - } - else if (frame < 0.0f) { - frame = 0.0f; - } + if (frame >= pc2_head.frame_tot) { + frame = (float)(pc2_head.frame_tot - 1); + } + else if (frame < 0.0f) { + frame = 0.0f; + } - *r_frame = frame; - return true; + *r_frame = frame; + return true; } -bool MOD_meshcache_read_pc2_index( - FILE *fp, - float (*vertexCos)[3], const int verts_tot, - const int index, const float factor, - const char **err_str) +bool MOD_meshcache_read_pc2_index(FILE *fp, + float (*vertexCos)[3], + const int verts_tot, + const int index, + const float factor, + const char **err_str) { - PC2Head pc2_head; - - if (meshcache_read_pc2_head(fp, verts_tot, &pc2_head, err_str) == false) { - return false; - } - - if (fseek(fp, sizeof(float) * 3 * index * pc2_head.verts_tot, SEEK_CUR) != 0) { - *err_str = "Failed to seek frame"; - return false; - } - - if (factor >= 1.0f) { - float *vco = *vertexCos; - unsigned int i; - for (i = pc2_head.verts_tot; i != 0 ; i--, vco += 3) { - fread(vco, sizeof(float) * 3, 1, fp); - -# ifdef __BIG_ENDIAN__ - BLI_endian_switch_float(vco + 0); - BLI_endian_switch_float(vco + 1); - BLI_endian_switch_float(vco + 2); -# endif /* __BIG_ENDIAN__ */ - } - } - else { - const float ifactor = 1.0f - factor; - float *vco = *vertexCos; - unsigned int i; - for (i = pc2_head.verts_tot; i != 0 ; i--, vco += 3) { - float tvec[3]; - fread(tvec, sizeof(float) * 3, 1, fp); + PC2Head pc2_head; + + if (meshcache_read_pc2_head(fp, verts_tot, &pc2_head, err_str) == false) { + return false; + } + + if (fseek(fp, sizeof(float) * 3 * index * pc2_head.verts_tot, SEEK_CUR) != 0) { + *err_str = "Failed to seek frame"; + return false; + } + + if (factor >= 1.0f) { + float *vco = *vertexCos; + unsigned int i; + for (i = pc2_head.verts_tot; i != 0; i--, vco += 3) { + fread(vco, sizeof(float) * 3, 1, fp); #ifdef __BIG_ENDIAN__ - BLI_endian_switch_float(tvec + 0); - BLI_endian_switch_float(tvec + 1); - BLI_endian_switch_float(tvec + 2); -#endif /* __BIG_ENDIAN__ */ - - vco[0] = (vco[0] * ifactor) + (tvec[0] * factor); - vco[1] = (vco[1] * ifactor) + (tvec[1] * factor); - vco[2] = (vco[2] * ifactor) + (tvec[2] * factor); - } - } - - return true; -} + BLI_endian_switch_float(vco + 0); + BLI_endian_switch_float(vco + 1); + BLI_endian_switch_float(vco + 2); +#endif /* __BIG_ENDIAN__ */ + } + } + else { + const float ifactor = 1.0f - factor; + float *vco = *vertexCos; + unsigned int i; + for (i = pc2_head.verts_tot; i != 0; i--, vco += 3) { + float tvec[3]; + fread(tvec, sizeof(float) * 3, 1, fp); +#ifdef __BIG_ENDIAN__ + BLI_endian_switch_float(tvec + 0); + BLI_endian_switch_float(tvec + 1); + BLI_endian_switch_float(tvec + 2); +#endif /* __BIG_ENDIAN__ */ + + vco[0] = (vco[0] * ifactor) + (tvec[0] * factor); + vco[1] = (vco[1] * ifactor) + (tvec[1] * factor); + vco[2] = (vco[2] * ifactor) + (tvec[2] * factor); + } + } + + return true; +} -bool MOD_meshcache_read_pc2_frame( - FILE *fp, - float (*vertexCos)[3], const int verts_tot, const char interp, - const float frame, - const char **err_str) +bool MOD_meshcache_read_pc2_frame(FILE *fp, + float (*vertexCos)[3], + const int verts_tot, + const char interp, + const float frame, + const char **err_str) { - int index_range[2]; - float factor; - - if (meshcache_read_pc2_range(fp, verts_tot, frame, interp, - index_range, &factor, /* read into these values */ - err_str) == false) - { - return false; - } - - if (index_range[0] == index_range[1]) { - /* read single */ - if ((fseek(fp, 0, SEEK_SET) == 0) && - MOD_meshcache_read_pc2_index(fp, vertexCos, verts_tot, index_range[0], 1.0f, err_str)) - { - return true; - } - else { - return false; - } - } - else { - /* read both and interpolate */ - if ((fseek(fp, 0, SEEK_SET) == 0) && - MOD_meshcache_read_pc2_index(fp, vertexCos, verts_tot, index_range[0], 1.0f, err_str) && - (fseek(fp, 0, SEEK_SET) == 0) && - MOD_meshcache_read_pc2_index(fp, vertexCos, verts_tot, index_range[1], factor, err_str)) - { - return true; - } - else { - return false; - } - } + int index_range[2]; + float factor; + + if (meshcache_read_pc2_range(fp, + verts_tot, + frame, + interp, + index_range, + &factor, /* read into these values */ + err_str) == false) { + return false; + } + + if (index_range[0] == index_range[1]) { + /* read single */ + if ((fseek(fp, 0, SEEK_SET) == 0) && + MOD_meshcache_read_pc2_index(fp, vertexCos, verts_tot, index_range[0], 1.0f, err_str)) { + return true; + } + else { + return false; + } + } + else { + /* read both and interpolate */ + if ((fseek(fp, 0, SEEK_SET) == 0) && + MOD_meshcache_read_pc2_index(fp, vertexCos, verts_tot, index_range[0], 1.0f, err_str) && + (fseek(fp, 0, SEEK_SET) == 0) && + MOD_meshcache_read_pc2_index(fp, vertexCos, verts_tot, index_range[1], factor, err_str)) { + return true; + } + else { + return false; + } + } } -bool MOD_meshcache_read_pc2_times( - const char *filepath, - float (*vertexCos)[3], const int verts_tot, const char interp, - const float time, const float fps, const char time_mode, - const char **err_str) +bool MOD_meshcache_read_pc2_times(const char *filepath, + float (*vertexCos)[3], + const int verts_tot, + const char interp, + const float time, + const float fps, + const char time_mode, + const char **err_str) { - float frame; - - FILE *fp = BLI_fopen(filepath, "rb"); - bool ok; - - if (fp == NULL) { - *err_str = errno ? strerror(errno) : "Unknown error opening file"; - return false; - } - - switch (time_mode) { - case MOD_MESHCACHE_TIME_FRAME: - { - frame = time; - break; - } - case MOD_MESHCACHE_TIME_SECONDS: - { - /* we need to find the closest time */ - if (meshcache_read_pc2_range_from_time(fp, verts_tot, time, fps, &frame, err_str) == false) { - fclose(fp); - return false; - } - rewind(fp); - break; - } - case MOD_MESHCACHE_TIME_FACTOR: - default: - { - PC2Head pc2_head; - if (meshcache_read_pc2_head(fp, verts_tot, &pc2_head, err_str) == false) { - fclose(fp); - return false; - } - - frame = CLAMPIS(time, 0.0f, 1.0f) * (float)pc2_head.frame_tot; - rewind(fp); - break; - } - } - - ok = MOD_meshcache_read_pc2_frame(fp, vertexCos, verts_tot, interp, frame, err_str); - - fclose(fp); - return ok; + float frame; + + FILE *fp = BLI_fopen(filepath, "rb"); + bool ok; + + if (fp == NULL) { + *err_str = errno ? strerror(errno) : "Unknown error opening file"; + return false; + } + + switch (time_mode) { + case MOD_MESHCACHE_TIME_FRAME: { + frame = time; + break; + } + case MOD_MESHCACHE_TIME_SECONDS: { + /* we need to find the closest time */ + if (meshcache_read_pc2_range_from_time(fp, verts_tot, time, fps, &frame, err_str) == false) { + fclose(fp); + return false; + } + rewind(fp); + break; + } + case MOD_MESHCACHE_TIME_FACTOR: + default: { + PC2Head pc2_head; + if (meshcache_read_pc2_head(fp, verts_tot, &pc2_head, err_str) == false) { + fclose(fp); + return false; + } + + frame = CLAMPIS(time, 0.0f, 1.0f) * (float)pc2_head.frame_tot; + rewind(fp); + break; + } + } + + ok = MOD_meshcache_read_pc2_frame(fp, vertexCos, verts_tot, interp, frame, err_str); + + fclose(fp); + return ok; } diff --git a/source/blender/modifiers/intern/MOD_meshcache_util.c b/source/blender/modifiers/intern/MOD_meshcache_util.c index 2db46af1188..0027ce5f7e2 100644 --- a/source/blender/modifiers/intern/MOD_meshcache_util.c +++ b/source/blender/modifiers/intern/MOD_meshcache_util.c @@ -26,42 +26,39 @@ #include "MOD_meshcache_util.h" -void MOD_meshcache_calc_range( - const float frame, const char interp, - const int frame_tot, - int r_index_range[2], float *r_factor) +void MOD_meshcache_calc_range(const float frame, + const char interp, + const int frame_tot, + int r_index_range[2], + float *r_factor) { - if (interp == MOD_MESHCACHE_INTERP_NONE) { - r_index_range[0] = r_index_range[1] = max_ii(0, min_ii(frame_tot - 1, round_fl_to_int(frame))); - *r_factor = 1.0f; /* dummy */ - } - else { - const float tframe = floorf(frame); - const float range = frame - tframe; - r_index_range[0] = (int)tframe; - if (range <= FRAME_SNAP_EPS) { - /* we're close enough not to need blending */ - r_index_range[1] = r_index_range[0]; - *r_factor = 1.0f; /* dummy */ - } - else { - /* blend between 2 frames */ - r_index_range[1] = r_index_range[0] + 1; - *r_factor = range; - } + if (interp == MOD_MESHCACHE_INTERP_NONE) { + r_index_range[0] = r_index_range[1] = max_ii(0, min_ii(frame_tot - 1, round_fl_to_int(frame))); + *r_factor = 1.0f; /* dummy */ + } + else { + const float tframe = floorf(frame); + const float range = frame - tframe; + r_index_range[0] = (int)tframe; + if (range <= FRAME_SNAP_EPS) { + /* we're close enough not to need blending */ + r_index_range[1] = r_index_range[0]; + *r_factor = 1.0f; /* dummy */ + } + else { + /* blend between 2 frames */ + r_index_range[1] = r_index_range[0] + 1; + *r_factor = range; + } - /* clamp */ - if ((r_index_range[0] >= frame_tot) || - (r_index_range[1] >= frame_tot)) - { - r_index_range[0] = r_index_range[1] = frame_tot - 1; - *r_factor = 1.0f; /* dummy */ - } - else if ((r_index_range[0] < 0) || - (r_index_range[1] < 0)) - { - r_index_range[0] = r_index_range[1] = 0; - *r_factor = 1.0f; /* dummy */ - } - } + /* clamp */ + if ((r_index_range[0] >= frame_tot) || (r_index_range[1] >= frame_tot)) { + r_index_range[0] = r_index_range[1] = frame_tot - 1; + *r_factor = 1.0f; /* dummy */ + } + else if ((r_index_range[0] < 0) || (r_index_range[1] < 0)) { + r_index_range[0] = r_index_range[1] = 0; + *r_factor = 1.0f; /* dummy */ + } + } } diff --git a/source/blender/modifiers/intern/MOD_meshcache_util.h b/source/blender/modifiers/intern/MOD_meshcache_util.h index a177ea467e7..0a6c0e73632 100644 --- a/source/blender/modifiers/intern/MOD_meshcache_util.h +++ b/source/blender/modifiers/intern/MOD_meshcache_util.h @@ -21,47 +21,57 @@ #ifndef __MOD_MESHCACHE_UTIL_H__ #define __MOD_MESHCACHE_UTIL_H__ - /* MOD_meshcache_mdd.c */ -bool MOD_meshcache_read_mdd_index( - FILE *fp, - float (*vertexCos)[3], const int vertex_tot, - const int index, const float factor, - const char **err_str); -bool MOD_meshcache_read_mdd_frame( - FILE *fp, - float (*vertexCos)[3], const int verts_tot, const char interp, - const float frame, - const char **err_str); -bool MOD_meshcache_read_mdd_times( - const char *filepath, - float (*vertexCos)[3], const int verts_tot, const char interp, - const float time, const float fps, const char time_mode, - const char **err_str); +bool MOD_meshcache_read_mdd_index(FILE *fp, + float (*vertexCos)[3], + const int vertex_tot, + const int index, + const float factor, + const char **err_str); +bool MOD_meshcache_read_mdd_frame(FILE *fp, + float (*vertexCos)[3], + const int verts_tot, + const char interp, + const float frame, + const char **err_str); +bool MOD_meshcache_read_mdd_times(const char *filepath, + float (*vertexCos)[3], + const int verts_tot, + const char interp, + const float time, + const float fps, + const char time_mode, + const char **err_str); /* MOD_meshcache_pc2.c */ -bool MOD_meshcache_read_pc2_index( - FILE *fp, - float (*vertexCos)[3], const int verts_tot, - const int index, const float factor, - const char **err_str); -bool MOD_meshcache_read_pc2_frame( - FILE *fp, - float (*vertexCos)[3], const int verts_tot, const char interp, - const float frame, - const char **err_str); -bool MOD_meshcache_read_pc2_times( - const char *filepath, - float (*vertexCos)[3], const int verts_tot, const char interp, - const float time, const float fps, const char time_mode, - const char **err_str); +bool MOD_meshcache_read_pc2_index(FILE *fp, + float (*vertexCos)[3], + const int verts_tot, + const int index, + const float factor, + const char **err_str); +bool MOD_meshcache_read_pc2_frame(FILE *fp, + float (*vertexCos)[3], + const int verts_tot, + const char interp, + const float frame, + const char **err_str); +bool MOD_meshcache_read_pc2_times(const char *filepath, + float (*vertexCos)[3], + const int verts_tot, + const char interp, + const float time, + const float fps, + const char time_mode, + const char **err_str); /* MOD_meshcache_util.c */ -void MOD_meshcache_calc_range( - const float frame, const char interp, - const int frame_tot, - int r_index_range[2], float *r_factor); +void MOD_meshcache_calc_range(const float frame, + const char interp, + const int frame_tot, + int r_index_range[2], + float *r_factor); #define FRAME_SNAP_EPS 0.0001f -#endif /* __MOD_MESHCACHE_UTIL_H__ */ +#endif /* __MOD_MESHCACHE_UTIL_H__ */ diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c index 7ae03cc43f3..9238057f032 100644 --- a/source/blender/modifiers/intern/MOD_meshdeform.c +++ b/source/blender/modifiers/intern/MOD_meshdeform.c @@ -53,466 +53,500 @@ static void initData(ModifierData *md) { - MeshDeformModifierData *mmd = (MeshDeformModifierData *) md; + MeshDeformModifierData *mmd = (MeshDeformModifierData *)md; - mmd->gridsize = 5; + mmd->gridsize = 5; } static void freeData(ModifierData *md) { - MeshDeformModifierData *mmd = (MeshDeformModifierData *) md; - - if (mmd->bindinfluences) MEM_freeN(mmd->bindinfluences); - if (mmd->bindoffsets) MEM_freeN(mmd->bindoffsets); - if (mmd->bindcagecos) MEM_freeN(mmd->bindcagecos); - if (mmd->dyngrid) MEM_freeN(mmd->dyngrid); - if (mmd->dyninfluences) MEM_freeN(mmd->dyninfluences); - if (mmd->dynverts) MEM_freeN(mmd->dynverts); - if (mmd->bindweights) MEM_freeN(mmd->bindweights); /* deprecated */ - if (mmd->bindcos) MEM_freeN(mmd->bindcos); /* deprecated */ + MeshDeformModifierData *mmd = (MeshDeformModifierData *)md; + + if (mmd->bindinfluences) + MEM_freeN(mmd->bindinfluences); + if (mmd->bindoffsets) + MEM_freeN(mmd->bindoffsets); + if (mmd->bindcagecos) + MEM_freeN(mmd->bindcagecos); + if (mmd->dyngrid) + MEM_freeN(mmd->dyngrid); + if (mmd->dyninfluences) + MEM_freeN(mmd->dyninfluences); + if (mmd->dynverts) + MEM_freeN(mmd->dynverts); + if (mmd->bindweights) + MEM_freeN(mmd->bindweights); /* deprecated */ + if (mmd->bindcos) + MEM_freeN(mmd->bindcos); /* deprecated */ } static void copyData(const ModifierData *md, ModifierData *target, const int flag) { - const MeshDeformModifierData *mmd = (const MeshDeformModifierData *) md; - MeshDeformModifierData *tmmd = (MeshDeformModifierData *) target; - - modifier_copyData_generic(md, target, flag); - - if (mmd->bindinfluences) tmmd->bindinfluences = MEM_dupallocN(mmd->bindinfluences); - if (mmd->bindoffsets) tmmd->bindoffsets = MEM_dupallocN(mmd->bindoffsets); - if (mmd->bindcagecos) tmmd->bindcagecos = MEM_dupallocN(mmd->bindcagecos); - if (mmd->dyngrid) tmmd->dyngrid = MEM_dupallocN(mmd->dyngrid); - if (mmd->dyninfluences) tmmd->dyninfluences = MEM_dupallocN(mmd->dyninfluences); - if (mmd->dynverts) tmmd->dynverts = MEM_dupallocN(mmd->dynverts); - if (mmd->bindweights) tmmd->bindweights = MEM_dupallocN(mmd->bindweights); /* deprecated */ - if (mmd->bindcos) tmmd->bindcos = MEM_dupallocN(mmd->bindcos); /* deprecated */ + const MeshDeformModifierData *mmd = (const MeshDeformModifierData *)md; + MeshDeformModifierData *tmmd = (MeshDeformModifierData *)target; + + modifier_copyData_generic(md, target, flag); + + if (mmd->bindinfluences) + tmmd->bindinfluences = MEM_dupallocN(mmd->bindinfluences); + if (mmd->bindoffsets) + tmmd->bindoffsets = MEM_dupallocN(mmd->bindoffsets); + if (mmd->bindcagecos) + tmmd->bindcagecos = MEM_dupallocN(mmd->bindcagecos); + if (mmd->dyngrid) + tmmd->dyngrid = MEM_dupallocN(mmd->dyngrid); + if (mmd->dyninfluences) + tmmd->dyninfluences = MEM_dupallocN(mmd->dyninfluences); + if (mmd->dynverts) + tmmd->dynverts = MEM_dupallocN(mmd->dynverts); + if (mmd->bindweights) + tmmd->bindweights = MEM_dupallocN(mmd->bindweights); /* deprecated */ + if (mmd->bindcos) + tmmd->bindcos = MEM_dupallocN(mmd->bindcos); /* deprecated */ } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - MeshDeformModifierData *mmd = (MeshDeformModifierData *)md; + MeshDeformModifierData *mmd = (MeshDeformModifierData *)md; - /* ask for vertexgroups if we need them */ - if (mmd->defgrp_name[0] != '\0') { - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; - } + /* ask for vertexgroups if we need them */ + if (mmd->defgrp_name[0] != '\0') { + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + } } -static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams)) +static bool isDisabled(const struct Scene *UNUSED(scene), + ModifierData *md, + bool UNUSED(useRenderParams)) { - MeshDeformModifierData *mmd = (MeshDeformModifierData *) md; + MeshDeformModifierData *mmd = (MeshDeformModifierData *)md; - return !mmd->object; + return !mmd->object; } -static void foreachObjectLink( - ModifierData *md, Object *ob, - ObjectWalkFunc walk, void *userData) +static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) { - MeshDeformModifierData *mmd = (MeshDeformModifierData *) md; + MeshDeformModifierData *mmd = (MeshDeformModifierData *)md; - walk(userData, ob, &mmd->object, IDWALK_CB_NOP); + walk(userData, ob, &mmd->object, IDWALK_CB_NOP); } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { - MeshDeformModifierData *mmd = (MeshDeformModifierData *)md; - if (mmd->object != NULL) { - /* TODO(sergey): Do we need transform component here? */ - DEG_add_object_relation(ctx->node, mmd->object, DEG_OB_COMP_GEOMETRY, "Mesh Deform Modifier"); - } + MeshDeformModifierData *mmd = (MeshDeformModifierData *)md; + if (mmd->object != NULL) { + /* TODO(sergey): Do we need transform component here? */ + DEG_add_object_relation(ctx->node, mmd->object, DEG_OB_COMP_GEOMETRY, "Mesh Deform Modifier"); + } } static float meshdeform_dynamic_bind(MeshDeformModifierData *mmd, float (*dco)[3], float vec[3]) { - MDefCell *cell; - MDefInfluence *inf; - float gridvec[3], dvec[3], ivec[3], wx, wy, wz; - float weight, cageweight, totweight, *cageco; - int i, j, a, x, y, z, size; + MDefCell *cell; + MDefInfluence *inf; + float gridvec[3], dvec[3], ivec[3], wx, wy, wz; + float weight, cageweight, totweight, *cageco; + int i, j, a, x, y, z, size; #ifdef __SSE2__ - __m128 co = _mm_setzero_ps(); + __m128 co = _mm_setzero_ps(); #else - float co[3] = {0.0f, 0.0f, 0.0f}; + float co[3] = {0.0f, 0.0f, 0.0f}; #endif - totweight = 0.0f; - size = mmd->dyngridsize; - - for (i = 0; i < 3; i++) { - gridvec[i] = (vec[i] - mmd->dyncellmin[i] - mmd->dyncellwidth * 0.5f) / mmd->dyncellwidth; - ivec[i] = (int)gridvec[i]; - dvec[i] = gridvec[i] - ivec[i]; - } - - for (i = 0; i < 8; i++) { - if (i & 1) { x = ivec[0] + 1; wx = dvec[0]; } - else { x = ivec[0]; wx = 1.0f - dvec[0]; } - - if (i & 2) { y = ivec[1] + 1; wy = dvec[1]; } - else { y = ivec[1]; wy = 1.0f - dvec[1]; } - - if (i & 4) { z = ivec[2] + 1; wz = dvec[2]; } - else { z = ivec[2]; wz = 1.0f - dvec[2]; } - - CLAMP(x, 0, size - 1); - CLAMP(y, 0, size - 1); - CLAMP(z, 0, size - 1); - - a = x + y * size + z * size * size; - weight = wx * wy * wz; - - cell = &mmd->dyngrid[a]; - inf = mmd->dyninfluences + cell->offset; - for (j = 0; j < cell->totinfluence; j++, inf++) { - cageco = dco[inf->vertex]; - cageweight = weight * inf->weight; + totweight = 0.0f; + size = mmd->dyngridsize; + + for (i = 0; i < 3; i++) { + gridvec[i] = (vec[i] - mmd->dyncellmin[i] - mmd->dyncellwidth * 0.5f) / mmd->dyncellwidth; + ivec[i] = (int)gridvec[i]; + dvec[i] = gridvec[i] - ivec[i]; + } + + for (i = 0; i < 8; i++) { + if (i & 1) { + x = ivec[0] + 1; + wx = dvec[0]; + } + else { + x = ivec[0]; + wx = 1.0f - dvec[0]; + } + + if (i & 2) { + y = ivec[1] + 1; + wy = dvec[1]; + } + else { + y = ivec[1]; + wy = 1.0f - dvec[1]; + } + + if (i & 4) { + z = ivec[2] + 1; + wz = dvec[2]; + } + else { + z = ivec[2]; + wz = 1.0f - dvec[2]; + } + + CLAMP(x, 0, size - 1); + CLAMP(y, 0, size - 1); + CLAMP(z, 0, size - 1); + + a = x + y * size + z * size * size; + weight = wx * wy * wz; + + cell = &mmd->dyngrid[a]; + inf = mmd->dyninfluences + cell->offset; + for (j = 0; j < cell->totinfluence; j++, inf++) { + cageco = dco[inf->vertex]; + cageweight = weight * inf->weight; #ifdef __SSE2__ - { - __m128 cageweight_r = _mm_set1_ps(cageweight); - /* This will load one extra element, this is ok because - * we ignore that part of register anyway. - */ - __m128 cageco_r = _mm_loadu_ps(cageco); - co = _mm_add_ps(co, - _mm_mul_ps(cageco_r, cageweight_r)); - } + { + __m128 cageweight_r = _mm_set1_ps(cageweight); + /* This will load one extra element, this is ok because + * we ignore that part of register anyway. + */ + __m128 cageco_r = _mm_loadu_ps(cageco); + co = _mm_add_ps(co, _mm_mul_ps(cageco_r, cageweight_r)); + } #else - co[0] += cageweight * cageco[0]; - co[1] += cageweight * cageco[1]; - co[2] += cageweight * cageco[2]; + co[0] += cageweight * cageco[0]; + co[1] += cageweight * cageco[1]; + co[2] += cageweight * cageco[2]; #endif - totweight += cageweight; - } - } + totweight += cageweight; + } + } #ifdef __SSE2__ - copy_v3_v3(vec, (float *)&co); + copy_v3_v3(vec, (float *)&co); #else - copy_v3_v3(vec, co); + copy_v3_v3(vec, co); #endif - return totweight; + return totweight; } typedef struct MeshdeformUserdata { - /*const*/ MeshDeformModifierData *mmd; - const MDeformVert *dvert; - /*const*/ float (*dco)[3]; - int defgrp_index; - float (*vertexCos)[3]; - float (*cagemat)[4]; - float (*icagemat)[3]; + /*const*/ MeshDeformModifierData *mmd; + const MDeformVert *dvert; + /*const*/ float (*dco)[3]; + int defgrp_index; + float (*vertexCos)[3]; + float (*cagemat)[4]; + float (*icagemat)[3]; } MeshdeformUserdata; -static void meshdeform_vert_task( - void *__restrict userdata, - const int iter, - const ParallelRangeTLS *__restrict UNUSED(tls)) +static void meshdeform_vert_task(void *__restrict userdata, + const int iter, + const ParallelRangeTLS *__restrict UNUSED(tls)) { - MeshdeformUserdata *data = userdata; - /*const*/ MeshDeformModifierData *mmd = data->mmd; - const MDeformVert *dvert = data->dvert; - const int defgrp_index = data->defgrp_index; - const int *offsets = mmd->bindoffsets; - const MDefInfluence *__restrict influences = mmd->bindinfluences; - /*const*/ float (*__restrict dco)[3] = data->dco; - float (*vertexCos)[3] = data->vertexCos; - float co[3]; - float weight, totweight, fac = 1.0f; - - if (mmd->flag & MOD_MDEF_DYNAMIC_BIND) - if (!mmd->dynverts[iter]) - return; - - if (dvert) { - fac = defvert_find_weight(&dvert[iter], defgrp_index); - - if (mmd->flag & MOD_MDEF_INVERT_VGROUP) { - fac = 1.0f - fac; - } - - if (fac <= 0.0f) { - return; - } - } - - if (mmd->flag & MOD_MDEF_DYNAMIC_BIND) { - /* transform coordinate into cage's local space */ - mul_v3_m4v3(co, data->cagemat, vertexCos[iter]); - totweight = meshdeform_dynamic_bind(mmd, dco, co); - } - else { - totweight = 0.0f; - zero_v3(co); - int start = offsets[iter]; - int end = offsets[iter + 1]; - - for (int a = start; a < end; 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(data->icagemat, co); - if (G.debug_value != 527) - add_v3_v3(vertexCos[iter], co); - else - copy_v3_v3(vertexCos[iter], co); - } + MeshdeformUserdata *data = userdata; + /*const*/ MeshDeformModifierData *mmd = data->mmd; + const MDeformVert *dvert = data->dvert; + const int defgrp_index = data->defgrp_index; + const int *offsets = mmd->bindoffsets; + const MDefInfluence *__restrict influences = mmd->bindinfluences; + /*const*/ float(*__restrict dco)[3] = data->dco; + float(*vertexCos)[3] = data->vertexCos; + float co[3]; + float weight, totweight, fac = 1.0f; + + if (mmd->flag & MOD_MDEF_DYNAMIC_BIND) + if (!mmd->dynverts[iter]) + return; + + if (dvert) { + fac = defvert_find_weight(&dvert[iter], defgrp_index); + + if (mmd->flag & MOD_MDEF_INVERT_VGROUP) { + fac = 1.0f - fac; + } + + if (fac <= 0.0f) { + return; + } + } + + if (mmd->flag & MOD_MDEF_DYNAMIC_BIND) { + /* transform coordinate into cage's local space */ + mul_v3_m4v3(co, data->cagemat, vertexCos[iter]); + totweight = meshdeform_dynamic_bind(mmd, dco, co); + } + else { + totweight = 0.0f; + zero_v3(co); + int start = offsets[iter]; + int end = offsets[iter + 1]; + + for (int a = start; a < end; 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(data->icagemat, co); + if (G.debug_value != 527) + add_v3_v3(vertexCos[iter], co); + else + copy_v3_v3(vertexCos[iter], co); + } } -static void meshdeformModifier_do( - ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh, - float (*vertexCos)[3], int numVerts) +static void meshdeformModifier_do(ModifierData *md, + const ModifierEvalContext *ctx, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - MeshDeformModifierData *mmd = (MeshDeformModifierData *) md; - Object *ob = ctx->object; - - Mesh *cagemesh; - MDeformVert *dvert = NULL; - float imat[4][4], cagemat[4][4], iobmat[4][4], icagemat[3][3], cmat[4][4]; - float co[3], (*dco)[3] = NULL, (*bindcagecos)[3]; - int a, totvert, totcagevert, defgrp_index; - float (*cagecos)[3] = NULL; - MeshdeformUserdata data; - - static int recursive_bind_sentinel = 0; - - if (mmd->object == NULL || (mmd->bindcagecos == NULL && mmd->bindfunc == NULL)) - return; - - /* Get cage mesh. - * - * Only do this is the target object is in edit mode by itself, meaning - * we don't allow linked edit meshes here. - * This is because editbmesh_get_mesh_cage_and_final() might easily - * conflict with the thread which evaluates object which is in the edit - * mode for this mesh. - * - * We'll support this case once granular dependency graph is landed. - */ - Object *ob_target = mmd->object; - cagemesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target, false); - if (cagemesh == NULL) { - 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, ob_target->obmat); - mul_m4_m4m4(cagemat, imat, ob->obmat); - mul_m4_m4m4(cmat, mmd->bindmat, cagemat); - invert_m4_m4(iobmat, cmat); - copy_m3_m4(icagemat, iobmat); - - /* bind weights if needed */ - if (!mmd->bindcagecos) { - /* progress bar redraw can make this recursive .. */ - if (!DEG_is_active(ctx->depsgraph)) { - modifier_setError(md, "Attempt to bind from inactive dependency graph"); - goto finally; - } - if (!recursive_bind_sentinel) { - recursive_bind_sentinel = 1; - mmd->bindfunc(mmd, cagemesh, (float *)vertexCos, numVerts, cagemat); - recursive_bind_sentinel = 0; - } - - goto finally; - } - - /* verify we have compatible weights */ - totvert = numVerts; - totcagevert = cagemesh->totvert; - - if (mmd->totvert != totvert) { - modifier_setError(md, "Verts changed from %d to %d", mmd->totvert, totvert); - goto finally; - } - else if (mmd->totcagevert != totcagevert) { - modifier_setError(md, "Cage verts changed from %d to %d", mmd->totcagevert, totcagevert); - goto finally; - } - else if (mmd->bindcagecos == NULL) { - modifier_setError(md, "Bind data missing"); - goto finally; - } - - /* setup deformation data */ - cagecos = BKE_mesh_vertexCos_get(cagemesh, NULL); - bindcagecos = (float(*)[3])mmd->bindcagecos; - - /* We allocate 1 element extra to make it possible to - * load the values to SSE registers, which are float4. - */ - dco = MEM_calloc_arrayN((totcagevert + 1), sizeof(*dco), "MDefDco"); - zero_v3(dco[totcagevert]); - 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); - } - } - - MOD_get_vgroup(ob, mesh, mmd->defgrp_name, &dvert, &defgrp_index); - - /* Initialize data to be pass to the for body function. */ - data.mmd = mmd; - data.dvert = dvert; - data.dco = dco; - data.defgrp_index = defgrp_index; - data.vertexCos = vertexCos; - data.cagemat = cagemat; - data.icagemat = icagemat; - - /* Do deformation. */ - ParallelRangeSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.min_iter_per_thread = 16; - BLI_task_parallel_range(0, totvert, - &data, - meshdeform_vert_task, - &settings); + MeshDeformModifierData *mmd = (MeshDeformModifierData *)md; + Object *ob = ctx->object; + + Mesh *cagemesh; + MDeformVert *dvert = NULL; + float imat[4][4], cagemat[4][4], iobmat[4][4], icagemat[3][3], cmat[4][4]; + float co[3], (*dco)[3] = NULL, (*bindcagecos)[3]; + int a, totvert, totcagevert, defgrp_index; + float(*cagecos)[3] = NULL; + MeshdeformUserdata data; + + static int recursive_bind_sentinel = 0; + + if (mmd->object == NULL || (mmd->bindcagecos == NULL && mmd->bindfunc == NULL)) + return; + + /* Get cage mesh. + * + * Only do this is the target object is in edit mode by itself, meaning + * we don't allow linked edit meshes here. + * This is because editbmesh_get_mesh_cage_and_final() might easily + * conflict with the thread which evaluates object which is in the edit + * mode for this mesh. + * + * We'll support this case once granular dependency graph is landed. + */ + Object *ob_target = mmd->object; + cagemesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target, false); + if (cagemesh == NULL) { + 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, ob_target->obmat); + mul_m4_m4m4(cagemat, imat, ob->obmat); + mul_m4_m4m4(cmat, mmd->bindmat, cagemat); + invert_m4_m4(iobmat, cmat); + copy_m3_m4(icagemat, iobmat); + + /* bind weights if needed */ + if (!mmd->bindcagecos) { + /* progress bar redraw can make this recursive .. */ + if (!DEG_is_active(ctx->depsgraph)) { + modifier_setError(md, "Attempt to bind from inactive dependency graph"); + goto finally; + } + if (!recursive_bind_sentinel) { + recursive_bind_sentinel = 1; + mmd->bindfunc(mmd, cagemesh, (float *)vertexCos, numVerts, cagemat); + recursive_bind_sentinel = 0; + } + + goto finally; + } + + /* verify we have compatible weights */ + totvert = numVerts; + totcagevert = cagemesh->totvert; + + if (mmd->totvert != totvert) { + modifier_setError(md, "Verts changed from %d to %d", mmd->totvert, totvert); + goto finally; + } + else if (mmd->totcagevert != totcagevert) { + modifier_setError(md, "Cage verts changed from %d to %d", mmd->totcagevert, totcagevert); + goto finally; + } + else if (mmd->bindcagecos == NULL) { + modifier_setError(md, "Bind data missing"); + goto finally; + } + + /* setup deformation data */ + cagecos = BKE_mesh_vertexCos_get(cagemesh, NULL); + bindcagecos = (float(*)[3])mmd->bindcagecos; + + /* We allocate 1 element extra to make it possible to + * load the values to SSE registers, which are float4. + */ + dco = MEM_calloc_arrayN((totcagevert + 1), sizeof(*dco), "MDefDco"); + zero_v3(dco[totcagevert]); + 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); + } + } + + MOD_get_vgroup(ob, mesh, mmd->defgrp_name, &dvert, &defgrp_index); + + /* Initialize data to be pass to the for body function. */ + data.mmd = mmd; + data.dvert = dvert; + data.dco = dco; + data.defgrp_index = defgrp_index; + data.vertexCos = vertexCos; + data.cagemat = cagemat; + data.icagemat = icagemat; + + /* Do deformation. */ + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = 16; + BLI_task_parallel_range(0, totvert, &data, meshdeform_vert_task, &settings); finally: - MEM_SAFE_FREE(dco); - MEM_SAFE_FREE(cagecos); + MEM_SAFE_FREE(dco); + MEM_SAFE_FREE(cagecos); } -static void deformVerts( - ModifierData *md, const ModifierEvalContext *ctx, - Mesh *mesh, - float (*vertexCos)[3], - int numVerts) +static void deformVerts(ModifierData *md, + const ModifierEvalContext *ctx, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); + Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); - MOD_previous_vcos_store(md, vertexCos); /* if next modifier needs original vertices */ + MOD_previous_vcos_store(md, vertexCos); /* if next modifier needs original vertices */ - meshdeformModifier_do(md, ctx, mesh_src, vertexCos, numVerts); + meshdeformModifier_do(md, ctx, mesh_src, vertexCos, numVerts); - if (!ELEM(mesh_src, NULL, mesh)) { - BKE_id_free(NULL, mesh_src); - } + if (!ELEM(mesh_src, NULL, mesh)) { + BKE_id_free(NULL, mesh_src); + } } -static void deformVertsEM( - ModifierData *md, const ModifierEvalContext *ctx, - struct BMEditMesh *editData, - Mesh *mesh, - float (*vertexCos)[3], - int numVerts) +static void deformVertsEM(ModifierData *md, + const ModifierEvalContext *ctx, + struct BMEditMesh *editData, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false); + Mesh *mesh_src = MOD_deform_mesh_eval_get( + ctx->object, editData, mesh, NULL, numVerts, false, false); - meshdeformModifier_do(md, ctx, mesh_src, vertexCos, numVerts); + meshdeformModifier_do(md, ctx, mesh_src, vertexCos, numVerts); - if (!ELEM(mesh_src, NULL, mesh)) { - BKE_id_free(NULL, mesh_src); - } + if (!ELEM(mesh_src, NULL, mesh)) { + BKE_id_free(NULL, mesh_src); + } } #define MESHDEFORM_MIN_INFLUENCE 0.00001f void modifier_mdef_compact_influences(ModifierData *md) { - MeshDeformModifierData *mmd = (MeshDeformModifierData *)md; - float weight, *weights, totweight; - int totinfluence, totvert, totcagevert, a, b; - - weights = mmd->bindweights; - if (!weights) - return; - - totvert = mmd->totvert; - totcagevert = mmd->totcagevert; - - /* count number of influences above threshold */ - for (b = 0; b < totvert; b++) { - for (a = 0; a < totcagevert; a++) { - weight = weights[a + b * totcagevert]; - - if (weight > MESHDEFORM_MIN_INFLUENCE) - mmd->totinfluence++; - } - } - - /* allocate bind influences */ - mmd->bindinfluences = MEM_calloc_arrayN(mmd->totinfluence, sizeof(MDefInfluence), "MDefBindInfluence"); - mmd->bindoffsets = MEM_calloc_arrayN((totvert + 1), sizeof(int), "MDefBindOffset"); - - /* write influences */ - totinfluence = 0; - - for (b = 0; b < totvert; b++) { - mmd->bindoffsets[b] = totinfluence; - totweight = 0.0f; - - /* sum total weight */ - for (a = 0; a < totcagevert; a++) { - weight = weights[a + b * totcagevert]; - - if (weight > MESHDEFORM_MIN_INFLUENCE) - totweight += weight; - } - - /* assign weights normalized */ - for (a = 0; a < totcagevert; a++) { - weight = weights[a + b * totcagevert]; - - if (weight > MESHDEFORM_MIN_INFLUENCE) { - mmd->bindinfluences[totinfluence].weight = weight / totweight; - mmd->bindinfluences[totinfluence].vertex = a; - totinfluence++; - } - } - } - - mmd->bindoffsets[b] = totinfluence; - - /* free */ - MEM_freeN(mmd->bindweights); - mmd->bindweights = NULL; + MeshDeformModifierData *mmd = (MeshDeformModifierData *)md; + float weight, *weights, totweight; + int totinfluence, totvert, totcagevert, a, b; + + weights = mmd->bindweights; + if (!weights) + return; + + totvert = mmd->totvert; + totcagevert = mmd->totcagevert; + + /* count number of influences above threshold */ + for (b = 0; b < totvert; b++) { + for (a = 0; a < totcagevert; a++) { + weight = weights[a + b * totcagevert]; + + if (weight > MESHDEFORM_MIN_INFLUENCE) + mmd->totinfluence++; + } + } + + /* allocate bind influences */ + mmd->bindinfluences = MEM_calloc_arrayN( + mmd->totinfluence, sizeof(MDefInfluence), "MDefBindInfluence"); + mmd->bindoffsets = MEM_calloc_arrayN((totvert + 1), sizeof(int), "MDefBindOffset"); + + /* write influences */ + totinfluence = 0; + + for (b = 0; b < totvert; b++) { + mmd->bindoffsets[b] = totinfluence; + totweight = 0.0f; + + /* sum total weight */ + for (a = 0; a < totcagevert; a++) { + weight = weights[a + b * totcagevert]; + + if (weight > MESHDEFORM_MIN_INFLUENCE) + totweight += weight; + } + + /* assign weights normalized */ + for (a = 0; a < totcagevert; a++) { + weight = weights[a + b * totcagevert]; + + if (weight > MESHDEFORM_MIN_INFLUENCE) { + mmd->bindinfluences[totinfluence].weight = weight / totweight; + mmd->bindinfluences[totinfluence].vertex = a; + totinfluence++; + } + } + } + + mmd->bindoffsets[b] = totinfluence; + + /* free */ + MEM_freeN(mmd->bindweights); + mmd->bindweights = NULL; } ModifierTypeInfo modifierType_MeshDeform = { - /* name */ "MeshDeform", - /* structName */ "MeshDeformModifierData", - /* structSize */ sizeof(MeshDeformModifierData), - /* type */ eModifierTypeType_OnlyDeform, - /* flags */ eModifierTypeFlag_AcceptsCVs | - eModifierTypeFlag_AcceptsLattice | - eModifierTypeFlag_SupportsEditmode, - - /* copyData */ copyData, - - /* deformVerts */ deformVerts, - /* deformMatrices */ NULL, - /* deformVertsEM */ deformVertsEM, - /* deformMatricesEM */ NULL, - /* applyModifier */ NULL, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ freeData, - /* isDisabled */ isDisabled, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ foreachObjectLink, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "MeshDeform", + /* structName */ "MeshDeformModifierData", + /* structSize */ sizeof(MeshDeformModifierData), + /* type */ eModifierTypeType_OnlyDeform, + /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice | + eModifierTypeFlag_SupportsEditmode, + + /* copyData */ copyData, + + /* deformVerts */ deformVerts, + /* deformMatrices */ NULL, + /* deformVertsEM */ deformVertsEM, + /* deformMatricesEM */ NULL, + /* applyModifier */ NULL, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ freeData, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c index 3b092bc7a76..7710082150b 100644 --- a/source/blender/modifiers/intern/MOD_meshsequencecache.c +++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c @@ -42,168 +42,158 @@ static void initData(ModifierData *md) { - MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md; + MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md; - mcmd->cache_file = NULL; - mcmd->object_path[0] = '\0'; - mcmd->read_flag = MOD_MESHSEQ_READ_ALL; + mcmd->cache_file = NULL; + mcmd->object_path[0] = '\0'; + mcmd->read_flag = MOD_MESHSEQ_READ_ALL; } static void copyData(const ModifierData *md, ModifierData *target, const int flag) { #if 0 - const MeshSeqCacheModifierData *mcmd = (const MeshSeqCacheModifierData *)md; + const MeshSeqCacheModifierData *mcmd = (const MeshSeqCacheModifierData *)md; #endif - MeshSeqCacheModifierData *tmcmd = (MeshSeqCacheModifierData *)target; + MeshSeqCacheModifierData *tmcmd = (MeshSeqCacheModifierData *)target; - modifier_copyData_generic(md, target, flag); + modifier_copyData_generic(md, target, flag); - tmcmd->reader = NULL; + tmcmd->reader = NULL; } static void freeData(ModifierData *md) { - MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md; + MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md; - if (mcmd->reader) { + if (mcmd->reader) { #ifdef WITH_ALEMBIC - CacheReader_free(mcmd->reader); + CacheReader_free(mcmd->reader); #endif - mcmd->reader = NULL; - } + mcmd->reader = NULL; + } } -static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams)) +static bool isDisabled(const struct Scene *UNUSED(scene), + ModifierData *md, + bool UNUSED(useRenderParams)) { - MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md; + MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md; - /* leave it up to the modifier to check the file is valid on calculation */ - return (mcmd->cache_file == NULL) || (mcmd->object_path[0] == '\0'); + /* leave it up to the modifier to check the file is valid on calculation */ + return (mcmd->cache_file == NULL) || (mcmd->object_path[0] == '\0'); } -static Mesh *applyModifier( - ModifierData *md, const ModifierEvalContext *ctx, - Mesh *mesh) +static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) { #ifdef WITH_ALEMBIC - MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md; - - /* Only used to check whether we are operating on org data or not... */ - Mesh *me = (ctx->object->type == OB_MESH) ? ctx->object->data : NULL; - Mesh *org_mesh = mesh; - - Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); - const float frame = DEG_get_ctime(ctx->depsgraph); - const float time = BKE_cachefile_time_offset(mcmd->cache_file, frame, FPS); - const char *err_str = NULL; - - CacheFile *cache_file = (CacheFile *)DEG_get_original_id(&mcmd->cache_file->id); - - BKE_cachefile_ensure_handle(G.main, cache_file); - - if (!mcmd->reader) { - mcmd->reader = CacheReader_open_alembic_object(cache_file->handle, - NULL, - ctx->object, - mcmd->object_path); - if (!mcmd->reader) { - modifier_setError(md, "Could not create Alembic reader for file %s", cache_file->filepath); - return mesh; - } - } - - if (me != NULL) { - MVert *mvert = mesh->mvert; - MEdge *medge = mesh->medge; - MPoly *mpoly = mesh->mpoly; - if ((me->mvert == mvert) || (me->medge == medge) || (me->mpoly == mpoly)) { - /* We need to duplicate data here, otherwise we'll modify org mesh, see T51701. */ - BKE_id_copy_ex(NULL, &mesh->id, (ID **)&mesh, - LIB_ID_CREATE_NO_MAIN | - LIB_ID_CREATE_NO_USER_REFCOUNT | - LIB_ID_CREATE_NO_DEG_TAG | - LIB_ID_COPY_NO_PREVIEW); - } - } - - Mesh *result = ABC_read_mesh(mcmd->reader, - ctx->object, - mesh, - time, - &err_str, - mcmd->read_flag); - - if (err_str) { - modifier_setError(md, "%s", err_str); - } - - if (!ELEM(result, NULL, mesh) && (mesh != org_mesh)) { - BKE_id_free(NULL, mesh); - mesh = org_mesh; - } - - return result ? result : mesh; + MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md; + + /* Only used to check whether we are operating on org data or not... */ + Mesh *me = (ctx->object->type == OB_MESH) ? ctx->object->data : NULL; + Mesh *org_mesh = mesh; + + Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); + const float frame = DEG_get_ctime(ctx->depsgraph); + const float time = BKE_cachefile_time_offset(mcmd->cache_file, frame, FPS); + const char *err_str = NULL; + + CacheFile *cache_file = (CacheFile *)DEG_get_original_id(&mcmd->cache_file->id); + + BKE_cachefile_ensure_handle(G.main, cache_file); + + if (!mcmd->reader) { + mcmd->reader = CacheReader_open_alembic_object( + cache_file->handle, NULL, ctx->object, mcmd->object_path); + if (!mcmd->reader) { + modifier_setError(md, "Could not create Alembic reader for file %s", cache_file->filepath); + return mesh; + } + } + + if (me != NULL) { + MVert *mvert = mesh->mvert; + MEdge *medge = mesh->medge; + MPoly *mpoly = mesh->mpoly; + if ((me->mvert == mvert) || (me->medge == medge) || (me->mpoly == mpoly)) { + /* We need to duplicate data here, otherwise we'll modify org mesh, see T51701. */ + BKE_id_copy_ex(NULL, + &mesh->id, + (ID **)&mesh, + LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT | + LIB_ID_CREATE_NO_DEG_TAG | LIB_ID_COPY_NO_PREVIEW); + } + } + + Mesh *result = ABC_read_mesh(mcmd->reader, ctx->object, mesh, time, &err_str, mcmd->read_flag); + + if (err_str) { + modifier_setError(md, "%s", err_str); + } + + if (!ELEM(result, NULL, mesh) && (mesh != org_mesh)) { + BKE_id_free(NULL, mesh); + mesh = org_mesh; + } + + return result ? result : mesh; #else - UNUSED_VARS(ctx, md); - return mesh; + UNUSED_VARS(ctx, md); + return mesh; #endif } static bool dependsOnTime(ModifierData *md) { #ifdef WITH_ALEMBIC - MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md; - return (mcmd->cache_file != NULL); + MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md; + return (mcmd->cache_file != NULL); #else - UNUSED_VARS(md); - return false; + UNUSED_VARS(md); + return false; #endif } -static void foreachIDLink( - ModifierData *md, Object *ob, - IDWalkFunc walk, void *userData) +static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData) { - MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md; + MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md; - walk(userData, ob, (ID **)&mcmd->cache_file, IDWALK_CB_USER); + walk(userData, ob, (ID **)&mcmd->cache_file, IDWALK_CB_USER); } - static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { - MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md; + MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md; - if (mcmd->cache_file != NULL) { - DEG_add_object_cache_relation(ctx->node, mcmd->cache_file, DEG_OB_COMP_CACHE, "Mesh Cache File"); - } + if (mcmd->cache_file != NULL) { + DEG_add_object_cache_relation( + ctx->node, mcmd->cache_file, DEG_OB_COMP_CACHE, "Mesh Cache File"); + } } ModifierTypeInfo modifierType_MeshSequenceCache = { - /* name */ "Mesh Sequence Cache", - /* structName */ "MeshSeqCacheModifierData", - /* structSize */ sizeof(MeshSeqCacheModifierData), - /* type */ eModifierTypeType_Constructive, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_AcceptsCVs, - - /* copyData */ copyData, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ initData, - /* requiredDataMask */ NULL, - /* freeData */ freeData, - /* isDisabled */ isDisabled, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ dependsOnTime, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ NULL, - /* foreachIDLink */ foreachIDLink, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Mesh Sequence Cache", + /* structName */ "MeshSeqCacheModifierData", + /* structSize */ sizeof(MeshSeqCacheModifierData), + /* type */ eModifierTypeType_Constructive, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs, + + /* copyData */ copyData, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ initData, + /* requiredDataMask */ NULL, + /* freeData */ freeData, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ dependsOnTime, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ foreachIDLink, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c index 5fb4c66471f..39b86ca48fd 100644 --- a/source/blender/modifiers/intern/MOD_mirror.c +++ b/source/blender/modifiers/intern/MOD_mirror.c @@ -21,7 +21,6 @@ * \ingroup modifiers */ - #include "BLI_math.h" #include "DNA_mesh_types.h" @@ -46,407 +45,402 @@ static void initData(ModifierData *md) { - MirrorModifierData *mmd = (MirrorModifierData *) md; + MirrorModifierData *mmd = (MirrorModifierData *)md; - mmd->flag |= (MOD_MIR_AXIS_X | MOD_MIR_VGROUP); - mmd->tolerance = 0.001; - mmd->mirror_ob = NULL; + mmd->flag |= (MOD_MIR_AXIS_X | MOD_MIR_VGROUP); + mmd->tolerance = 0.001; + mmd->mirror_ob = NULL; } -static void foreachObjectLink( - ModifierData *md, Object *ob, - ObjectWalkFunc walk, void *userData) +static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) { - MirrorModifierData *mmd = (MirrorModifierData *) md; + MirrorModifierData *mmd = (MirrorModifierData *)md; - walk(userData, ob, &mmd->mirror_ob, IDWALK_CB_NOP); + walk(userData, ob, &mmd->mirror_ob, IDWALK_CB_NOP); } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { - MirrorModifierData *mmd = (MirrorModifierData *)md; - if (mmd->mirror_ob != NULL) { - DEG_add_object_relation(ctx->node, mmd->mirror_ob, DEG_OB_COMP_TRANSFORM, "Mirror Modifier"); - DEG_add_modifier_to_transform_relation(ctx->node, "Mirror Modifier"); - } + MirrorModifierData *mmd = (MirrorModifierData *)md; + if (mmd->mirror_ob != NULL) { + DEG_add_object_relation(ctx->node, mmd->mirror_ob, DEG_OB_COMP_TRANSFORM, "Mirror Modifier"); + DEG_add_modifier_to_transform_relation(ctx->node, "Mirror Modifier"); + } } static Mesh *doBiscetOnMirrorPlane( - MirrorModifierData *mmd, - const Mesh *mesh, - int axis, - float plane_co[3], - float plane_no[3]) + MirrorModifierData *mmd, const Mesh *mesh, int axis, float plane_co[3], float plane_no[3]) { - bool do_bisect_flip_axis = ( - (axis == 0 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_X) || - (axis == 1 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_Y) || - (axis == 2 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_Z)); - - const float bisect_distance = 0.001f; - - Mesh *result; - BMesh *bm; - BMIter viter; - BMVert *v, *v_next; - - bm = BKE_mesh_to_bmesh_ex( - mesh, - &(struct BMeshCreateParams){0}, - &(struct BMeshFromMeshParams){ - .calc_face_normal = true, - .cd_mask_extra = {.vmask = CD_MASK_ORIGINDEX, .emask = CD_MASK_ORIGINDEX, .pmask = CD_MASK_ORIGINDEX}, - }); - - /* Define bisecting plane (aka mirror plane). */ - float plane[4]; - if (!do_bisect_flip_axis) { - /* That reversed condition is a tad weird, but for some reason that's how you keep - * the part of the mesh which is on the non-mirrored side when flip option is disabled, - * think that that is the expected behavior. */ - negate_v3(plane_no); - } - plane_from_point_normal_v3(plane, plane_co, plane_no); - - BM_mesh_bisect_plane(bm, plane, false, false, 0, 0, bisect_distance); - - /* Plane definitions for vert killing. */ - float plane_offset[4]; - copy_v3_v3(plane_offset, plane); - plane_offset[3] = plane[3] - bisect_distance; - - /* Delete verts across the mirror plane. */ - BM_ITER_MESH_MUTABLE(v, v_next, &viter, bm, BM_VERTS_OF_MESH) { - if (plane_point_side_v3(plane_offset, v->co) > 0.0f) { - BM_vert_kill(bm, v); - } - } - - result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL); - BM_mesh_free(bm); - - return result; + bool do_bisect_flip_axis = ((axis == 0 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_X) || + (axis == 1 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_Y) || + (axis == 2 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_Z)); + + const float bisect_distance = 0.001f; + + Mesh *result; + BMesh *bm; + BMIter viter; + BMVert *v, *v_next; + + bm = BKE_mesh_to_bmesh_ex(mesh, + &(struct BMeshCreateParams){0}, + &(struct BMeshFromMeshParams){ + .calc_face_normal = true, + .cd_mask_extra = {.vmask = CD_MASK_ORIGINDEX, + .emask = CD_MASK_ORIGINDEX, + .pmask = CD_MASK_ORIGINDEX}, + }); + + /* Define bisecting plane (aka mirror plane). */ + float plane[4]; + if (!do_bisect_flip_axis) { + /* That reversed condition is a tad weird, but for some reason that's how you keep + * the part of the mesh which is on the non-mirrored side when flip option is disabled, + * think that that is the expected behavior. */ + negate_v3(plane_no); + } + plane_from_point_normal_v3(plane, plane_co, plane_no); + + BM_mesh_bisect_plane(bm, plane, false, false, 0, 0, bisect_distance); + + /* Plane definitions for vert killing. */ + float plane_offset[4]; + copy_v3_v3(plane_offset, plane); + plane_offset[3] = plane[3] - bisect_distance; + + /* Delete verts across the mirror plane. */ + BM_ITER_MESH_MUTABLE (v, v_next, &viter, bm, BM_VERTS_OF_MESH) { + if (plane_point_side_v3(plane_offset, v->co) > 0.0f) { + BM_vert_kill(bm, v); + } + } + + result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL); + BM_mesh_free(bm); + + return result; } -static Mesh *doMirrorOnAxis( - MirrorModifierData *mmd, - const ModifierEvalContext *UNUSED(ctx), - Object *ob, - const Mesh *mesh, - int axis) +static Mesh *doMirrorOnAxis(MirrorModifierData *mmd, + const ModifierEvalContext *UNUSED(ctx), + Object *ob, + const Mesh *mesh, + int axis) { - const float tolerance_sq = mmd->tolerance * mmd->tolerance; - const bool do_vtargetmap = (mmd->flag & MOD_MIR_NO_MERGE) == 0; - int tot_vtargetmap = 0; /* total merge vertices */ - - const bool do_bisect = ( - (axis == 0 && mmd->flag & MOD_MIR_BISECT_AXIS_X) || - (axis == 1 && mmd->flag & MOD_MIR_BISECT_AXIS_Y) || - (axis == 2 && mmd->flag & MOD_MIR_BISECT_AXIS_Z)); - - Mesh *result; - MVert *mv, *mv_prev; - MEdge *me; - MLoop *ml; - MPoly *mp; - float mtx[4][4]; - float plane_co[3], plane_no[3]; - int i; - int a, totshape; - int *vtargetmap = NULL, *vtmap_a = NULL, *vtmap_b = NULL; - - /* mtx is the mirror transformation */ - unit_m4(mtx); - mtx[axis][axis] = -1.0f; - - Object *mirror_ob = mmd->mirror_ob; - if (mirror_ob != NULL) { - float tmp[4][4]; - float itmp[4][4]; - - /* tmp is a transform from coords relative to the object's own origin, - * to coords relative to the mirror object origin */ - invert_m4_m4(tmp, mirror_ob->obmat); - mul_m4_m4m4(tmp, tmp, ob->obmat); - - /* itmp is the reverse transform back to origin-relative coordinates */ - invert_m4_m4(itmp, tmp); - - /* combine matrices to get a single matrix that translates coordinates into - * mirror-object-relative space, does the mirror, and translates back to - * origin-relative space */ - mul_m4_series(mtx, itmp, mtx, tmp); - - if (do_bisect) { - copy_v3_v3(plane_co, itmp[3]); - copy_v3_v3(plane_no, itmp[axis]); - } - } - else if (do_bisect) { - copy_v3_v3(plane_co, mtx[3]); - /* Need to negate here, since that axis is inverted (for mirror transform). */ - negate_v3_v3(plane_no, mtx[axis]); - } - - Mesh *mesh_bisect = NULL; - if (do_bisect) { - mesh_bisect = doBiscetOnMirrorPlane(mmd, mesh, axis, plane_co, plane_no); - mesh = mesh_bisect; - } - - const int maxVerts = mesh->totvert; - const int maxEdges = mesh->totedge; - const int maxLoops = mesh->totloop; - const int maxPolys = mesh->totpoly; - - result = BKE_mesh_new_nomain_from_template( - mesh, maxVerts * 2, maxEdges * 2, 0, maxLoops * 2, maxPolys * 2); - - /*copy customdata to original geometry*/ - CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, maxVerts); - CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, maxEdges); - CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, maxLoops); - CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, maxPolys); - - /* Subsurf for eg won't have mesh data in the custom data arrays. - * now add mvert/medge/mpoly layers. */ - if (!CustomData_has_layer(&mesh->vdata, CD_MVERT)) { - memcpy(result->mvert, mesh->mvert, sizeof(*result->mvert) * mesh->totvert); - } - if (!CustomData_has_layer(&mesh->edata, CD_MEDGE)) { - memcpy(result->medge, mesh->medge, sizeof(*result->medge) * mesh->totedge); - } - if (!CustomData_has_layer(&mesh->pdata, CD_MPOLY)) { - memcpy(result->mloop, mesh->mloop, sizeof(*result->mloop) * mesh->totloop); - memcpy(result->mpoly, mesh->mpoly, sizeof(*result->mpoly) * mesh->totpoly); - } - - /* copy customdata to new geometry, - * copy from its self because this data may have been created in the checks above */ - CustomData_copy_data(&result->vdata, &result->vdata, 0, maxVerts, maxVerts); - CustomData_copy_data(&result->edata, &result->edata, 0, maxEdges, maxEdges); - /* loops are copied later */ - CustomData_copy_data(&result->pdata, &result->pdata, 0, maxPolys, maxPolys); - - if (do_vtargetmap) { - /* second half is filled with -1 */ - vtargetmap = MEM_malloc_arrayN(maxVerts, 2 * sizeof(int), "MOD_mirror tarmap"); - - vtmap_a = vtargetmap; - vtmap_b = vtargetmap + maxVerts; - } - - /* mirror vertex coordinates */ - mv_prev = result->mvert; - mv = mv_prev + maxVerts; - for (i = 0; i < maxVerts; i++, mv++, mv_prev++) { - mul_m4_v3(mtx, mv->co); - - if (do_vtargetmap) { - /* compare location of the original and mirrored vertex, to see if they - * should be mapped for merging */ - if (UNLIKELY(len_squared_v3v3(mv_prev->co, mv->co) < tolerance_sq)) { - *vtmap_a = maxVerts + i; - tot_vtargetmap++; - - /* average location */ - mid_v3_v3v3(mv->co, mv_prev->co, mv->co); - copy_v3_v3(mv_prev->co, mv->co); - } - else { - *vtmap_a = -1; - } - - *vtmap_b = -1; /* fill here to avoid 2x loops */ - - vtmap_a++; - vtmap_b++; - } - } - - /* handle shape keys */ - totshape = CustomData_number_of_layers(&result->vdata, CD_SHAPEKEY); - for (a = 0; a < totshape; a++) { - float (*cos)[3] = CustomData_get_layer_n(&result->vdata, CD_SHAPEKEY, a); - for (i = maxVerts; i < result->totvert; i++) { - mul_m4_v3(mtx, cos[i]); - } - } - - /* adjust mirrored edge vertex indices */ - me = result->medge + maxEdges; - for (i = 0; i < maxEdges; i++, me++) { - me->v1 += maxVerts; - me->v2 += maxVerts; - } - - /* adjust mirrored poly loopstart indices, and reverse loop order (normals) */ - mp = result->mpoly + maxPolys; - ml = result->mloop; - for (i = 0; i < maxPolys; i++, mp++) { - MLoop *ml2; - int j, e; - - /* reverse the loop, but we keep the first vertex in the face the same, - * to ensure that quads are split the same way as on the other side */ - CustomData_copy_data(&result->ldata, &result->ldata, mp->loopstart, mp->loopstart + maxLoops, 1); - - for (j = 1; j < mp->totloop; j++) - CustomData_copy_data(&result->ldata, &result->ldata, - mp->loopstart + j, - mp->loopstart + maxLoops + mp->totloop - j, - 1); - - ml2 = ml + mp->loopstart + maxLoops; - 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 += maxLoops; - } - - /* adjust mirrored loop vertex and edge indices */ - ml = result->mloop + maxLoops; - for (i = 0; i < maxLoops; i++, ml++) { - ml->v += maxVerts; - ml->e += maxEdges; - } - - /* handle uvs, - * let tessface recalc handle updating the MTFace data */ - if (mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V) || (is_zero_v2(mmd->uv_offset_copy) == false)) { - const bool do_mirr_u = (mmd->flag & MOD_MIR_MIRROR_U) != 0; - const bool do_mirr_v = (mmd->flag & MOD_MIR_MIRROR_V) != 0; - - const int totuv = CustomData_number_of_layers(&result->ldata, CD_MLOOPUV); - - for (a = 0; a < totuv; a++) { - MLoopUV *dmloopuv = CustomData_get_layer_n(&result->ldata, CD_MLOOPUV, a); - int j = maxLoops; - dmloopuv += j; /* second set of loops only */ - for (; j-- > 0; dmloopuv++) { - if (do_mirr_u) dmloopuv->uv[0] = 1.0f - dmloopuv->uv[0] + mmd->uv_offset[0]; - if (do_mirr_v) dmloopuv->uv[1] = 1.0f - dmloopuv->uv[1] + mmd->uv_offset[1]; - dmloopuv->uv[0] += mmd->uv_offset_copy[0]; - dmloopuv->uv[1] += mmd->uv_offset_copy[1]; - } - } - } - - /* handle vgroup stuff */ - if ((mmd->flag & MOD_MIR_VGROUP) && CustomData_has_layer(&result->vdata, CD_MDEFORMVERT)) { - MDeformVert *dvert = (MDeformVert *) CustomData_get_layer(&result->vdata, CD_MDEFORMVERT) + maxVerts; - int *flip_map = NULL, flip_map_len = 0; - - flip_map = defgroup_flip_map(ob, &flip_map_len, false); - - if (flip_map) { - for (i = 0; i < maxVerts; dvert++, i++) { - /* merged vertices get both groups, others get flipped */ - if (do_vtargetmap && (vtargetmap[i] != -1)) - defvert_flip_merged(dvert, flip_map, flip_map_len); - else - defvert_flip(dvert, flip_map, flip_map_len); - } - - MEM_freeN(flip_map); - } - } - - if (do_vtargetmap) { - /* slow - so only call if one or more merge verts are found, - * users may leave this on and not realize there is nothing to merge - campbell */ - if (tot_vtargetmap) { - result = BKE_mesh_merge_verts(result, vtargetmap, tot_vtargetmap, MESH_MERGE_VERTS_DUMP_IF_MAPPED); - } - MEM_freeN(vtargetmap); - } - - if (mesh_bisect != NULL) { - BKE_id_free(NULL, mesh_bisect); - } - - return result; + const float tolerance_sq = mmd->tolerance * mmd->tolerance; + const bool do_vtargetmap = (mmd->flag & MOD_MIR_NO_MERGE) == 0; + int tot_vtargetmap = 0; /* total merge vertices */ + + const bool do_bisect = ((axis == 0 && mmd->flag & MOD_MIR_BISECT_AXIS_X) || + (axis == 1 && mmd->flag & MOD_MIR_BISECT_AXIS_Y) || + (axis == 2 && mmd->flag & MOD_MIR_BISECT_AXIS_Z)); + + Mesh *result; + MVert *mv, *mv_prev; + MEdge *me; + MLoop *ml; + MPoly *mp; + float mtx[4][4]; + float plane_co[3], plane_no[3]; + int i; + int a, totshape; + int *vtargetmap = NULL, *vtmap_a = NULL, *vtmap_b = NULL; + + /* mtx is the mirror transformation */ + unit_m4(mtx); + mtx[axis][axis] = -1.0f; + + Object *mirror_ob = mmd->mirror_ob; + if (mirror_ob != NULL) { + float tmp[4][4]; + float itmp[4][4]; + + /* tmp is a transform from coords relative to the object's own origin, + * to coords relative to the mirror object origin */ + invert_m4_m4(tmp, mirror_ob->obmat); + mul_m4_m4m4(tmp, tmp, ob->obmat); + + /* itmp is the reverse transform back to origin-relative coordinates */ + invert_m4_m4(itmp, tmp); + + /* combine matrices to get a single matrix that translates coordinates into + * mirror-object-relative space, does the mirror, and translates back to + * origin-relative space */ + mul_m4_series(mtx, itmp, mtx, tmp); + + if (do_bisect) { + copy_v3_v3(plane_co, itmp[3]); + copy_v3_v3(plane_no, itmp[axis]); + } + } + else if (do_bisect) { + copy_v3_v3(plane_co, mtx[3]); + /* Need to negate here, since that axis is inverted (for mirror transform). */ + negate_v3_v3(plane_no, mtx[axis]); + } + + Mesh *mesh_bisect = NULL; + if (do_bisect) { + mesh_bisect = doBiscetOnMirrorPlane(mmd, mesh, axis, plane_co, plane_no); + mesh = mesh_bisect; + } + + const int maxVerts = mesh->totvert; + const int maxEdges = mesh->totedge; + const int maxLoops = mesh->totloop; + const int maxPolys = mesh->totpoly; + + result = BKE_mesh_new_nomain_from_template( + mesh, maxVerts * 2, maxEdges * 2, 0, maxLoops * 2, maxPolys * 2); + + /*copy customdata to original geometry*/ + CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, maxVerts); + CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, maxEdges); + CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, maxLoops); + CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, maxPolys); + + /* Subsurf for eg won't have mesh data in the custom data arrays. + * now add mvert/medge/mpoly layers. */ + if (!CustomData_has_layer(&mesh->vdata, CD_MVERT)) { + memcpy(result->mvert, mesh->mvert, sizeof(*result->mvert) * mesh->totvert); + } + if (!CustomData_has_layer(&mesh->edata, CD_MEDGE)) { + memcpy(result->medge, mesh->medge, sizeof(*result->medge) * mesh->totedge); + } + if (!CustomData_has_layer(&mesh->pdata, CD_MPOLY)) { + memcpy(result->mloop, mesh->mloop, sizeof(*result->mloop) * mesh->totloop); + memcpy(result->mpoly, mesh->mpoly, sizeof(*result->mpoly) * mesh->totpoly); + } + + /* copy customdata to new geometry, + * copy from its self because this data may have been created in the checks above */ + CustomData_copy_data(&result->vdata, &result->vdata, 0, maxVerts, maxVerts); + CustomData_copy_data(&result->edata, &result->edata, 0, maxEdges, maxEdges); + /* loops are copied later */ + CustomData_copy_data(&result->pdata, &result->pdata, 0, maxPolys, maxPolys); + + if (do_vtargetmap) { + /* second half is filled with -1 */ + vtargetmap = MEM_malloc_arrayN(maxVerts, 2 * sizeof(int), "MOD_mirror tarmap"); + + vtmap_a = vtargetmap; + vtmap_b = vtargetmap + maxVerts; + } + + /* mirror vertex coordinates */ + mv_prev = result->mvert; + mv = mv_prev + maxVerts; + for (i = 0; i < maxVerts; i++, mv++, mv_prev++) { + mul_m4_v3(mtx, mv->co); + + if (do_vtargetmap) { + /* compare location of the original and mirrored vertex, to see if they + * should be mapped for merging */ + if (UNLIKELY(len_squared_v3v3(mv_prev->co, mv->co) < tolerance_sq)) { + *vtmap_a = maxVerts + i; + tot_vtargetmap++; + + /* average location */ + mid_v3_v3v3(mv->co, mv_prev->co, mv->co); + copy_v3_v3(mv_prev->co, mv->co); + } + else { + *vtmap_a = -1; + } + + *vtmap_b = -1; /* fill here to avoid 2x loops */ + + vtmap_a++; + vtmap_b++; + } + } + + /* handle shape keys */ + totshape = CustomData_number_of_layers(&result->vdata, CD_SHAPEKEY); + for (a = 0; a < totshape; a++) { + float(*cos)[3] = CustomData_get_layer_n(&result->vdata, CD_SHAPEKEY, a); + for (i = maxVerts; i < result->totvert; i++) { + mul_m4_v3(mtx, cos[i]); + } + } + + /* adjust mirrored edge vertex indices */ + me = result->medge + maxEdges; + for (i = 0; i < maxEdges; i++, me++) { + me->v1 += maxVerts; + me->v2 += maxVerts; + } + + /* adjust mirrored poly loopstart indices, and reverse loop order (normals) */ + mp = result->mpoly + maxPolys; + ml = result->mloop; + for (i = 0; i < maxPolys; i++, mp++) { + MLoop *ml2; + int j, e; + + /* reverse the loop, but we keep the first vertex in the face the same, + * to ensure that quads are split the same way as on the other side */ + CustomData_copy_data( + &result->ldata, &result->ldata, mp->loopstart, mp->loopstart + maxLoops, 1); + + for (j = 1; j < mp->totloop; j++) + CustomData_copy_data(&result->ldata, + &result->ldata, + mp->loopstart + j, + mp->loopstart + maxLoops + mp->totloop - j, + 1); + + ml2 = ml + mp->loopstart + maxLoops; + 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 += maxLoops; + } + + /* adjust mirrored loop vertex and edge indices */ + ml = result->mloop + maxLoops; + for (i = 0; i < maxLoops; i++, ml++) { + ml->v += maxVerts; + ml->e += maxEdges; + } + + /* handle uvs, + * let tessface recalc handle updating the MTFace data */ + if (mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V) || + (is_zero_v2(mmd->uv_offset_copy) == false)) { + const bool do_mirr_u = (mmd->flag & MOD_MIR_MIRROR_U) != 0; + const bool do_mirr_v = (mmd->flag & MOD_MIR_MIRROR_V) != 0; + + const int totuv = CustomData_number_of_layers(&result->ldata, CD_MLOOPUV); + + for (a = 0; a < totuv; a++) { + MLoopUV *dmloopuv = CustomData_get_layer_n(&result->ldata, CD_MLOOPUV, a); + int j = maxLoops; + dmloopuv += j; /* second set of loops only */ + for (; j-- > 0; dmloopuv++) { + if (do_mirr_u) + dmloopuv->uv[0] = 1.0f - dmloopuv->uv[0] + mmd->uv_offset[0]; + if (do_mirr_v) + dmloopuv->uv[1] = 1.0f - dmloopuv->uv[1] + mmd->uv_offset[1]; + dmloopuv->uv[0] += mmd->uv_offset_copy[0]; + dmloopuv->uv[1] += mmd->uv_offset_copy[1]; + } + } + } + + /* handle vgroup stuff */ + if ((mmd->flag & MOD_MIR_VGROUP) && CustomData_has_layer(&result->vdata, CD_MDEFORMVERT)) { + MDeformVert *dvert = (MDeformVert *)CustomData_get_layer(&result->vdata, CD_MDEFORMVERT) + + maxVerts; + int *flip_map = NULL, flip_map_len = 0; + + flip_map = defgroup_flip_map(ob, &flip_map_len, false); + + if (flip_map) { + for (i = 0; i < maxVerts; dvert++, i++) { + /* merged vertices get both groups, others get flipped */ + if (do_vtargetmap && (vtargetmap[i] != -1)) + defvert_flip_merged(dvert, flip_map, flip_map_len); + else + defvert_flip(dvert, flip_map, flip_map_len); + } + + MEM_freeN(flip_map); + } + } + + if (do_vtargetmap) { + /* slow - so only call if one or more merge verts are found, + * users may leave this on and not realize there is nothing to merge - campbell */ + if (tot_vtargetmap) { + result = BKE_mesh_merge_verts( + result, vtargetmap, tot_vtargetmap, MESH_MERGE_VERTS_DUMP_IF_MAPPED); + } + MEM_freeN(vtargetmap); + } + + if (mesh_bisect != NULL) { + BKE_id_free(NULL, mesh_bisect); + } + + return result; } -static Mesh *mirrorModifier__doMirror( - MirrorModifierData *mmd, const ModifierEvalContext *ctx, - Object *ob, Mesh *mesh) +static Mesh *mirrorModifier__doMirror(MirrorModifierData *mmd, + const ModifierEvalContext *ctx, + Object *ob, + Mesh *mesh) { - Mesh *result = mesh; - - /* check which axes have been toggled and mirror accordingly */ - if (mmd->flag & MOD_MIR_AXIS_X) { - result = doMirrorOnAxis(mmd, ctx, ob, result, 0); - } - if (mmd->flag & MOD_MIR_AXIS_Y) { - Mesh *tmp = result; - result = doMirrorOnAxis(mmd, ctx, ob, result, 1); - if (tmp != mesh) { - /* free intermediate results */ - BKE_id_free(NULL, tmp); - } - } - if (mmd->flag & MOD_MIR_AXIS_Z) { - Mesh *tmp = result; - result = doMirrorOnAxis(mmd, ctx, ob, result, 2); - if (tmp != mesh) { - /* free intermediate results */ - BKE_id_free(NULL, tmp); - } - } - - return result; + Mesh *result = mesh; + + /* check which axes have been toggled and mirror accordingly */ + if (mmd->flag & MOD_MIR_AXIS_X) { + result = doMirrorOnAxis(mmd, ctx, ob, result, 0); + } + if (mmd->flag & MOD_MIR_AXIS_Y) { + Mesh *tmp = result; + result = doMirrorOnAxis(mmd, ctx, ob, result, 1); + if (tmp != mesh) { + /* free intermediate results */ + BKE_id_free(NULL, tmp); + } + } + if (mmd->flag & MOD_MIR_AXIS_Z) { + Mesh *tmp = result; + result = doMirrorOnAxis(mmd, ctx, ob, result, 2); + if (tmp != mesh) { + /* free intermediate results */ + BKE_id_free(NULL, tmp); + } + } + + return result; } -static Mesh *applyModifier( - ModifierData *md, const ModifierEvalContext *ctx, - Mesh *mesh) +static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) { - Mesh *result; - MirrorModifierData *mmd = (MirrorModifierData *) md; + Mesh *result; + MirrorModifierData *mmd = (MirrorModifierData *)md; - result = mirrorModifier__doMirror(mmd, ctx, ctx->object, mesh); + result = mirrorModifier__doMirror(mmd, ctx, ctx->object, mesh); - if (result != mesh) { - result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; - } - return result; + if (result != mesh) { + result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + } + return result; } - ModifierTypeInfo modifierType_Mirror = { - /* name */ "Mirror", - /* structName */ "MirrorModifierData", - /* structSize */ sizeof(MirrorModifierData), - /* type */ eModifierTypeType_Constructive, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_SupportsMapping | - eModifierTypeFlag_SupportsEditmode | - eModifierTypeFlag_EnableInEditmode | - eModifierTypeFlag_AcceptsCVs | - /* this is only the case when 'MOD_MIR_VGROUP' is used */ - eModifierTypeFlag_UsesPreview, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ initData, - /* requiredDataMask */ NULL, - /* freeData */ NULL, - /* isDisabled */ NULL, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ foreachObjectLink, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Mirror", + /* structName */ "MirrorModifierData", + /* structSize */ sizeof(MirrorModifierData), + /* type */ eModifierTypeType_Constructive, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping | + eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode | + eModifierTypeFlag_AcceptsCVs | + /* this is only the case when 'MOD_MIR_VGROUP' is used */ + eModifierTypeFlag_UsesPreview, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ initData, + /* requiredDataMask */ NULL, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c index a8760d05834..6e5426bbf40 100644 --- a/source/blender/modifiers/intern/MOD_multires.c +++ b/source/blender/modifiers/intern/MOD_multires.c @@ -21,7 +21,6 @@ * \ingroup modifiers */ - #include #include "MEM_guardedalloc.h" @@ -47,55 +46,54 @@ #include "MOD_modifiertypes.h" typedef struct MultiresRuntimeData { - /* Cached subdivision surface descriptor, with topology and settings. */ - struct Subdiv *subdiv; + /* Cached subdivision surface descriptor, with topology and settings. */ + struct Subdiv *subdiv; } MultiresRuntimeData; static void initData(ModifierData *md) { - MultiresModifierData *mmd = (MultiresModifierData *)md; - - mmd->lvl = 0; - mmd->sculptlvl = 0; - mmd->renderlvl = 0; - mmd->totlvl = 0; - mmd->uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS; - mmd->quality = 3; - mmd->flags |= eMultiresModifierFlag_UseCrease; + MultiresModifierData *mmd = (MultiresModifierData *)md; + + mmd->lvl = 0; + mmd->sculptlvl = 0; + mmd->renderlvl = 0; + mmd->totlvl = 0; + mmd->uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS; + mmd->quality = 3; + mmd->flags |= eMultiresModifierFlag_UseCrease; } static void copyData(const ModifierData *md_src, ModifierData *md_dst, const int flag) { - modifier_copyData_generic(md_src, md_dst, flag); + modifier_copyData_generic(md_src, md_dst, flag); } static void freeRuntimeData(void *runtime_data_v) { - if (runtime_data_v == NULL) { - return; - } - MultiresRuntimeData *runtime_data = (MultiresRuntimeData *)runtime_data_v; - if (runtime_data->subdiv != NULL) { - BKE_subdiv_free(runtime_data->subdiv); - } - MEM_freeN(runtime_data); + if (runtime_data_v == NULL) { + return; + } + MultiresRuntimeData *runtime_data = (MultiresRuntimeData *)runtime_data_v; + if (runtime_data->subdiv != NULL) { + BKE_subdiv_free(runtime_data->subdiv); + } + MEM_freeN(runtime_data); } static void freeData(ModifierData *md) { - MultiresModifierData *mmd = (MultiresModifierData *) md; - freeRuntimeData(mmd->modifier.runtime); + MultiresModifierData *mmd = (MultiresModifierData *)md; + freeRuntimeData(mmd->modifier.runtime); } static MultiresRuntimeData *multires_ensure_runtime(MultiresModifierData *mmd) { - MultiresRuntimeData *runtime_data = - (MultiresRuntimeData *)mmd->modifier.runtime; - if (runtime_data == NULL) { - runtime_data = MEM_callocN(sizeof(*runtime_data), "subsurf runtime"); - mmd->modifier.runtime = runtime_data; - } - return runtime_data; + MultiresRuntimeData *runtime_data = (MultiresRuntimeData *)mmd->modifier.runtime; + if (runtime_data == NULL) { + runtime_data = MEM_callocN(sizeof(*runtime_data), "subsurf runtime"); + mmd->modifier.runtime = runtime_data; + } + return runtime_data; } /* Main goal of this function is to give usable subdivision surface descriptor @@ -104,12 +102,10 @@ static Subdiv *subdiv_descriptor_ensure(MultiresModifierData *mmd, const SubdivSettings *subdiv_settings, const Mesh *mesh) { - MultiresRuntimeData *runtime_data = - (MultiresRuntimeData *)mmd->modifier.runtime; - Subdiv *subdiv = BKE_subdiv_update_from_mesh( - runtime_data->subdiv, subdiv_settings, mesh); - runtime_data->subdiv = subdiv; - return subdiv; + MultiresRuntimeData *runtime_data = (MultiresRuntimeData *)mmd->modifier.runtime; + Subdiv *subdiv = BKE_subdiv_update_from_mesh(runtime_data->subdiv, subdiv_settings, mesh); + runtime_data->subdiv = subdiv; + return subdiv; } /* Subdivide into fully qualified mesh. */ @@ -119,20 +115,20 @@ static Mesh *multires_as_mesh(MultiresModifierData *mmd, Mesh *mesh, Subdiv *subdiv) { - Mesh *result = mesh; - const bool use_render_params = (ctx->flag & MOD_APPLY_RENDER); - const bool ignore_simplify = (ctx->flag & MOD_APPLY_IGNORE_SIMPLIFY); - const Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); - Object *object = ctx->object; - SubdivToMeshSettings mesh_settings; - BKE_multires_subdiv_mesh_settings_init( - &mesh_settings, scene, object, mmd, use_render_params, ignore_simplify); - if (mesh_settings.resolution < 3) { - return result; - } - BKE_subdiv_displacement_attach_from_multires(subdiv, mesh, mmd); - result = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh); - return result; + Mesh *result = mesh; + const bool use_render_params = (ctx->flag & MOD_APPLY_RENDER); + const bool ignore_simplify = (ctx->flag & MOD_APPLY_IGNORE_SIMPLIFY); + const Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); + Object *object = ctx->object; + SubdivToMeshSettings mesh_settings; + BKE_multires_subdiv_mesh_settings_init( + &mesh_settings, scene, object, mmd, use_render_params, ignore_simplify); + if (mesh_settings.resolution < 3) { + return result; + } + BKE_subdiv_displacement_attach_from_multires(subdiv, mesh, mmd); + result = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh); + return result; } /* Subdivide into CCG. */ @@ -142,17 +138,15 @@ static void multires_ccg_settings_init(SubdivToCCGSettings *settings, const ModifierEvalContext *ctx, Mesh *mesh) { - const bool has_mask = - CustomData_has_layer(&mesh->ldata, CD_GRID_PAINT_MASK); - const bool use_render_params = (ctx->flag & MOD_APPLY_RENDER); - const bool ignore_simplify = (ctx->flag & MOD_APPLY_IGNORE_SIMPLIFY); - const Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); - Object *object = ctx->object; - const int level = multires_get_level( - scene, object, mmd, use_render_params, ignore_simplify); - settings->resolution = (1 << level) + 1; - settings->need_normal = true; - settings->need_mask = has_mask; + const bool has_mask = CustomData_has_layer(&mesh->ldata, CD_GRID_PAINT_MASK); + const bool use_render_params = (ctx->flag & MOD_APPLY_RENDER); + const bool ignore_simplify = (ctx->flag & MOD_APPLY_IGNORE_SIMPLIFY); + const Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); + Object *object = ctx->object; + const int level = multires_get_level(scene, object, mmd, use_render_params, ignore_simplify); + settings->resolution = (1 << level) + 1; + settings->need_normal = true; + settings->need_mask = has_mask; } static Mesh *multires_as_ccg(MultiresModifierData *mmd, @@ -160,93 +154,90 @@ static Mesh *multires_as_ccg(MultiresModifierData *mmd, Mesh *mesh, Subdiv *subdiv) { - Mesh *result = mesh; - SubdivToCCGSettings ccg_settings; - multires_ccg_settings_init(&ccg_settings, mmd, ctx, mesh); - if (ccg_settings.resolution < 3) { - return result; - } - BKE_subdiv_displacement_attach_from_multires(subdiv, mesh, mmd); - result = BKE_subdiv_to_ccg_mesh(subdiv, &ccg_settings, mesh); - return result; + Mesh *result = mesh; + SubdivToCCGSettings ccg_settings; + multires_ccg_settings_init(&ccg_settings, mmd, ctx, mesh); + if (ccg_settings.resolution < 3) { + return result; + } + BKE_subdiv_displacement_attach_from_multires(subdiv, mesh, mmd); + result = BKE_subdiv_to_ccg_mesh(subdiv, &ccg_settings, mesh); + return result; } -static Mesh *applyModifier(ModifierData *md, - const ModifierEvalContext *ctx, - Mesh *mesh) +static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) { - Mesh *result = mesh; - MultiresModifierData *mmd = (MultiresModifierData *)md; - SubdivSettings subdiv_settings; - BKE_multires_subdiv_settings_init(&subdiv_settings, mmd); - if (subdiv_settings.level == 0) { - return result; - } - BKE_subdiv_settings_validate_for_mesh(&subdiv_settings, mesh); - MultiresRuntimeData *runtime_data = multires_ensure_runtime(mmd); - Subdiv *subdiv = subdiv_descriptor_ensure(mmd, &subdiv_settings, mesh); - if (subdiv == NULL) { - /* Happens on bad topology, ut also on empty input mesh. */ - return result; - } - /* NOTE: Orco needs final coordinates on CPU side, which are expected to be - * accessible via MVert. For this reason we do not evaluate multires to - * grids when orco is requested. */ - const bool for_orco = (ctx->flag & MOD_APPLY_ORCO) != 0; - if ((ctx->object->mode & OB_MODE_SCULPT) && !for_orco) { - /* NOTE: CCG takes ownership over Subdiv. */ - result = multires_as_ccg(mmd, ctx, mesh, subdiv); - result->runtime.subdiv_ccg_tot_level = mmd->totlvl; - /* TODO(sergey): Usually it is sculpt stroke's update variants which - * takes care of this, but is possible that we need this before the - * stroke: i.e. when exiting blender right after stroke is done. - * Annoying and not so much black-boxed as far as sculpting goes, and - * surely there is a better way of solving this. */ - if (ctx->object->sculpt != NULL) { - ctx->object->sculpt->subdiv_ccg = result->runtime.subdiv_ccg; - } - /* NOTE: CCG becomes an owner of Subdiv descriptor, so can not share - * this pointer. Not sure if it's needed, but might have a second look - * on the ownership model here. */ - runtime_data->subdiv = NULL; - // BKE_subdiv_stats_print(&subdiv->stats); - } - else { - result = multires_as_mesh(mmd, ctx, mesh, subdiv); - // BKE_subdiv_stats_print(&subdiv->stats); - if (subdiv != runtime_data->subdiv) { - BKE_subdiv_free(subdiv); - } - } - return result; + Mesh *result = mesh; + MultiresModifierData *mmd = (MultiresModifierData *)md; + SubdivSettings subdiv_settings; + BKE_multires_subdiv_settings_init(&subdiv_settings, mmd); + if (subdiv_settings.level == 0) { + return result; + } + BKE_subdiv_settings_validate_for_mesh(&subdiv_settings, mesh); + MultiresRuntimeData *runtime_data = multires_ensure_runtime(mmd); + Subdiv *subdiv = subdiv_descriptor_ensure(mmd, &subdiv_settings, mesh); + if (subdiv == NULL) { + /* Happens on bad topology, ut also on empty input mesh. */ + return result; + } + /* NOTE: Orco needs final coordinates on CPU side, which are expected to be + * accessible via MVert. For this reason we do not evaluate multires to + * grids when orco is requested. */ + const bool for_orco = (ctx->flag & MOD_APPLY_ORCO) != 0; + if ((ctx->object->mode & OB_MODE_SCULPT) && !for_orco) { + /* NOTE: CCG takes ownership over Subdiv. */ + result = multires_as_ccg(mmd, ctx, mesh, subdiv); + result->runtime.subdiv_ccg_tot_level = mmd->totlvl; + /* TODO(sergey): Usually it is sculpt stroke's update variants which + * takes care of this, but is possible that we need this before the + * stroke: i.e. when exiting blender right after stroke is done. + * Annoying and not so much black-boxed as far as sculpting goes, and + * surely there is a better way of solving this. */ + if (ctx->object->sculpt != NULL) { + ctx->object->sculpt->subdiv_ccg = result->runtime.subdiv_ccg; + } + /* NOTE: CCG becomes an owner of Subdiv descriptor, so can not share + * this pointer. Not sure if it's needed, but might have a second look + * on the ownership model here. */ + runtime_data->subdiv = NULL; + // BKE_subdiv_stats_print(&subdiv->stats); + } + else { + result = multires_as_mesh(mmd, ctx, mesh, subdiv); + // BKE_subdiv_stats_print(&subdiv->stats); + if (subdiv != runtime_data->subdiv) { + BKE_subdiv_free(subdiv); + } + } + return result; } ModifierTypeInfo modifierType_Multires = { - /* name */ "Multires", - /* structName */ "MultiresModifierData", - /* structSize */ sizeof(MultiresModifierData), - /* type */ eModifierTypeType_Constructive, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_SupportsMapping | - eModifierTypeFlag_RequiresOriginalData, - - /* copyData */ copyData, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ initData, - /* requiredDataMask */ NULL, - /* freeData */ freeData, - /* isDisabled */ NULL, - /* updateDepsgraph */ NULL, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ NULL, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ freeRuntimeData, + /* name */ "Multires", + /* structName */ "MultiresModifierData", + /* structSize */ sizeof(MultiresModifierData), + /* type */ eModifierTypeType_Constructive, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping | + eModifierTypeFlag_RequiresOriginalData, + + /* copyData */ copyData, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ initData, + /* requiredDataMask */ NULL, + /* freeData */ freeData, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ freeRuntimeData, }; diff --git a/source/blender/modifiers/intern/MOD_none.c b/source/blender/modifiers/intern/MOD_none.c index 749c329b3b6..9be422afab9 100644 --- a/source/blender/modifiers/intern/MOD_none.c +++ b/source/blender/modifiers/intern/MOD_none.c @@ -31,36 +31,37 @@ * no other functions will be called */ -static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *UNUSED(md), bool UNUSED(userRenderParams)) +static bool isDisabled(const struct Scene *UNUSED(scene), + ModifierData *UNUSED(md), + bool UNUSED(userRenderParams)) { - return true; + return true; } ModifierTypeInfo modifierType_None = { - /* name */ "None", - /* structName */ "ModifierData", - /* structSize */ sizeof(ModifierData), - /* type */ eModifierTypeType_None, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_AcceptsCVs, + /* name */ "None", + /* structName */ "ModifierData", + /* structSize */ sizeof(ModifierData), + /* type */ eModifierTypeType_None, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs, - /* copyData */ NULL, + /* copyData */ NULL, - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ NULL, + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ NULL, - /* initData */ NULL, - /* requiredDataMask */ NULL, - /* freeData */ NULL, - /* isDisabled */ isDisabled, - /* updateDepsgraph */ NULL, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ NULL, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* initData */ NULL, + /* requiredDataMask */ NULL, + /* freeData */ NULL, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c index 2a8bca895be..0c5b260eadc 100644 --- a/source/blender/modifiers/intern/MOD_normal_edit.c +++ b/source/blender/modifiers/intern/MOD_normal_edit.c @@ -40,537 +40,672 @@ #include "MOD_util.h" - -static void generate_vert_coordinates( - Mesh *mesh, Object *ob, Object *ob_center, const float offset[3], - const int num_verts, float (*r_cos)[3], float r_size[3]) +static void generate_vert_coordinates(Mesh *mesh, + Object *ob, + Object *ob_center, + const float offset[3], + const int num_verts, + float (*r_cos)[3], + float r_size[3]) { - float min_co[3], max_co[3]; - float diff[3]; - bool do_diff = false; - - INIT_MINMAX(min_co, max_co); - - MVert *mv = mesh->mvert; - for (int i = 0; i < mesh->totvert; i++, mv++) { - copy_v3_v3(r_cos[i], mv->co); - if (r_size != NULL && ob_center == NULL) { - minmax_v3v3_v3(min_co, max_co, r_cos[i]); - } - } - - /* Get size (i.e. deformation of the spheroid generating normals), either from target object, or own geometry. */ - if (r_size != NULL) { - if (ob_center != NULL) { - /* Using 'scale' as 'size' here. The input object is typically an empty - * who's scale is used to define an ellipsoid instead of a simple sphere. */ - - /* Not we are not interested in signs here - they are even troublesome actually, due to security clamping! */ - abs_v3_v3(r_size, ob_center->scale); - } - else { - /* Set size. */ - sub_v3_v3v3(r_size, max_co, min_co); - } - - /* Error checks - we do not want one or more of our sizes to be null! */ - if (is_zero_v3(r_size)) { - r_size[0] = r_size[1] = r_size[2] = 1.0f; - } - else { - CLAMP_MIN(r_size[0], FLT_EPSILON); - CLAMP_MIN(r_size[1], FLT_EPSILON); - CLAMP_MIN(r_size[2], FLT_EPSILON); - } - } - - if (ob_center != NULL) { - float inv_obmat[4][4]; - - /* Translate our coordinates so that center of ob_center is at (0, 0, 0). */ - /* Get ob_center (world) coordinates in ob local coordinates. - * No need to take into account ob_center's space here, see T44027. */ - invert_m4_m4(inv_obmat, ob->obmat); - mul_v3_m4v3(diff, inv_obmat, ob_center->obmat[3]); - negate_v3(diff); - - do_diff = true; - } - else if (offset != NULL && !is_zero_v3(offset)) { - negate_v3_v3(diff, offset); - - do_diff = true; - } - /* Else, no need to change coordinates! */ - - if (do_diff) { - int i = num_verts; - while (i--) { - add_v3_v3(r_cos[i], diff); - } - } + float min_co[3], max_co[3]; + float diff[3]; + bool do_diff = false; + + INIT_MINMAX(min_co, max_co); + + MVert *mv = mesh->mvert; + for (int i = 0; i < mesh->totvert; i++, mv++) { + copy_v3_v3(r_cos[i], mv->co); + if (r_size != NULL && ob_center == NULL) { + minmax_v3v3_v3(min_co, max_co, r_cos[i]); + } + } + + /* Get size (i.e. deformation of the spheroid generating normals), either from target object, or own geometry. */ + if (r_size != NULL) { + if (ob_center != NULL) { + /* Using 'scale' as 'size' here. The input object is typically an empty + * who's scale is used to define an ellipsoid instead of a simple sphere. */ + + /* Not we are not interested in signs here - they are even troublesome actually, due to security clamping! */ + abs_v3_v3(r_size, ob_center->scale); + } + else { + /* Set size. */ + sub_v3_v3v3(r_size, max_co, min_co); + } + + /* Error checks - we do not want one or more of our sizes to be null! */ + if (is_zero_v3(r_size)) { + r_size[0] = r_size[1] = r_size[2] = 1.0f; + } + else { + CLAMP_MIN(r_size[0], FLT_EPSILON); + CLAMP_MIN(r_size[1], FLT_EPSILON); + CLAMP_MIN(r_size[2], FLT_EPSILON); + } + } + + if (ob_center != NULL) { + float inv_obmat[4][4]; + + /* Translate our coordinates so that center of ob_center is at (0, 0, 0). */ + /* Get ob_center (world) coordinates in ob local coordinates. + * No need to take into account ob_center's space here, see T44027. */ + invert_m4_m4(inv_obmat, ob->obmat); + mul_v3_m4v3(diff, inv_obmat, ob_center->obmat[3]); + negate_v3(diff); + + do_diff = true; + } + else if (offset != NULL && !is_zero_v3(offset)) { + negate_v3_v3(diff, offset); + + do_diff = true; + } + /* Else, no need to change coordinates! */ + + if (do_diff) { + int i = num_verts; + while (i--) { + add_v3_v3(r_cos[i], diff); + } + } } /* Note this modifies nos_new in-place. */ -static void mix_normals( - const float mix_factor, MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup, - const float mix_limit, const short mix_mode, - const int num_verts, MLoop *mloop, float (*nos_old)[3], float (*nos_new)[3], const int num_loops) +static void mix_normals(const float mix_factor, + MDeformVert *dvert, + const int defgrp_index, + const bool use_invert_vgroup, + const float mix_limit, + const short mix_mode, + const int num_verts, + MLoop *mloop, + float (*nos_old)[3], + float (*nos_new)[3], + const int num_loops) { - /* Mix with org normals... */ - float *facs = NULL, *wfac; - float (*no_new)[3], (*no_old)[3]; - int i; - - if (dvert) { - facs = MEM_malloc_arrayN((size_t)num_loops, sizeof(*facs), __func__); - BKE_defvert_extract_vgroup_to_loopweights( - dvert, defgrp_index, num_verts, mloop, num_loops, facs, use_invert_vgroup); - } - - for (i = num_loops, no_new = nos_new, no_old = nos_old, wfac = facs; i--; no_new++, no_old++, wfac++) { - const float fac = facs ? *wfac * mix_factor : mix_factor; - - switch (mix_mode) { - case MOD_NORMALEDIT_MIX_ADD: - add_v3_v3(*no_new, *no_old); - normalize_v3(*no_new); - break; - case MOD_NORMALEDIT_MIX_SUB: - sub_v3_v3(*no_new, *no_old); - normalize_v3(*no_new); - break; - case MOD_NORMALEDIT_MIX_MUL: - mul_v3_v3(*no_new, *no_old); - normalize_v3(*no_new); - break; - case MOD_NORMALEDIT_MIX_COPY: - break; - } - - interp_v3_v3v3_slerp_safe( - *no_new, *no_old, *no_new, - (mix_limit < (float)M_PI) ? min_ff(fac, mix_limit / angle_v3v3(*no_new, *no_old)) : fac); - } - - MEM_SAFE_FREE(facs); + /* Mix with org normals... */ + float *facs = NULL, *wfac; + float(*no_new)[3], (*no_old)[3]; + int i; + + if (dvert) { + facs = MEM_malloc_arrayN((size_t)num_loops, sizeof(*facs), __func__); + BKE_defvert_extract_vgroup_to_loopweights( + dvert, defgrp_index, num_verts, mloop, num_loops, facs, use_invert_vgroup); + } + + for (i = num_loops, no_new = nos_new, no_old = nos_old, wfac = facs; i--; + no_new++, no_old++, wfac++) { + const float fac = facs ? *wfac * mix_factor : mix_factor; + + switch (mix_mode) { + case MOD_NORMALEDIT_MIX_ADD: + add_v3_v3(*no_new, *no_old); + normalize_v3(*no_new); + break; + case MOD_NORMALEDIT_MIX_SUB: + sub_v3_v3(*no_new, *no_old); + normalize_v3(*no_new); + break; + case MOD_NORMALEDIT_MIX_MUL: + mul_v3_v3(*no_new, *no_old); + normalize_v3(*no_new); + break; + case MOD_NORMALEDIT_MIX_COPY: + break; + } + + interp_v3_v3v3_slerp_safe( + *no_new, + *no_old, + *no_new, + (mix_limit < (float)M_PI) ? min_ff(fac, mix_limit / angle_v3v3(*no_new, *no_old)) : fac); + } + + MEM_SAFE_FREE(facs); } /* Check poly normals and new loop normals are compatible, otherwise flip polygons * (and invert matching poly normals). */ -static bool polygons_check_flip( - MLoop *mloop, float (*nos)[3], CustomData *ldata, - MPoly *mpoly, float (*polynors)[3], const int num_polys) +static bool polygons_check_flip(MLoop *mloop, + float (*nos)[3], + CustomData *ldata, + MPoly *mpoly, + float (*polynors)[3], + const int num_polys) { - MPoly *mp; - MDisps *mdisp = CustomData_get_layer(ldata, CD_MDISPS); - int i; - bool flipped = false; - - for (i = 0, mp = mpoly; i < num_polys; i++, mp++) { - float norsum[3] = {0.0f}; - float (*no)[3]; - int j; - - for (j = 0, no = &nos[mp->loopstart]; j < mp->totloop; j++, no++) { - add_v3_v3(norsum, *no); - } - - if (!normalize_v3(norsum)) { - continue; - } - - /* If average of new loop normals is opposed to polygon normal, flip polygon. */ - if (dot_v3v3(polynors[i], norsum) < 0.0f) { - BKE_mesh_polygon_flip_ex(mp, mloop, ldata, nos, mdisp, true); - negate_v3(polynors[i]); - flipped = true; - } - } - - return flipped; + MPoly *mp; + MDisps *mdisp = CustomData_get_layer(ldata, CD_MDISPS); + int i; + bool flipped = false; + + for (i = 0, mp = mpoly; i < num_polys; i++, mp++) { + float norsum[3] = {0.0f}; + float(*no)[3]; + int j; + + for (j = 0, no = &nos[mp->loopstart]; j < mp->totloop; j++, no++) { + add_v3_v3(norsum, *no); + } + + if (!normalize_v3(norsum)) { + continue; + } + + /* If average of new loop normals is opposed to polygon normal, flip polygon. */ + if (dot_v3v3(polynors[i], norsum) < 0.0f) { + BKE_mesh_polygon_flip_ex(mp, mloop, ldata, nos, mdisp, true); + negate_v3(polynors[i]); + flipped = true; + } + } + + return flipped; } -static void normalEditModifier_do_radial( - NormalEditModifierData *enmd, const ModifierEvalContext *UNUSED(ctx), - Object *ob, Mesh *mesh, - short (*clnors)[2], float (*loopnors)[3], float (*polynors)[3], - const short mix_mode, const float mix_factor, const float mix_limit, - MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup, - MVert *mvert, const int num_verts, MEdge *medge, const int num_edges, - MLoop *mloop, const int num_loops, MPoly *mpoly, const int num_polys) +static void normalEditModifier_do_radial(NormalEditModifierData *enmd, + const ModifierEvalContext *UNUSED(ctx), + Object *ob, + Mesh *mesh, + short (*clnors)[2], + float (*loopnors)[3], + float (*polynors)[3], + const short mix_mode, + const float mix_factor, + const float mix_limit, + MDeformVert *dvert, + const int defgrp_index, + const bool use_invert_vgroup, + MVert *mvert, + const int num_verts, + MEdge *medge, + const int num_edges, + MLoop *mloop, + const int num_loops, + MPoly *mpoly, + const int num_polys) { - Object *ob_target = enmd->target; - - const bool do_polynors_fix = (enmd->flag & MOD_NORMALEDIT_NO_POLYNORS_FIX) == 0; - int i; - - float (*cos)[3] = MEM_malloc_arrayN((size_t)num_verts, sizeof(*cos), __func__); - float (*nos)[3] = MEM_malloc_arrayN((size_t)num_loops, sizeof(*nos), __func__); - float size[3]; - - BLI_bitmap *done_verts = BLI_BITMAP_NEW((size_t)num_verts, __func__); - - generate_vert_coordinates(mesh, ob, ob_target, enmd->offset, num_verts, cos, size); - - /** - * size gives us our spheroid coefficients ``(A, B, C)``. - * Then, we want to find out for each vert its (a, b, c) triple (proportional to (A, B, C) one). - * - * Ellipsoid basic equation: ``(x^2/a^2) + (y^2/b^2) + (z^2/c^2) = 1.`` - * Since we want to find (a, b, c) matching this equation and proportional to (A, B, C), we can do: - *
-	 *     m = B / A
-	 *     n = C / A
-	 * 
- * - * hence: - *
-	 *     (x^2/a^2) + (y^2/b^2) + (z^2/c^2) = 1
-	 *  -> b^2*c^2*x^2 + a^2*c^2*y^2 + a^2*b^2*z^2 = a^2*b^2*c^2
-	 *     b = ma
-	 *     c = na
-	 *  -> m^2*a^2*n^2*a^2*x^2 + a^2*n^2*a^2*y^2 + a^2*m^2*a^2*z^2 = a^2*m^2*a^2*n^2*a^2
-	 *  -> m^2*n^2*a^4*x^2 + n^2*a^4*y^2 + m^2*a^4*z^2 = m^2*n^2*a^6
-	 *  -> a^2 = (m^2*n^2*x^2 + n^2y^2 + m^2z^2) / (m^2*n^2) = x^2 + (y^2 / m^2) + (z^2 / n^2)
-	 *  -> b^2 = (m^2*n^2*x^2 + n^2y^2 + m^2z^2) / (n^2)     = (m^2 * x^2) + y^2 + (m^2 * z^2 / n^2)
-	 *  -> c^2 = (m^2*n^2*x^2 + n^2y^2 + m^2z^2) / (m^2)     = (n^2 * x^2) + (n^2 * y^2 / m^2) + z^2
-	 * 
- * - * All we have to do now is compute normal of the spheroid at that point: - *
-	 *     n = (x / a^2, y / b^2, z / c^2)
-	 * 
- * And we are done! - */ - { - const float a = size[0], b = size[1], c = size[2]; - const float m2 = (b * b) / (a * a); - const float n2 = (c * c) / (a * a); - - MLoop *ml; - float (*no)[3]; - - /* We reuse cos to now store the ellipsoid-normal of the verts! */ - for (i = num_loops, ml = mloop, no = nos; i-- ; ml++, no++) { - const int vidx = ml->v; - float *co = cos[vidx]; - - if (!BLI_BITMAP_TEST(done_verts, vidx)) { - const float x2 = co[0] * co[0]; - const float y2 = co[1] * co[1]; - const float z2 = co[2] * co[2]; - const float a2 = x2 + (y2 / m2) + (z2 / n2); - const float b2 = (m2 * x2) + y2 + (m2 * z2 / n2); - const float c2 = (n2 * x2) + (n2 * y2 / m2) + z2; - - co[0] /= a2; - co[1] /= b2; - co[2] /= c2; - normalize_v3(co); - - BLI_BITMAP_ENABLE(done_verts, vidx); - } - copy_v3_v3(*no, co); - } - } - - if (loopnors) { - mix_normals(mix_factor, dvert, defgrp_index, use_invert_vgroup, - mix_limit, mix_mode, num_verts, mloop, loopnors, nos, num_loops); - } - - if (do_polynors_fix && polygons_check_flip(mloop, nos, &mesh->ldata, mpoly, polynors, num_polys)) { - /* XXX TODO is this still needed? */ - // mesh->dirty |= DM_DIRTY_TESS_CDLAYERS; - /* We need to recompute vertex normals! */ - BKE_mesh_calc_normals(mesh); - } - - BKE_mesh_normals_loop_custom_set(mvert, num_verts, medge, num_edges, mloop, nos, num_loops, - mpoly, (const float(*)[3])polynors, num_polys, clnors); - - MEM_freeN(cos); - MEM_freeN(nos); - MEM_freeN(done_verts); + Object *ob_target = enmd->target; + + const bool do_polynors_fix = (enmd->flag & MOD_NORMALEDIT_NO_POLYNORS_FIX) == 0; + int i; + + float(*cos)[3] = MEM_malloc_arrayN((size_t)num_verts, sizeof(*cos), __func__); + float(*nos)[3] = MEM_malloc_arrayN((size_t)num_loops, sizeof(*nos), __func__); + float size[3]; + + BLI_bitmap *done_verts = BLI_BITMAP_NEW((size_t)num_verts, __func__); + + generate_vert_coordinates(mesh, ob, ob_target, enmd->offset, num_verts, cos, size); + + /** + * size gives us our spheroid coefficients ``(A, B, C)``. + * Then, we want to find out for each vert its (a, b, c) triple (proportional to (A, B, C) one). + * + * Ellipsoid basic equation: ``(x^2/a^2) + (y^2/b^2) + (z^2/c^2) = 1.`` + * Since we want to find (a, b, c) matching this equation and proportional to (A, B, C), we can do: + *
+   *     m = B / A
+   *     n = C / A
+   * 
+ * + * hence: + *
+   *     (x^2/a^2) + (y^2/b^2) + (z^2/c^2) = 1
+   *  -> b^2*c^2*x^2 + a^2*c^2*y^2 + a^2*b^2*z^2 = a^2*b^2*c^2
+   *     b = ma
+   *     c = na
+   *  -> m^2*a^2*n^2*a^2*x^2 + a^2*n^2*a^2*y^2 + a^2*m^2*a^2*z^2 = a^2*m^2*a^2*n^2*a^2
+   *  -> m^2*n^2*a^4*x^2 + n^2*a^4*y^2 + m^2*a^4*z^2 = m^2*n^2*a^6
+   *  -> a^2 = (m^2*n^2*x^2 + n^2y^2 + m^2z^2) / (m^2*n^2) = x^2 + (y^2 / m^2) + (z^2 / n^2)
+   *  -> b^2 = (m^2*n^2*x^2 + n^2y^2 + m^2z^2) / (n^2)     = (m^2 * x^2) + y^2 + (m^2 * z^2 / n^2)
+   *  -> c^2 = (m^2*n^2*x^2 + n^2y^2 + m^2z^2) / (m^2)     = (n^2 * x^2) + (n^2 * y^2 / m^2) + z^2
+   * 
+ * + * All we have to do now is compute normal of the spheroid at that point: + *
+   *     n = (x / a^2, y / b^2, z / c^2)
+   * 
+ * And we are done! + */ + { + const float a = size[0], b = size[1], c = size[2]; + const float m2 = (b * b) / (a * a); + const float n2 = (c * c) / (a * a); + + MLoop *ml; + float(*no)[3]; + + /* We reuse cos to now store the ellipsoid-normal of the verts! */ + for (i = num_loops, ml = mloop, no = nos; i--; ml++, no++) { + const int vidx = ml->v; + float *co = cos[vidx]; + + if (!BLI_BITMAP_TEST(done_verts, vidx)) { + const float x2 = co[0] * co[0]; + const float y2 = co[1] * co[1]; + const float z2 = co[2] * co[2]; + const float a2 = x2 + (y2 / m2) + (z2 / n2); + const float b2 = (m2 * x2) + y2 + (m2 * z2 / n2); + const float c2 = (n2 * x2) + (n2 * y2 / m2) + z2; + + co[0] /= a2; + co[1] /= b2; + co[2] /= c2; + normalize_v3(co); + + BLI_BITMAP_ENABLE(done_verts, vidx); + } + copy_v3_v3(*no, co); + } + } + + if (loopnors) { + mix_normals(mix_factor, + dvert, + defgrp_index, + use_invert_vgroup, + mix_limit, + mix_mode, + num_verts, + mloop, + loopnors, + nos, + num_loops); + } + + if (do_polynors_fix && + polygons_check_flip(mloop, nos, &mesh->ldata, mpoly, polynors, num_polys)) { + /* XXX TODO is this still needed? */ + // mesh->dirty |= DM_DIRTY_TESS_CDLAYERS; + /* We need to recompute vertex normals! */ + BKE_mesh_calc_normals(mesh); + } + + BKE_mesh_normals_loop_custom_set(mvert, + num_verts, + medge, + num_edges, + mloop, + nos, + num_loops, + mpoly, + (const float(*)[3])polynors, + num_polys, + clnors); + + MEM_freeN(cos); + MEM_freeN(nos); + MEM_freeN(done_verts); } -static void normalEditModifier_do_directional( - NormalEditModifierData *enmd, const ModifierEvalContext *UNUSED(ctx), - Object *ob, Mesh *mesh, - short (*clnors)[2], float (*loopnors)[3], float (*polynors)[3], - const short mix_mode, const float mix_factor, const float mix_limit, - MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup, - MVert *mvert, const int num_verts, MEdge *medge, const int num_edges, - MLoop *mloop, const int num_loops, MPoly *mpoly, const int num_polys) +static void normalEditModifier_do_directional(NormalEditModifierData *enmd, + const ModifierEvalContext *UNUSED(ctx), + Object *ob, + Mesh *mesh, + short (*clnors)[2], + float (*loopnors)[3], + float (*polynors)[3], + const short mix_mode, + const float mix_factor, + const float mix_limit, + MDeformVert *dvert, + const int defgrp_index, + const bool use_invert_vgroup, + MVert *mvert, + const int num_verts, + MEdge *medge, + const int num_edges, + MLoop *mloop, + const int num_loops, + MPoly *mpoly, + const int num_polys) { - Object *ob_target = enmd->target; - - const bool do_polynors_fix = (enmd->flag & MOD_NORMALEDIT_NO_POLYNORS_FIX) == 0; - const bool use_parallel_normals = (enmd->flag & MOD_NORMALEDIT_USE_DIRECTION_PARALLEL) != 0; - - float (*nos)[3] = MEM_malloc_arrayN((size_t)num_loops, sizeof(*nos), __func__); - - float target_co[3]; - int i; - - /* Get target's center coordinates in ob local coordinates. */ - float mat[4][4]; - - invert_m4_m4(mat, ob->obmat); - mul_m4_m4m4(mat, mat, ob_target->obmat); - copy_v3_v3(target_co, mat[3]); - - if (use_parallel_normals) { - float no[3]; - - sub_v3_v3v3(no, target_co, enmd->offset); - normalize_v3(no); - - for (i = num_loops; i--; ) { - copy_v3_v3(nos[i], no); - } - } - else { - float (*cos)[3] = MEM_malloc_arrayN((size_t)num_verts, sizeof(*cos), __func__); - generate_vert_coordinates(mesh, ob, ob_target, NULL, num_verts, cos, NULL); + Object *ob_target = enmd->target; + + const bool do_polynors_fix = (enmd->flag & MOD_NORMALEDIT_NO_POLYNORS_FIX) == 0; + const bool use_parallel_normals = (enmd->flag & MOD_NORMALEDIT_USE_DIRECTION_PARALLEL) != 0; + + float(*nos)[3] = MEM_malloc_arrayN((size_t)num_loops, sizeof(*nos), __func__); + + float target_co[3]; + int i; + + /* Get target's center coordinates in ob local coordinates. */ + float mat[4][4]; + + invert_m4_m4(mat, ob->obmat); + mul_m4_m4m4(mat, mat, ob_target->obmat); + copy_v3_v3(target_co, mat[3]); + + if (use_parallel_normals) { + float no[3]; + + sub_v3_v3v3(no, target_co, enmd->offset); + normalize_v3(no); + + for (i = num_loops; i--;) { + copy_v3_v3(nos[i], no); + } + } + else { + float(*cos)[3] = MEM_malloc_arrayN((size_t)num_verts, sizeof(*cos), __func__); + generate_vert_coordinates(mesh, ob, ob_target, NULL, num_verts, cos, NULL); + + BLI_bitmap *done_verts = BLI_BITMAP_NEW((size_t)num_verts, __func__); + MLoop *ml; + float(*no)[3]; + + /* We reuse cos to now store the 'to target' normal of the verts! */ + for (i = num_loops, no = nos, ml = mloop; i--; no++, ml++) { + const int vidx = ml->v; + float *co = cos[vidx]; + + if (!BLI_BITMAP_TEST(done_verts, vidx)) { + sub_v3_v3v3(co, target_co, co); + normalize_v3(co); + + BLI_BITMAP_ENABLE(done_verts, vidx); + } + + copy_v3_v3(*no, co); + } + + MEM_freeN(done_verts); + MEM_freeN(cos); + } + + if (loopnors) { + mix_normals(mix_factor, + dvert, + defgrp_index, + use_invert_vgroup, + mix_limit, + mix_mode, + num_verts, + mloop, + loopnors, + nos, + num_loops); + } + + if (do_polynors_fix && + polygons_check_flip(mloop, nos, &mesh->ldata, mpoly, polynors, num_polys)) { + mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + } + + BKE_mesh_normals_loop_custom_set(mvert, + num_verts, + medge, + num_edges, + mloop, + nos, + num_loops, + mpoly, + (const float(*)[3])polynors, + num_polys, + clnors); + + MEM_freeN(nos); +} - BLI_bitmap *done_verts = BLI_BITMAP_NEW((size_t)num_verts, __func__); - MLoop *ml; - float (*no)[3]; +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; +} - /* We reuse cos to now store the 'to target' normal of the verts! */ - for (i = num_loops, no = nos, ml = mloop; i--; no++, ml++) { - const int vidx = ml->v; - float *co = cos[vidx]; +static Mesh *normalEditModifier_do(NormalEditModifierData *enmd, + const ModifierEvalContext *ctx, + Object *ob, + Mesh *mesh) +{ + 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)); + + /* Do not run that modifier at all if autosmooth is disabled! */ + if (!is_valid_target(enmd) || mesh->totloop == 0) { + return mesh; + } + + /* XXX TODO ARG GRRR XYQWNMPRXTYY + * Once we fully switch to Mesh evaluation of modifiers, we can expect to get that flag from the COW copy. + * But for now, it is lost in the DM intermediate step, so we need to directly check orig object's data. */ +#if 0 + if (!(mesh->flag & ME_AUTOSMOOTH)) { +#else + if (!(((Mesh *)ob->data)->flag & ME_AUTOSMOOTH)) { +#endif + modifier_setError((ModifierData *)enmd, "Enable 'Auto Smooth' option in mesh settings"); + return mesh; +} - if (!BLI_BITMAP_TEST(done_verts, vidx)) { - sub_v3_v3v3(co, target_co, co); - normalize_v3(co); +Mesh *result; +if (mesh->medge == ((Mesh *)ob->data)->medge) { + /* We need to duplicate data here, otherwise setting custom normals (which may also affect sharp edges) could + * modify org mesh, see T43671. */ + BKE_id_copy_ex(NULL, &mesh->id, (ID **)&result, LIB_ID_COPY_LOCALIZE); +} +else { + result = mesh; +} - BLI_BITMAP_ENABLE(done_verts, vidx); - } +const int num_verts = result->totvert; +const int num_edges = result->totedge; +const int num_loops = result->totloop; +const int num_polys = result->totpoly; +MVert *mvert = result->mvert; +MEdge *medge = result->medge; +MLoop *mloop = result->mloop; +MPoly *mpoly = result->mpoly; - copy_v3_v3(*no, co); - } +int defgrp_index; +MDeformVert *dvert; - MEM_freeN(done_verts); - MEM_freeN(cos); - } +float (*loopnors)[3] = NULL; +short (*clnors)[2] = NULL; - if (loopnors) { - mix_normals(mix_factor, dvert, defgrp_index, use_invert_vgroup, - mix_limit, mix_mode, num_verts, mloop, loopnors, nos, num_loops); - } +float (*polynors)[3]; - if (do_polynors_fix && polygons_check_flip(mloop, nos, &mesh->ldata, mpoly, polynors, num_polys)) { - mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL; - } +CustomData *ldata = &result->ldata; +if (CustomData_has_layer(ldata, CD_NORMAL)) { + loopnors = CustomData_get_layer(ldata, CD_NORMAL); +} +else { + loopnors = CustomData_add_layer(ldata, CD_NORMAL, CD_CALLOC, NULL, num_loops); +} - BKE_mesh_normals_loop_custom_set(mvert, num_verts, medge, num_edges, mloop, nos, num_loops, - mpoly, (const float(*)[3])polynors, num_polys, clnors); +/* Compute poly (always needed) and vert normals. */ +CustomData *pdata = &result->pdata; +polynors = CustomData_get_layer(pdata, CD_NORMAL); +if (!polynors) { + polynors = CustomData_add_layer(pdata, CD_NORMAL, CD_CALLOC, NULL, num_polys); +} +BKE_mesh_calc_normals_poly(mvert, + NULL, + num_verts, + mloop, + mpoly, + num_loops, + num_polys, + polynors, + (result->runtime.cd_dirty_vert & CD_MASK_NORMAL) ? false : true); + +result->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL; + +if (use_current_clnors) { + clnors = CustomData_duplicate_referenced_layer(ldata, CD_CUSTOMLOOPNORMAL, num_loops); + + BKE_mesh_normals_loop_split(mvert, + num_verts, + medge, + num_edges, + mloop, + loopnors, + num_loops, + mpoly, + (const float(*)[3])polynors, + num_polys, + true, + result->smoothresh, + NULL, + clnors, + NULL); +} - MEM_freeN(nos); +if (!clnors) { + clnors = CustomData_add_layer(ldata, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL, num_loops); } -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; +MOD_get_vgroup(ob, result, enmd->defgrp_name, &dvert, &defgrp_index); + +if (enmd->mode == MOD_NORMALEDIT_MODE_RADIAL) { + normalEditModifier_do_radial(enmd, + ctx, + ob, + result, + 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, + ctx, + ob, + result, + 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); } -static Mesh *normalEditModifier_do( - NormalEditModifierData *enmd, const ModifierEvalContext *ctx, Object *ob, Mesh *mesh) -{ - 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)); - - /* Do not run that modifier at all if autosmooth is disabled! */ - if (!is_valid_target(enmd) || mesh->totloop == 0) { - return mesh; - } - - /* XXX TODO ARG GRRR XYQWNMPRXTYY - * Once we fully switch to Mesh evaluation of modifiers, we can expect to get that flag from the COW copy. - * But for now, it is lost in the DM intermediate step, so we need to directly check orig object's data. */ -#if 0 - if (!(mesh->flag & ME_AUTOSMOOTH)) { -#else - if (!(((Mesh *)ob->data)->flag & ME_AUTOSMOOTH)) { -#endif - modifier_setError((ModifierData *)enmd, "Enable 'Auto Smooth' option in mesh settings"); - return mesh; - } - - Mesh *result; - if (mesh->medge == ((Mesh *)ob->data)->medge) { - /* We need to duplicate data here, otherwise setting custom normals (which may also affect sharp edges) could - * modify org mesh, see T43671. */ - BKE_id_copy_ex(NULL, &mesh->id, (ID **)&result, LIB_ID_COPY_LOCALIZE); - } - else { - result = mesh; - } - - const int num_verts = result->totvert; - const int num_edges = result->totedge; - const int num_loops = result->totloop; - const int num_polys = result->totpoly; - MVert *mvert = result->mvert; - MEdge *medge = result->medge; - MLoop *mloop = result->mloop; - MPoly *mpoly = result->mpoly; - - int defgrp_index; - MDeformVert *dvert; - - float (*loopnors)[3] = NULL; - short (*clnors)[2] = NULL; - - float (*polynors)[3]; - - CustomData *ldata = &result->ldata; - if (CustomData_has_layer(ldata, CD_NORMAL)) { - loopnors = CustomData_get_layer(ldata, CD_NORMAL); - } - else { - loopnors = CustomData_add_layer(ldata, CD_NORMAL, CD_CALLOC, NULL, num_loops); - } - - /* Compute poly (always needed) and vert normals. */ - CustomData *pdata = &result->pdata; - polynors = CustomData_get_layer(pdata, CD_NORMAL); - if (!polynors) { - polynors = CustomData_add_layer(pdata, CD_NORMAL, CD_CALLOC, NULL, num_polys); - } - BKE_mesh_calc_normals_poly(mvert, NULL, num_verts, mloop, mpoly, num_loops, num_polys, polynors, - (result->runtime.cd_dirty_vert & CD_MASK_NORMAL) ? false : true); - - result->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL; - - if (use_current_clnors) { - clnors = CustomData_duplicate_referenced_layer(ldata, CD_CUSTOMLOOPNORMAL, num_loops); - - BKE_mesh_normals_loop_split(mvert, num_verts, medge, num_edges, mloop, loopnors, num_loops, - mpoly, (const float (*)[3])polynors, num_polys, - true, result->smoothresh, - NULL, clnors, NULL); - } - - if (!clnors) { - clnors = CustomData_add_layer(ldata, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL, num_loops); - } - - MOD_get_vgroup(ob, result, enmd->defgrp_name, &dvert, &defgrp_index); - - if (enmd->mode == MOD_NORMALEDIT_MODE_RADIAL) { - normalEditModifier_do_radial( - enmd, ctx, ob, result, 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, ctx, ob, result, 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); - } - - return result; +return result; } static void initData(ModifierData *md) { - NormalEditModifierData *enmd = (NormalEditModifierData *)md; + NormalEditModifierData *enmd = (NormalEditModifierData *)md; - enmd->mode = MOD_NORMALEDIT_MODE_RADIAL; + enmd->mode = MOD_NORMALEDIT_MODE_RADIAL; - enmd->mix_mode = MOD_NORMALEDIT_MIX_COPY; - enmd->mix_factor = 1.0f; - enmd->mix_limit = M_PI; + enmd->mix_mode = MOD_NORMALEDIT_MIX_COPY; + enmd->mix_factor = 1.0f; + enmd->mix_limit = M_PI; } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - NormalEditModifierData *enmd = (NormalEditModifierData *)md; + NormalEditModifierData *enmd = (NormalEditModifierData *)md; - r_cddata_masks->lmask |= CD_MASK_CUSTOMLOOPNORMAL; + r_cddata_masks->lmask |= CD_MASK_CUSTOMLOOPNORMAL; - /* Ask for vertexgroups if we need them. */ - if (enmd->defgrp_name[0] != '\0') { - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; - } + /* Ask for vertexgroups if we need them. */ + if (enmd->defgrp_name[0] != '\0') { + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + } } static bool dependsOnNormals(ModifierData *UNUSED(md)) { - return true; + return true; } static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) { - NormalEditModifierData *enmd = (NormalEditModifierData *) md; + NormalEditModifierData *enmd = (NormalEditModifierData *)md; - walk(userData, ob, &enmd->target, IDWALK_CB_NOP); + walk(userData, ob, &enmd->target, IDWALK_CB_NOP); } -static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams)) +static bool isDisabled(const struct Scene *UNUSED(scene), + ModifierData *md, + bool UNUSED(useRenderParams)) { - NormalEditModifierData *enmd = (NormalEditModifierData *)md; + NormalEditModifierData *enmd = (NormalEditModifierData *)md; - return !is_valid_target(enmd); + return !is_valid_target(enmd); } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { - NormalEditModifierData *enmd = (NormalEditModifierData *) md; - if (enmd->target) { - DEG_add_object_relation(ctx->node, enmd->target, DEG_OB_COMP_TRANSFORM, "NormalEdit Modifier"); - DEG_add_modifier_to_transform_relation(ctx->node, "NormalEdit Modifier"); - } + NormalEditModifierData *enmd = (NormalEditModifierData *)md; + if (enmd->target) { + DEG_add_object_relation(ctx->node, enmd->target, DEG_OB_COMP_TRANSFORM, "NormalEdit Modifier"); + DEG_add_modifier_to_transform_relation(ctx->node, "NormalEdit Modifier"); + } } static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) { - return normalEditModifier_do((NormalEditModifierData *)md, ctx, ctx->object, mesh); + return normalEditModifier_do((NormalEditModifierData *)md, ctx, ctx->object, mesh); } ModifierTypeInfo modifierType_NormalEdit = { - /* name */ "Set Split Normals", - /* structName */ "NormalEditModifierData", - /* structSize */ sizeof(NormalEditModifierData), - /* type */ eModifierTypeType_Constructive, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_SupportsMapping | - eModifierTypeFlag_SupportsEditmode | - eModifierTypeFlag_EnableInEditmode, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ NULL, - /* isDisabled */ isDisabled, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ dependsOnNormals, - /* foreachObjectLink */ foreachObjectLink, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Set Split Normals", + /* structName */ "NormalEditModifierData", + /* structSize */ sizeof(NormalEditModifierData), + /* type */ eModifierTypeType_Constructive, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping | + eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ NULL, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ dependsOnNormals, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c index 5379321239c..983ea7b4309 100644 --- a/source/blender/modifiers/intern/MOD_ocean.c +++ b/source/blender/modifiers/intern/MOD_ocean.c @@ -46,471 +46,472 @@ #ifdef WITH_OCEANSIM static void init_cache_data(Object *ob, struct OceanModifierData *omd) { - const char *relbase = modifier_path_relbase_from_global(ob); - - omd->oceancache = BKE_ocean_init_cache(omd->cachepath, relbase, - omd->bakestart, omd->bakeend, omd->wave_scale, - omd->chop_amount, omd->foam_coverage, omd->foam_fade, omd->resolution); + const char *relbase = modifier_path_relbase_from_global(ob); + + omd->oceancache = BKE_ocean_init_cache(omd->cachepath, + relbase, + omd->bakestart, + omd->bakeend, + omd->wave_scale, + omd->chop_amount, + omd->foam_coverage, + omd->foam_fade, + omd->resolution); } static void simulate_ocean_modifier(struct OceanModifierData *omd) { - BKE_ocean_simulate(omd->ocean, omd->time, omd->wave_scale, omd->chop_amount); + BKE_ocean_simulate(omd->ocean, omd->time, omd->wave_scale, omd->chop_amount); } #endif /* WITH_OCEANSIM */ - - /* Modifier Code */ static void initData(ModifierData *md) { #ifdef WITH_OCEANSIM - OceanModifierData *omd = (OceanModifierData *) md; + OceanModifierData *omd = (OceanModifierData *)md; - omd->resolution = 7; - omd->spatial_size = 50; + omd->resolution = 7; + omd->spatial_size = 50; - omd->wave_alignment = 0.0; - omd->wind_velocity = 30.0; + omd->wave_alignment = 0.0; + omd->wind_velocity = 30.0; - omd->damp = 0.5; - omd->smallest_wave = 0.01; - omd->wave_direction = 0.0; - omd->depth = 200.0; + omd->damp = 0.5; + omd->smallest_wave = 0.01; + omd->wave_direction = 0.0; + omd->depth = 200.0; - omd->wave_scale = 1.0; + omd->wave_scale = 1.0; - omd->chop_amount = 1.0; + omd->chop_amount = 1.0; - omd->foam_coverage = 0.0; + omd->foam_coverage = 0.0; - omd->seed = 0; - omd->time = 1.0; + omd->seed = 0; + omd->time = 1.0; - omd->size = 1.0; - omd->repeat_x = 1; - omd->repeat_y = 1; + omd->size = 1.0; + omd->repeat_x = 1; + omd->repeat_y = 1; - modifier_path_init(omd->cachepath, sizeof(omd->cachepath), "cache_ocean"); + modifier_path_init(omd->cachepath, sizeof(omd->cachepath), "cache_ocean"); - omd->cached = 0; - omd->bakestart = 1; - omd->bakeend = 250; - omd->oceancache = NULL; - omd->foam_fade = 0.98; - omd->foamlayername[0] = '\0'; /* layer name empty by default */ + omd->cached = 0; + omd->bakestart = 1; + omd->bakeend = 250; + omd->oceancache = NULL; + omd->foam_fade = 0.98; + omd->foamlayername[0] = '\0'; /* layer name empty by default */ - omd->ocean = BKE_ocean_add(); - BKE_ocean_init_from_modifier(omd->ocean, omd); - simulate_ocean_modifier(omd); + omd->ocean = BKE_ocean_add(); + BKE_ocean_init_from_modifier(omd->ocean, omd); + simulate_ocean_modifier(omd); #else /* WITH_OCEANSIM */ - /* unused */ - (void)md; + /* unused */ + (void)md; #endif /* WITH_OCEANSIM */ } static void freeData(ModifierData *md) { #ifdef WITH_OCEANSIM - OceanModifierData *omd = (OceanModifierData *) md; - - BKE_ocean_free(omd->ocean); - if (omd->oceancache) - BKE_ocean_free_cache(omd->oceancache); -#else /* WITH_OCEANSIM */ - /* unused */ - (void)md; + OceanModifierData *omd = (OceanModifierData *)md; + + BKE_ocean_free(omd->ocean); + if (omd->oceancache) + BKE_ocean_free_cache(omd->oceancache); +#else /* WITH_OCEANSIM */ + /* unused */ + (void)md; #endif /* WITH_OCEANSIM */ } static void copyData(const ModifierData *md, ModifierData *target, const int flag) { #ifdef WITH_OCEANSIM -#if 0 - const OceanModifierData *omd = (const OceanModifierData *) md; -#endif - OceanModifierData *tomd = (OceanModifierData *) target; - - modifier_copyData_generic(md, target, flag); - - /* The oceancache object will be recreated for this copy - * automatically when cached=true */ - tomd->oceancache = NULL; - - tomd->ocean = BKE_ocean_add(); - BKE_ocean_init_from_modifier(tomd->ocean, tomd); - simulate_ocean_modifier(tomd); -#else /* WITH_OCEANSIM */ - /* unused */ - (void)md; - (void)target; - (void)flag; +# if 0 + const OceanModifierData *omd = (const OceanModifierData *) md; +# endif + OceanModifierData *tomd = (OceanModifierData *)target; + + modifier_copyData_generic(md, target, flag); + + /* The oceancache object will be recreated for this copy + * automatically when cached=true */ + tomd->oceancache = NULL; + + tomd->ocean = BKE_ocean_add(); + BKE_ocean_init_from_modifier(tomd->ocean, tomd); + simulate_ocean_modifier(tomd); +#else /* WITH_OCEANSIM */ + /* unused */ + (void)md; + (void)target; + (void)flag; #endif /* WITH_OCEANSIM */ } #ifdef WITH_OCEANSIM -static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - OceanModifierData *omd = (OceanModifierData *)md; + OceanModifierData *omd = (OceanModifierData *)md; - if (omd->flag & MOD_OCEAN_GENERATE_FOAM) { - r_cddata_masks->fmask |= CD_MASK_MCOL; /* XXX Should be loop cddata I guess? */ - } + if (omd->flag & MOD_OCEAN_GENERATE_FOAM) { + r_cddata_masks->fmask |= CD_MASK_MCOL; /* XXX Should be loop cddata I guess? */ + } } -#else /* WITH_OCEANSIM */ -static void requiredDataMask(Object *UNUSED(ob), ModifierData *UNUSED(md), CustomData_MeshMasks *UNUSED(r_cddata_masks)) +#else /* WITH_OCEANSIM */ +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *UNUSED(md), + CustomData_MeshMasks *UNUSED(r_cddata_masks)) { } #endif /* WITH_OCEANSIM */ static bool dependsOnNormals(ModifierData *md) { - OceanModifierData *omd = (OceanModifierData *)md; - return (omd->geometry_mode != MOD_OCEAN_GEOM_GENERATE); + OceanModifierData *omd = (OceanModifierData *)md; + return (omd->geometry_mode != MOD_OCEAN_GEOM_GENERATE); } #ifdef WITH_OCEANSIM typedef struct GenerateOceanGeometryData { - MVert *mverts; - MPoly *mpolys; - MLoop *mloops; - MLoopUV *mloopuvs; - - int res_x, res_y; - int rx, ry; - float ox, oy; - float sx, sy; - float ix, iy; + MVert *mverts; + MPoly *mpolys; + MLoop *mloops; + MLoopUV *mloopuvs; + + int res_x, res_y; + int rx, ry; + float ox, oy; + float sx, sy; + float ix, iy; } GenerateOceanGeometryData; -static void generate_ocean_geometry_vertices( - void *__restrict userdata, - const int y, - const ParallelRangeTLS *__restrict UNUSED(tls)) +static void generate_ocean_geometry_vertices(void *__restrict userdata, + const int y, + const ParallelRangeTLS *__restrict UNUSED(tls)) { - GenerateOceanGeometryData *gogd = userdata; - int x; - - for (x = 0; x <= gogd->res_x; x++) { - const int i = y * (gogd->res_x + 1) + x; - float *co = gogd->mverts[i].co; - co[0] = gogd->ox + (x * gogd->sx); - co[1] = gogd->oy + (y * gogd->sy); - co[2] = 0.0f; - } + GenerateOceanGeometryData *gogd = userdata; + int x; + + for (x = 0; x <= gogd->res_x; x++) { + const int i = y * (gogd->res_x + 1) + x; + float *co = gogd->mverts[i].co; + co[0] = gogd->ox + (x * gogd->sx); + co[1] = gogd->oy + (y * gogd->sy); + co[2] = 0.0f; + } } -static void generate_ocean_geometry_polygons( - void *__restrict userdata, - const int y, - const ParallelRangeTLS *__restrict UNUSED(tls)) +static void generate_ocean_geometry_polygons(void *__restrict userdata, + const int y, + const ParallelRangeTLS *__restrict UNUSED(tls)) { - GenerateOceanGeometryData *gogd = userdata; - int x; - - for (x = 0; x < gogd->res_x; x++) { - const int fi = y * gogd->res_x + x; - const int vi = y * (gogd->res_x + 1) + x; - MPoly *mp = &gogd->mpolys[fi]; - MLoop *ml = &gogd->mloops[fi * 4]; - - ml->v = vi; - ml++; - ml->v = vi + 1; - ml++; - ml->v = vi + 1 + gogd->res_x + 1; - ml++; - ml->v = vi + gogd->res_x + 1; - ml++; - - mp->loopstart = fi * 4; - mp->totloop = 4; - - mp->flag |= ME_SMOOTH; - } + GenerateOceanGeometryData *gogd = userdata; + int x; + + for (x = 0; x < gogd->res_x; x++) { + const int fi = y * gogd->res_x + x; + const int vi = y * (gogd->res_x + 1) + x; + MPoly *mp = &gogd->mpolys[fi]; + MLoop *ml = &gogd->mloops[fi * 4]; + + ml->v = vi; + ml++; + ml->v = vi + 1; + ml++; + ml->v = vi + 1 + gogd->res_x + 1; + ml++; + ml->v = vi + gogd->res_x + 1; + ml++; + + mp->loopstart = fi * 4; + mp->totloop = 4; + + mp->flag |= ME_SMOOTH; + } } -static void generate_ocean_geometry_uvs( - void *__restrict userdata, - const int y, - const ParallelRangeTLS *__restrict UNUSED(tls)) +static void generate_ocean_geometry_uvs(void *__restrict userdata, + const int y, + const ParallelRangeTLS *__restrict UNUSED(tls)) { - GenerateOceanGeometryData *gogd = userdata; - int x; + GenerateOceanGeometryData *gogd = userdata; + int x; - for (x = 0; x < gogd->res_x; x++) { - const int i = y * gogd->res_x + x; - MLoopUV *luv = &gogd->mloopuvs[i * 4]; + for (x = 0; x < gogd->res_x; x++) { + const int i = y * gogd->res_x + x; + MLoopUV *luv = &gogd->mloopuvs[i * 4]; - luv->uv[0] = x * gogd->ix; - luv->uv[1] = y * gogd->iy; - luv++; + luv->uv[0] = x * gogd->ix; + luv->uv[1] = y * gogd->iy; + luv++; - luv->uv[0] = (x + 1) * gogd->ix; - luv->uv[1] = y * gogd->iy; - luv++; + luv->uv[0] = (x + 1) * gogd->ix; + luv->uv[1] = y * gogd->iy; + luv++; - luv->uv[0] = (x + 1) * gogd->ix; - luv->uv[1] = (y + 1) * gogd->iy; - luv++; + luv->uv[0] = (x + 1) * gogd->ix; + luv->uv[1] = (y + 1) * gogd->iy; + luv++; - luv->uv[0] = x * gogd->ix; - luv->uv[1] = (y + 1) * gogd->iy; - luv++; - } + luv->uv[0] = x * gogd->ix; + luv->uv[1] = (y + 1) * gogd->iy; + luv++; + } } static Mesh *generate_ocean_geometry(OceanModifierData *omd) { - Mesh *result; + Mesh *result; - GenerateOceanGeometryData gogd; + GenerateOceanGeometryData gogd; - int num_verts; - int num_polys; + int num_verts; + int num_polys; - const bool use_threading = omd->resolution > 4; + const bool use_threading = omd->resolution > 4; - gogd.rx = omd->resolution * omd->resolution; - gogd.ry = omd->resolution * omd->resolution; - gogd.res_x = gogd.rx * omd->repeat_x; - gogd.res_y = gogd.ry * omd->repeat_y; + gogd.rx = omd->resolution * omd->resolution; + gogd.ry = omd->resolution * omd->resolution; + gogd.res_x = gogd.rx * omd->repeat_x; + gogd.res_y = gogd.ry * omd->repeat_y; - num_verts = (gogd.res_x + 1) * (gogd.res_y + 1); - num_polys = gogd.res_x * gogd.res_y; + num_verts = (gogd.res_x + 1) * (gogd.res_y + 1); + num_polys = gogd.res_x * gogd.res_y; - gogd.sx = omd->size * omd->spatial_size; - gogd.sy = omd->size * omd->spatial_size; - gogd.ox = -gogd.sx / 2.0f; - gogd.oy = -gogd.sy / 2.0f; + gogd.sx = omd->size * omd->spatial_size; + gogd.sy = omd->size * omd->spatial_size; + gogd.ox = -gogd.sx / 2.0f; + gogd.oy = -gogd.sy / 2.0f; - gogd.sx /= gogd.rx; - gogd.sy /= gogd.ry; + gogd.sx /= gogd.rx; + gogd.sy /= gogd.ry; - result = BKE_mesh_new_nomain(num_verts, 0, 0, num_polys * 4, num_polys); + result = BKE_mesh_new_nomain(num_verts, 0, 0, num_polys * 4, num_polys); - gogd.mverts = result->mvert; - gogd.mpolys = result->mpoly; - gogd.mloops = result->mloop; + gogd.mverts = result->mvert; + gogd.mpolys = result->mpoly; + gogd.mloops = result->mloop; - ParallelRangeSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = use_threading; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = use_threading; - /* create vertices */ - BLI_task_parallel_range(0, gogd.res_y + 1, &gogd, generate_ocean_geometry_vertices, &settings); + /* create vertices */ + BLI_task_parallel_range(0, gogd.res_y + 1, &gogd, generate_ocean_geometry_vertices, &settings); - /* create faces */ - BLI_task_parallel_range(0, gogd.res_y, &gogd, generate_ocean_geometry_polygons, &settings); + /* create faces */ + BLI_task_parallel_range(0, gogd.res_y, &gogd, generate_ocean_geometry_polygons, &settings); - BKE_mesh_calc_edges(result, false, false); + BKE_mesh_calc_edges(result, false, false); - /* add uvs */ - if (CustomData_number_of_layers(&result->ldata, CD_MLOOPUV) < MAX_MTFACE) { - gogd.mloopuvs = CustomData_add_layer(&result->ldata, CD_MLOOPUV, CD_CALLOC, NULL, num_polys * 4); + /* add uvs */ + if (CustomData_number_of_layers(&result->ldata, CD_MLOOPUV) < MAX_MTFACE) { + gogd.mloopuvs = CustomData_add_layer( + &result->ldata, CD_MLOOPUV, CD_CALLOC, NULL, num_polys * 4); - if (gogd.mloopuvs) { /* unlikely to fail */ - gogd.ix = 1.0 / gogd.rx; - gogd.iy = 1.0 / gogd.ry; + if (gogd.mloopuvs) { /* unlikely to fail */ + gogd.ix = 1.0 / gogd.rx; + gogd.iy = 1.0 / gogd.ry; - BLI_task_parallel_range(0, gogd.res_y, &gogd, generate_ocean_geometry_uvs, &settings); - } - } + BLI_task_parallel_range(0, gogd.res_y, &gogd, generate_ocean_geometry_uvs, &settings); + } + } - result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; - return result; + return result; } static Mesh *doOcean(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) { - OceanModifierData *omd = (OceanModifierData *) md; - int cfra_scene = (int)DEG_get_ctime(ctx->depsgraph); - Object *ob = ctx->object; - bool allocated_ocean = false; - - Mesh *result = NULL; - OceanResult ocr; - - MVert *mverts; - - int cfra_for_cache; - int i, j; - - /* use cached & inverted value for speed - * expanded this would read... - * - * (axis / (omd->size * omd->spatial_size)) + 0.5f) */ -#define OCEAN_CO(_size_co_inv, _v) ((_v * _size_co_inv) + 0.5f) - - const float size_co_inv = 1.0f / (omd->size * omd->spatial_size); - - /* can happen in when size is small, avoid bad array lookups later and quit now */ - if (!isfinite(size_co_inv)) { - return mesh; - } - - /* do ocean simulation */ - if (omd->cached == true) { - if (!omd->oceancache) { - init_cache_data(ob, omd); - } - BKE_ocean_simulate_cache(omd->oceancache, cfra_scene); - } - else { - /* omd->ocean is NULL on an original object (in contrast to an evaluated one). - * We can create a new one, but we have to free it as well once we're done. - * This function is only called on an original object when applying the modifier - * using the 'Apply Modifier' button, and thus it is not called frequently for - * simulation. */ - allocated_ocean |= BKE_ocean_ensure(omd); - simulate_ocean_modifier(omd); - } - - if (omd->geometry_mode == MOD_OCEAN_GEOM_GENERATE) { - result = generate_ocean_geometry(omd); - BKE_mesh_ensure_normals(result); - } - else if (omd->geometry_mode == MOD_OCEAN_GEOM_DISPLACE) { - BKE_id_copy_ex(NULL, &mesh->id, (ID **)&result, LIB_ID_COPY_LOCALIZE); - } - - cfra_for_cache = cfra_scene; - CLAMP(cfra_for_cache, omd->bakestart, omd->bakeend); - cfra_for_cache -= omd->bakestart; /* shift to 0 based */ - - mverts = result->mvert; - - /* add vcols before displacement - allows lookup based on position */ - - if (omd->flag & MOD_OCEAN_GENERATE_FOAM) { - if (CustomData_number_of_layers(&result->ldata, CD_MLOOPCOL) < MAX_MCOL) { - const int num_polys = result->totpoly; - const int num_loops = result->totloop; - MLoop *mloops = result->mloop; - MLoopCol *mloopcols = CustomData_add_layer_named( - &result->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, num_loops, omd->foamlayername); - - if (mloopcols) { /* unlikely to fail */ - MPoly *mpolys = result->mpoly; - MPoly *mp; - - for (i = 0, mp = mpolys; i < num_polys; i++, mp++) { - MLoop *ml = &mloops[mp->loopstart]; - MLoopCol *mlcol = &mloopcols[mp->loopstart]; - - for (j = mp->totloop; j--; ml++, mlcol++) { - const float *vco = mverts[ml->v].co; - const float u = OCEAN_CO(size_co_inv, vco[0]); - const float v = OCEAN_CO(size_co_inv, vco[1]); - float foam; - - if (omd->oceancache && omd->cached == true) { - BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra_for_cache, u, v); - foam = ocr.foam; - CLAMP(foam, 0.0f, 1.0f); - } - else { - BKE_ocean_eval_uv(omd->ocean, &ocr, u, v); - foam = BKE_ocean_jminus_to_foam(ocr.Jminus, omd->foam_coverage); - } - - mlcol->r = mlcol->g = mlcol->b = (char)(foam * 255); - /* This needs to be set (render engine uses) */ - mlcol->a = 255; - } - } - } - } - } - - - /* displace the geometry */ - - /* Note: tried to parallelized that one and previous foam loop, but gives 20% slower results... odd. */ - { - const int num_verts = result->totvert; - - for (i = 0; i < num_verts; i++) { - float *vco = mverts[i].co; - const float u = OCEAN_CO(size_co_inv, vco[0]); - const float v = OCEAN_CO(size_co_inv, vco[1]); - - if (omd->oceancache && omd->cached == true) { - BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra_for_cache, u, v); - } - else { - BKE_ocean_eval_uv(omd->ocean, &ocr, u, v); - } - - vco[2] += ocr.disp[1]; - - if (omd->chop_amount > 0.0f) { - vco[0] += ocr.disp[0]; - vco[1] += ocr.disp[2]; - } - } - } - - if (allocated_ocean) { - BKE_ocean_free(omd->ocean); - omd->ocean = NULL; - } - -#undef OCEAN_CO - - return result; + OceanModifierData *omd = (OceanModifierData *)md; + int cfra_scene = (int)DEG_get_ctime(ctx->depsgraph); + Object *ob = ctx->object; + bool allocated_ocean = false; + + Mesh *result = NULL; + OceanResult ocr; + + MVert *mverts; + + int cfra_for_cache; + int i, j; + + /* use cached & inverted value for speed + * expanded this would read... + * + * (axis / (omd->size * omd->spatial_size)) + 0.5f) */ +# define OCEAN_CO(_size_co_inv, _v) ((_v * _size_co_inv) + 0.5f) + + const float size_co_inv = 1.0f / (omd->size * omd->spatial_size); + + /* can happen in when size is small, avoid bad array lookups later and quit now */ + if (!isfinite(size_co_inv)) { + return mesh; + } + + /* do ocean simulation */ + if (omd->cached == true) { + if (!omd->oceancache) { + init_cache_data(ob, omd); + } + BKE_ocean_simulate_cache(omd->oceancache, cfra_scene); + } + else { + /* omd->ocean is NULL on an original object (in contrast to an evaluated one). + * We can create a new one, but we have to free it as well once we're done. + * This function is only called on an original object when applying the modifier + * using the 'Apply Modifier' button, and thus it is not called frequently for + * simulation. */ + allocated_ocean |= BKE_ocean_ensure(omd); + simulate_ocean_modifier(omd); + } + + if (omd->geometry_mode == MOD_OCEAN_GEOM_GENERATE) { + result = generate_ocean_geometry(omd); + BKE_mesh_ensure_normals(result); + } + else if (omd->geometry_mode == MOD_OCEAN_GEOM_DISPLACE) { + BKE_id_copy_ex(NULL, &mesh->id, (ID **)&result, LIB_ID_COPY_LOCALIZE); + } + + cfra_for_cache = cfra_scene; + CLAMP(cfra_for_cache, omd->bakestart, omd->bakeend); + cfra_for_cache -= omd->bakestart; /* shift to 0 based */ + + mverts = result->mvert; + + /* add vcols before displacement - allows lookup based on position */ + + if (omd->flag & MOD_OCEAN_GENERATE_FOAM) { + if (CustomData_number_of_layers(&result->ldata, CD_MLOOPCOL) < MAX_MCOL) { + const int num_polys = result->totpoly; + const int num_loops = result->totloop; + MLoop *mloops = result->mloop; + MLoopCol *mloopcols = CustomData_add_layer_named( + &result->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, num_loops, omd->foamlayername); + + if (mloopcols) { /* unlikely to fail */ + MPoly *mpolys = result->mpoly; + MPoly *mp; + + for (i = 0, mp = mpolys; i < num_polys; i++, mp++) { + MLoop *ml = &mloops[mp->loopstart]; + MLoopCol *mlcol = &mloopcols[mp->loopstart]; + + for (j = mp->totloop; j--; ml++, mlcol++) { + const float *vco = mverts[ml->v].co; + const float u = OCEAN_CO(size_co_inv, vco[0]); + const float v = OCEAN_CO(size_co_inv, vco[1]); + float foam; + + if (omd->oceancache && omd->cached == true) { + BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra_for_cache, u, v); + foam = ocr.foam; + CLAMP(foam, 0.0f, 1.0f); + } + else { + BKE_ocean_eval_uv(omd->ocean, &ocr, u, v); + foam = BKE_ocean_jminus_to_foam(ocr.Jminus, omd->foam_coverage); + } + + mlcol->r = mlcol->g = mlcol->b = (char)(foam * 255); + /* This needs to be set (render engine uses) */ + mlcol->a = 255; + } + } + } + } + } + + /* displace the geometry */ + + /* Note: tried to parallelized that one and previous foam loop, but gives 20% slower results... odd. */ + { + const int num_verts = result->totvert; + + for (i = 0; i < num_verts; i++) { + float *vco = mverts[i].co; + const float u = OCEAN_CO(size_co_inv, vco[0]); + const float v = OCEAN_CO(size_co_inv, vco[1]); + + if (omd->oceancache && omd->cached == true) { + BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra_for_cache, u, v); + } + else { + BKE_ocean_eval_uv(omd->ocean, &ocr, u, v); + } + + vco[2] += ocr.disp[1]; + + if (omd->chop_amount > 0.0f) { + vco[0] += ocr.disp[0]; + vco[1] += ocr.disp[2]; + } + } + } + + if (allocated_ocean) { + BKE_ocean_free(omd->ocean); + omd->ocean = NULL; + } + +# undef OCEAN_CO + + return result; } #else /* WITH_OCEANSIM */ static Mesh *doOcean(ModifierData *UNUSED(md), const ModifierEvalContext *UNUSED(ctx), Mesh *mesh) { - return mesh; + return mesh; } #endif /* WITH_OCEANSIM */ -static Mesh *applyModifier( - ModifierData *md, const ModifierEvalContext *ctx, - Mesh *mesh) +static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) { - Mesh *result; + Mesh *result; - result = doOcean(md, ctx, mesh); + result = doOcean(md, ctx, mesh); - if (result != mesh) - result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + if (result != mesh) + result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; - return result; + return result; } - ModifierTypeInfo modifierType_Ocean = { - /* name */ "Ocean", - /* structName */ "OceanModifierData", - /* structSize */ sizeof(OceanModifierData), - /* type */ eModifierTypeType_Constructive, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_SupportsEditmode | - eModifierTypeFlag_EnableInEditmode, - - /* copyData */ copyData, - /* deformMatrices_DM */ NULL, - - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ freeData, - /* isDisabled */ NULL, - /* updateDepsgraph */ NULL, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ dependsOnNormals, - /* foreachObjectLink */ NULL, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Ocean", + /* structName */ "OceanModifierData", + /* structSize */ sizeof(OceanModifierData), + /* type */ eModifierTypeType_Constructive, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsEditmode | + eModifierTypeFlag_EnableInEditmode, + + /* copyData */ copyData, + /* deformMatrices_DM */ NULL, + + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ freeData, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ dependsOnNormals, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c index 189255a7dd1..718c1e6a038 100644 --- a/source/blender/modifiers/intern/MOD_particleinstance.c +++ b/source/blender/modifiers/intern/MOD_particleinstance.c @@ -48,497 +48,502 @@ static void initData(ModifierData *md) { - ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md; - - pimd->flag = eParticleInstanceFlag_Parents | eParticleInstanceFlag_Unborn | - eParticleInstanceFlag_Alive | eParticleInstanceFlag_Dead; - pimd->psys = 1; - pimd->position = 1.0f; - pimd->axis = 2; - pimd->space = eParticleInstanceSpace_World; - pimd->particle_amount = 1.0f; - pimd->particle_offset = 0.0f; - - STRNCPY(pimd->index_layer_name, ""); - STRNCPY(pimd->value_layer_name, ""); + ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md; + + pimd->flag = eParticleInstanceFlag_Parents | eParticleInstanceFlag_Unborn | + eParticleInstanceFlag_Alive | eParticleInstanceFlag_Dead; + pimd->psys = 1; + pimd->position = 1.0f; + pimd->axis = 2; + pimd->space = eParticleInstanceSpace_World; + pimd->particle_amount = 1.0f; + pimd->particle_offset = 0.0f; + + STRNCPY(pimd->index_layer_name, ""); + STRNCPY(pimd->value_layer_name, ""); } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md; + ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md; - if (pimd->index_layer_name[0] != '\0' || - pimd->value_layer_name[0] != '\0') - { - r_cddata_masks->lmask |= CD_MASK_MLOOPCOL; - } + if (pimd->index_layer_name[0] != '\0' || pimd->value_layer_name[0] != '\0') { + r_cddata_masks->lmask |= CD_MASK_MLOOPCOL; + } } static bool isDisabled(const struct Scene *scene, ModifierData *md, bool useRenderParams) { - ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md; - ParticleSystem *psys; - ModifierData *ob_md; - - if (!pimd->ob) - return true; - - psys = BLI_findlink(&pimd->ob->particlesystem, pimd->psys - 1); - if (psys == NULL) - return true; - - /* If the psys modifier is disabled we cannot use its data. - * First look up the psys modifier from the object, then check if it is enabled. - */ - for (ob_md = pimd->ob->modifiers.first; ob_md; ob_md = ob_md->next) { - if (ob_md->type == eModifierType_ParticleSystem) { - ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)ob_md; - if (psmd->psys == psys) { - int required_mode; - - if (useRenderParams) required_mode = eModifierMode_Render; - else required_mode = eModifierMode_Realtime; - - if (!modifier_isEnabled(scene, ob_md, required_mode)) - return true; - - break; - } - } - } - - return false; + ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md; + ParticleSystem *psys; + ModifierData *ob_md; + + if (!pimd->ob) + return true; + + psys = BLI_findlink(&pimd->ob->particlesystem, pimd->psys - 1); + if (psys == NULL) + return true; + + /* If the psys modifier is disabled we cannot use its data. + * First look up the psys modifier from the object, then check if it is enabled. + */ + for (ob_md = pimd->ob->modifiers.first; ob_md; ob_md = ob_md->next) { + if (ob_md->type == eModifierType_ParticleSystem) { + ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)ob_md; + if (psmd->psys == psys) { + int required_mode; + + if (useRenderParams) + required_mode = eModifierMode_Render; + else + required_mode = eModifierMode_Realtime; + + if (!modifier_isEnabled(scene, ob_md, required_mode)) + return true; + + break; + } + } + } + + return false; } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { - ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md; - if (pimd->ob != NULL) { - DEG_add_object_relation(ctx->node, pimd->ob, DEG_OB_COMP_TRANSFORM, "Particle Instance Modifier"); - DEG_add_object_relation(ctx->node, pimd->ob, DEG_OB_COMP_GEOMETRY, "Particle Instance Modifier"); - } + ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md; + if (pimd->ob != NULL) { + DEG_add_object_relation( + ctx->node, pimd->ob, DEG_OB_COMP_TRANSFORM, "Particle Instance Modifier"); + DEG_add_object_relation( + ctx->node, pimd->ob, DEG_OB_COMP_GEOMETRY, "Particle Instance Modifier"); + } } -static void foreachObjectLink( - ModifierData *md, Object *ob, - ObjectWalkFunc walk, void *userData) +static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) { - ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md; + ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md; - walk(userData, ob, &pimd->ob, IDWALK_CB_NOP); + walk(userData, ob, &pimd->ob, IDWALK_CB_NOP); } static bool particle_skip(ParticleInstanceModifierData *pimd, ParticleSystem *psys, int p) { - const bool between = (psys->part->childtype == PART_CHILD_FACES); - ParticleData *pa; - int totpart, randp, minp, maxp; - - if (p >= psys->totpart) { - ChildParticle *cpa = psys->child + (p - psys->totpart); - pa = psys->particles + (between ? cpa->pa[0] : cpa->parent); - } - else { - pa = psys->particles + p; - } - - if (pa) { - if (pa->alive == PARS_UNBORN && (pimd->flag & eParticleInstanceFlag_Unborn) == 0) return true; - if (pa->alive == PARS_ALIVE && (pimd->flag & eParticleInstanceFlag_Alive) == 0) return true; - if (pa->alive == PARS_DEAD && (pimd->flag & eParticleInstanceFlag_Dead) == 0) return true; - } - - if (pimd->particle_amount == 1.0f) { - /* Early output, all particles are to be instanced. */ - return false; - } - - /* Randomly skip particles based on desired amount of visible particles. */ - - totpart = psys->totpart + psys->totchild; - - /* TODO make randomization optional? */ - randp = (int)(psys_frand(psys, 3578 + p) * totpart) % totpart; - - minp = (int)(totpart * pimd->particle_offset) % (totpart + 1); - maxp = (int)(totpart * (pimd->particle_offset + pimd->particle_amount)) % (totpart + 1); - - if (maxp > minp) { - return randp < minp || randp >= maxp; - } - else if (maxp < minp) { - return randp < minp && randp >= maxp; - } - else { - return true; - } - - return false; + const bool between = (psys->part->childtype == PART_CHILD_FACES); + ParticleData *pa; + int totpart, randp, minp, maxp; + + if (p >= psys->totpart) { + ChildParticle *cpa = psys->child + (p - psys->totpart); + pa = psys->particles + (between ? cpa->pa[0] : cpa->parent); + } + else { + pa = psys->particles + p; + } + + if (pa) { + if (pa->alive == PARS_UNBORN && (pimd->flag & eParticleInstanceFlag_Unborn) == 0) + return true; + if (pa->alive == PARS_ALIVE && (pimd->flag & eParticleInstanceFlag_Alive) == 0) + return true; + if (pa->alive == PARS_DEAD && (pimd->flag & eParticleInstanceFlag_Dead) == 0) + return true; + } + + if (pimd->particle_amount == 1.0f) { + /* Early output, all particles are to be instanced. */ + return false; + } + + /* Randomly skip particles based on desired amount of visible particles. */ + + totpart = psys->totpart + psys->totchild; + + /* TODO make randomization optional? */ + randp = (int)(psys_frand(psys, 3578 + p) * totpart) % totpart; + + minp = (int)(totpart * pimd->particle_offset) % (totpart + 1); + maxp = (int)(totpart * (pimd->particle_offset + pimd->particle_amount)) % (totpart + 1); + + if (maxp > minp) { + return randp < minp || randp >= maxp; + } + else if (maxp < minp) { + return randp < minp && randp >= maxp; + } + else { + return true; + } + + return false; } static void store_float_in_vcol(MLoopCol *vcol, float float_value) { - const uchar value = unit_float_to_uchar_clamp(float_value); - vcol->r = vcol->g = vcol->b = value; - vcol->a = 1.0f; + const uchar value = unit_float_to_uchar_clamp(float_value); + vcol->r = vcol->g = vcol->b = value; + vcol->a = 1.0f; } -static Mesh *applyModifier( - ModifierData *md, const ModifierEvalContext *ctx, - Mesh *mesh) +static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) { - Mesh *result; - ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md; - struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); - ParticleSimulationData sim; - ParticleSystem *psys = NULL; - ParticleData *pa = NULL; - MPoly *mpoly, *orig_mpoly; - MLoop *mloop, *orig_mloop; - MVert *mvert, *orig_mvert; - int totvert, totpoly, totloop, totedge; - int maxvert, maxpoly, maxloop, maxedge, part_end = 0, part_start; - int k, p, p_skip; - short track = ctx->object->trackflag % 3, trackneg, axis = pimd->axis; - float max_co = 0.0, min_co = 0.0, temp_co[3]; - float *size = NULL; - float spacemat[4][4]; - const bool use_parents = pimd->flag & eParticleInstanceFlag_Parents; - const bool use_children = pimd->flag & eParticleInstanceFlag_Children; - bool between; - - trackneg = ((ctx->object->trackflag > 2) ? 1 : 0); - - if (pimd->ob == ctx->object) { - pimd->ob = NULL; - return mesh; - } - - if (pimd->ob) { - psys = BLI_findlink(&pimd->ob->particlesystem, pimd->psys - 1); - if (psys == NULL || psys->totpart == 0) - return mesh; - } - else { - return mesh; - } - - part_start = use_parents ? 0 : psys->totpart; - - part_end = 0; - if (use_parents) - part_end += psys->totpart; - if (use_children) - part_end += psys->totchild; - - if (part_end == 0) - return mesh; - - sim.depsgraph = ctx->depsgraph; - sim.scene = scene; - sim.ob = pimd->ob; - sim.psys = psys; - sim.psmd = psys_get_modifier(pimd->ob, psys); - between = (psys->part->childtype == PART_CHILD_FACES); - - if (pimd->flag & eParticleInstanceFlag_UseSize) { - float *si; - si = size = MEM_calloc_arrayN(part_end, sizeof(float), "particle size array"); - - if (pimd->flag & eParticleInstanceFlag_Parents) { - for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++, si++) - *si = pa->size; - } - - if (pimd->flag & eParticleInstanceFlag_Children) { - ChildParticle *cpa = psys->child; - - for (p = 0; p < psys->totchild; p++, cpa++, si++) { - *si = psys_get_child_size(psys, cpa, 0.0f, NULL); - } - } - } - - switch (pimd->space) { - case eParticleInstanceSpace_World: - /* particle states are in world space already */ - unit_m4(spacemat); - break; - case eParticleInstanceSpace_Local: - /* get particle states in the particle object's local space */ - invert_m4_m4(spacemat, pimd->ob->obmat); - break; - default: - /* should not happen */ - BLI_assert(false); - break; - } - - totvert = mesh->totvert; - totpoly = mesh->totpoly; - totloop = mesh->totloop; - totedge = mesh->totedge; - - /* count particles */ - maxvert = 0; - maxpoly = 0; - maxloop = 0; - maxedge = 0; - - for (p = part_start; p < part_end; p++) { - if (particle_skip(pimd, psys, p)) - continue; - - maxvert += totvert; - maxpoly += totpoly; - maxloop += totloop; - maxedge += totedge; - } - - psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); - - if (psys->flag & (PSYS_HAIR_DONE | PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED) { - float min[3], max[3]; - INIT_MINMAX(min, max); - BKE_mesh_minmax(mesh, min, max); - min_co = min[track]; - max_co = max[track]; - } - - result = BKE_mesh_new_nomain_from_template(mesh, maxvert, maxedge, 0, maxloop, maxpoly); - - mvert = result->mvert; - orig_mvert = mesh->mvert; - mpoly = result->mpoly; - orig_mpoly = mesh->mpoly; - mloop = result->mloop; - orig_mloop = mesh->mloop; - - MLoopCol *mloopcols_index = CustomData_get_layer_named(&result->ldata, CD_MLOOPCOL, pimd->index_layer_name); - MLoopCol *mloopcols_value = CustomData_get_layer_named(&result->ldata, CD_MLOOPCOL, pimd->value_layer_name); - int *vert_part_index = NULL; - float *vert_part_value = NULL; - if (mloopcols_index != NULL) { - vert_part_index = MEM_calloc_arrayN(maxvert, sizeof(int), "vertex part index array"); - } - if (mloopcols_value) { - vert_part_value = MEM_calloc_arrayN(maxvert, sizeof(float), "vertex part value array"); - } - - for (p = part_start, p_skip = 0; p < part_end; p++) { - float prev_dir[3]; - float frame[4]; /* frame orientation quaternion */ - float p_random = psys_frand(psys, 77091 + 283 * p); - - /* skip particle? */ - if (particle_skip(pimd, psys, p)) - continue; - - /* set vertices coordinates */ - for (k = 0; k < totvert; k++) { - ParticleKey state; - MVert *inMV; - int vindex = p_skip * totvert + k; - MVert *mv = mvert + vindex; - - inMV = orig_mvert + k; - CustomData_copy_data(&mesh->vdata, &result->vdata, k, p_skip * totvert + k, 1); - *mv = *inMV; - - if (vert_part_index != NULL) { - vert_part_index[vindex] = p; - } - if (vert_part_value != NULL) { - vert_part_value[vindex] = p_random; - } - - /*change orientation based on object trackflag*/ - copy_v3_v3(temp_co, mv->co); - mv->co[axis] = temp_co[track]; - mv->co[(axis + 1) % 3] = temp_co[(track + 1) % 3]; - mv->co[(axis + 2) % 3] = temp_co[(track + 2) % 3]; - - /* get particle state */ - if ((psys->flag & (PSYS_HAIR_DONE | PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED) && - (pimd->flag & eParticleInstanceFlag_Path)) - { - float ran = 0.0f; - if (pimd->random_position != 0.0f) { - ran = pimd->random_position * BLI_hash_frand(psys->seed + p); - } - - if (pimd->flag & eParticleInstanceFlag_KeepShape) { - state.time = pimd->position * (1.0f - ran); - } - else { - state.time = (mv->co[axis] - min_co) / (max_co - min_co) * pimd->position * (1.0f - ran); - - if (trackneg) - state.time = 1.0f - state.time; - - mv->co[axis] = 0.0; - } - - psys_get_particle_on_path(&sim, p, &state, 1); - - normalize_v3(state.vel); - - /* Incrementally Rotating Frame (Bishop Frame) */ - if (k == 0) { - float hairmat[4][4]; - float mat[3][3]; - - if (p < psys->totpart) - pa = psys->particles + p; - else { - ChildParticle *cpa = psys->child + (p - psys->totpart); - pa = psys->particles + (between ? cpa->pa[0] : cpa->parent); - } - psys_mat_hair_to_global(sim.ob, sim.psmd->mesh_final, sim.psys->part->from, pa, hairmat); - copy_m3_m4(mat, hairmat); - /* to quaternion */ - mat3_to_quat(frame, mat); - - if (pimd->rotation > 0.0f || pimd->random_rotation > 0.0f) { - float angle = 2.0f * M_PI * (pimd->rotation + pimd->random_rotation * (psys_frand(psys, 19957323 + p) - 0.5f)); - float eul[3] = { 0.0f, 0.0f, angle }; - float rot[4]; - - eul_to_quat(rot, eul); - mul_qt_qtqt(frame, frame, rot); - } - - /* note: direction is same as normal vector currently, - * but best to keep this separate so the frame can be - * rotated later if necessary - */ - copy_v3_v3(prev_dir, state.vel); - } - else { - float rot[4]; - - /* incrementally rotate along bend direction */ - rotation_between_vecs_to_quat(rot, prev_dir, state.vel); - mul_qt_qtqt(frame, rot, frame); - - copy_v3_v3(prev_dir, state.vel); - } - - copy_qt_qt(state.rot, frame); + Mesh *result; + ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md; + struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); + ParticleSimulationData sim; + ParticleSystem *psys = NULL; + ParticleData *pa = NULL; + MPoly *mpoly, *orig_mpoly; + MLoop *mloop, *orig_mloop; + MVert *mvert, *orig_mvert; + int totvert, totpoly, totloop, totedge; + int maxvert, maxpoly, maxloop, maxedge, part_end = 0, part_start; + int k, p, p_skip; + short track = ctx->object->trackflag % 3, trackneg, axis = pimd->axis; + float max_co = 0.0, min_co = 0.0, temp_co[3]; + float *size = NULL; + float spacemat[4][4]; + const bool use_parents = pimd->flag & eParticleInstanceFlag_Parents; + const bool use_children = pimd->flag & eParticleInstanceFlag_Children; + bool between; + + trackneg = ((ctx->object->trackflag > 2) ? 1 : 0); + + if (pimd->ob == ctx->object) { + pimd->ob = NULL; + return mesh; + } + + if (pimd->ob) { + psys = BLI_findlink(&pimd->ob->particlesystem, pimd->psys - 1); + if (psys == NULL || psys->totpart == 0) + return mesh; + } + else { + return mesh; + } + + part_start = use_parents ? 0 : psys->totpart; + + part_end = 0; + if (use_parents) + part_end += psys->totpart; + if (use_children) + part_end += psys->totchild; + + if (part_end == 0) + return mesh; + + sim.depsgraph = ctx->depsgraph; + sim.scene = scene; + sim.ob = pimd->ob; + sim.psys = psys; + sim.psmd = psys_get_modifier(pimd->ob, psys); + between = (psys->part->childtype == PART_CHILD_FACES); + + if (pimd->flag & eParticleInstanceFlag_UseSize) { + float *si; + si = size = MEM_calloc_arrayN(part_end, sizeof(float), "particle size array"); + + if (pimd->flag & eParticleInstanceFlag_Parents) { + for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++, si++) + *si = pa->size; + } + + if (pimd->flag & eParticleInstanceFlag_Children) { + ChildParticle *cpa = psys->child; + + for (p = 0; p < psys->totchild; p++, cpa++, si++) { + *si = psys_get_child_size(psys, cpa, 0.0f, NULL); + } + } + } + + switch (pimd->space) { + case eParticleInstanceSpace_World: + /* particle states are in world space already */ + unit_m4(spacemat); + break; + case eParticleInstanceSpace_Local: + /* get particle states in the particle object's local space */ + invert_m4_m4(spacemat, pimd->ob->obmat); + break; + default: + /* should not happen */ + BLI_assert(false); + break; + } + + totvert = mesh->totvert; + totpoly = mesh->totpoly; + totloop = mesh->totloop; + totedge = mesh->totedge; + + /* count particles */ + maxvert = 0; + maxpoly = 0; + maxloop = 0; + maxedge = 0; + + for (p = part_start; p < part_end; p++) { + if (particle_skip(pimd, psys, p)) + continue; + + maxvert += totvert; + maxpoly += totpoly; + maxloop += totloop; + maxedge += totedge; + } + + psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); + + if (psys->flag & (PSYS_HAIR_DONE | PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED) { + float min[3], max[3]; + INIT_MINMAX(min, max); + BKE_mesh_minmax(mesh, min, max); + min_co = min[track]; + max_co = max[track]; + } + + result = BKE_mesh_new_nomain_from_template(mesh, maxvert, maxedge, 0, maxloop, maxpoly); + + mvert = result->mvert; + orig_mvert = mesh->mvert; + mpoly = result->mpoly; + orig_mpoly = mesh->mpoly; + mloop = result->mloop; + orig_mloop = mesh->mloop; + + MLoopCol *mloopcols_index = CustomData_get_layer_named( + &result->ldata, CD_MLOOPCOL, pimd->index_layer_name); + MLoopCol *mloopcols_value = CustomData_get_layer_named( + &result->ldata, CD_MLOOPCOL, pimd->value_layer_name); + int *vert_part_index = NULL; + float *vert_part_value = NULL; + if (mloopcols_index != NULL) { + vert_part_index = MEM_calloc_arrayN(maxvert, sizeof(int), "vertex part index array"); + } + if (mloopcols_value) { + vert_part_value = MEM_calloc_arrayN(maxvert, sizeof(float), "vertex part value array"); + } + + for (p = part_start, p_skip = 0; p < part_end; p++) { + float prev_dir[3]; + float frame[4]; /* frame orientation quaternion */ + float p_random = psys_frand(psys, 77091 + 283 * p); + + /* skip particle? */ + if (particle_skip(pimd, psys, p)) + continue; + + /* set vertices coordinates */ + for (k = 0; k < totvert; k++) { + ParticleKey state; + MVert *inMV; + int vindex = p_skip * totvert + k; + MVert *mv = mvert + vindex; + + inMV = orig_mvert + k; + CustomData_copy_data(&mesh->vdata, &result->vdata, k, p_skip * totvert + k, 1); + *mv = *inMV; + + if (vert_part_index != NULL) { + vert_part_index[vindex] = p; + } + if (vert_part_value != NULL) { + vert_part_value[vindex] = p_random; + } + + /*change orientation based on object trackflag*/ + copy_v3_v3(temp_co, mv->co); + mv->co[axis] = temp_co[track]; + mv->co[(axis + 1) % 3] = temp_co[(track + 1) % 3]; + mv->co[(axis + 2) % 3] = temp_co[(track + 2) % 3]; + + /* get particle state */ + if ((psys->flag & (PSYS_HAIR_DONE | PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED) && + (pimd->flag & eParticleInstanceFlag_Path)) { + float ran = 0.0f; + if (pimd->random_position != 0.0f) { + ran = pimd->random_position * BLI_hash_frand(psys->seed + p); + } + + if (pimd->flag & eParticleInstanceFlag_KeepShape) { + state.time = pimd->position * (1.0f - ran); + } + else { + state.time = (mv->co[axis] - min_co) / (max_co - min_co) * pimd->position * (1.0f - ran); + + if (trackneg) + state.time = 1.0f - state.time; + + mv->co[axis] = 0.0; + } + + psys_get_particle_on_path(&sim, p, &state, 1); + + normalize_v3(state.vel); + + /* Incrementally Rotating Frame (Bishop Frame) */ + if (k == 0) { + float hairmat[4][4]; + float mat[3][3]; + + if (p < psys->totpart) + pa = psys->particles + p; + else { + ChildParticle *cpa = psys->child + (p - psys->totpart); + pa = psys->particles + (between ? cpa->pa[0] : cpa->parent); + } + psys_mat_hair_to_global(sim.ob, sim.psmd->mesh_final, sim.psys->part->from, pa, hairmat); + copy_m3_m4(mat, hairmat); + /* to quaternion */ + mat3_to_quat(frame, mat); + + if (pimd->rotation > 0.0f || pimd->random_rotation > 0.0f) { + float angle = 2.0f * M_PI * + (pimd->rotation + + pimd->random_rotation * (psys_frand(psys, 19957323 + p) - 0.5f)); + float eul[3] = {0.0f, 0.0f, angle}; + float rot[4]; + + eul_to_quat(rot, eul); + mul_qt_qtqt(frame, frame, rot); + } + + /* note: direction is same as normal vector currently, + * but best to keep this separate so the frame can be + * rotated later if necessary + */ + copy_v3_v3(prev_dir, state.vel); + } + else { + float rot[4]; + + /* incrementally rotate along bend direction */ + rotation_between_vecs_to_quat(rot, prev_dir, state.vel); + mul_qt_qtqt(frame, rot, frame); + + copy_v3_v3(prev_dir, state.vel); + } + + copy_qt_qt(state.rot, frame); #if 0 - /* Absolute Frame (Frenet Frame) */ - if (state.vel[axis] < -0.9999f || state.vel[axis] > 0.9999f) { - unit_qt(state.rot); - } - else { - float cross[3]; - float temp[3] = {0.0f, 0.0f, 0.0f}; - temp[axis] = 1.0f; - - cross_v3_v3v3(cross, temp, state.vel); - - /* state.vel[axis] is the only component surviving from a dot product with the axis */ - axis_angle_to_quat(state.rot, cross, saacos(state.vel[axis])); - } + /* Absolute Frame (Frenet Frame) */ + if (state.vel[axis] < -0.9999f || state.vel[axis] > 0.9999f) { + unit_qt(state.rot); + } + else { + float cross[3]; + float temp[3] = {0.0f, 0.0f, 0.0f}; + temp[axis] = 1.0f; + + cross_v3_v3v3(cross, temp, state.vel); + + /* state.vel[axis] is the only component surviving from a dot product with the axis */ + axis_angle_to_quat(state.rot, cross, saacos(state.vel[axis])); + } #endif - } - else { - state.time = -1.0; - psys_get_particle_state(&sim, p, &state, 1); - } - - mul_qt_v3(state.rot, mv->co); - if (pimd->flag & eParticleInstanceFlag_UseSize) - mul_v3_fl(mv->co, size[p]); - add_v3_v3(mv->co, state.co); - - mul_m4_v3(spacemat, mv->co); - } - - /* create edges and adjust edge vertex indices*/ - CustomData_copy_data(&mesh->edata, &result->edata, 0, p_skip * totedge, totedge); - MEdge *me = &result->medge[p_skip * totedge]; - for (k = 0; k < totedge; k++, me++) { - me->v1 += p_skip * totvert; - me->v2 += p_skip * totvert; - } - - /* create polys and loops */ - for (k = 0; k < totpoly; k++) { - - MPoly *inMP = orig_mpoly + k; - MPoly *mp = mpoly + p_skip * totpoly + k; - - CustomData_copy_data(&mesh->pdata, &result->pdata, k, p_skip * totpoly + k, 1); - *mp = *inMP; - mp->loopstart += p_skip * totloop; - - { - MLoop *inML = orig_mloop + inMP->loopstart; - MLoop *ml = mloop + mp->loopstart; - int j = mp->totloop; - - CustomData_copy_data(&mesh->ldata, &result->ldata, inMP->loopstart, mp->loopstart, j); - for (; j; j--, ml++, inML++) { - ml->v = inML->v + (p_skip * totvert); - ml->e = inML->e + (p_skip * totedge); - const int ml_index = (ml - mloop); - if (mloopcols_index != NULL) { - const int part_index = vert_part_index[ml->v]; - store_float_in_vcol(&mloopcols_index[ml_index], (float)part_index / (float)(psys->totpart - 1)); - } - if (mloopcols_value != NULL) { - const float part_value = vert_part_value[ml->v]; - store_float_in_vcol(&mloopcols_value[ml_index], part_value); - } - } - } - } - p_skip++; - } - - if (psys->lattice_deform_data) { - end_latt_deform(psys->lattice_deform_data); - psys->lattice_deform_data = NULL; - } - - if (size) - MEM_freeN(size); - - MEM_SAFE_FREE(vert_part_index); - MEM_SAFE_FREE(vert_part_value); - - result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; - - return result; + } + else { + state.time = -1.0; + psys_get_particle_state(&sim, p, &state, 1); + } + + mul_qt_v3(state.rot, mv->co); + if (pimd->flag & eParticleInstanceFlag_UseSize) + mul_v3_fl(mv->co, size[p]); + add_v3_v3(mv->co, state.co); + + mul_m4_v3(spacemat, mv->co); + } + + /* create edges and adjust edge vertex indices*/ + CustomData_copy_data(&mesh->edata, &result->edata, 0, p_skip * totedge, totedge); + MEdge *me = &result->medge[p_skip * totedge]; + for (k = 0; k < totedge; k++, me++) { + me->v1 += p_skip * totvert; + me->v2 += p_skip * totvert; + } + + /* create polys and loops */ + for (k = 0; k < totpoly; k++) { + + MPoly *inMP = orig_mpoly + k; + MPoly *mp = mpoly + p_skip * totpoly + k; + + CustomData_copy_data(&mesh->pdata, &result->pdata, k, p_skip * totpoly + k, 1); + *mp = *inMP; + mp->loopstart += p_skip * totloop; + + { + MLoop *inML = orig_mloop + inMP->loopstart; + MLoop *ml = mloop + mp->loopstart; + int j = mp->totloop; + + CustomData_copy_data(&mesh->ldata, &result->ldata, inMP->loopstart, mp->loopstart, j); + for (; j; j--, ml++, inML++) { + ml->v = inML->v + (p_skip * totvert); + ml->e = inML->e + (p_skip * totedge); + const int ml_index = (ml - mloop); + if (mloopcols_index != NULL) { + const int part_index = vert_part_index[ml->v]; + store_float_in_vcol(&mloopcols_index[ml_index], + (float)part_index / (float)(psys->totpart - 1)); + } + if (mloopcols_value != NULL) { + const float part_value = vert_part_value[ml->v]; + store_float_in_vcol(&mloopcols_value[ml_index], part_value); + } + } + } + } + p_skip++; + } + + if (psys->lattice_deform_data) { + end_latt_deform(psys->lattice_deform_data); + psys->lattice_deform_data = NULL; + } + + if (size) + MEM_freeN(size); + + MEM_SAFE_FREE(vert_part_index); + MEM_SAFE_FREE(vert_part_value); + + result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + + return result; } ModifierTypeInfo modifierType_ParticleInstance = { - /* name */ "ParticleInstance", - /* structName */ "ParticleInstanceModifierData", - /* structSize */ sizeof(ParticleInstanceModifierData), - /* type */ eModifierTypeType_Constructive, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_SupportsMapping | - eModifierTypeFlag_SupportsEditmode | - eModifierTypeFlag_EnableInEditmode, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ NULL, - /* isDisabled */ isDisabled, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ foreachObjectLink, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "ParticleInstance", + /* structName */ "ParticleInstanceModifierData", + /* structSize */ sizeof(ParticleInstanceModifierData), + /* type */ eModifierTypeType_Constructive, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping | + eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ NULL, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c index 5b3e104072c..547e5facbbe 100644 --- a/source/blender/modifiers/intern/MOD_particlesystem.c +++ b/source/blender/modifiers/intern/MOD_particlesystem.c @@ -21,7 +21,6 @@ * \ingroup modifiers */ - #include #include "BLI_utildefines.h" @@ -41,174 +40,175 @@ static void initData(ModifierData *md) { - ParticleSystemModifierData *psmd = (ParticleSystemModifierData *) md; - psmd->psys = NULL; - psmd->mesh_final = NULL; - psmd->mesh_original = NULL; - psmd->totdmvert = psmd->totdmedge = psmd->totdmface = 0; + ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md; + psmd->psys = NULL; + psmd->mesh_final = NULL; + psmd->mesh_original = NULL; + psmd->totdmvert = psmd->totdmedge = psmd->totdmface = 0; } static void freeData(ModifierData *md) { - ParticleSystemModifierData *psmd = (ParticleSystemModifierData *) md; - - if (psmd->mesh_final) { - BKE_id_free(NULL, psmd->mesh_final); - psmd->mesh_final = NULL; - if (psmd->mesh_original) { - BKE_id_free(NULL, psmd->mesh_original); - psmd->mesh_original = NULL; - } - } - psmd->totdmvert = psmd->totdmedge = psmd->totdmface = 0; - - /* ED_object_modifier_remove may have freed this first before calling - * modifier_free (which calls this function) */ - if (psmd->psys) - psmd->psys->flag |= PSYS_DELETE; + ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md; + + if (psmd->mesh_final) { + BKE_id_free(NULL, psmd->mesh_final); + psmd->mesh_final = NULL; + if (psmd->mesh_original) { + BKE_id_free(NULL, psmd->mesh_original); + psmd->mesh_original = NULL; + } + } + psmd->totdmvert = psmd->totdmedge = psmd->totdmface = 0; + + /* ED_object_modifier_remove may have freed this first before calling + * modifier_free (which calls this function) */ + if (psmd->psys) + psmd->psys->flag |= PSYS_DELETE; } static void copyData(const ModifierData *md, ModifierData *target, const int flag) { #if 0 - const ParticleSystemModifierData *psmd = (const ParticleSystemModifierData *) md; + const ParticleSystemModifierData *psmd = (const ParticleSystemModifierData *) md; #endif - ParticleSystemModifierData *tpsmd = (ParticleSystemModifierData *) target; + ParticleSystemModifierData *tpsmd = (ParticleSystemModifierData *)target; - modifier_copyData_generic(md, target, flag); + modifier_copyData_generic(md, target, flag); - tpsmd->mesh_final = NULL; - tpsmd->mesh_original = NULL; - tpsmd->totdmvert = tpsmd->totdmedge = tpsmd->totdmface = 0; + tpsmd->mesh_final = NULL; + tpsmd->mesh_original = NULL; + tpsmd->totdmvert = tpsmd->totdmedge = tpsmd->totdmface = 0; } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - ParticleSystemModifierData *psmd = (ParticleSystemModifierData *) md; + ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md; - psys_emitter_customdata_mask(psmd->psys, r_cddata_masks); + psys_emitter_customdata_mask(psmd->psys, r_cddata_masks); } /* saves the current emitter state for a particle system and calculates particles */ -static void deformVerts( - ModifierData *md, const ModifierEvalContext *ctx, - Mesh *mesh, - float (*vertexCos)[3], - int numVerts) +static void deformVerts(ModifierData *md, + const ModifierEvalContext *ctx, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - Mesh *mesh_src = mesh; - ParticleSystemModifierData *psmd = (ParticleSystemModifierData *) md; - ParticleSystem *psys = NULL; - /* float cfra = BKE_scene_frame_get(md->scene); */ /* UNUSED */ - - if (ctx->object->particlesystem.first) - psys = psmd->psys; - else - return; - - if (!psys_check_enabled(ctx->object, psys, (ctx->flag & MOD_APPLY_RENDER) != 0)) - return; - - if (mesh_src == NULL) { - mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, NULL, vertexCos, numVerts, false, true); - if (mesh_src == NULL) { - return; - } - } - - /* clear old dm */ - bool had_mesh_final = (psmd->mesh_final != NULL); - if (psmd->mesh_final) { - BKE_id_free(NULL, psmd->mesh_final); - psmd->mesh_final = NULL; - if (psmd->mesh_original) { - BKE_id_free(NULL, psmd->mesh_original); - psmd->mesh_original = NULL; - } - } - else if (psmd->flag & eParticleSystemFlag_file_loaded) { - /* in file read mesh just wasn't saved in file so no need to reset everything */ - psmd->flag &= ~eParticleSystemFlag_file_loaded; - if (psys->particles == NULL) { - psys->recalc |= ID_RECALC_PSYS_RESET; - } - /* TODO(sergey): This is not how particles were working prior to copy on - * write, but now evaluation is similar to case when one duplicates the - * object. In that case particles were doing reset here. */ - psys->recalc |= ID_RECALC_PSYS_RESET; - } - - /* make new mesh */ - psmd->mesh_final = BKE_mesh_copy_for_eval(mesh_src, false); - BKE_mesh_apply_vert_coords(psmd->mesh_final, vertexCos); - BKE_mesh_calc_normals(psmd->mesh_final); - - BKE_mesh_tessface_ensure(psmd->mesh_final); - - if (!psmd->mesh_final->runtime.deformed_only) { - /* Get the original mesh from the object, this is what the particles - * are attached to so in case of non-deform modifiers we need to remap - * them to the final mesh (typically subdivision surfaces). */ - Mesh *mesh_original = NULL; - - if (ctx->object->type == OB_MESH) { - BMEditMesh *em = BKE_editmesh_from_object(ctx->object); - - if (em) { - /* In edit mode get directly from the edit mesh. */ - psmd->mesh_original = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL); - } - else { - /* Otherwise get regular mesh. */ - mesh_original = ctx->object->data; - } - } - else { - mesh_original = mesh_src; - } - - if (mesh_original) { - /* Make a persistent copy of the mesh. We don't actually need - * all this data, just some topology for remapping. Could be - * optimized once. */ - psmd->mesh_original = BKE_mesh_copy_for_eval(mesh_original, false); - } - - BKE_mesh_tessface_ensure(psmd->mesh_original); - } - - if (mesh_src != psmd->mesh_final && mesh_src != mesh) { - BKE_id_free(NULL, mesh_src); - } - - /* Report change in mesh structure. - * This is an unreliable check for the topology check, but allows some - * handy configuration like emitting particles from inside particle - * instance. */ - if (had_mesh_final && - (psmd->mesh_final->totvert != psmd->totdmvert || - psmd->mesh_final->totedge != psmd->totdmedge || - psmd->mesh_final->totface != psmd->totdmface)) - { - psys->recalc |= ID_RECALC_PSYS_RESET; - psmd->totdmvert = psmd->mesh_final->totvert; - psmd->totdmedge = psmd->mesh_final->totedge; - psmd->totdmface = psmd->mesh_final->totface; - } - - if (!(ctx->object->transflag & OB_NO_PSYS_UPDATE)) { - struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); - psmd->flag &= ~eParticleSystemFlag_psys_updated; - particle_system_update(ctx->depsgraph, scene, ctx->object, psys, (ctx->flag & MOD_APPLY_RENDER) != 0); - psmd->flag |= eParticleSystemFlag_psys_updated; - } - - if (DEG_is_active(ctx->depsgraph)) { - Object *object_orig = DEG_get_original_object(ctx->object); - ModifierData *md_orig = modifiers_findByName(object_orig, psmd->modifier.name); - BLI_assert(md_orig != NULL); - ParticleSystemModifierData *psmd_orig = (ParticleSystemModifierData *) md_orig; - psmd_orig->flag = psmd->flag; - } + Mesh *mesh_src = mesh; + ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md; + ParticleSystem *psys = NULL; + /* float cfra = BKE_scene_frame_get(md->scene); */ /* UNUSED */ + + if (ctx->object->particlesystem.first) + psys = psmd->psys; + else + return; + + if (!psys_check_enabled(ctx->object, psys, (ctx->flag & MOD_APPLY_RENDER) != 0)) + return; + + if (mesh_src == NULL) { + mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, NULL, vertexCos, numVerts, false, true); + if (mesh_src == NULL) { + return; + } + } + + /* clear old dm */ + bool had_mesh_final = (psmd->mesh_final != NULL); + if (psmd->mesh_final) { + BKE_id_free(NULL, psmd->mesh_final); + psmd->mesh_final = NULL; + if (psmd->mesh_original) { + BKE_id_free(NULL, psmd->mesh_original); + psmd->mesh_original = NULL; + } + } + else if (psmd->flag & eParticleSystemFlag_file_loaded) { + /* in file read mesh just wasn't saved in file so no need to reset everything */ + psmd->flag &= ~eParticleSystemFlag_file_loaded; + if (psys->particles == NULL) { + psys->recalc |= ID_RECALC_PSYS_RESET; + } + /* TODO(sergey): This is not how particles were working prior to copy on + * write, but now evaluation is similar to case when one duplicates the + * object. In that case particles were doing reset here. */ + psys->recalc |= ID_RECALC_PSYS_RESET; + } + + /* make new mesh */ + psmd->mesh_final = BKE_mesh_copy_for_eval(mesh_src, false); + BKE_mesh_apply_vert_coords(psmd->mesh_final, vertexCos); + BKE_mesh_calc_normals(psmd->mesh_final); + + BKE_mesh_tessface_ensure(psmd->mesh_final); + + if (!psmd->mesh_final->runtime.deformed_only) { + /* Get the original mesh from the object, this is what the particles + * are attached to so in case of non-deform modifiers we need to remap + * them to the final mesh (typically subdivision surfaces). */ + Mesh *mesh_original = NULL; + + if (ctx->object->type == OB_MESH) { + BMEditMesh *em = BKE_editmesh_from_object(ctx->object); + + if (em) { + /* In edit mode get directly from the edit mesh. */ + psmd->mesh_original = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL); + } + else { + /* Otherwise get regular mesh. */ + mesh_original = ctx->object->data; + } + } + else { + mesh_original = mesh_src; + } + + if (mesh_original) { + /* Make a persistent copy of the mesh. We don't actually need + * all this data, just some topology for remapping. Could be + * optimized once. */ + psmd->mesh_original = BKE_mesh_copy_for_eval(mesh_original, false); + } + + BKE_mesh_tessface_ensure(psmd->mesh_original); + } + + if (mesh_src != psmd->mesh_final && mesh_src != mesh) { + BKE_id_free(NULL, mesh_src); + } + + /* Report change in mesh structure. + * This is an unreliable check for the topology check, but allows some + * handy configuration like emitting particles from inside particle + * instance. */ + if (had_mesh_final && (psmd->mesh_final->totvert != psmd->totdmvert || + psmd->mesh_final->totedge != psmd->totdmedge || + psmd->mesh_final->totface != psmd->totdmface)) { + psys->recalc |= ID_RECALC_PSYS_RESET; + psmd->totdmvert = psmd->mesh_final->totvert; + psmd->totdmedge = psmd->mesh_final->totedge; + psmd->totdmface = psmd->mesh_final->totface; + } + + if (!(ctx->object->transflag & OB_NO_PSYS_UPDATE)) { + struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); + psmd->flag &= ~eParticleSystemFlag_psys_updated; + particle_system_update( + ctx->depsgraph, scene, ctx->object, psys, (ctx->flag & MOD_APPLY_RENDER) != 0); + psmd->flag |= eParticleSystemFlag_psys_updated; + } + + if (DEG_is_active(ctx->depsgraph)) { + Object *object_orig = DEG_get_original_object(ctx->object); + ModifierData *md_orig = modifiers_findByName(object_orig, psmd->modifier.name); + BLI_assert(md_orig != NULL); + ParticleSystemModifierData *psmd_orig = (ParticleSystemModifierData *)md_orig; + psmd_orig->flag = psmd->flag; + } } /* disabled particles in editmode for now, until support for proper evaluated mesh @@ -218,49 +218,48 @@ static void deformVertsEM( ModifierData *md, Object *ob, BMEditMesh *editData, Mesh *mesh, float (*vertexCos)[3], int numVerts) { - const bool do_temp_mesh = (mesh == NULL); - if (do_temp_mesh) { - mesh = BKE_id_new_nomain(ID_ME, ((ID *)ob->data)->name); - BM_mesh_bm_to_me(NULL, editData->bm, mesh, &((BMeshToMeshParams){0})); - } + const bool do_temp_mesh = (mesh == NULL); + if (do_temp_mesh) { + mesh = BKE_id_new_nomain(ID_ME, ((ID *)ob->data)->name); + BM_mesh_bm_to_me(NULL, editData->bm, mesh, &((BMeshToMeshParams){0})); + } - deformVerts(md, ob, mesh, vertexCos, numVerts); + deformVerts(md, ob, mesh, vertexCos, numVerts); - if (derivedData) { - BKE_id_free(NULL, mesh); - } + if (derivedData) { + BKE_id_free(NULL, mesh); + } } #endif - ModifierTypeInfo modifierType_ParticleSystem = { - /* name */ "ParticleSystem", - /* structName */ "ParticleSystemModifierData", - /* structSize */ sizeof(ParticleSystemModifierData), - /* type */ eModifierTypeType_OnlyDeform, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_SupportsMapping | - eModifierTypeFlag_UsesPointCache /* | - eModifierTypeFlag_SupportsEditmode | - eModifierTypeFlag_EnableInEditmode */, - - /* copyData */ copyData, - - /* deformVerts */ deformVerts, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ NULL, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ freeData, - /* isDisabled */ NULL, - /* updateDepsgraph */ NULL, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ NULL, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "ParticleSystem", + /* structName */ "ParticleSystemModifierData", + /* structSize */ sizeof(ParticleSystemModifierData), + /* type */ eModifierTypeType_OnlyDeform, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping | + eModifierTypeFlag_UsesPointCache /* | + eModifierTypeFlag_SupportsEditmode | + eModifierTypeFlag_EnableInEditmode */ + , + + /* copyData */ copyData, + + /* deformVerts */ deformVerts, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ NULL, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ freeData, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_remesh.c b/source/blender/modifiers/intern/MOD_remesh.c index 345ee6477ac..daf9a615f3f 100644 --- a/source/blender/modifiers/intern/MOD_remesh.c +++ b/source/blender/modifiers/intern/MOD_remesh.c @@ -48,188 +48,181 @@ static void initData(ModifierData *md) { - RemeshModifierData *rmd = (RemeshModifierData *) md; - - rmd->scale = 0.9; - rmd->depth = 4; - rmd->hermite_num = 1; - rmd->flag = MOD_REMESH_FLOOD_FILL; - rmd->mode = MOD_REMESH_SHARP_FEATURES; - rmd->threshold = 1; + RemeshModifierData *rmd = (RemeshModifierData *)md; + + rmd->scale = 0.9; + rmd->depth = 4; + rmd->hermite_num = 1; + rmd->flag = MOD_REMESH_FLOOD_FILL; + rmd->mode = MOD_REMESH_SHARP_FEATURES; + rmd->threshold = 1; } #ifdef WITH_MOD_REMESH static void init_dualcon_mesh(DualConInput *input, Mesh *mesh) { - memset(input, 0, sizeof(DualConInput)); + memset(input, 0, sizeof(DualConInput)); - input->co = (void *)mesh->mvert; - input->co_stride = sizeof(MVert); - input->totco = mesh->totvert; + input->co = (void *)mesh->mvert; + input->co_stride = sizeof(MVert); + input->totco = mesh->totvert; - input->mloop = (void *)mesh->mloop; - input->loop_stride = sizeof(MLoop); + input->mloop = (void *)mesh->mloop; + input->loop_stride = sizeof(MLoop); - BKE_mesh_runtime_looptri_ensure(mesh); - input->looptri = (void *)mesh->runtime.looptris.array; - input->tri_stride = sizeof(MLoopTri); - input->tottri = mesh->runtime.looptris.len; + BKE_mesh_runtime_looptri_ensure(mesh); + input->looptri = (void *)mesh->runtime.looptris.array; + input->tri_stride = sizeof(MLoopTri); + input->tottri = mesh->runtime.looptris.len; - INIT_MINMAX(input->min, input->max); - BKE_mesh_minmax(mesh, input->min, input->max); + INIT_MINMAX(input->min, input->max); + BKE_mesh_minmax(mesh, input->min, input->max); } /* simple structure to hold the output: a CDDM and two counters to * keep track of the current elements */ typedef struct { - Mesh *mesh; - int curvert, curface; + Mesh *mesh; + int curvert, curface; } DualConOutput; /* allocate and initialize a DualConOutput */ static void *dualcon_alloc_output(int totvert, int totquad) { - DualConOutput *output; + DualConOutput *output; - if (!(output = MEM_callocN(sizeof(DualConOutput), - "DualConOutput"))) - { - return NULL; - } + if (!(output = MEM_callocN(sizeof(DualConOutput), "DualConOutput"))) { + return NULL; + } - output->mesh = BKE_mesh_new_nomain(totvert, 0, 0, 4 * totquad, totquad); - return output; + output->mesh = BKE_mesh_new_nomain(totvert, 0, 0, 4 * totquad, totquad); + return output; } static void dualcon_add_vert(void *output_v, const float co[3]) { - DualConOutput *output = output_v; - Mesh *mesh = output->mesh; + DualConOutput *output = output_v; + Mesh *mesh = output->mesh; - assert(output->curvert < mesh->totvert); + assert(output->curvert < mesh->totvert); - copy_v3_v3(mesh->mvert[output->curvert].co, co); - output->curvert++; + copy_v3_v3(mesh->mvert[output->curvert].co, co); + output->curvert++; } static void dualcon_add_quad(void *output_v, const int vert_indices[4]) { - DualConOutput *output = output_v; - Mesh *mesh = output->mesh; - MLoop *mloop; - MPoly *cur_poly; - int i; + DualConOutput *output = output_v; + Mesh *mesh = output->mesh; + MLoop *mloop; + MPoly *cur_poly; + int i; - assert(output->curface < mesh->totpoly); + assert(output->curface < mesh->totpoly); - mloop = mesh->mloop; - cur_poly = &mesh->mpoly[output->curface]; + mloop = mesh->mloop; + cur_poly = &mesh->mpoly[output->curface]; - cur_poly->loopstart = output->curface * 4; - cur_poly->totloop = 4; - for (i = 0; i < 4; i++) - mloop[output->curface * 4 + i].v = vert_indices[i]; + cur_poly->loopstart = output->curface * 4; + cur_poly->totloop = 4; + for (i = 0; i < 4; i++) + mloop[output->curface * 4 + i].v = vert_indices[i]; - output->curface++; + output->curface++; } -static Mesh *applyModifier( - ModifierData *md, - const ModifierEvalContext *UNUSED(ctx), - Mesh *mesh) +static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *UNUSED(ctx), Mesh *mesh) { - RemeshModifierData *rmd; - DualConOutput *output; - DualConInput input; - Mesh *result; - DualConFlags flags = 0; - DualConMode mode = 0; - - rmd = (RemeshModifierData *)md; - - init_dualcon_mesh(&input, mesh); - - if (rmd->flag & MOD_REMESH_FLOOD_FILL) - flags |= DUALCON_FLOOD_FILL; - - switch (rmd->mode) { - case MOD_REMESH_CENTROID: - mode = DUALCON_CENTROID; - break; - case MOD_REMESH_MASS_POINT: - mode = DUALCON_MASS_POINT; - break; - case MOD_REMESH_SHARP_FEATURES: - mode = DUALCON_SHARP_FEATURES; - break; - } - - output = dualcon(&input, - dualcon_alloc_output, - dualcon_add_vert, - dualcon_add_quad, - flags, - mode, - rmd->threshold, - rmd->hermite_num, - rmd->scale, - rmd->depth); - result = output->mesh; - MEM_freeN(output); - - if (rmd->flag & MOD_REMESH_SMOOTH_SHADING) { - MPoly *mpoly = result->mpoly; - int i, totpoly = result->totpoly; - - /* Apply smooth shading to output faces */ - for (i = 0; i < totpoly; i++) { - mpoly[i].flag |= ME_SMOOTH; - } - } - - BKE_mesh_calc_edges(result, true, false); - result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; - return result; + RemeshModifierData *rmd; + DualConOutput *output; + DualConInput input; + Mesh *result; + DualConFlags flags = 0; + DualConMode mode = 0; + + rmd = (RemeshModifierData *)md; + + init_dualcon_mesh(&input, mesh); + + if (rmd->flag & MOD_REMESH_FLOOD_FILL) + flags |= DUALCON_FLOOD_FILL; + + switch (rmd->mode) { + case MOD_REMESH_CENTROID: + mode = DUALCON_CENTROID; + break; + case MOD_REMESH_MASS_POINT: + mode = DUALCON_MASS_POINT; + break; + case MOD_REMESH_SHARP_FEATURES: + mode = DUALCON_SHARP_FEATURES; + break; + } + + output = dualcon(&input, + dualcon_alloc_output, + dualcon_add_vert, + dualcon_add_quad, + flags, + mode, + rmd->threshold, + rmd->hermite_num, + rmd->scale, + rmd->depth); + result = output->mesh; + MEM_freeN(output); + + if (rmd->flag & MOD_REMESH_SMOOTH_SHADING) { + MPoly *mpoly = result->mpoly; + int i, totpoly = result->totpoly; + + /* Apply smooth shading to output faces */ + for (i = 0; i < totpoly; i++) { + mpoly[i].flag |= ME_SMOOTH; + } + } + + BKE_mesh_calc_edges(result, true, false); + result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + return result; } #else /* !WITH_MOD_REMESH */ -static Mesh *applyModifier( - ModifierData *UNUSED(md), - const ModifierEvalContext *UNUSED(ctx), - Mesh *mesh) +static Mesh *applyModifier(ModifierData *UNUSED(md), + const ModifierEvalContext *UNUSED(ctx), + Mesh *mesh) { - return mesh; + return mesh; } #endif /* !WITH_MOD_REMESH */ ModifierTypeInfo modifierType_Remesh = { - /* name */ "Remesh", - /* structName */ "RemeshModifierData", - /* structSize */ sizeof(RemeshModifierData), - /* type */ eModifierTypeType_Nonconstructive, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_AcceptsCVs | - eModifierTypeFlag_SupportsEditmode, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ initData, - /* requiredDataMask */ NULL, - /* freeData */ NULL, - /* isDisabled */ NULL, - /* updateDepsgraph */ NULL, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ NULL, - /* foreachIDLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Remesh", + /* structName */ "RemeshModifierData", + /* structSize */ sizeof(RemeshModifierData), + /* type */ eModifierTypeType_Nonconstructive, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs | + eModifierTypeFlag_SupportsEditmode, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ initData, + /* requiredDataMask */ NULL, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c index 8e881fd09f0..e2917e2f82a 100644 --- a/source/blender/modifiers/intern/MOD_screw.c +++ b/source/blender/modifiers/intern/MOD_screw.c @@ -21,7 +21,6 @@ * \ingroup modifiers */ - /* Screw modifier: revolves the edges about an axis */ #include @@ -47,1109 +46,1117 @@ /* used for gathering edge connectivity */ typedef struct ScrewVertConnect { - float dist; /* distance from the center axis */ - float co[3]; /* location relative to the transformed axis */ - float no[3]; /* calc normal of the vertex */ - unsigned int v[2]; /* 2 verts on either side of this one */ - MEdge *e[2]; /* edges on either side, a bit of a waste since each edge ref's 2 edges */ - char flag; + float dist; /* distance from the center axis */ + float co[3]; /* location relative to the transformed axis */ + float no[3]; /* calc normal of the vertex */ + unsigned int v[2]; /* 2 verts on either side of this one */ + MEdge *e[2]; /* edges on either side, a bit of a waste since each edge ref's 2 edges */ + char flag; } ScrewVertConnect; typedef struct ScrewVertIter { - ScrewVertConnect *v_array; - ScrewVertConnect *v_poin; - unsigned int v, v_other; - MEdge *e; + ScrewVertConnect *v_array; + ScrewVertConnect *v_poin; + unsigned int v, v_other; + MEdge *e; } ScrewVertIter; #define SV_UNUSED (UINT_MAX) -#define SV_INVALID ((UINT_MAX) - 1) +#define SV_INVALID ((UINT_MAX)-1) #define SV_IS_VALID(v) ((v) < SV_INVALID) -static void screwvert_iter_init(ScrewVertIter *iter, ScrewVertConnect *array, unsigned int v_init, unsigned int dir) +static void screwvert_iter_init(ScrewVertIter *iter, + ScrewVertConnect *array, + unsigned int v_init, + unsigned int dir) { - iter->v_array = array; - iter->v = v_init; - - if (SV_IS_VALID(v_init)) { - iter->v_poin = &array[v_init]; - iter->v_other = iter->v_poin->v[dir]; - iter->e = iter->v_poin->e[!dir]; - } - else { - iter->v_poin = NULL; - iter->e = NULL; - } + iter->v_array = array; + iter->v = v_init; + + if (SV_IS_VALID(v_init)) { + iter->v_poin = &array[v_init]; + iter->v_other = iter->v_poin->v[dir]; + iter->e = iter->v_poin->e[!dir]; + } + else { + iter->v_poin = NULL; + iter->e = NULL; + } } - static void screwvert_iter_step(ScrewVertIter *iter) { - if (iter->v_poin->v[0] == iter->v_other) { - iter->v_other = iter->v; - iter->v = iter->v_poin->v[1]; - } - else if (iter->v_poin->v[1] == iter->v_other) { - iter->v_other = iter->v; - iter->v = iter->v_poin->v[0]; - } - if (SV_IS_VALID(iter->v)) { - iter->v_poin = &iter->v_array[iter->v]; - iter->e = iter->v_poin->e[(iter->v_poin->e[0] == iter->e)]; - } - else { - iter->e = NULL; - iter->v_poin = NULL; - } + if (iter->v_poin->v[0] == iter->v_other) { + iter->v_other = iter->v; + iter->v = iter->v_poin->v[1]; + } + else if (iter->v_poin->v[1] == iter->v_other) { + iter->v_other = iter->v; + iter->v = iter->v_poin->v[0]; + } + if (SV_IS_VALID(iter->v)) { + iter->v_poin = &iter->v_array[iter->v]; + iter->e = iter->v_poin->e[(iter->v_poin->e[0] == iter->e)]; + } + else { + iter->e = NULL; + iter->v_poin = NULL; + } } -static Mesh *mesh_remove_doubles_on_axis( - Mesh *result, MVert *mvert_new, const uint totvert, const uint step_tot, - const float axis_vec[3], const float axis_offset[3], const float merge_threshold) +static Mesh *mesh_remove_doubles_on_axis(Mesh *result, + MVert *mvert_new, + const uint totvert, + const uint step_tot, + const float axis_vec[3], + const float axis_offset[3], + const float merge_threshold) { - const float merge_threshold_sq = SQUARE(merge_threshold); - const bool use_offset = axis_offset != NULL; - uint tot_doubles = 0; - for (uint i = 0; i < totvert; i += 1) { - float axis_co[3]; - if (use_offset) { - float offset_co[3]; - sub_v3_v3v3(offset_co, mvert_new[i].co, axis_offset); - project_v3_v3v3_normalized(axis_co, offset_co, axis_vec); - add_v3_v3(axis_co, axis_offset); - } - else { - project_v3_v3v3_normalized(axis_co, mvert_new[i].co, axis_vec); - } - const float dist_sq = len_squared_v3v3(axis_co, mvert_new[i].co); - if (dist_sq <= merge_threshold_sq) { - mvert_new[i].flag |= ME_VERT_TMP_TAG; - tot_doubles += 1; - copy_v3_v3(mvert_new[i].co, axis_co); - } - } - - if (tot_doubles != 0) { - uint tot = totvert * step_tot; - int *full_doubles_map = MEM_malloc_arrayN(tot, sizeof(int), __func__); - copy_vn_i(full_doubles_map, (int)tot, -1); - - uint tot_doubles_left = tot_doubles; - for (uint i = 0; i < totvert; i += 1) { - if (mvert_new[i].flag & ME_VERT_TMP_TAG) { - int *doubles_map = &full_doubles_map[totvert + i] ; - for (uint step = 1; step < step_tot; step += 1) { - *doubles_map = (int)i; - doubles_map += totvert; - } - tot_doubles_left -= 1; - if (tot_doubles_left == 0) { - break; - } - } - } - result = BKE_mesh_merge_verts(result, full_doubles_map, (int)(tot_doubles * (step_tot - 1)), MESH_MERGE_VERTS_DUMP_IF_MAPPED); - MEM_freeN(full_doubles_map); - } - return result; + const float merge_threshold_sq = SQUARE(merge_threshold); + const bool use_offset = axis_offset != NULL; + uint tot_doubles = 0; + for (uint i = 0; i < totvert; i += 1) { + float axis_co[3]; + if (use_offset) { + float offset_co[3]; + sub_v3_v3v3(offset_co, mvert_new[i].co, axis_offset); + project_v3_v3v3_normalized(axis_co, offset_co, axis_vec); + add_v3_v3(axis_co, axis_offset); + } + else { + project_v3_v3v3_normalized(axis_co, mvert_new[i].co, axis_vec); + } + const float dist_sq = len_squared_v3v3(axis_co, mvert_new[i].co); + if (dist_sq <= merge_threshold_sq) { + mvert_new[i].flag |= ME_VERT_TMP_TAG; + tot_doubles += 1; + copy_v3_v3(mvert_new[i].co, axis_co); + } + } + + if (tot_doubles != 0) { + uint tot = totvert * step_tot; + int *full_doubles_map = MEM_malloc_arrayN(tot, sizeof(int), __func__); + copy_vn_i(full_doubles_map, (int)tot, -1); + + uint tot_doubles_left = tot_doubles; + for (uint i = 0; i < totvert; i += 1) { + if (mvert_new[i].flag & ME_VERT_TMP_TAG) { + int *doubles_map = &full_doubles_map[totvert + i]; + for (uint step = 1; step < step_tot; step += 1) { + *doubles_map = (int)i; + doubles_map += totvert; + } + tot_doubles_left -= 1; + if (tot_doubles_left == 0) { + break; + } + } + } + result = BKE_mesh_merge_verts(result, + full_doubles_map, + (int)(tot_doubles * (step_tot - 1)), + MESH_MERGE_VERTS_DUMP_IF_MAPPED); + MEM_freeN(full_doubles_map); + } + return result; } static void initData(ModifierData *md) { - ScrewModifierData *ltmd = (ScrewModifierData *) md; - ltmd->ob_axis = NULL; - ltmd->angle = (float)(M_PI * 2.0); - ltmd->axis = 2; - ltmd->flag = MOD_SCREW_SMOOTH_SHADING; - ltmd->steps = 16; - ltmd->render_steps = 16; - ltmd->iter = 1; - ltmd->merge_dist = 0.01f; + ScrewModifierData *ltmd = (ScrewModifierData *)md; + ltmd->ob_axis = NULL; + ltmd->angle = (float)(M_PI * 2.0); + ltmd->axis = 2; + ltmd->flag = MOD_SCREW_SMOOTH_SHADING; + ltmd->steps = 16; + ltmd->render_steps = 16; + ltmd->iter = 1; + ltmd->merge_dist = 0.01f; } -static Mesh *applyModifier( - ModifierData *md, const ModifierEvalContext *ctx, - Mesh *meshData) +static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *meshData) { - Mesh *mesh = meshData; - Mesh *result; - ScrewModifierData *ltmd = (ScrewModifierData *) md; - const bool use_render_params = (ctx->flag & MOD_APPLY_RENDER) != 0; - - int *origindex; - int mpoly_index = 0; - unsigned int step; - unsigned int i, j; - unsigned int i1, i2; - unsigned int step_tot = use_render_params ? ltmd->render_steps : ltmd->steps; - const bool do_flip = (ltmd->flag & MOD_SCREW_NORMAL_FLIP) != 0; - - const int quad_ord[4] = { - do_flip ? 3 : 0, - do_flip ? 2 : 1, - do_flip ? 1 : 2, - do_flip ? 0 : 3, - }; - const int quad_ord_ofs[4] = { - do_flip ? 2 : 0, - 1, - do_flip ? 0 : 2, - 3, - }; - - unsigned int maxVerts = 0, maxEdges = 0, maxPolys = 0; - const unsigned int totvert = (unsigned int)mesh->totvert; - const unsigned int totedge = (unsigned int)mesh->totedge; - const unsigned int totpoly = (unsigned int)mesh->totpoly; - - unsigned int *edge_poly_map = NULL; /* orig edge to orig poly */ - unsigned int *vert_loop_map = NULL; /* orig vert to orig loop */ - - /* UV Coords */ - const unsigned int mloopuv_layers_tot = (unsigned int)CustomData_number_of_layers(&mesh->ldata, CD_MLOOPUV); - MLoopUV **mloopuv_layers = BLI_array_alloca(mloopuv_layers, mloopuv_layers_tot); - float uv_u_scale; - float uv_v_minmax[2] = {FLT_MAX, -FLT_MAX}; - float uv_v_range_inv; - float uv_axis_plane[4]; - - char axis_char = 'X'; - bool close; - float angle = ltmd->angle; - float screw_ofs = ltmd->screw_ofs; - float axis_vec[3] = {0.0f, 0.0f, 0.0f}; - float tmp_vec1[3], tmp_vec2[3]; - float mat3[3][3]; - /* transform the coords by an object relative to this objects transformation */ - float mtx_tx[4][4]; - float mtx_tx_inv[4][4]; /* inverted */ - float mtx_tmp_a[4][4]; - - unsigned int vc_tot_linked = 0; - short other_axis_1, other_axis_2; - const float *tmpf1, *tmpf2; - - unsigned int edge_offset; - - MPoly *mpoly_orig, *mpoly_new, *mp_new; - MLoop *mloop_orig, *mloop_new, *ml_new; - MEdge *medge_orig, *med_orig, *med_new, *med_new_firstloop, *medge_new; - MVert *mvert_new, *mvert_orig, *mv_orig, *mv_new, *mv_new_base; - - Object *ob_axis = ltmd->ob_axis; - - ScrewVertConnect *vc, *vc_tmp, *vert_connect = NULL; - - const char mpoly_flag = (ltmd->flag & MOD_SCREW_SMOOTH_SHADING) ? ME_SMOOTH : 0; - - /* don't do anything? */ - if (!totvert) - return BKE_mesh_new_nomain_from_template(mesh, 0, 0, 0, 0, 0); - - switch (ltmd->axis) { - case 0: - other_axis_1 = 1; - other_axis_2 = 2; - break; - case 1: - other_axis_1 = 0; - other_axis_2 = 2; - break; - default: /* 2, use default to quiet warnings */ - other_axis_1 = 0; - other_axis_2 = 1; - break; - } - - axis_vec[ltmd->axis] = 1.0f; - - if (ob_axis != NULL) { - /* calc the matrix relative to the axis object */ - invert_m4_m4(mtx_tmp_a, ctx->object->obmat); - copy_m4_m4(mtx_tx_inv, ob_axis->obmat); - mul_m4_m4m4(mtx_tx, mtx_tmp_a, mtx_tx_inv); - - /* calc the axis vec */ - mul_mat3_m4_v3(mtx_tx, axis_vec); /* only rotation component */ - normalize_v3(axis_vec); - - /* screw */ - if (ltmd->flag & MOD_SCREW_OBJECT_OFFSET) { - /* find the offset along this axis relative to this objects matrix */ - float totlen = len_v3(mtx_tx[3]); - - if (totlen != 0.0f) { - float zero[3] = {0.0f, 0.0f, 0.0f}; - float cp[3]; - screw_ofs = closest_to_line_v3(cp, mtx_tx[3], zero, axis_vec); - } - else { - screw_ofs = 0.0f; - } - } - - /* angle */ - -#if 0 /* can't include this, not predictable enough, though quite fun. */ - if (ltmd->flag & MOD_SCREW_OBJECT_ANGLE) { - float mtx3_tx[3][3]; - copy_m3_m4(mtx3_tx, mtx_tx); - - float vec[3] = {0, 1, 0}; - float cross1[3]; - float cross2[3]; - cross_v3_v3v3(cross1, vec, axis_vec); - - mul_v3_m3v3(cross2, mtx3_tx, cross1); - { - float c1[3]; - float c2[3]; - float axis_tmp[3]; - - cross_v3_v3v3(c1, cross2, axis_vec); - cross_v3_v3v3(c2, axis_vec, c1); - - - angle = angle_v3v3(cross1, c2); - - cross_v3_v3v3(axis_tmp, cross1, c2); - normalize_v3(axis_tmp); - - if (len_v3v3(axis_tmp, axis_vec) > 1.0f) - angle = -angle; - - } - } + Mesh *mesh = meshData; + Mesh *result; + ScrewModifierData *ltmd = (ScrewModifierData *)md; + const bool use_render_params = (ctx->flag & MOD_APPLY_RENDER) != 0; + + int *origindex; + int mpoly_index = 0; + unsigned int step; + unsigned int i, j; + unsigned int i1, i2; + unsigned int step_tot = use_render_params ? ltmd->render_steps : ltmd->steps; + const bool do_flip = (ltmd->flag & MOD_SCREW_NORMAL_FLIP) != 0; + + const int quad_ord[4] = { + do_flip ? 3 : 0, + do_flip ? 2 : 1, + do_flip ? 1 : 2, + do_flip ? 0 : 3, + }; + const int quad_ord_ofs[4] = { + do_flip ? 2 : 0, + 1, + do_flip ? 0 : 2, + 3, + }; + + unsigned int maxVerts = 0, maxEdges = 0, maxPolys = 0; + const unsigned int totvert = (unsigned int)mesh->totvert; + const unsigned int totedge = (unsigned int)mesh->totedge; + const unsigned int totpoly = (unsigned int)mesh->totpoly; + + unsigned int *edge_poly_map = NULL; /* orig edge to orig poly */ + unsigned int *vert_loop_map = NULL; /* orig vert to orig loop */ + + /* UV Coords */ + const unsigned int mloopuv_layers_tot = (unsigned int)CustomData_number_of_layers(&mesh->ldata, + CD_MLOOPUV); + MLoopUV **mloopuv_layers = BLI_array_alloca(mloopuv_layers, mloopuv_layers_tot); + float uv_u_scale; + float uv_v_minmax[2] = {FLT_MAX, -FLT_MAX}; + float uv_v_range_inv; + float uv_axis_plane[4]; + + char axis_char = 'X'; + bool close; + float angle = ltmd->angle; + float screw_ofs = ltmd->screw_ofs; + float axis_vec[3] = {0.0f, 0.0f, 0.0f}; + float tmp_vec1[3], tmp_vec2[3]; + float mat3[3][3]; + /* transform the coords by an object relative to this objects transformation */ + float mtx_tx[4][4]; + float mtx_tx_inv[4][4]; /* inverted */ + float mtx_tmp_a[4][4]; + + unsigned int vc_tot_linked = 0; + short other_axis_1, other_axis_2; + const float *tmpf1, *tmpf2; + + unsigned int edge_offset; + + MPoly *mpoly_orig, *mpoly_new, *mp_new; + MLoop *mloop_orig, *mloop_new, *ml_new; + MEdge *medge_orig, *med_orig, *med_new, *med_new_firstloop, *medge_new; + MVert *mvert_new, *mvert_orig, *mv_orig, *mv_new, *mv_new_base; + + Object *ob_axis = ltmd->ob_axis; + + ScrewVertConnect *vc, *vc_tmp, *vert_connect = NULL; + + const char mpoly_flag = (ltmd->flag & MOD_SCREW_SMOOTH_SHADING) ? ME_SMOOTH : 0; + + /* don't do anything? */ + if (!totvert) + return BKE_mesh_new_nomain_from_template(mesh, 0, 0, 0, 0, 0); + + switch (ltmd->axis) { + case 0: + other_axis_1 = 1; + other_axis_2 = 2; + break; + case 1: + other_axis_1 = 0; + other_axis_2 = 2; + break; + default: /* 2, use default to quiet warnings */ + other_axis_1 = 0; + other_axis_2 = 1; + break; + } + + axis_vec[ltmd->axis] = 1.0f; + + if (ob_axis != NULL) { + /* calc the matrix relative to the axis object */ + invert_m4_m4(mtx_tmp_a, ctx->object->obmat); + copy_m4_m4(mtx_tx_inv, ob_axis->obmat); + mul_m4_m4m4(mtx_tx, mtx_tmp_a, mtx_tx_inv); + + /* calc the axis vec */ + mul_mat3_m4_v3(mtx_tx, axis_vec); /* only rotation component */ + normalize_v3(axis_vec); + + /* screw */ + if (ltmd->flag & MOD_SCREW_OBJECT_OFFSET) { + /* find the offset along this axis relative to this objects matrix */ + float totlen = len_v3(mtx_tx[3]); + + if (totlen != 0.0f) { + float zero[3] = {0.0f, 0.0f, 0.0f}; + float cp[3]; + screw_ofs = closest_to_line_v3(cp, mtx_tx[3], zero, axis_vec); + } + else { + screw_ofs = 0.0f; + } + } + + /* angle */ + +#if 0 /* can't include this, not predictable enough, though quite fun. */ + if (ltmd->flag & MOD_SCREW_OBJECT_ANGLE) { + float mtx3_tx[3][3]; + copy_m3_m4(mtx3_tx, mtx_tx); + + float vec[3] = {0, 1, 0}; + float cross1[3]; + float cross2[3]; + cross_v3_v3v3(cross1, vec, axis_vec); + + mul_v3_m3v3(cross2, mtx3_tx, cross1); + { + float c1[3]; + float c2[3]; + float axis_tmp[3]; + + cross_v3_v3v3(c1, cross2, axis_vec); + cross_v3_v3v3(c2, axis_vec, c1); + + + angle = angle_v3v3(cross1, c2); + + cross_v3_v3v3(axis_tmp, cross1, c2); + normalize_v3(axis_tmp); + + if (len_v3v3(axis_tmp, axis_vec) > 1.0f) + angle = -angle; + + } + } #endif - } - else { - /* exis char is used by i_rotate*/ - axis_char = (char)(axis_char + ltmd->axis); /* 'X' + axis */ - - /* useful to be able to use the axis vec in some cases still */ - zero_v3(axis_vec); - axis_vec[ltmd->axis] = 1.0f; - } - - /* apply the multiplier */ - angle *= (float)ltmd->iter; - screw_ofs *= (float)ltmd->iter; - uv_u_scale = 1.0f / (float)(step_tot); - - /* multiplying the steps is a bit tricky, this works best */ - step_tot = ((step_tot + 1) * ltmd->iter) - (ltmd->iter - 1); - - /* will the screw be closed? - * Note! smaller then FLT_EPSILON * 100 gives problems with float precision so its never closed. */ - if (fabsf(screw_ofs) <= (FLT_EPSILON * 100.0f) && - fabsf(fabsf(angle) - ((float)M_PI * 2.0f)) <= (FLT_EPSILON * 100.0f)) - { - close = 1; - step_tot--; - if (step_tot < 3) step_tot = 3; - - maxVerts = totvert * step_tot; /* -1 because we're joining back up */ - maxEdges = (totvert * step_tot) + /* these are the edges between new verts */ - (totedge * step_tot); /* -1 because vert edges join */ - maxPolys = totedge * step_tot; - - screw_ofs = 0.0f; - } - else { - close = 0; - if (step_tot < 3) step_tot = 3; - - maxVerts = totvert * step_tot; /* -1 because we're joining back up */ - maxEdges = (totvert * (step_tot - 1)) + /* these are the edges between new verts */ - (totedge * step_tot); /* -1 because vert edges join */ - maxPolys = totedge * (step_tot - 1); - } - - if ((ltmd->flag & MOD_SCREW_UV_STRETCH_U) == 0) { - uv_u_scale = (uv_u_scale / (float)ltmd->iter) * (angle / ((float)M_PI * 2.0f)); - } - - result = BKE_mesh_new_nomain_from_template(mesh, (int)maxVerts, (int)maxEdges, 0, (int)maxPolys * 4, (int)maxPolys); - - /* copy verts from mesh */ - mvert_orig = mesh->mvert; - medge_orig = mesh->medge; - - mvert_new = result->mvert; - mpoly_new = result->mpoly; - mloop_new = result->mloop; - medge_new = result->medge; - - if (!CustomData_has_layer(&result->pdata, CD_ORIGINDEX)) { - CustomData_add_layer(&result->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, (int)maxPolys); - } - - origindex = CustomData_get_layer(&result->pdata, CD_ORIGINDEX); - - CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, (int)totvert); - - if (mloopuv_layers_tot) { - float zero_co[3] = {0}; - plane_from_point_normal_v3(uv_axis_plane, zero_co, axis_vec); - } - - if (mloopuv_layers_tot) { - unsigned int uv_lay; - for (uv_lay = 0; uv_lay < mloopuv_layers_tot; uv_lay++) { - mloopuv_layers[uv_lay] = CustomData_get_layer_n(&result->ldata, CD_MLOOPUV, (int)uv_lay); - } - - if (ltmd->flag & MOD_SCREW_UV_STRETCH_V) { - for (i = 0, mv_orig = mvert_orig; i < totvert; i++, mv_orig++) { - const float v = dist_signed_squared_to_plane_v3(mv_orig->co, uv_axis_plane); - uv_v_minmax[0] = min_ff(v, uv_v_minmax[0]); - uv_v_minmax[1] = max_ff(v, uv_v_minmax[1]); - } - uv_v_minmax[0] = sqrtf_signed(uv_v_minmax[0]); - uv_v_minmax[1] = sqrtf_signed(uv_v_minmax[1]); - } - - uv_v_range_inv = uv_v_minmax[1] - uv_v_minmax[0]; - uv_v_range_inv = uv_v_range_inv ? 1.0f / uv_v_range_inv : 0.0f; - } - - /* Set the locations of the first set of verts */ - - mv_new = mvert_new; - mv_orig = mvert_orig; - - /* Copy the first set of edges */ - med_orig = medge_orig; - med_new = medge_new; - for (i = 0; i < totedge; i++, med_orig++, med_new++) { - med_new->v1 = med_orig->v1; - med_new->v2 = med_orig->v2; - med_new->crease = med_orig->crease; - med_new->flag = med_orig->flag & ~ME_LOOSEEDGE; - } - - /* build polygon -> edge map */ - if (totpoly) { - MPoly *mp_orig; - - mpoly_orig = mesh->mpoly; - mloop_orig = mesh->mloop; - edge_poly_map = MEM_malloc_arrayN(totedge, sizeof(*edge_poly_map), __func__); - memset(edge_poly_map, 0xff, sizeof(*edge_poly_map) * totedge); - - vert_loop_map = MEM_malloc_arrayN(totvert, sizeof(*vert_loop_map), __func__); - memset(vert_loop_map, 0xff, sizeof(*vert_loop_map) * totvert); - - for (i = 0, mp_orig = mpoly_orig; i < totpoly; i++, mp_orig++) { - unsigned int loopstart = (unsigned int)mp_orig->loopstart; - unsigned int loopend = loopstart + (unsigned int)mp_orig->totloop; - - MLoop *ml_orig = &mloop_orig[loopstart]; - unsigned int k; - for (k = loopstart; k < loopend; k++, ml_orig++) { - edge_poly_map[ml_orig->e] = i; - vert_loop_map[ml_orig->v] = k; - - /* also order edges based on faces */ - if (medge_new[ml_orig->e].v1 != ml_orig->v) { - SWAP(unsigned int, medge_new[ml_orig->e].v1, medge_new[ml_orig->e].v2); - } - } - } - } - - if (ltmd->flag & MOD_SCREW_NORMAL_CALC) { - /* - * Normal Calculation (for face flipping) - * Sort edge verts for correct face flipping - * NOT REALLY NEEDED but face flipping is nice. - * - * */ - - - /* Notice! - * - * Since we are only ordering the edges here it can avoid mallocing the - * extra space by abusing the vert array before its filled with new verts. - * The new array for vert_connect must be at least sizeof(ScrewVertConnect) * totvert - * and the size of our resulting meshes array is sizeof(MVert) * totvert * 3 - * so its safe to use the second 2 thrids of MVert the array for vert_connect, - * just make sure ScrewVertConnect struct is no more than twice as big as MVert, - * at the moment there is no chance of that being a problem, - * unless MVert becomes half its current size. - * - * once the edges are ordered, vert_connect is not needed and it can be used for verts - * - * This makes the modifier faster with one less alloc. - */ - - vert_connect = MEM_malloc_arrayN(totvert, sizeof(ScrewVertConnect), "ScrewVertConnect"); - //vert_connect = (ScrewVertConnect *) &medge_new[totvert]; /* skip the first slice of verts */ - vc = vert_connect; - - /* Copy Vert Locations */ - /* - We can do this in a later loop - only do here if no normal calc */ - if (!totedge) { - for (i = 0; i < totvert; i++, mv_orig++, mv_new++) { - copy_v3_v3(mv_new->co, mv_orig->co); - normalize_v3_v3(vc->no, mv_new->co); /* no edges- this is really a dummy normal */ - } - } - else { - /*printf("\n\n\n\n\nStarting Modifier\n");*/ - /* set edge users */ - med_new = medge_new; - mv_new = mvert_new; - - if (ob_axis != NULL) { - /*mtx_tx is initialized early on */ - for (i = 0; i < totvert; i++, mv_new++, mv_orig++, vc++) { - vc->co[0] = mv_new->co[0] = mv_orig->co[0]; - vc->co[1] = mv_new->co[1] = mv_orig->co[1]; - vc->co[2] = mv_new->co[2] = mv_orig->co[2]; - - vc->flag = 0; - vc->e[0] = vc->e[1] = NULL; - vc->v[0] = vc->v[1] = SV_UNUSED; - - mul_m4_v3(mtx_tx, vc->co); - /* length in 2d, don't sqrt because this is only for comparison */ - vc->dist = vc->co[other_axis_1] * vc->co[other_axis_1] + - vc->co[other_axis_2] * vc->co[other_axis_2]; - - /* printf("location %f %f %f -- %f\n", vc->co[0], vc->co[1], vc->co[2], vc->dist);*/ - } - } - else { - for (i = 0; i < totvert; i++, mv_new++, mv_orig++, vc++) { - vc->co[0] = mv_new->co[0] = mv_orig->co[0]; - vc->co[1] = mv_new->co[1] = mv_orig->co[1]; - vc->co[2] = mv_new->co[2] = mv_orig->co[2]; - - vc->flag = 0; - vc->e[0] = vc->e[1] = NULL; - vc->v[0] = vc->v[1] = SV_UNUSED; - - /* length in 2d, don't sqrt because this is only for comparison */ - vc->dist = vc->co[other_axis_1] * vc->co[other_axis_1] + - vc->co[other_axis_2] * vc->co[other_axis_2]; - - /* printf("location %f %f %f -- %f\n", vc->co[0], vc->co[1], vc->co[2], vc->dist);*/ - } - } - - /* this loop builds connectivity info for verts */ - for (i = 0; i < totedge; i++, med_new++) { - vc = &vert_connect[med_new->v1]; - - if (vc->v[0] == SV_UNUSED) { /* unused */ - vc->v[0] = med_new->v2; - vc->e[0] = med_new; - } - else if (vc->v[1] == SV_UNUSED) { - vc->v[1] = med_new->v2; - vc->e[1] = med_new; - } - else { - vc->v[0] = vc->v[1] = SV_INVALID; /* error value - don't use, 3 edges on vert */ - } - - vc = &vert_connect[med_new->v2]; - - /* same as above but swap v1/2 */ - if (vc->v[0] == SV_UNUSED) { /* unused */ - vc->v[0] = med_new->v1; - vc->e[0] = med_new; - } - else if (vc->v[1] == SV_UNUSED) { - vc->v[1] = med_new->v1; - vc->e[1] = med_new; - } - else { - vc->v[0] = vc->v[1] = SV_INVALID; /* error value - don't use, 3 edges on vert */ - } - } - - /* find the first vert */ - vc = vert_connect; - for (i = 0; i < totvert; i++, vc++) { - /* Now do search for connected verts, order all edges and flip them - * so resulting faces are flipped the right way */ - vc_tot_linked = 0; /* count the number of linked verts for this loop */ - if (vc->flag == 0) { - unsigned int v_best = SV_UNUSED, ed_loop_closed = 0; /* vert and vert new */ - ScrewVertIter lt_iter; - float fl = -1.0f; - - /* compiler complains if not initialized, but it should be initialized below */ - bool ed_loop_flip = false; - - /*printf("Loop on connected vert: %i\n", i);*/ - - for (j = 0; j < 2; j++) { - /*printf("\tSide: %i\n", j);*/ - screwvert_iter_init(<_iter, vert_connect, i, j); - if (j == 1) { - screwvert_iter_step(<_iter); - } - while (lt_iter.v_poin) { - /*printf("\t\tVERT: %i\n", lt_iter.v);*/ - if (lt_iter.v_poin->flag) { - /*printf("\t\t\tBreaking Found end\n");*/ - //endpoints[0] = endpoints[1] = SV_UNUSED; - ed_loop_closed = 1; /* circle */ - break; - } - lt_iter.v_poin->flag = 1; - vc_tot_linked++; - /*printf("Testing 2 floats %f : %f\n", fl, lt_iter.v_poin->dist);*/ - if (fl <= lt_iter.v_poin->dist) { - fl = lt_iter.v_poin->dist; - v_best = lt_iter.v; - /*printf("\t\t\tVERT BEST: %i\n", v_best);*/ - } - screwvert_iter_step(<_iter); - if (!lt_iter.v_poin) { - /*printf("\t\t\tFound End Also Num %i\n", j);*/ - /*endpoints[j] = lt_iter.v_other;*/ /* other is still valid */ - break; - } - } - } - - /* now we have a collection of used edges. flip their edges the right way*/ - /*if (v_best != SV_UNUSED) - */ - - /*printf("Done Looking - vc_tot_linked: %i\n", vc_tot_linked);*/ - - if (vc_tot_linked > 1) { - float vf_1, vf_2, vf_best; - - vc_tmp = &vert_connect[v_best]; - - tmpf1 = vert_connect[vc_tmp->v[0]].co; - tmpf2 = vert_connect[vc_tmp->v[1]].co; - - - /* edge connects on each side! */ - if (SV_IS_VALID(vc_tmp->v[0]) && SV_IS_VALID(vc_tmp->v[1])) { - /*printf("Verts on each side (%i %i)\n", vc_tmp->v[0], vc_tmp->v[1]);*/ - /* find out which is higher */ - - vf_1 = tmpf1[ltmd->axis]; - vf_2 = tmpf2[ltmd->axis]; - vf_best = vc_tmp->co[ltmd->axis]; - - if (vf_1 < vf_best && vf_best < vf_2) { - ed_loop_flip = 0; - } - else if (vf_1 > vf_best && vf_best > vf_2) { - ed_loop_flip = 1; - } - else { - /* not so simple to work out which edge is higher */ - sub_v3_v3v3(tmp_vec1, tmpf1, vc_tmp->co); - sub_v3_v3v3(tmp_vec2, tmpf2, vc_tmp->co); - normalize_v3(tmp_vec1); - normalize_v3(tmp_vec2); - - if (tmp_vec1[ltmd->axis] < tmp_vec2[ltmd->axis]) { - ed_loop_flip = 1; - } - else { - ed_loop_flip = 0; - } - } - } - else if (SV_IS_VALID(vc_tmp->v[0])) { /*vertex only connected on 1 side */ - /*printf("Verts on ONE side (%i %i)\n", vc_tmp->v[0], vc_tmp->v[1]);*/ - if (tmpf1[ltmd->axis] < vc_tmp->co[ltmd->axis]) { /* best is above */ - ed_loop_flip = 1; - } - else { /* best is below or even... in even case we can't know what to do. */ - ed_loop_flip = 0; - } - - } + } + else { + /* exis char is used by i_rotate*/ + axis_char = (char)(axis_char + ltmd->axis); /* 'X' + axis */ + + /* useful to be able to use the axis vec in some cases still */ + zero_v3(axis_vec); + axis_vec[ltmd->axis] = 1.0f; + } + + /* apply the multiplier */ + angle *= (float)ltmd->iter; + screw_ofs *= (float)ltmd->iter; + uv_u_scale = 1.0f / (float)(step_tot); + + /* multiplying the steps is a bit tricky, this works best */ + step_tot = ((step_tot + 1) * ltmd->iter) - (ltmd->iter - 1); + + /* will the screw be closed? + * Note! smaller then FLT_EPSILON * 100 gives problems with float precision so its never closed. */ + if (fabsf(screw_ofs) <= (FLT_EPSILON * 100.0f) && + fabsf(fabsf(angle) - ((float)M_PI * 2.0f)) <= (FLT_EPSILON * 100.0f)) { + close = 1; + step_tot--; + if (step_tot < 3) + step_tot = 3; + + maxVerts = totvert * step_tot; /* -1 because we're joining back up */ + maxEdges = (totvert * step_tot) + /* these are the edges between new verts */ + (totedge * step_tot); /* -1 because vert edges join */ + maxPolys = totedge * step_tot; + + screw_ofs = 0.0f; + } + else { + close = 0; + if (step_tot < 3) + step_tot = 3; + + maxVerts = totvert * step_tot; /* -1 because we're joining back up */ + maxEdges = (totvert * (step_tot - 1)) + /* these are the edges between new verts */ + (totedge * step_tot); /* -1 because vert edges join */ + maxPolys = totedge * (step_tot - 1); + } + + if ((ltmd->flag & MOD_SCREW_UV_STRETCH_U) == 0) { + uv_u_scale = (uv_u_scale / (float)ltmd->iter) * (angle / ((float)M_PI * 2.0f)); + } + + result = BKE_mesh_new_nomain_from_template( + mesh, (int)maxVerts, (int)maxEdges, 0, (int)maxPolys * 4, (int)maxPolys); + + /* copy verts from mesh */ + mvert_orig = mesh->mvert; + medge_orig = mesh->medge; + + mvert_new = result->mvert; + mpoly_new = result->mpoly; + mloop_new = result->mloop; + medge_new = result->medge; + + if (!CustomData_has_layer(&result->pdata, CD_ORIGINDEX)) { + CustomData_add_layer(&result->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, (int)maxPolys); + } + + origindex = CustomData_get_layer(&result->pdata, CD_ORIGINDEX); + + CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, (int)totvert); + + if (mloopuv_layers_tot) { + float zero_co[3] = {0}; + plane_from_point_normal_v3(uv_axis_plane, zero_co, axis_vec); + } + + if (mloopuv_layers_tot) { + unsigned int uv_lay; + for (uv_lay = 0; uv_lay < mloopuv_layers_tot; uv_lay++) { + mloopuv_layers[uv_lay] = CustomData_get_layer_n(&result->ldata, CD_MLOOPUV, (int)uv_lay); + } + + if (ltmd->flag & MOD_SCREW_UV_STRETCH_V) { + for (i = 0, mv_orig = mvert_orig; i < totvert; i++, mv_orig++) { + const float v = dist_signed_squared_to_plane_v3(mv_orig->co, uv_axis_plane); + uv_v_minmax[0] = min_ff(v, uv_v_minmax[0]); + uv_v_minmax[1] = max_ff(v, uv_v_minmax[1]); + } + uv_v_minmax[0] = sqrtf_signed(uv_v_minmax[0]); + uv_v_minmax[1] = sqrtf_signed(uv_v_minmax[1]); + } + + uv_v_range_inv = uv_v_minmax[1] - uv_v_minmax[0]; + uv_v_range_inv = uv_v_range_inv ? 1.0f / uv_v_range_inv : 0.0f; + } + + /* Set the locations of the first set of verts */ + + mv_new = mvert_new; + mv_orig = mvert_orig; + + /* Copy the first set of edges */ + med_orig = medge_orig; + med_new = medge_new; + for (i = 0; i < totedge; i++, med_orig++, med_new++) { + med_new->v1 = med_orig->v1; + med_new->v2 = med_orig->v2; + med_new->crease = med_orig->crease; + med_new->flag = med_orig->flag & ~ME_LOOSEEDGE; + } + + /* build polygon -> edge map */ + if (totpoly) { + MPoly *mp_orig; + + mpoly_orig = mesh->mpoly; + mloop_orig = mesh->mloop; + edge_poly_map = MEM_malloc_arrayN(totedge, sizeof(*edge_poly_map), __func__); + memset(edge_poly_map, 0xff, sizeof(*edge_poly_map) * totedge); + + vert_loop_map = MEM_malloc_arrayN(totvert, sizeof(*vert_loop_map), __func__); + memset(vert_loop_map, 0xff, sizeof(*vert_loop_map) * totvert); + + for (i = 0, mp_orig = mpoly_orig; i < totpoly; i++, mp_orig++) { + unsigned int loopstart = (unsigned int)mp_orig->loopstart; + unsigned int loopend = loopstart + (unsigned int)mp_orig->totloop; + + MLoop *ml_orig = &mloop_orig[loopstart]; + unsigned int k; + for (k = loopstart; k < loopend; k++, ml_orig++) { + edge_poly_map[ml_orig->e] = i; + vert_loop_map[ml_orig->v] = k; + + /* also order edges based on faces */ + if (medge_new[ml_orig->e].v1 != ml_orig->v) { + SWAP(unsigned int, medge_new[ml_orig->e].v1, medge_new[ml_orig->e].v2); + } + } + } + } + + if (ltmd->flag & MOD_SCREW_NORMAL_CALC) { + /* + * Normal Calculation (for face flipping) + * Sort edge verts for correct face flipping + * NOT REALLY NEEDED but face flipping is nice. + * + * */ + + /* Notice! + * + * Since we are only ordering the edges here it can avoid mallocing the + * extra space by abusing the vert array before its filled with new verts. + * The new array for vert_connect must be at least sizeof(ScrewVertConnect) * totvert + * and the size of our resulting meshes array is sizeof(MVert) * totvert * 3 + * so its safe to use the second 2 thrids of MVert the array for vert_connect, + * just make sure ScrewVertConnect struct is no more than twice as big as MVert, + * at the moment there is no chance of that being a problem, + * unless MVert becomes half its current size. + * + * once the edges are ordered, vert_connect is not needed and it can be used for verts + * + * This makes the modifier faster with one less alloc. + */ + + vert_connect = MEM_malloc_arrayN(totvert, sizeof(ScrewVertConnect), "ScrewVertConnect"); + //vert_connect = (ScrewVertConnect *) &medge_new[totvert]; /* skip the first slice of verts */ + vc = vert_connect; + + /* Copy Vert Locations */ + /* - We can do this in a later loop - only do here if no normal calc */ + if (!totedge) { + for (i = 0; i < totvert; i++, mv_orig++, mv_new++) { + copy_v3_v3(mv_new->co, mv_orig->co); + normalize_v3_v3(vc->no, mv_new->co); /* no edges- this is really a dummy normal */ + } + } + else { + /*printf("\n\n\n\n\nStarting Modifier\n");*/ + /* set edge users */ + med_new = medge_new; + mv_new = mvert_new; + + if (ob_axis != NULL) { + /*mtx_tx is initialized early on */ + for (i = 0; i < totvert; i++, mv_new++, mv_orig++, vc++) { + vc->co[0] = mv_new->co[0] = mv_orig->co[0]; + vc->co[1] = mv_new->co[1] = mv_orig->co[1]; + vc->co[2] = mv_new->co[2] = mv_orig->co[2]; + + vc->flag = 0; + vc->e[0] = vc->e[1] = NULL; + vc->v[0] = vc->v[1] = SV_UNUSED; + + mul_m4_v3(mtx_tx, vc->co); + /* length in 2d, don't sqrt because this is only for comparison */ + vc->dist = vc->co[other_axis_1] * vc->co[other_axis_1] + + vc->co[other_axis_2] * vc->co[other_axis_2]; + + /* printf("location %f %f %f -- %f\n", vc->co[0], vc->co[1], vc->co[2], vc->dist);*/ + } + } + else { + for (i = 0; i < totvert; i++, mv_new++, mv_orig++, vc++) { + vc->co[0] = mv_new->co[0] = mv_orig->co[0]; + vc->co[1] = mv_new->co[1] = mv_orig->co[1]; + vc->co[2] = mv_new->co[2] = mv_orig->co[2]; + + vc->flag = 0; + vc->e[0] = vc->e[1] = NULL; + vc->v[0] = vc->v[1] = SV_UNUSED; + + /* length in 2d, don't sqrt because this is only for comparison */ + vc->dist = vc->co[other_axis_1] * vc->co[other_axis_1] + + vc->co[other_axis_2] * vc->co[other_axis_2]; + + /* printf("location %f %f %f -- %f\n", vc->co[0], vc->co[1], vc->co[2], vc->dist);*/ + } + } + + /* this loop builds connectivity info for verts */ + for (i = 0; i < totedge; i++, med_new++) { + vc = &vert_connect[med_new->v1]; + + if (vc->v[0] == SV_UNUSED) { /* unused */ + vc->v[0] = med_new->v2; + vc->e[0] = med_new; + } + else if (vc->v[1] == SV_UNUSED) { + vc->v[1] = med_new->v2; + vc->e[1] = med_new; + } + else { + vc->v[0] = vc->v[1] = SV_INVALID; /* error value - don't use, 3 edges on vert */ + } + + vc = &vert_connect[med_new->v2]; + + /* same as above but swap v1/2 */ + if (vc->v[0] == SV_UNUSED) { /* unused */ + vc->v[0] = med_new->v1; + vc->e[0] = med_new; + } + else if (vc->v[1] == SV_UNUSED) { + vc->v[1] = med_new->v1; + vc->e[1] = med_new; + } + else { + vc->v[0] = vc->v[1] = SV_INVALID; /* error value - don't use, 3 edges on vert */ + } + } + + /* find the first vert */ + vc = vert_connect; + for (i = 0; i < totvert; i++, vc++) { + /* Now do search for connected verts, order all edges and flip them + * so resulting faces are flipped the right way */ + vc_tot_linked = 0; /* count the number of linked verts for this loop */ + if (vc->flag == 0) { + unsigned int v_best = SV_UNUSED, ed_loop_closed = 0; /* vert and vert new */ + ScrewVertIter lt_iter; + float fl = -1.0f; + + /* compiler complains if not initialized, but it should be initialized below */ + bool ed_loop_flip = false; + + /*printf("Loop on connected vert: %i\n", i);*/ + + for (j = 0; j < 2; j++) { + /*printf("\tSide: %i\n", j);*/ + screwvert_iter_init(<_iter, vert_connect, i, j); + if (j == 1) { + screwvert_iter_step(<_iter); + } + while (lt_iter.v_poin) { + /*printf("\t\tVERT: %i\n", lt_iter.v);*/ + if (lt_iter.v_poin->flag) { + /*printf("\t\t\tBreaking Found end\n");*/ + //endpoints[0] = endpoints[1] = SV_UNUSED; + ed_loop_closed = 1; /* circle */ + break; + } + lt_iter.v_poin->flag = 1; + vc_tot_linked++; + /*printf("Testing 2 floats %f : %f\n", fl, lt_iter.v_poin->dist);*/ + if (fl <= lt_iter.v_poin->dist) { + fl = lt_iter.v_poin->dist; + v_best = lt_iter.v; + /*printf("\t\t\tVERT BEST: %i\n", v_best);*/ + } + screwvert_iter_step(<_iter); + if (!lt_iter.v_poin) { + /*printf("\t\t\tFound End Also Num %i\n", j);*/ + /*endpoints[j] = lt_iter.v_other;*/ /* other is still valid */ + break; + } + } + } + + /* now we have a collection of used edges. flip their edges the right way*/ + /*if (v_best != SV_UNUSED) - */ + + /*printf("Done Looking - vc_tot_linked: %i\n", vc_tot_linked);*/ + + if (vc_tot_linked > 1) { + float vf_1, vf_2, vf_best; + + vc_tmp = &vert_connect[v_best]; + + tmpf1 = vert_connect[vc_tmp->v[0]].co; + tmpf2 = vert_connect[vc_tmp->v[1]].co; + + /* edge connects on each side! */ + if (SV_IS_VALID(vc_tmp->v[0]) && SV_IS_VALID(vc_tmp->v[1])) { + /*printf("Verts on each side (%i %i)\n", vc_tmp->v[0], vc_tmp->v[1]);*/ + /* find out which is higher */ + + vf_1 = tmpf1[ltmd->axis]; + vf_2 = tmpf2[ltmd->axis]; + vf_best = vc_tmp->co[ltmd->axis]; + + if (vf_1 < vf_best && vf_best < vf_2) { + ed_loop_flip = 0; + } + else if (vf_1 > vf_best && vf_best > vf_2) { + ed_loop_flip = 1; + } + else { + /* not so simple to work out which edge is higher */ + sub_v3_v3v3(tmp_vec1, tmpf1, vc_tmp->co); + sub_v3_v3v3(tmp_vec2, tmpf2, vc_tmp->co); + normalize_v3(tmp_vec1); + normalize_v3(tmp_vec2); + + if (tmp_vec1[ltmd->axis] < tmp_vec2[ltmd->axis]) { + ed_loop_flip = 1; + } + else { + ed_loop_flip = 0; + } + } + } + else if (SV_IS_VALID(vc_tmp->v[0])) { /*vertex only connected on 1 side */ + /*printf("Verts on ONE side (%i %i)\n", vc_tmp->v[0], vc_tmp->v[1]);*/ + if (tmpf1[ltmd->axis] < vc_tmp->co[ltmd->axis]) { /* best is above */ + ed_loop_flip = 1; + } + else { /* best is below or even... in even case we can't know what to do. */ + ed_loop_flip = 0; + } + } #if 0 - else { - printf("No Connected ___\n"); - } + else { + printf("No Connected ___\n"); + } #endif - /*printf("flip direction %i\n", ed_loop_flip);*/ - + /*printf("flip direction %i\n", ed_loop_flip);*/ - /* switch the flip option if set - * note: flip is now done at face level so copying vgroup slizes is easier */ + /* switch the flip option if set + * note: flip is now done at face level so copying vgroup slizes is easier */ #if 0 - if (do_flip) - ed_loop_flip = !ed_loop_flip; + if (do_flip) + ed_loop_flip = !ed_loop_flip; #endif - if (angle < 0.0f) - ed_loop_flip = !ed_loop_flip; - - /* if its closed, we only need 1 loop */ - for (j = ed_loop_closed; j < 2; j++) { - /*printf("Ordering Side J %i\n", j);*/ - - screwvert_iter_init(<_iter, vert_connect, v_best, j); - /*printf("\n\nStarting - Loop\n");*/ - lt_iter.v_poin->flag = 1; /* so a non loop will traverse the other side */ - - - /* If this is the vert off the best vert and - * the best vert has 2 edges connected too it - * then swap the flip direction */ - if (j == 1 && SV_IS_VALID(vc_tmp->v[0]) && SV_IS_VALID(vc_tmp->v[1])) - ed_loop_flip = !ed_loop_flip; - - while (lt_iter.v_poin && lt_iter.v_poin->flag != 2) { - /*printf("\tOrdering Vert V %i\n", lt_iter.v);*/ - - lt_iter.v_poin->flag = 2; - if (lt_iter.e) { - if (lt_iter.v == lt_iter.e->v1) { - if (ed_loop_flip == 0) { - /*printf("\t\t\tFlipping 0\n");*/ - SWAP(unsigned int, lt_iter.e->v1, lt_iter.e->v2); - } - /* else { - printf("\t\t\tFlipping Not 0\n"); - }*/ - } - else if (lt_iter.v == lt_iter.e->v2) { - if (ed_loop_flip == 1) { - /*printf("\t\t\tFlipping 1\n");*/ - SWAP(unsigned int, lt_iter.e->v1, lt_iter.e->v2); - } - /* else { - printf("\t\t\tFlipping Not 1\n"); - }*/ - } - /* else { - printf("\t\tIncorrect edge topology"); - }*/ - } - /* else { - printf("\t\tNo Edge at this point\n"); - }*/ - screwvert_iter_step(<_iter); - } - } - } - } - - /* *VERTEX NORMALS* - * we know the surrounding edges are ordered correctly now - * so its safe to create vertex normals. - * - * calculate vertex normals that can be propagated on lathing - * use edge connectivity work this out */ - if (SV_IS_VALID(vc->v[0])) { - if (SV_IS_VALID(vc->v[1])) { - /* 2 edges connedted */ - /* make 2 connecting vert locations relative to the middle vert */ - sub_v3_v3v3(tmp_vec1, mvert_new[vc->v[0]].co, mvert_new[i].co); - sub_v3_v3v3(tmp_vec2, mvert_new[vc->v[1]].co, mvert_new[i].co); - /* normalize so both edges have the same influence, no matter their length */ - normalize_v3(tmp_vec1); - normalize_v3(tmp_vec2); - - /* vc_no_tmp1 - this line is the average direction of both connecting edges - * - * Use the edge order to make the subtraction, flip the normal the right way - * edge should be there but check just in case... */ - if (vc->e[0]->v1 == i) { - sub_v3_v3(tmp_vec1, tmp_vec2); - } - else { - sub_v3_v3v3(tmp_vec1, tmp_vec2, tmp_vec1); - } - } - else { - /* only 1 edge connected - same as above except - * don't need to average edge direction */ - if (vc->e[0]->v2 == i) { - sub_v3_v3v3(tmp_vec1, mvert_new[i].co, mvert_new[vc->v[0]].co); - } - else { - sub_v3_v3v3(tmp_vec1, mvert_new[vc->v[0]].co, mvert_new[i].co); - } - } - - /* tmp_vec2 - is a line 90d from the pivot to the vec - * This is used so the resulting normal points directly away from the middle */ - cross_v3_v3v3(tmp_vec2, axis_vec, vc->co); - - if (UNLIKELY(is_zero_v3(tmp_vec2))) { - /* we're _on_ the axis, so copy it based on our winding */ - if (vc->e[0]->v2 == i) { - negate_v3_v3(vc->no, axis_vec); - } - else { - copy_v3_v3(vc->no, axis_vec); - } - } - else { - /* edge average vector and right angle to the pivot make the normal */ - cross_v3_v3v3(vc->no, tmp_vec1, tmp_vec2); - } - - } - else { - copy_v3_v3(vc->no, vc->co); - } - - /* we won't be looping on this data again so copy normals here */ - if ((angle < 0.0f) != do_flip) - negate_v3(vc->no); - - normalize_v3(vc->no); - normal_float_to_short_v3(mvert_new[i].no, vc->no); - - /* Done with normals */ - } - } - } - else { - mv_orig = mvert_orig; - mv_new = mvert_new; - - for (i = 0; i < totvert; i++, mv_new++, mv_orig++) { - copy_v3_v3(mv_new->co, mv_orig->co); - } - } - /* done with edge connectivity based normal flipping */ - - /* Add Faces */ - for (step = 1; step < step_tot; step++) { - const unsigned int varray_stride = totvert * step; - float step_angle; - float nor_tx[3]; - float mat[4][4]; - /* Rotation Matrix */ - step_angle = (angle / (float)(step_tot - (!close))) * (float)step; - - if (ob_axis != NULL) { - axis_angle_normalized_to_mat3(mat3, axis_vec, step_angle); - } - else { - axis_angle_to_mat3_single(mat3, axis_char, step_angle); - } - copy_m4_m3(mat, mat3); - - if (screw_ofs) - madd_v3_v3fl(mat[3], axis_vec, screw_ofs * ((float)step / (float)(step_tot - 1))); - - /* copy a slice */ - CustomData_copy_data(&mesh->vdata, &result->vdata, 0, (int)varray_stride, (int)totvert); - - mv_new_base = mvert_new; - mv_new = &mvert_new[varray_stride]; /* advance to the next slice */ - - for (j = 0; j < totvert; j++, mv_new_base++, mv_new++) { - /* set normal */ - if (vert_connect) { - mul_v3_m3v3(nor_tx, mat3, vert_connect[j].no); - - /* set the normal now its transformed */ - normal_float_to_short_v3(mv_new->no, nor_tx); - } - - /* set location */ - copy_v3_v3(mv_new->co, mv_new_base->co); - - /* only need to set these if using non cleared memory */ - /*mv_new->mat_nr = mv_new->flag = 0;*/ - - if (ob_axis != NULL) { - sub_v3_v3(mv_new->co, mtx_tx[3]); - - mul_m4_v3(mat, mv_new->co); - - add_v3_v3(mv_new->co, mtx_tx[3]); - } - else { - mul_m4_v3(mat, mv_new->co); - } - - /* add the new edge */ - med_new->v1 = varray_stride + j; - med_new->v2 = med_new->v1 - totvert; - med_new->flag = ME_EDGEDRAW | ME_EDGERENDER; - med_new++; - } - } - - /* we can avoid if using vert alloc trick */ - if (vert_connect) { - MEM_freeN(vert_connect); - vert_connect = NULL; - } - - if (close) { - /* last loop of edges, previous loop doesn't account for the last set of edges */ - const unsigned int varray_stride = (step_tot - 1) * totvert; - - for (i = 0; i < totvert; i++) { - med_new->v1 = i; - med_new->v2 = varray_stride + i; - med_new->flag = ME_EDGEDRAW | ME_EDGERENDER; - med_new++; - } - } - - mp_new = mpoly_new; - ml_new = mloop_new; - med_new_firstloop = medge_new; - - /* more of an offset in this case */ - edge_offset = totedge + (totvert * (step_tot - (close ? 0 : 1))); - - for (i = 0; i < totedge; i++, med_new_firstloop++) { - const unsigned int step_last = step_tot - (close ? 1 : 2); - const unsigned int mpoly_index_orig = totpoly ? edge_poly_map[i] : UINT_MAX; - const bool has_mpoly_orig = (mpoly_index_orig != UINT_MAX); - float uv_v_offset_a, uv_v_offset_b; - - const unsigned int mloop_index_orig[2] = { - vert_loop_map ? vert_loop_map[medge_new[i].v1] : UINT_MAX, - vert_loop_map ? vert_loop_map[medge_new[i].v2] : UINT_MAX, - }; - const bool has_mloop_orig = mloop_index_orig[0] != UINT_MAX; - - short mat_nr; - - /* for each edge, make a cylinder of quads */ - i1 = med_new_firstloop->v1; - i2 = med_new_firstloop->v2; - - if (has_mpoly_orig) { - mat_nr = mpoly_orig[mpoly_index_orig].mat_nr; - } - else { - mat_nr = 0; - } - - if (has_mloop_orig == false && mloopuv_layers_tot) { - uv_v_offset_a = dist_signed_to_plane_v3(mvert_new[medge_new[i].v1].co, uv_axis_plane); - uv_v_offset_b = dist_signed_to_plane_v3(mvert_new[medge_new[i].v2].co, uv_axis_plane); - - if (ltmd->flag & MOD_SCREW_UV_STRETCH_V) { - uv_v_offset_a = (uv_v_offset_a - uv_v_minmax[0]) * uv_v_range_inv; - uv_v_offset_b = (uv_v_offset_b - uv_v_minmax[0]) * uv_v_range_inv; - } - } - - for (step = 0; step <= step_last; step++) { - - /* Polygon */ - if (has_mpoly_orig) { - CustomData_copy_data(&mesh->pdata, &result->pdata, (int)mpoly_index_orig, (int)mpoly_index, 1); - origindex[mpoly_index] = (int)mpoly_index_orig; - } - else { - origindex[mpoly_index] = ORIGINDEX_NONE; - mp_new->flag = mpoly_flag; - mp_new->mat_nr = mat_nr; - } - mp_new->loopstart = mpoly_index * 4; - mp_new->totloop = 4; - - - /* Loop-Custom-Data */ - if (has_mloop_orig) { - int l_index = (int)(ml_new - mloop_new); - - CustomData_copy_data(&mesh->ldata, &result->ldata, (int)mloop_index_orig[0], l_index + 0, 1); - CustomData_copy_data(&mesh->ldata, &result->ldata, (int)mloop_index_orig[1], l_index + 1, 1); - CustomData_copy_data(&mesh->ldata, &result->ldata, (int)mloop_index_orig[1], l_index + 2, 1); - CustomData_copy_data(&mesh->ldata, &result->ldata, (int)mloop_index_orig[0], l_index + 3, 1); - - if (mloopuv_layers_tot) { - unsigned int uv_lay; - const float uv_u_offset_a = (float)(step) * uv_u_scale; - const float uv_u_offset_b = (float)(step + 1) * uv_u_scale; - for (uv_lay = 0; uv_lay < mloopuv_layers_tot; uv_lay++) { - MLoopUV *mluv = &mloopuv_layers[uv_lay][l_index]; - - mluv[quad_ord[0]].uv[0] += uv_u_offset_a; - mluv[quad_ord[1]].uv[0] += uv_u_offset_a; - mluv[quad_ord[2]].uv[0] += uv_u_offset_b; - mluv[quad_ord[3]].uv[0] += uv_u_offset_b; - } - } - } - else { - if (mloopuv_layers_tot) { - int l_index = (int)(ml_new - mloop_new); - - unsigned int uv_lay; - const float uv_u_offset_a = (float)(step) * uv_u_scale; - const float uv_u_offset_b = (float)(step + 1) * uv_u_scale; - for (uv_lay = 0; uv_lay < mloopuv_layers_tot; uv_lay++) { - MLoopUV *mluv = &mloopuv_layers[uv_lay][l_index]; - - copy_v2_fl2(mluv[quad_ord[0]].uv, uv_u_offset_a, uv_v_offset_a); - copy_v2_fl2(mluv[quad_ord[1]].uv, uv_u_offset_a, uv_v_offset_b); - copy_v2_fl2(mluv[quad_ord[2]].uv, uv_u_offset_b, uv_v_offset_b); - copy_v2_fl2(mluv[quad_ord[3]].uv, uv_u_offset_b, uv_v_offset_a); - } - } - } - - /* Loop-Data */ - if (!(close && step == step_last)) { - /* regular segments */ - ml_new[quad_ord[0]].v = i1; - ml_new[quad_ord[1]].v = i2; - ml_new[quad_ord[2]].v = i2 + totvert; - ml_new[quad_ord[3]].v = i1 + totvert; - - ml_new[quad_ord_ofs[0]].e = step == 0 ? i : (edge_offset + step + (i * (step_tot - 1))) - 1; - ml_new[quad_ord_ofs[1]].e = totedge + i2; - ml_new[quad_ord_ofs[2]].e = edge_offset + step + (i * (step_tot - 1)); - ml_new[quad_ord_ofs[3]].e = totedge + i1; - - - /* new vertical edge */ - if (step) { /* The first set is already done */ - med_new->v1 = i1; - med_new->v2 = i2; - med_new->flag = med_new_firstloop->flag; - med_new->crease = med_new_firstloop->crease; - med_new++; - } - i1 += totvert; - i2 += totvert; - } - else { - /* last segment */ - ml_new[quad_ord[0]].v = i1; - ml_new[quad_ord[1]].v = i2; - ml_new[quad_ord[2]].v = med_new_firstloop->v2; - ml_new[quad_ord[3]].v = med_new_firstloop->v1; - - ml_new[quad_ord_ofs[0]].e = (edge_offset + step + (i * (step_tot - 1))) - 1; - ml_new[quad_ord_ofs[1]].e = totedge + i2; - ml_new[quad_ord_ofs[2]].e = i; - ml_new[quad_ord_ofs[3]].e = totedge + i1; - } - - mp_new++; - ml_new += 4; - mpoly_index++; - } - - /* new vertical edge */ - med_new->v1 = i1; - med_new->v2 = i2; - med_new->flag = med_new_firstloop->flag & ~ME_LOOSEEDGE; - med_new->crease = med_new_firstloop->crease; - med_new++; - } - - /* validate loop edges */ + if (angle < 0.0f) + ed_loop_flip = !ed_loop_flip; + + /* if its closed, we only need 1 loop */ + for (j = ed_loop_closed; j < 2; j++) { + /*printf("Ordering Side J %i\n", j);*/ + + screwvert_iter_init(<_iter, vert_connect, v_best, j); + /*printf("\n\nStarting - Loop\n");*/ + lt_iter.v_poin->flag = 1; /* so a non loop will traverse the other side */ + + /* If this is the vert off the best vert and + * the best vert has 2 edges connected too it + * then swap the flip direction */ + if (j == 1 && SV_IS_VALID(vc_tmp->v[0]) && SV_IS_VALID(vc_tmp->v[1])) + ed_loop_flip = !ed_loop_flip; + + while (lt_iter.v_poin && lt_iter.v_poin->flag != 2) { + /*printf("\tOrdering Vert V %i\n", lt_iter.v);*/ + + lt_iter.v_poin->flag = 2; + if (lt_iter.e) { + if (lt_iter.v == lt_iter.e->v1) { + if (ed_loop_flip == 0) { + /*printf("\t\t\tFlipping 0\n");*/ + SWAP(unsigned int, lt_iter.e->v1, lt_iter.e->v2); + } + /* else { + printf("\t\t\tFlipping Not 0\n"); + }*/ + } + else if (lt_iter.v == lt_iter.e->v2) { + if (ed_loop_flip == 1) { + /*printf("\t\t\tFlipping 1\n");*/ + SWAP(unsigned int, lt_iter.e->v1, lt_iter.e->v2); + } + /* else { + printf("\t\t\tFlipping Not 1\n"); + }*/ + } + /* else { + printf("\t\tIncorrect edge topology"); + }*/ + } + /* else { + printf("\t\tNo Edge at this point\n"); + }*/ + screwvert_iter_step(<_iter); + } + } + } + } + + /* *VERTEX NORMALS* + * we know the surrounding edges are ordered correctly now + * so its safe to create vertex normals. + * + * calculate vertex normals that can be propagated on lathing + * use edge connectivity work this out */ + if (SV_IS_VALID(vc->v[0])) { + if (SV_IS_VALID(vc->v[1])) { + /* 2 edges connedted */ + /* make 2 connecting vert locations relative to the middle vert */ + sub_v3_v3v3(tmp_vec1, mvert_new[vc->v[0]].co, mvert_new[i].co); + sub_v3_v3v3(tmp_vec2, mvert_new[vc->v[1]].co, mvert_new[i].co); + /* normalize so both edges have the same influence, no matter their length */ + normalize_v3(tmp_vec1); + normalize_v3(tmp_vec2); + + /* vc_no_tmp1 - this line is the average direction of both connecting edges + * + * Use the edge order to make the subtraction, flip the normal the right way + * edge should be there but check just in case... */ + if (vc->e[0]->v1 == i) { + sub_v3_v3(tmp_vec1, tmp_vec2); + } + else { + sub_v3_v3v3(tmp_vec1, tmp_vec2, tmp_vec1); + } + } + else { + /* only 1 edge connected - same as above except + * don't need to average edge direction */ + if (vc->e[0]->v2 == i) { + sub_v3_v3v3(tmp_vec1, mvert_new[i].co, mvert_new[vc->v[0]].co); + } + else { + sub_v3_v3v3(tmp_vec1, mvert_new[vc->v[0]].co, mvert_new[i].co); + } + } + + /* tmp_vec2 - is a line 90d from the pivot to the vec + * This is used so the resulting normal points directly away from the middle */ + cross_v3_v3v3(tmp_vec2, axis_vec, vc->co); + + if (UNLIKELY(is_zero_v3(tmp_vec2))) { + /* we're _on_ the axis, so copy it based on our winding */ + if (vc->e[0]->v2 == i) { + negate_v3_v3(vc->no, axis_vec); + } + else { + copy_v3_v3(vc->no, axis_vec); + } + } + else { + /* edge average vector and right angle to the pivot make the normal */ + cross_v3_v3v3(vc->no, tmp_vec1, tmp_vec2); + } + } + else { + copy_v3_v3(vc->no, vc->co); + } + + /* we won't be looping on this data again so copy normals here */ + if ((angle < 0.0f) != do_flip) + negate_v3(vc->no); + + normalize_v3(vc->no); + normal_float_to_short_v3(mvert_new[i].no, vc->no); + + /* Done with normals */ + } + } + } + else { + mv_orig = mvert_orig; + mv_new = mvert_new; + + for (i = 0; i < totvert; i++, mv_new++, mv_orig++) { + copy_v3_v3(mv_new->co, mv_orig->co); + } + } + /* done with edge connectivity based normal flipping */ + + /* Add Faces */ + for (step = 1; step < step_tot; step++) { + const unsigned int varray_stride = totvert * step; + float step_angle; + float nor_tx[3]; + float mat[4][4]; + /* Rotation Matrix */ + step_angle = (angle / (float)(step_tot - (!close))) * (float)step; + + if (ob_axis != NULL) { + axis_angle_normalized_to_mat3(mat3, axis_vec, step_angle); + } + else { + axis_angle_to_mat3_single(mat3, axis_char, step_angle); + } + copy_m4_m3(mat, mat3); + + if (screw_ofs) + madd_v3_v3fl(mat[3], axis_vec, screw_ofs * ((float)step / (float)(step_tot - 1))); + + /* copy a slice */ + CustomData_copy_data(&mesh->vdata, &result->vdata, 0, (int)varray_stride, (int)totvert); + + mv_new_base = mvert_new; + mv_new = &mvert_new[varray_stride]; /* advance to the next slice */ + + for (j = 0; j < totvert; j++, mv_new_base++, mv_new++) { + /* set normal */ + if (vert_connect) { + mul_v3_m3v3(nor_tx, mat3, vert_connect[j].no); + + /* set the normal now its transformed */ + normal_float_to_short_v3(mv_new->no, nor_tx); + } + + /* set location */ + copy_v3_v3(mv_new->co, mv_new_base->co); + + /* only need to set these if using non cleared memory */ + /*mv_new->mat_nr = mv_new->flag = 0;*/ + + if (ob_axis != NULL) { + sub_v3_v3(mv_new->co, mtx_tx[3]); + + mul_m4_v3(mat, mv_new->co); + + add_v3_v3(mv_new->co, mtx_tx[3]); + } + else { + mul_m4_v3(mat, mv_new->co); + } + + /* add the new edge */ + med_new->v1 = varray_stride + j; + med_new->v2 = med_new->v1 - totvert; + med_new->flag = ME_EDGEDRAW | ME_EDGERENDER; + med_new++; + } + } + + /* we can avoid if using vert alloc trick */ + if (vert_connect) { + MEM_freeN(vert_connect); + vert_connect = NULL; + } + + if (close) { + /* last loop of edges, previous loop doesn't account for the last set of edges */ + const unsigned int varray_stride = (step_tot - 1) * totvert; + + for (i = 0; i < totvert; i++) { + med_new->v1 = i; + med_new->v2 = varray_stride + i; + med_new->flag = ME_EDGEDRAW | ME_EDGERENDER; + med_new++; + } + } + + mp_new = mpoly_new; + ml_new = mloop_new; + med_new_firstloop = medge_new; + + /* more of an offset in this case */ + edge_offset = totedge + (totvert * (step_tot - (close ? 0 : 1))); + + for (i = 0; i < totedge; i++, med_new_firstloop++) { + const unsigned int step_last = step_tot - (close ? 1 : 2); + const unsigned int mpoly_index_orig = totpoly ? edge_poly_map[i] : UINT_MAX; + const bool has_mpoly_orig = (mpoly_index_orig != UINT_MAX); + float uv_v_offset_a, uv_v_offset_b; + + const unsigned int mloop_index_orig[2] = { + vert_loop_map ? vert_loop_map[medge_new[i].v1] : UINT_MAX, + vert_loop_map ? vert_loop_map[medge_new[i].v2] : UINT_MAX, + }; + const bool has_mloop_orig = mloop_index_orig[0] != UINT_MAX; + + short mat_nr; + + /* for each edge, make a cylinder of quads */ + i1 = med_new_firstloop->v1; + i2 = med_new_firstloop->v2; + + if (has_mpoly_orig) { + mat_nr = mpoly_orig[mpoly_index_orig].mat_nr; + } + else { + mat_nr = 0; + } + + if (has_mloop_orig == false && mloopuv_layers_tot) { + uv_v_offset_a = dist_signed_to_plane_v3(mvert_new[medge_new[i].v1].co, uv_axis_plane); + uv_v_offset_b = dist_signed_to_plane_v3(mvert_new[medge_new[i].v2].co, uv_axis_plane); + + if (ltmd->flag & MOD_SCREW_UV_STRETCH_V) { + uv_v_offset_a = (uv_v_offset_a - uv_v_minmax[0]) * uv_v_range_inv; + uv_v_offset_b = (uv_v_offset_b - uv_v_minmax[0]) * uv_v_range_inv; + } + } + + for (step = 0; step <= step_last; step++) { + + /* Polygon */ + if (has_mpoly_orig) { + CustomData_copy_data( + &mesh->pdata, &result->pdata, (int)mpoly_index_orig, (int)mpoly_index, 1); + origindex[mpoly_index] = (int)mpoly_index_orig; + } + else { + origindex[mpoly_index] = ORIGINDEX_NONE; + mp_new->flag = mpoly_flag; + mp_new->mat_nr = mat_nr; + } + mp_new->loopstart = mpoly_index * 4; + mp_new->totloop = 4; + + /* Loop-Custom-Data */ + if (has_mloop_orig) { + int l_index = (int)(ml_new - mloop_new); + + CustomData_copy_data( + &mesh->ldata, &result->ldata, (int)mloop_index_orig[0], l_index + 0, 1); + CustomData_copy_data( + &mesh->ldata, &result->ldata, (int)mloop_index_orig[1], l_index + 1, 1); + CustomData_copy_data( + &mesh->ldata, &result->ldata, (int)mloop_index_orig[1], l_index + 2, 1); + CustomData_copy_data( + &mesh->ldata, &result->ldata, (int)mloop_index_orig[0], l_index + 3, 1); + + if (mloopuv_layers_tot) { + unsigned int uv_lay; + const float uv_u_offset_a = (float)(step)*uv_u_scale; + const float uv_u_offset_b = (float)(step + 1) * uv_u_scale; + for (uv_lay = 0; uv_lay < mloopuv_layers_tot; uv_lay++) { + MLoopUV *mluv = &mloopuv_layers[uv_lay][l_index]; + + mluv[quad_ord[0]].uv[0] += uv_u_offset_a; + mluv[quad_ord[1]].uv[0] += uv_u_offset_a; + mluv[quad_ord[2]].uv[0] += uv_u_offset_b; + mluv[quad_ord[3]].uv[0] += uv_u_offset_b; + } + } + } + else { + if (mloopuv_layers_tot) { + int l_index = (int)(ml_new - mloop_new); + + unsigned int uv_lay; + const float uv_u_offset_a = (float)(step)*uv_u_scale; + const float uv_u_offset_b = (float)(step + 1) * uv_u_scale; + for (uv_lay = 0; uv_lay < mloopuv_layers_tot; uv_lay++) { + MLoopUV *mluv = &mloopuv_layers[uv_lay][l_index]; + + copy_v2_fl2(mluv[quad_ord[0]].uv, uv_u_offset_a, uv_v_offset_a); + copy_v2_fl2(mluv[quad_ord[1]].uv, uv_u_offset_a, uv_v_offset_b); + copy_v2_fl2(mluv[quad_ord[2]].uv, uv_u_offset_b, uv_v_offset_b); + copy_v2_fl2(mluv[quad_ord[3]].uv, uv_u_offset_b, uv_v_offset_a); + } + } + } + + /* Loop-Data */ + if (!(close && step == step_last)) { + /* regular segments */ + ml_new[quad_ord[0]].v = i1; + ml_new[quad_ord[1]].v = i2; + ml_new[quad_ord[2]].v = i2 + totvert; + ml_new[quad_ord[3]].v = i1 + totvert; + + ml_new[quad_ord_ofs[0]].e = step == 0 ? i : + (edge_offset + step + (i * (step_tot - 1))) - 1; + ml_new[quad_ord_ofs[1]].e = totedge + i2; + ml_new[quad_ord_ofs[2]].e = edge_offset + step + (i * (step_tot - 1)); + ml_new[quad_ord_ofs[3]].e = totedge + i1; + + /* new vertical edge */ + if (step) { /* The first set is already done */ + med_new->v1 = i1; + med_new->v2 = i2; + med_new->flag = med_new_firstloop->flag; + med_new->crease = med_new_firstloop->crease; + med_new++; + } + i1 += totvert; + i2 += totvert; + } + else { + /* last segment */ + ml_new[quad_ord[0]].v = i1; + ml_new[quad_ord[1]].v = i2; + ml_new[quad_ord[2]].v = med_new_firstloop->v2; + ml_new[quad_ord[3]].v = med_new_firstloop->v1; + + ml_new[quad_ord_ofs[0]].e = (edge_offset + step + (i * (step_tot - 1))) - 1; + ml_new[quad_ord_ofs[1]].e = totedge + i2; + ml_new[quad_ord_ofs[2]].e = i; + ml_new[quad_ord_ofs[3]].e = totedge + i1; + } + + mp_new++; + ml_new += 4; + mpoly_index++; + } + + /* new vertical edge */ + med_new->v1 = i1; + med_new->v2 = i2; + med_new->flag = med_new_firstloop->flag & ~ME_LOOSEEDGE; + med_new->crease = med_new_firstloop->crease; + med_new++; + } + + /* validate loop edges */ #if 0 - { - unsigned i = 0; - printf("\n"); - for (; i < maxPolys * 4; i += 4) { - unsigned int ii; - ml_new = mloop_new + i; - ii = findEd(medge_new, maxEdges, ml_new[0].v, ml_new[1].v); - printf("%d %d -- ", ii, ml_new[0].e); - ml_new[0].e = ii; - - ii = findEd(medge_new, maxEdges, ml_new[1].v, ml_new[2].v); - printf("%d %d -- ", ii, ml_new[1].e); - ml_new[1].e = ii; - - ii = findEd(medge_new, maxEdges, ml_new[2].v, ml_new[3].v); - printf("%d %d -- ", ii, ml_new[2].e); - ml_new[2].e = ii; - - ii = findEd(medge_new, maxEdges, ml_new[3].v, ml_new[0].v); - printf("%d %d\n", ii, ml_new[3].e); - ml_new[3].e = ii; - - } - } + { + unsigned i = 0; + printf("\n"); + for (; i < maxPolys * 4; i += 4) { + unsigned int ii; + ml_new = mloop_new + i; + ii = findEd(medge_new, maxEdges, ml_new[0].v, ml_new[1].v); + printf("%d %d -- ", ii, ml_new[0].e); + ml_new[0].e = ii; + + ii = findEd(medge_new, maxEdges, ml_new[1].v, ml_new[2].v); + printf("%d %d -- ", ii, ml_new[1].e); + ml_new[1].e = ii; + + ii = findEd(medge_new, maxEdges, ml_new[2].v, ml_new[3].v); + printf("%d %d -- ", ii, ml_new[2].e); + ml_new[2].e = ii; + + ii = findEd(medge_new, maxEdges, ml_new[3].v, ml_new[0].v); + printf("%d %d\n", ii, ml_new[3].e); + ml_new[3].e = ii; + + } + } #endif - if (edge_poly_map) { - MEM_freeN(edge_poly_map); - } - - if (vert_loop_map) { - MEM_freeN(vert_loop_map); - } - - if ((ltmd->flag & MOD_SCREW_MERGE) && (screw_ofs == 0.0f)) { - Mesh *result_prev = result; - result = mesh_remove_doubles_on_axis( - result, mvert_new, totvert, step_tot, - axis_vec, ob_axis != NULL ? mtx_tx[3] : NULL, ltmd->merge_dist); - if (result != result_prev) { - result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; - } - } - - if ((ltmd->flag & MOD_SCREW_NORMAL_CALC) == 0) { - result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; - } - - return result; + if (edge_poly_map) { + MEM_freeN(edge_poly_map); + } + + if (vert_loop_map) { + MEM_freeN(vert_loop_map); + } + + if ((ltmd->flag & MOD_SCREW_MERGE) && (screw_ofs == 0.0f)) { + Mesh *result_prev = result; + result = mesh_remove_doubles_on_axis(result, + mvert_new, + totvert, + step_tot, + axis_vec, + ob_axis != NULL ? mtx_tx[3] : NULL, + ltmd->merge_dist); + if (result != result_prev) { + result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + } + } + + if ((ltmd->flag & MOD_SCREW_NORMAL_CALC) == 0) { + result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + } + + return result; } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { - ScrewModifierData *ltmd = (ScrewModifierData *)md; - if (ltmd->ob_axis != NULL) { - DEG_add_object_relation(ctx->node, ltmd->ob_axis, DEG_OB_COMP_TRANSFORM, "Screw Modifier"); - DEG_add_modifier_to_transform_relation(ctx->node, "Screw Modifier"); - } + ScrewModifierData *ltmd = (ScrewModifierData *)md; + if (ltmd->ob_axis != NULL) { + DEG_add_object_relation(ctx->node, ltmd->ob_axis, DEG_OB_COMP_TRANSFORM, "Screw Modifier"); + DEG_add_modifier_to_transform_relation(ctx->node, "Screw Modifier"); + } } -static void foreachObjectLink( - ModifierData *md, Object *ob, - ObjectWalkFunc walk, void *userData) +static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) { - ScrewModifierData *ltmd = (ScrewModifierData *) md; + ScrewModifierData *ltmd = (ScrewModifierData *)md; - walk(userData, ob, <md->ob_axis, IDWALK_CB_NOP); + walk(userData, ob, <md->ob_axis, IDWALK_CB_NOP); } ModifierTypeInfo modifierType_Screw = { - /* name */ "Screw", - /* structName */ "ScrewModifierData", - /* structSize */ sizeof(ScrewModifierData), - /* type */ eModifierTypeType_Constructive, - - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_AcceptsCVs | - eModifierTypeFlag_SupportsEditmode | - eModifierTypeFlag_EnableInEditmode, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ initData, - /* requiredDataMask */ NULL, - /* freeData */ NULL, - /* isDisabled */ NULL, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ foreachObjectLink, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Screw", + /* structName */ "ScrewModifierData", + /* structSize */ sizeof(ScrewModifierData), + /* type */ eModifierTypeType_Constructive, + + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs | + eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ initData, + /* requiredDataMask */ NULL, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_shapekey.c b/source/blender/modifiers/intern/MOD_shapekey.c index dd5f53c408a..5667a74bce6 100644 --- a/source/blender/modifiers/intern/MOD_shapekey.c +++ b/source/blender/modifiers/intern/MOD_shapekey.c @@ -33,109 +33,110 @@ #include "MOD_modifiertypes.h" -static void deformVerts( - ModifierData *UNUSED(md), const ModifierEvalContext *ctx, - Mesh *UNUSED(mesh), - float (*vertexCos)[3], - int numVerts) +static void deformVerts(ModifierData *UNUSED(md), + const ModifierEvalContext *ctx, + Mesh *UNUSED(mesh), + float (*vertexCos)[3], + int numVerts) { - Key *key = BKE_key_from_object(ctx->object); + Key *key = BKE_key_from_object(ctx->object); - if (key && key->block.first) { - int deformedVerts_tot; - BKE_key_evaluate_object_ex( - ctx->object, &deformedVerts_tot, - (float *)vertexCos, sizeof(*vertexCos) * numVerts); - - } + if (key && key->block.first) { + int deformedVerts_tot; + BKE_key_evaluate_object_ex( + ctx->object, &deformedVerts_tot, (float *)vertexCos, sizeof(*vertexCos) * numVerts); + } } -static void deformMatrices( - ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh, - float (*vertexCos)[3], float (*defMats)[3][3], int numVerts) +static void deformMatrices(ModifierData *md, + const ModifierEvalContext *ctx, + Mesh *mesh, + float (*vertexCos)[3], + float (*defMats)[3][3], + int numVerts) { - Key *key = BKE_key_from_object(ctx->object); - KeyBlock *kb = BKE_keyblock_from_object(ctx->object); - float scale[3][3]; + Key *key = BKE_key_from_object(ctx->object); + KeyBlock *kb = BKE_keyblock_from_object(ctx->object); + float scale[3][3]; - (void)vertexCos; /* unused */ + (void)vertexCos; /* unused */ - if (kb && kb->totelem == numVerts && kb != key->refkey) { - int a; + if (kb && kb->totelem == numVerts && kb != key->refkey) { + int a; - if (ctx->object->shapeflag & OB_SHAPE_LOCK) scale_m3_fl(scale, 1); - else scale_m3_fl(scale, kb->curval); + if (ctx->object->shapeflag & OB_SHAPE_LOCK) + scale_m3_fl(scale, 1); + else + scale_m3_fl(scale, kb->curval); - for (a = 0; a < numVerts; a++) - copy_m3_m3(defMats[a], scale); - } + for (a = 0; a < numVerts; a++) + copy_m3_m3(defMats[a], scale); + } - deformVerts(md, ctx, mesh, vertexCos, numVerts); + deformVerts(md, ctx, mesh, vertexCos, numVerts); } -static void deformVertsEM( - ModifierData *md, const ModifierEvalContext *ctx, - struct BMEditMesh *UNUSED(editData), - Mesh *mesh, - float (*vertexCos)[3], - int numVerts) +static void deformVertsEM(ModifierData *md, + const ModifierEvalContext *ctx, + struct BMEditMesh *UNUSED(editData), + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - Key *key = BKE_key_from_object(ctx->object); + Key *key = BKE_key_from_object(ctx->object); - if (key && key->type == KEY_RELATIVE) - deformVerts(md, ctx, mesh, vertexCos, numVerts); + if (key && key->type == KEY_RELATIVE) + deformVerts(md, ctx, mesh, vertexCos, numVerts); } -static void deformMatricesEM( - ModifierData *UNUSED(md), const ModifierEvalContext *ctx, - struct BMEditMesh *UNUSED(editData), - Mesh *UNUSED(mesh), - float (*vertexCos)[3], - float (*defMats)[3][3], - int numVerts) +static void deformMatricesEM(ModifierData *UNUSED(md), + const ModifierEvalContext *ctx, + struct BMEditMesh *UNUSED(editData), + Mesh *UNUSED(mesh), + float (*vertexCos)[3], + float (*defMats)[3][3], + int numVerts) { - Key *key = BKE_key_from_object(ctx->object); - KeyBlock *kb = BKE_keyblock_from_object(ctx->object); - float scale[3][3]; + Key *key = BKE_key_from_object(ctx->object); + KeyBlock *kb = BKE_keyblock_from_object(ctx->object); + float scale[3][3]; - (void)vertexCos; /* unused */ + (void)vertexCos; /* unused */ - if (kb && kb->totelem == numVerts && kb != key->refkey) { - int a; - scale_m3_fl(scale, kb->curval); + if (kb && kb->totelem == numVerts && kb != key->refkey) { + int a; + scale_m3_fl(scale, kb->curval); - for (a = 0; a < numVerts; a++) - copy_m3_m3(defMats[a], scale); - } + for (a = 0; a < numVerts; a++) + copy_m3_m3(defMats[a], scale); + } } - ModifierTypeInfo modifierType_ShapeKey = { - /* name */ "ShapeKey", - /* structName */ "ShapeKeyModifierData", - /* structSize */ sizeof(ShapeKeyModifierData), - /* type */ eModifierTypeType_OnlyDeform, - /* flags */ eModifierTypeFlag_AcceptsCVs | - eModifierTypeFlag_AcceptsLattice | - eModifierTypeFlag_SupportsEditmode, - - /* copyData */ NULL, - - /* deformVerts */ deformVerts, - /* deformMatrices */ deformMatrices, - /* deformVertsEM */ deformVertsEM, - /* deformMatricesEM */ deformMatricesEM, - /* applyModifier */ NULL, - - /* initData */ NULL, - /* requiredDataMask */ NULL, - /* freeData */ NULL, - /* isDisabled */ NULL, - /* updateDepsgraph */ NULL, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ NULL, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "ShapeKey", + /* structName */ "ShapeKeyModifierData", + /* structSize */ sizeof(ShapeKeyModifierData), + /* type */ eModifierTypeType_OnlyDeform, + /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice | + eModifierTypeFlag_SupportsEditmode, + + /* copyData */ NULL, + + /* deformVerts */ deformVerts, + /* deformMatrices */ deformMatrices, + /* deformVertsEM */ deformVertsEM, + /* deformMatricesEM */ deformMatricesEM, + /* applyModifier */ NULL, + + /* initData */ NULL, + /* requiredDataMask */ NULL, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_shrinkwrap.c b/source/blender/modifiers/intern/MOD_shrinkwrap.c index 73e99738458..3b4d6251c0a 100644 --- a/source/blender/modifiers/intern/MOD_shrinkwrap.c +++ b/source/blender/modifiers/intern/MOD_shrinkwrap.c @@ -21,7 +21,6 @@ * \ingroup modifiers */ - #include #include "BLI_utildefines.h" @@ -42,162 +41,169 @@ static bool dependsOnNormals(ModifierData *md); - static void initData(ModifierData *md) { - ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *) md; - smd->shrinkType = MOD_SHRINKWRAP_NEAREST_SURFACE; - smd->shrinkOpts = MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR; - smd->keepDist = 0.0f; + ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *)md; + smd->shrinkType = MOD_SHRINKWRAP_NEAREST_SURFACE; + smd->shrinkOpts = MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR; + smd->keepDist = 0.0f; - smd->target = NULL; - smd->auxTarget = NULL; + smd->target = NULL; + smd->auxTarget = NULL; } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *)md; - - /* ask for vertexgroups if we need them */ - if (smd->vgroup_name[0] != '\0') { - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; - } - - if ((smd->shrinkType == MOD_SHRINKWRAP_PROJECT) && - (smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL)) - { - r_cddata_masks->vmask |= CD_MASK_MVERT; /* XXX Really? These should always be present, always... */ - } + ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *)md; + + /* ask for vertexgroups if we need them */ + if (smd->vgroup_name[0] != '\0') { + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + } + + if ((smd->shrinkType == MOD_SHRINKWRAP_PROJECT) && + (smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL)) { + r_cddata_masks->vmask |= + CD_MASK_MVERT; /* XXX Really? These should always be present, always... */ + } } -static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams)) +static bool isDisabled(const struct Scene *UNUSED(scene), + ModifierData *md, + bool UNUSED(useRenderParams)) { - ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *) md; - return !smd->target; + ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *)md; + return !smd->target; } - static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) { - ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *) md; + ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *)md; - walk(userData, ob, &smd->target, IDWALK_CB_NOP); - walk(userData, ob, &smd->auxTarget, IDWALK_CB_NOP); + walk(userData, ob, &smd->target, IDWALK_CB_NOP); + walk(userData, ob, &smd->auxTarget, IDWALK_CB_NOP); } -static void deformVerts( - ModifierData *md, const ModifierEvalContext *ctx, - Mesh *mesh, - float (*vertexCos)[3], - int numVerts) +static void deformVerts(ModifierData *md, + const ModifierEvalContext *ctx, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - ShrinkwrapModifierData *swmd = (ShrinkwrapModifierData *)md; - struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); - Mesh *mesh_src = NULL; + ShrinkwrapModifierData *swmd = (ShrinkwrapModifierData *)md; + struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); + Mesh *mesh_src = NULL; - if (ctx->object->type == OB_MESH) { - /* mesh_src is only needed for vgroups. */ - mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); - } + if (ctx->object->type == OB_MESH) { + /* mesh_src is only needed for vgroups. */ + mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); + } - struct MDeformVert *dvert = NULL; - int defgrp_index = -1; - MOD_get_vgroup(ctx->object, mesh_src, swmd->vgroup_name, &dvert, &defgrp_index); + struct MDeformVert *dvert = NULL; + int defgrp_index = -1; + MOD_get_vgroup(ctx->object, mesh_src, swmd->vgroup_name, &dvert, &defgrp_index); - shrinkwrapModifier_deform(swmd, ctx, scene, ctx->object, mesh_src, dvert, defgrp_index, vertexCos, numVerts); + shrinkwrapModifier_deform( + swmd, ctx, scene, ctx->object, mesh_src, dvert, defgrp_index, vertexCos, numVerts); - if (!ELEM(mesh_src, NULL, mesh)) { - BKE_id_free(NULL, mesh_src); - } + if (!ELEM(mesh_src, NULL, mesh)) { + BKE_id_free(NULL, mesh_src); + } } -static void deformVertsEM( - ModifierData *md, const ModifierEvalContext *ctx, - struct BMEditMesh *editData, Mesh *mesh, - float (*vertexCos)[3], int numVerts) +static void deformVertsEM(ModifierData *md, + const ModifierEvalContext *ctx, + struct BMEditMesh *editData, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - ShrinkwrapModifierData *swmd = (ShrinkwrapModifierData *)md; - struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); - Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false); + ShrinkwrapModifierData *swmd = (ShrinkwrapModifierData *)md; + struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); + Mesh *mesh_src = MOD_deform_mesh_eval_get( + ctx->object, editData, mesh, NULL, numVerts, false, false); - struct MDeformVert *dvert = NULL; - int defgrp_index = -1; - MOD_get_vgroup(ctx->object, mesh_src, swmd->vgroup_name, &dvert, &defgrp_index); + struct MDeformVert *dvert = NULL; + int defgrp_index = -1; + MOD_get_vgroup(ctx->object, mesh_src, swmd->vgroup_name, &dvert, &defgrp_index); - shrinkwrapModifier_deform(swmd, ctx, scene, ctx->object, mesh_src, dvert, defgrp_index, vertexCos, numVerts); + shrinkwrapModifier_deform( + swmd, ctx, scene, ctx->object, mesh_src, dvert, defgrp_index, vertexCos, numVerts); - if (!ELEM(mesh_src, NULL, mesh)) { - BKE_id_free(NULL, mesh_src); - } + if (!ELEM(mesh_src, NULL, mesh)) { + BKE_id_free(NULL, mesh_src); + } } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { - ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *)md; - CustomData_MeshMasks mask = {0}; - - if (BKE_shrinkwrap_needs_normals(smd->shrinkType, smd->shrinkMode)) { - mask.vmask |= CD_MASK_NORMAL; - mask.lmask |= CD_MASK_NORMAL | CD_MASK_CUSTOMLOOPNORMAL; - } - - if (smd->target != NULL) { - DEG_add_object_relation(ctx->node, smd->target, DEG_OB_COMP_TRANSFORM, "Shrinkwrap Modifier"); - DEG_add_object_relation(ctx->node, smd->target, DEG_OB_COMP_GEOMETRY, "Shrinkwrap Modifier"); - DEG_add_customdata_mask(ctx->node, smd->target, &mask); - if (smd->shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) { - DEG_add_special_eval_flag(ctx->node, &smd->target->id, DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY); - } - } - if (smd->auxTarget != NULL) { - DEG_add_object_relation(ctx->node, smd->auxTarget, DEG_OB_COMP_TRANSFORM, "Shrinkwrap Modifier"); - DEG_add_object_relation(ctx->node, smd->auxTarget, DEG_OB_COMP_GEOMETRY, "Shrinkwrap Modifier"); - DEG_add_customdata_mask(ctx->node, smd->auxTarget, &mask); - if (smd->shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) { - DEG_add_special_eval_flag(ctx->node, &smd->auxTarget->id, DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY); - } - } - DEG_add_modifier_to_transform_relation(ctx->node, "Shrinkwrap Modifier"); + ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *)md; + CustomData_MeshMasks mask = {0}; + + if (BKE_shrinkwrap_needs_normals(smd->shrinkType, smd->shrinkMode)) { + mask.vmask |= CD_MASK_NORMAL; + mask.lmask |= CD_MASK_NORMAL | CD_MASK_CUSTOMLOOPNORMAL; + } + + if (smd->target != NULL) { + DEG_add_object_relation(ctx->node, smd->target, DEG_OB_COMP_TRANSFORM, "Shrinkwrap Modifier"); + DEG_add_object_relation(ctx->node, smd->target, DEG_OB_COMP_GEOMETRY, "Shrinkwrap Modifier"); + DEG_add_customdata_mask(ctx->node, smd->target, &mask); + if (smd->shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) { + DEG_add_special_eval_flag(ctx->node, &smd->target->id, DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY); + } + } + if (smd->auxTarget != NULL) { + DEG_add_object_relation( + ctx->node, smd->auxTarget, DEG_OB_COMP_TRANSFORM, "Shrinkwrap Modifier"); + DEG_add_object_relation( + ctx->node, smd->auxTarget, DEG_OB_COMP_GEOMETRY, "Shrinkwrap Modifier"); + DEG_add_customdata_mask(ctx->node, smd->auxTarget, &mask); + if (smd->shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) { + DEG_add_special_eval_flag(ctx->node, &smd->auxTarget->id, DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY); + } + } + DEG_add_modifier_to_transform_relation(ctx->node, "Shrinkwrap Modifier"); } static bool dependsOnNormals(ModifierData *md) { - ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *)md; + ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *)md; - if (smd->target && smd->shrinkType == MOD_SHRINKWRAP_PROJECT) - return (smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL); + if (smd->target && smd->shrinkType == MOD_SHRINKWRAP_PROJECT) + return (smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL); - return false; + return false; } ModifierTypeInfo modifierType_Shrinkwrap = { - /* name */ "Shrinkwrap", - /* structName */ "ShrinkwrapModifierData", - /* structSize */ sizeof(ShrinkwrapModifierData), - /* type */ eModifierTypeType_OnlyDeform, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_AcceptsCVs | - eModifierTypeFlag_AcceptsLattice | - eModifierTypeFlag_SupportsEditmode | - eModifierTypeFlag_EnableInEditmode, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ deformVerts, - /* deformMatrices */ NULL, - /* deformVertsEM */ deformVertsEM, - /* deformMatricesEM */ NULL, - /* applyModifier */ NULL, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ NULL, - /* isDisabled */ isDisabled, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ dependsOnNormals, - /* foreachObjectLink */ foreachObjectLink, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Shrinkwrap", + /* structName */ "ShrinkwrapModifierData", + /* structSize */ sizeof(ShrinkwrapModifierData), + /* type */ eModifierTypeType_OnlyDeform, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs | + eModifierTypeFlag_AcceptsLattice | eModifierTypeFlag_SupportsEditmode | + eModifierTypeFlag_EnableInEditmode, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ deformVerts, + /* deformMatrices */ NULL, + /* deformVertsEM */ deformVertsEM, + /* deformMatricesEM */ NULL, + /* applyModifier */ NULL, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ NULL, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ dependsOnNormals, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_simpledeform.c b/source/blender/modifiers/intern/MOD_simpledeform.c index 0ebeb1cd761..2434bd514f4 100644 --- a/source/blender/modifiers/intern/MOD_simpledeform.c +++ b/source/blender/modifiers/intern/MOD_simpledeform.c @@ -49,401 +49,428 @@ * exists because the deformations (excluding bend) are based on the Z axis. * Having this helps avoid long, drawn out switches. */ static const uint axis_map_table[3][3] = { - {1, 2, 0}, - {2, 0, 1}, - {0, 1, 2}, + {1, 2, 0}, + {2, 0, 1}, + {0, 1, 2}, }; BLI_INLINE void copy_v3_v3_map(float a[3], const float b[3], const uint map[3]) { - a[0] = b[map[0]]; - a[1] = b[map[1]]; - a[2] = b[map[2]]; + a[0] = b[map[0]]; + a[1] = b[map[1]]; + a[2] = b[map[2]]; } BLI_INLINE void copy_v3_v3_unmap(float a[3], const float b[3], const uint map[3]) { - a[map[0]] = b[0]; - a[map[1]] = b[1]; - a[map[2]] = b[2]; + a[map[0]] = b[0]; + a[map[1]] = b[1]; + a[map[2]] = b[2]; } /* Clamps/Limits the given coordinate to: limits[0] <= co[axis] <= limits[1] * The amount of clamp is saved on dcut */ static void axis_limit(const int axis, const float limits[2], float co[3], float dcut[3]) { - float val = co[axis]; - if (limits[0] > val) val = limits[0]; - if (limits[1] < val) val = limits[1]; - - dcut[axis] = co[axis] - val; - co[axis] = val; + float val = co[axis]; + if (limits[0] > val) + val = limits[0]; + if (limits[1] < val) + val = limits[1]; + + dcut[axis] = co[axis] - val; + co[axis] = val; } -static void simpleDeform_taper(const float factor, const int UNUSED(axis), const float dcut[3], float r_co[3]) +static void simpleDeform_taper(const float factor, + const int UNUSED(axis), + const float dcut[3], + float r_co[3]) { - float x = r_co[0], y = r_co[1], z = r_co[2]; - float scale = z * factor; + float x = r_co[0], y = r_co[1], z = r_co[2]; + float scale = z * factor; - r_co[0] = x + x * scale; - r_co[1] = y + y * scale; - r_co[2] = z; + r_co[0] = x + x * scale; + r_co[1] = y + y * scale; + r_co[2] = z; - add_v3_v3(r_co, dcut); + add_v3_v3(r_co, dcut); } -static void simpleDeform_stretch(const float factor, const int UNUSED(axis), const float dcut[3], float r_co[3]) +static void simpleDeform_stretch(const float factor, + const int UNUSED(axis), + const float dcut[3], + float r_co[3]) { - float x = r_co[0], y = r_co[1], z = r_co[2]; - float scale; + float x = r_co[0], y = r_co[1], z = r_co[2]; + float scale; - scale = (z * z * factor - factor + 1.0f); + scale = (z * z * factor - factor + 1.0f); - r_co[0] = x * scale; - r_co[1] = y * scale; - r_co[2] = z * (1.0f + factor); + r_co[0] = x * scale; + r_co[1] = y * scale; + r_co[2] = z * (1.0f + factor); - add_v3_v3(r_co, dcut); + add_v3_v3(r_co, dcut); } -static void simpleDeform_twist(const float factor, const int UNUSED(axis), const float *dcut, float r_co[3]) +static void simpleDeform_twist(const float factor, + const int UNUSED(axis), + const float *dcut, + float r_co[3]) { - float x = r_co[0], y = r_co[1], z = r_co[2]; - float theta, sint, cost; + float x = r_co[0], y = r_co[1], z = r_co[2]; + float theta, sint, cost; - theta = z * factor; - sint = sinf(theta); - cost = cosf(theta); + theta = z * factor; + sint = sinf(theta); + cost = cosf(theta); - r_co[0] = x * cost - y * sint; - r_co[1] = x * sint + y * cost; - r_co[2] = z; + r_co[0] = x * cost - y * sint; + r_co[1] = x * sint + y * cost; + r_co[2] = z; - add_v3_v3(r_co, dcut); + add_v3_v3(r_co, dcut); } -static void simpleDeform_bend(const float factor, const int axis, const float dcut[3], float r_co[3]) +static void simpleDeform_bend(const float factor, + const int axis, + const float dcut[3], + float r_co[3]) { - float x = r_co[0], y = r_co[1], z = r_co[2]; - float theta, sint, cost; - - BLI_assert(!(fabsf(factor) < BEND_EPS)); - - switch (axis) { - case 0: - ATTR_FALLTHROUGH; - case 1: - theta = z * factor; - break; - default: - theta = x * factor; - } - sint = sinf(theta); - cost = cosf(theta); - - switch (axis) { - case 0: - r_co[0] = x; - r_co[1] = (y - 1.0f / factor) * cost + 1.0f / factor; - r_co[2] = -(y - 1.0f / factor) * sint; - { - r_co[0] += dcut[0]; - r_co[1] += sint * dcut[2]; - r_co[2] += cost * dcut[2]; - } - break; - case 1: - r_co[0] = (x - 1.0f / factor) * cost + 1.0f / factor; - r_co[1] = y; - r_co[2] = -(x - 1.0f / factor) * sint; - { - r_co[0] += sint * dcut[2]; - r_co[1] += dcut[1]; - r_co[2] += cost * dcut[2]; - } - break; - default: - r_co[0] = -(y - 1.0f / factor) * sint; - r_co[1] = (y - 1.0f / factor) * cost + 1.0f / factor; - r_co[2] = z; - { - r_co[0] += cost * dcut[0]; - r_co[1] += sint * dcut[0]; - r_co[2] += dcut[2]; - } - } - + float x = r_co[0], y = r_co[1], z = r_co[2]; + float theta, sint, cost; + + BLI_assert(!(fabsf(factor) < BEND_EPS)); + + switch (axis) { + case 0: + ATTR_FALLTHROUGH; + case 1: + theta = z * factor; + break; + default: + theta = x * factor; + } + sint = sinf(theta); + cost = cosf(theta); + + switch (axis) { + case 0: + r_co[0] = x; + r_co[1] = (y - 1.0f / factor) * cost + 1.0f / factor; + r_co[2] = -(y - 1.0f / factor) * sint; + { + r_co[0] += dcut[0]; + r_co[1] += sint * dcut[2]; + r_co[2] += cost * dcut[2]; + } + break; + case 1: + r_co[0] = (x - 1.0f / factor) * cost + 1.0f / factor; + r_co[1] = y; + r_co[2] = -(x - 1.0f / factor) * sint; + { + r_co[0] += sint * dcut[2]; + r_co[1] += dcut[1]; + r_co[2] += cost * dcut[2]; + } + break; + default: + r_co[0] = -(y - 1.0f / factor) * sint; + r_co[1] = (y - 1.0f / factor) * cost + 1.0f / factor; + r_co[2] = z; + { + r_co[0] += cost * dcut[0]; + r_co[1] += sint * dcut[0]; + r_co[2] += dcut[2]; + } + } } - /* simple deform modifier */ -static void SimpleDeformModifier_do( - SimpleDeformModifierData *smd, const ModifierEvalContext *UNUSED(ctx), - struct Object *ob, struct Mesh *mesh, - float (*vertexCos)[3], int numVerts) +static void SimpleDeformModifier_do(SimpleDeformModifierData *smd, + const ModifierEvalContext *UNUSED(ctx), + struct Object *ob, + struct Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - const float base_limit[2] = {0.0f, 0.0f}; - int i; - float smd_limit[2], smd_factor; - SpaceTransform *transf = NULL, tmp_transf; - void (*simpleDeform_callback)(const float factor, const int axis, const float dcut[3], float co[3]) = NULL; /* Mode callback */ - int vgroup; - MDeformVert *dvert; - - /* This is historically the lock axis, _not_ the deform axis as the name would imply */ - const int deform_axis = smd->deform_axis; - int lock_axis = smd->axis; - if (smd->mode == MOD_SIMPLEDEFORM_MODE_BEND) { /* Bend mode shouldn't have any lock axis */ - lock_axis = 0; - } - else { - /* Don't lock axis if it is the chosen deform axis, as this flattens - * the geometry */ - if (deform_axis == 0) { - lock_axis &= ~MOD_SIMPLEDEFORM_LOCK_AXIS_X; - } - if (deform_axis == 1) { - lock_axis &= ~MOD_SIMPLEDEFORM_LOCK_AXIS_Y; - } - if (deform_axis == 2) { - lock_axis &= ~MOD_SIMPLEDEFORM_LOCK_AXIS_Z; - } - } - - - /* Safe-check */ - if (smd->origin == ob) smd->origin = NULL; /* No self references */ - - if (smd->limit[0] < 0.0f) smd->limit[0] = 0.0f; - if (smd->limit[0] > 1.0f) smd->limit[0] = 1.0f; - - smd->limit[0] = min_ff(smd->limit[0], smd->limit[1]); /* Upper limit >= than lower limit */ - - /* Calculate matrixs do convert between coordinate spaces */ - if (smd->origin != NULL) { - transf = &tmp_transf; - BLI_SPACE_TRANSFORM_SETUP(transf, ob, smd->origin); - } - - /* Update limits if needed */ - int limit_axis = deform_axis; - if (smd->mode == MOD_SIMPLEDEFORM_MODE_BEND) { - /* Bend is a special case. */ - switch (deform_axis) { - case 0: - ATTR_FALLTHROUGH; - case 1: - limit_axis = 2; - break; - default: - limit_axis = 0; - } - } - - { - float lower = FLT_MAX; - float upper = -FLT_MAX; - - for (i = 0; i < numVerts; i++) { - float tmp[3]; - copy_v3_v3(tmp, vertexCos[i]); - - if (transf) { - BLI_space_transform_apply(transf, tmp); - } - - lower = min_ff(lower, tmp[limit_axis]); - upper = max_ff(upper, tmp[limit_axis]); - } - - - /* SMD values are normalized to the BV, calculate the absolute values */ - smd_limit[1] = lower + (upper - lower) * smd->limit[1]; - smd_limit[0] = lower + (upper - lower) * smd->limit[0]; - - smd_factor = smd->factor / max_ff(FLT_EPSILON, smd_limit[1] - smd_limit[0]); - } - - switch (smd->mode) { - case MOD_SIMPLEDEFORM_MODE_TWIST: simpleDeform_callback = simpleDeform_twist; break; - case MOD_SIMPLEDEFORM_MODE_BEND: simpleDeform_callback = simpleDeform_bend; break; - case MOD_SIMPLEDEFORM_MODE_TAPER: simpleDeform_callback = simpleDeform_taper; break; - case MOD_SIMPLEDEFORM_MODE_STRETCH: simpleDeform_callback = simpleDeform_stretch; break; - default: - return; /* No simpledeform mode? */ - } - - if (smd->mode == MOD_SIMPLEDEFORM_MODE_BEND) { - if (fabsf(smd_factor) < BEND_EPS) { - return; - } - } - - MOD_get_vgroup(ob, mesh, smd->vgroup_name, &dvert, &vgroup); - const bool invert_vgroup = (smd->flag & MOD_SIMPLEDEFORM_FLAG_INVERT_VGROUP) != 0; - const uint *axis_map = axis_map_table[(smd->mode != MOD_SIMPLEDEFORM_MODE_BEND) ? deform_axis : 2]; - - for (i = 0; i < numVerts; i++) { - float weight = defvert_array_find_weight_safe(dvert, i, vgroup); - - if (invert_vgroup) { - weight = 1.0f - weight; - } - - if (weight != 0.0f) { - float co[3], dcut[3] = {0.0f, 0.0f, 0.0f}; - - if (transf) { - BLI_space_transform_apply(transf, vertexCos[i]); - } - - copy_v3_v3(co, vertexCos[i]); - - /* Apply axis limits, and axis mappings */ - if (lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_X) { - axis_limit(0, base_limit, co, dcut); - } - if (lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_Y) { - axis_limit(1, base_limit, co, dcut); - } - if (lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_Z) { - axis_limit(2, base_limit, co, dcut); - } - axis_limit(limit_axis, smd_limit, co, dcut); - - /* apply the deform to a mapped copy of the vertex, and then re-map it back. */ - float co_remap[3]; - float dcut_remap[3]; - copy_v3_v3_map(co_remap, co, axis_map); - copy_v3_v3_map(dcut_remap, dcut, axis_map); - simpleDeform_callback(smd_factor, deform_axis, dcut_remap, co_remap); /* apply deform */ - copy_v3_v3_unmap(co, co_remap, axis_map); - - interp_v3_v3v3(vertexCos[i], vertexCos[i], co, weight); /* Use vertex weight has coef of linear interpolation */ - - if (transf) { - BLI_space_transform_invert(transf, vertexCos[i]); - } - } - } + const float base_limit[2] = {0.0f, 0.0f}; + int i; + float smd_limit[2], smd_factor; + SpaceTransform *transf = NULL, tmp_transf; + void (*simpleDeform_callback)(const float factor, + const int axis, + const float dcut[3], + float co[3]) = NULL; /* Mode callback */ + int vgroup; + MDeformVert *dvert; + + /* This is historically the lock axis, _not_ the deform axis as the name would imply */ + const int deform_axis = smd->deform_axis; + int lock_axis = smd->axis; + if (smd->mode == MOD_SIMPLEDEFORM_MODE_BEND) { /* Bend mode shouldn't have any lock axis */ + lock_axis = 0; + } + else { + /* Don't lock axis if it is the chosen deform axis, as this flattens + * the geometry */ + if (deform_axis == 0) { + lock_axis &= ~MOD_SIMPLEDEFORM_LOCK_AXIS_X; + } + if (deform_axis == 1) { + lock_axis &= ~MOD_SIMPLEDEFORM_LOCK_AXIS_Y; + } + if (deform_axis == 2) { + lock_axis &= ~MOD_SIMPLEDEFORM_LOCK_AXIS_Z; + } + } + + /* Safe-check */ + if (smd->origin == ob) + smd->origin = NULL; /* No self references */ + + if (smd->limit[0] < 0.0f) + smd->limit[0] = 0.0f; + if (smd->limit[0] > 1.0f) + smd->limit[0] = 1.0f; + + smd->limit[0] = min_ff(smd->limit[0], smd->limit[1]); /* Upper limit >= than lower limit */ + + /* Calculate matrixs do convert between coordinate spaces */ + if (smd->origin != NULL) { + transf = &tmp_transf; + BLI_SPACE_TRANSFORM_SETUP(transf, ob, smd->origin); + } + + /* Update limits if needed */ + int limit_axis = deform_axis; + if (smd->mode == MOD_SIMPLEDEFORM_MODE_BEND) { + /* Bend is a special case. */ + switch (deform_axis) { + case 0: + ATTR_FALLTHROUGH; + case 1: + limit_axis = 2; + break; + default: + limit_axis = 0; + } + } + + { + float lower = FLT_MAX; + float upper = -FLT_MAX; + + for (i = 0; i < numVerts; i++) { + float tmp[3]; + copy_v3_v3(tmp, vertexCos[i]); + + if (transf) { + BLI_space_transform_apply(transf, tmp); + } + + lower = min_ff(lower, tmp[limit_axis]); + upper = max_ff(upper, tmp[limit_axis]); + } + + /* SMD values are normalized to the BV, calculate the absolute values */ + smd_limit[1] = lower + (upper - lower) * smd->limit[1]; + smd_limit[0] = lower + (upper - lower) * smd->limit[0]; + + smd_factor = smd->factor / max_ff(FLT_EPSILON, smd_limit[1] - smd_limit[0]); + } + + switch (smd->mode) { + case MOD_SIMPLEDEFORM_MODE_TWIST: + simpleDeform_callback = simpleDeform_twist; + break; + case MOD_SIMPLEDEFORM_MODE_BEND: + simpleDeform_callback = simpleDeform_bend; + break; + case MOD_SIMPLEDEFORM_MODE_TAPER: + simpleDeform_callback = simpleDeform_taper; + break; + case MOD_SIMPLEDEFORM_MODE_STRETCH: + simpleDeform_callback = simpleDeform_stretch; + break; + default: + return; /* No simpledeform mode? */ + } + + if (smd->mode == MOD_SIMPLEDEFORM_MODE_BEND) { + if (fabsf(smd_factor) < BEND_EPS) { + return; + } + } + + MOD_get_vgroup(ob, mesh, smd->vgroup_name, &dvert, &vgroup); + const bool invert_vgroup = (smd->flag & MOD_SIMPLEDEFORM_FLAG_INVERT_VGROUP) != 0; + const uint *axis_map = + axis_map_table[(smd->mode != MOD_SIMPLEDEFORM_MODE_BEND) ? deform_axis : 2]; + + for (i = 0; i < numVerts; i++) { + float weight = defvert_array_find_weight_safe(dvert, i, vgroup); + + if (invert_vgroup) { + weight = 1.0f - weight; + } + + if (weight != 0.0f) { + float co[3], dcut[3] = {0.0f, 0.0f, 0.0f}; + + if (transf) { + BLI_space_transform_apply(transf, vertexCos[i]); + } + + copy_v3_v3(co, vertexCos[i]); + + /* Apply axis limits, and axis mappings */ + if (lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_X) { + axis_limit(0, base_limit, co, dcut); + } + if (lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_Y) { + axis_limit(1, base_limit, co, dcut); + } + if (lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_Z) { + axis_limit(2, base_limit, co, dcut); + } + axis_limit(limit_axis, smd_limit, co, dcut); + + /* apply the deform to a mapped copy of the vertex, and then re-map it back. */ + float co_remap[3]; + float dcut_remap[3]; + copy_v3_v3_map(co_remap, co, axis_map); + copy_v3_v3_map(dcut_remap, dcut, axis_map); + simpleDeform_callback(smd_factor, deform_axis, dcut_remap, co_remap); /* apply deform */ + copy_v3_v3_unmap(co, co_remap, axis_map); + + interp_v3_v3v3(vertexCos[i], + vertexCos[i], + co, + weight); /* Use vertex weight has coef of linear interpolation */ + + if (transf) { + BLI_space_transform_invert(transf, vertexCos[i]); + } + } + } } - /* SimpleDeform */ static void initData(ModifierData *md) { - SimpleDeformModifierData *smd = (SimpleDeformModifierData *) md; + SimpleDeformModifierData *smd = (SimpleDeformModifierData *)md; - smd->mode = MOD_SIMPLEDEFORM_MODE_TWIST; - smd->axis = 0; - smd->deform_axis = 0; + smd->mode = MOD_SIMPLEDEFORM_MODE_TWIST; + smd->axis = 0; + smd->deform_axis = 0; - smd->origin = NULL; - smd->factor = DEG2RADF(45.0f); - smd->limit[0] = 0.0f; - smd->limit[1] = 1.0f; + smd->origin = NULL; + smd->factor = DEG2RADF(45.0f); + smd->limit[0] = 0.0f; + smd->limit[1] = 1.0f; } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - SimpleDeformModifierData *smd = (SimpleDeformModifierData *)md; + SimpleDeformModifierData *smd = (SimpleDeformModifierData *)md; - /* ask for vertexgroups if we need them */ - if (smd->vgroup_name[0] != '\0') { - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; - } + /* ask for vertexgroups if we need them */ + if (smd->vgroup_name[0] != '\0') { + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + } } -static void foreachObjectLink( - ModifierData *md, Object *ob, - ObjectWalkFunc walk, void *userData) +static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) { - SimpleDeformModifierData *smd = (SimpleDeformModifierData *)md; - walk(userData, ob, &smd->origin, IDWALK_CB_NOP); + SimpleDeformModifierData *smd = (SimpleDeformModifierData *)md; + walk(userData, ob, &smd->origin, IDWALK_CB_NOP); } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { - SimpleDeformModifierData *smd = (SimpleDeformModifierData *)md; - if (smd->origin != NULL) { - DEG_add_object_relation(ctx->node, smd->origin, DEG_OB_COMP_TRANSFORM, "SimpleDeform Modifier"); - DEG_add_modifier_to_transform_relation(ctx->node, "SimpleDeform Modifier"); - } + SimpleDeformModifierData *smd = (SimpleDeformModifierData *)md; + if (smd->origin != NULL) { + DEG_add_object_relation( + ctx->node, smd->origin, DEG_OB_COMP_TRANSFORM, "SimpleDeform Modifier"); + DEG_add_modifier_to_transform_relation(ctx->node, "SimpleDeform Modifier"); + } } -static void deformVerts( - ModifierData *md, const ModifierEvalContext *ctx, - struct Mesh *mesh, - float (*vertexCos)[3], - int numVerts) +static void deformVerts(ModifierData *md, + const ModifierEvalContext *ctx, + struct Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - SimpleDeformModifierData *sdmd = (SimpleDeformModifierData *)md; - Mesh *mesh_src = NULL; + SimpleDeformModifierData *sdmd = (SimpleDeformModifierData *)md; + Mesh *mesh_src = NULL; - if (ctx->object->type == OB_MESH && sdmd->vgroup_name[0] != '\0') { - /* mesh_src is only needed for vgroups. */ - mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); - } + if (ctx->object->type == OB_MESH && sdmd->vgroup_name[0] != '\0') { + /* mesh_src is only needed for vgroups. */ + mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); + } - SimpleDeformModifier_do(sdmd, ctx, ctx->object, mesh_src, vertexCos, numVerts); + SimpleDeformModifier_do(sdmd, ctx, ctx->object, mesh_src, vertexCos, numVerts); - if (!ELEM(mesh_src, NULL, mesh)) { - BKE_id_free(NULL, mesh_src); - } + if (!ELEM(mesh_src, NULL, mesh)) { + BKE_id_free(NULL, mesh_src); + } } -static void deformVertsEM( - ModifierData *md, const ModifierEvalContext *ctx, - struct BMEditMesh *editData, - struct Mesh *mesh, - float (*vertexCos)[3], - int numVerts) +static void deformVertsEM(ModifierData *md, + const ModifierEvalContext *ctx, + struct BMEditMesh *editData, + struct Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - SimpleDeformModifierData *sdmd = (SimpleDeformModifierData *)md; - Mesh *mesh_src = NULL; + SimpleDeformModifierData *sdmd = (SimpleDeformModifierData *)md; + Mesh *mesh_src = NULL; - if (ctx->object->type == OB_MESH && sdmd->vgroup_name[0] != '\0') { - /* mesh_src is only needed for vgroups. */ - mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false); - } + if (ctx->object->type == OB_MESH && sdmd->vgroup_name[0] != '\0') { + /* mesh_src is only needed for vgroups. */ + mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false); + } - SimpleDeformModifier_do(sdmd, ctx, ctx->object, mesh_src, vertexCos, numVerts); + SimpleDeformModifier_do(sdmd, ctx, ctx->object, mesh_src, vertexCos, numVerts); - if (!ELEM(mesh_src, NULL, mesh)) { - BKE_id_free(NULL, mesh_src); - } + if (!ELEM(mesh_src, NULL, mesh)) { + BKE_id_free(NULL, mesh_src); + } } - ModifierTypeInfo modifierType_SimpleDeform = { - /* name */ "SimpleDeform", - /* structName */ "SimpleDeformModifierData", - /* structSize */ sizeof(SimpleDeformModifierData), - /* type */ eModifierTypeType_OnlyDeform, - - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_AcceptsCVs | - eModifierTypeFlag_AcceptsLattice | - eModifierTypeFlag_SupportsEditmode | - eModifierTypeFlag_EnableInEditmode, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ deformVerts, - /* deformMatrices */ NULL, - /* deformVertsEM */ deformVertsEM, - /* deformMatricesEM */ NULL, - /* applyModifier */ NULL, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ NULL, - /* isDisabled */ NULL, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ foreachObjectLink, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "SimpleDeform", + /* structName */ "SimpleDeformModifierData", + /* structSize */ sizeof(SimpleDeformModifierData), + /* type */ eModifierTypeType_OnlyDeform, + + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs | + eModifierTypeFlag_AcceptsLattice | eModifierTypeFlag_SupportsEditmode | + eModifierTypeFlag_EnableInEditmode, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ deformVerts, + /* deformMatrices */ NULL, + /* deformVertsEM */ deformVertsEM, + /* deformMatricesEM */ NULL, + /* applyModifier */ NULL, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c index dab2d72133b..ffef1197491 100644 --- a/source/blender/modifiers/intern/MOD_skin.c +++ b/source/blender/modifiers/intern/MOD_skin.c @@ -76,262 +76,249 @@ #include "bmesh.h" typedef struct { - float mat[3][3]; - /* Vert that edge is pointing away from, no relation to - * MEdge.v1 */ - int origin; + float mat[3][3]; + /* Vert that edge is pointing away from, no relation to + * MEdge.v1 */ + int origin; } EMat; typedef enum { - CAP_START = 1, - CAP_END = 2, - SEAM_FRAME = 4, - ROOT = 8, + CAP_START = 1, + CAP_END = 2, + SEAM_FRAME = 4, + ROOT = 8, } SkinNodeFlag; typedef struct Frame { - /* Index in the MVert array */ - BMVert *verts[4]; - /* Location of each corner */ - float co[4][3]; - /* Indicates which corners have been merged with another - * frame's corner (so they share an MVert index) */ - struct { - /* Merge to target frame/corner (no merge if frame is null) */ - struct Frame *frame; - int corner; - /* checked to avoid chaining. - * (merging when we're already been referenced), see T39775 */ - unsigned int is_target : 1; - } merge[4]; - - /* For hull frames, whether each vertex is detached or not */ - bool inside_hull[4]; - /* Whether any part of the frame (corner or edge) is detached */ - bool detached; + /* Index in the MVert array */ + BMVert *verts[4]; + /* Location of each corner */ + float co[4][3]; + /* Indicates which corners have been merged with another + * frame's corner (so they share an MVert index) */ + struct { + /* Merge to target frame/corner (no merge if frame is null) */ + struct Frame *frame; + int corner; + /* checked to avoid chaining. + * (merging when we're already been referenced), see T39775 */ + unsigned int is_target : 1; + } merge[4]; + + /* For hull frames, whether each vertex is detached or not */ + bool inside_hull[4]; + /* Whether any part of the frame (corner or edge) is detached */ + bool detached; } Frame; #define MAX_SKIN_NODE_FRAMES 2 typedef struct { - Frame frames[MAX_SKIN_NODE_FRAMES]; - int totframe; + Frame frames[MAX_SKIN_NODE_FRAMES]; + int totframe; - SkinNodeFlag flag; + SkinNodeFlag flag; - /* Used for hulling a loop seam */ - int seam_edges[2]; + /* Used for hulling a loop seam */ + int seam_edges[2]; } SkinNode; typedef struct { - BMesh *bm; - SkinModifierData *smd; - int mat_nr; + BMesh *bm; + SkinModifierData *smd; + int mat_nr; } SkinOutput; -static void add_poly( - SkinOutput *so, - BMVert *v1, - BMVert *v2, - BMVert *v3, - BMVert *v4); +static void add_poly(SkinOutput *so, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4); /***************************** Convex Hull ****************************/ -static bool is_quad_symmetric( - BMVert *quad[4], - const SkinModifierData *smd) +static bool is_quad_symmetric(BMVert *quad[4], const SkinModifierData *smd) { - const float threshold = 0.0001f; - const float threshold_squared = threshold * threshold; - int axis; - - for (axis = 0; axis < 3; axis++) { - if (smd->symmetry_axes & (1 << axis)) { - float a[3]; - - copy_v3_v3(a, quad[0]->co); - a[axis] = -a[axis]; - - if (len_squared_v3v3(a, quad[1]->co) < threshold_squared) { - copy_v3_v3(a, quad[2]->co); - a[axis] = -a[axis]; - if (len_squared_v3v3(a, quad[3]->co) < threshold_squared) - return 1; - } - else if (len_squared_v3v3(a, quad[3]->co) < threshold_squared) { - copy_v3_v3(a, quad[2]->co); - a[axis] = -a[axis]; - if (len_squared_v3v3(a, quad[1]->co) < threshold_squared) - return 1; - } - } - } - - return 0; + const float threshold = 0.0001f; + const float threshold_squared = threshold * threshold; + int axis; + + for (axis = 0; axis < 3; axis++) { + if (smd->symmetry_axes & (1 << axis)) { + float a[3]; + + copy_v3_v3(a, quad[0]->co); + a[axis] = -a[axis]; + + if (len_squared_v3v3(a, quad[1]->co) < threshold_squared) { + copy_v3_v3(a, quad[2]->co); + a[axis] = -a[axis]; + if (len_squared_v3v3(a, quad[3]->co) < threshold_squared) + return 1; + } + else if (len_squared_v3v3(a, quad[3]->co) < threshold_squared) { + copy_v3_v3(a, quad[2]->co); + a[axis] = -a[axis]; + if (len_squared_v3v3(a, quad[1]->co) < threshold_squared) + return 1; + } + } + } + + return 0; } /* Returns true if the quad crosses the plane of symmetry, false otherwise */ -static bool quad_crosses_symmetry_plane( - BMVert *quad[4], - const SkinModifierData *smd) +static bool quad_crosses_symmetry_plane(BMVert *quad[4], const SkinModifierData *smd) { - int axis; - - for (axis = 0; axis < 3; axis++) { - if (smd->symmetry_axes & (1 << axis)) { - bool left = false, right = false; - int i; - - for (i = 0; i < 4; i++) { - if (quad[i]->co[axis] < 0.0f) - left = true; - else if (quad[i]->co[axis] > 0.0f) - right = true; - - if (left && right) - return true; - } - } - } - - return false; + int axis; + + for (axis = 0; axis < 3; axis++) { + if (smd->symmetry_axes & (1 << axis)) { + bool left = false, right = false; + int i; + + for (i = 0; i < 4; i++) { + if (quad[i]->co[axis] < 0.0f) + left = true; + else if (quad[i]->co[axis] > 0.0f) + right = true; + + if (left && right) + return true; + } + } + } + + return false; } /* Returns true if the frame is filled by precisely two faces (and * outputs those faces to fill_faces), otherwise returns false. */ -static bool skin_frame_find_contained_faces( - const Frame *frame, - BMFace *fill_faces[2]) +static bool skin_frame_find_contained_faces(const Frame *frame, BMFace *fill_faces[2]) { - BMEdge *diag; + BMEdge *diag; - /* See if the frame is bisected by a diagonal edge */ - diag = BM_edge_exists(frame->verts[0], frame->verts[2]); - if (!diag) - diag = BM_edge_exists(frame->verts[1], frame->verts[3]); + /* See if the frame is bisected by a diagonal edge */ + diag = BM_edge_exists(frame->verts[0], frame->verts[2]); + if (!diag) + diag = BM_edge_exists(frame->verts[1], frame->verts[3]); - if (diag) - return BM_edge_face_pair(diag, &fill_faces[0], &fill_faces[1]); - else - return false; + if (diag) + return BM_edge_face_pair(diag, &fill_faces[0], &fill_faces[1]); + else + return false; } /* Returns true if hull is successfully built, false otherwise */ static bool build_hull(SkinOutput *so, Frame **frames, int totframe) { #ifdef WITH_BULLET - BMesh *bm = so->bm; - BMOperator op; - BMIter iter; - BMOIter oiter; - BMVert *v; - BMFace *f; - BMEdge *e; - int i, j; - - BM_mesh_elem_hflag_disable_all(bm, BM_VERT, BM_ELEM_TAG, false); - - for (i = 0; i < totframe; i++) { - for (j = 0; j < 4; j++) { - BM_elem_flag_enable(frames[i]->verts[j], BM_ELEM_TAG); - } - } - - /* Deselect all faces so that only new hull output faces are - * selected after the operator is run */ - BM_mesh_elem_hflag_disable_all(bm, BM_ALL_NOLOOP, BM_ELEM_SELECT, false); - - BMO_op_initf(bm, &op, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), - "convex_hull input=%hv", BM_ELEM_TAG); - BMO_op_exec(bm, &op); - - if (BMO_error_occurred(bm)) { - BMO_op_finish(bm, &op); - return false; - } - - /* Apply face attributes to hull output */ - BMO_ITER (f, &oiter, op.slots_out, "geom.out", BM_FACE) { - BM_face_normal_update(f); - if (so->smd->flag & MOD_SKIN_SMOOTH_SHADING) - BM_elem_flag_enable(f, BM_ELEM_SMOOTH); - f->mat_nr = so->mat_nr; - } - - /* Mark interior frames */ - BMO_ITER (v, &oiter, op.slots_out, "geom_interior.out", BM_VERT) { - for (i = 0; i < totframe; i++) { - Frame *frame = frames[i]; - - if (!frame->detached) { - for (j = 0; j < 4; j++) { - if (frame->verts[j] == v) { - frame->inside_hull[j] = true; - frame->detached = true; - break; - } - } - } - } - } - - /* Also mark frames as interior if an edge is not in the hull */ - for (i = 0; i < totframe; i++) { - Frame *frame = frames[i]; - - if (!frame->detached && - (!BM_edge_exists(frame->verts[0], frame->verts[1]) || - !BM_edge_exists(frame->verts[1], frame->verts[2]) || - !BM_edge_exists(frame->verts[2], frame->verts[3]) || - !BM_edge_exists(frame->verts[3], frame->verts[0]))) - { - frame->detached = true; - } - } - - /* Remove triangles that would fill the original frames -- skip if - * frame is partially detached */ - BM_mesh_elem_hflag_disable_all(bm, BM_ALL_NOLOOP, BM_ELEM_TAG, false); - for (i = 0; i < totframe; i++) { - Frame *frame = frames[i]; - if (!frame->detached) { - BMFace *fill_faces[2]; - - /* Check if the frame is filled by precisely two - * triangles. If so, delete the triangles and their shared - * edge. Otherwise, give up and mark the frame as - * detached. */ - if (skin_frame_find_contained_faces(frame, fill_faces)) { - BM_elem_flag_enable(fill_faces[0], BM_ELEM_TAG); - BM_elem_flag_enable(fill_faces[1], BM_ELEM_TAG); - } - else - frame->detached = true; - } - } - - /* Check if removing triangles above will create wire triangles, - * mark them too */ - BMO_ITER (e, &oiter, op.slots_out, "geom.out", BM_EDGE) { - bool is_wire = true; - BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) { - if (!BM_elem_flag_test(f, BM_ELEM_TAG)) { - is_wire = false; - break; - } - } - if (is_wire) - BM_elem_flag_enable(e, BM_ELEM_TAG); - } - - BMO_op_finish(bm, &op); - - BM_mesh_delete_hflag_tagged(bm, BM_ELEM_TAG, BM_EDGE | BM_FACE); - - return true; + BMesh *bm = so->bm; + BMOperator op; + BMIter iter; + BMOIter oiter; + BMVert *v; + BMFace *f; + BMEdge *e; + int i, j; + + BM_mesh_elem_hflag_disable_all(bm, BM_VERT, BM_ELEM_TAG, false); + + for (i = 0; i < totframe; i++) { + for (j = 0; j < 4; j++) { + BM_elem_flag_enable(frames[i]->verts[j], BM_ELEM_TAG); + } + } + + /* Deselect all faces so that only new hull output faces are + * selected after the operator is run */ + BM_mesh_elem_hflag_disable_all(bm, BM_ALL_NOLOOP, BM_ELEM_SELECT, false); + + BMO_op_initf( + bm, &op, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), "convex_hull input=%hv", BM_ELEM_TAG); + BMO_op_exec(bm, &op); + + if (BMO_error_occurred(bm)) { + BMO_op_finish(bm, &op); + return false; + } + + /* Apply face attributes to hull output */ + BMO_ITER (f, &oiter, op.slots_out, "geom.out", BM_FACE) { + BM_face_normal_update(f); + if (so->smd->flag & MOD_SKIN_SMOOTH_SHADING) + BM_elem_flag_enable(f, BM_ELEM_SMOOTH); + f->mat_nr = so->mat_nr; + } + + /* Mark interior frames */ + BMO_ITER (v, &oiter, op.slots_out, "geom_interior.out", BM_VERT) { + for (i = 0; i < totframe; i++) { + Frame *frame = frames[i]; + + if (!frame->detached) { + for (j = 0; j < 4; j++) { + if (frame->verts[j] == v) { + frame->inside_hull[j] = true; + frame->detached = true; + break; + } + } + } + } + } + + /* Also mark frames as interior if an edge is not in the hull */ + for (i = 0; i < totframe; i++) { + Frame *frame = frames[i]; + + if (!frame->detached && (!BM_edge_exists(frame->verts[0], frame->verts[1]) || + !BM_edge_exists(frame->verts[1], frame->verts[2]) || + !BM_edge_exists(frame->verts[2], frame->verts[3]) || + !BM_edge_exists(frame->verts[3], frame->verts[0]))) { + frame->detached = true; + } + } + + /* Remove triangles that would fill the original frames -- skip if + * frame is partially detached */ + BM_mesh_elem_hflag_disable_all(bm, BM_ALL_NOLOOP, BM_ELEM_TAG, false); + for (i = 0; i < totframe; i++) { + Frame *frame = frames[i]; + if (!frame->detached) { + BMFace *fill_faces[2]; + + /* Check if the frame is filled by precisely two + * triangles. If so, delete the triangles and their shared + * edge. Otherwise, give up and mark the frame as + * detached. */ + if (skin_frame_find_contained_faces(frame, fill_faces)) { + BM_elem_flag_enable(fill_faces[0], BM_ELEM_TAG); + BM_elem_flag_enable(fill_faces[1], BM_ELEM_TAG); + } + else + frame->detached = true; + } + } + + /* Check if removing triangles above will create wire triangles, + * mark them too */ + BMO_ITER (e, &oiter, op.slots_out, "geom.out", BM_EDGE) { + bool is_wire = true; + BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) { + if (!BM_elem_flag_test(f, BM_ELEM_TAG)) { + is_wire = false; + break; + } + } + if (is_wire) + BM_elem_flag_enable(e, BM_ELEM_TAG); + } + + BMO_op_finish(bm, &op); + + BM_mesh_delete_hflag_tagged(bm, BM_ELEM_TAG, BM_EDGE | BM_FACE); + + return true; #else - UNUSED_VARS(so, frames, totframe, skin_frame_find_contained_faces); - return false; + UNUSED_VARS(so, frames, totframe, skin_frame_find_contained_faces); + return false; #endif } @@ -339,428 +326,421 @@ static bool build_hull(SkinOutput *so, Frame **frames, int totframe) * just the average of two adjacent edge lengths) */ static float frame_len(const Frame *frame) { - return (len_v3v3(frame->co[0], frame->co[1]) + - len_v3v3(frame->co[1], frame->co[2])) * 0.5f; + return (len_v3v3(frame->co[0], frame->co[1]) + len_v3v3(frame->co[1], frame->co[2])) * 0.5f; } static void merge_frame_corners(Frame **frames, int totframe) { - float dist, side_a, side_b, thresh, mid[3]; - int i, j, k, l; - - for (i = 0; i < totframe; i++) { - side_a = frame_len(frames[i]); - - /* For each corner of each frame... */ - for (j = 0; j < 4; j++) { - - /* Ensure the merge target is not itself a merge target */ - if (frames[i]->merge[j].frame) - continue; - - for (k = i + 1; k < totframe; k++) { - BLI_assert(frames[i] != frames[k]); - - side_b = frame_len(frames[k]); - thresh = min_ff(side_a, side_b) / 2.0f; - - /* Compare with each corner of all other frames... */ - for (l = 0; l < 4; l++) { - if (frames[k]->merge[l].frame || frames[k]->merge[l].is_target) - continue; - - /* Some additional concerns that could be checked - * further: - * - * + Vertex coords are being used for the - * edge-length test, but are also being - * modified, might cause symmetry problems. - * - * + A frame could be merged diagonally across - * another, would generate a weird (bad) T - * junction - */ - - /* Check if corners are near each other, where - * 'near' is based in the frames' minimum side - * length */ - dist = len_v3v3(frames[i]->co[j], - frames[k]->co[l]); - if (dist < thresh) { - mid_v3_v3v3(mid, - frames[i]->co[j], - frames[k]->co[l]); - - copy_v3_v3(frames[i]->co[j], mid); - copy_v3_v3(frames[k]->co[l], mid); - - frames[k]->merge[l].frame = frames[i]; - frames[k]->merge[l].corner = j; - frames[i]->merge[j].is_target = true; - - /* Can't merge another corner into the same - * frame corner, so move on to frame k+1 */ - break; - } - } - } - } - } + float dist, side_a, side_b, thresh, mid[3]; + int i, j, k, l; + + for (i = 0; i < totframe; i++) { + side_a = frame_len(frames[i]); + + /* For each corner of each frame... */ + for (j = 0; j < 4; j++) { + + /* Ensure the merge target is not itself a merge target */ + if (frames[i]->merge[j].frame) + continue; + + for (k = i + 1; k < totframe; k++) { + BLI_assert(frames[i] != frames[k]); + + side_b = frame_len(frames[k]); + thresh = min_ff(side_a, side_b) / 2.0f; + + /* Compare with each corner of all other frames... */ + for (l = 0; l < 4; l++) { + if (frames[k]->merge[l].frame || frames[k]->merge[l].is_target) + continue; + + /* Some additional concerns that could be checked + * further: + * + * + Vertex coords are being used for the + * edge-length test, but are also being + * modified, might cause symmetry problems. + * + * + A frame could be merged diagonally across + * another, would generate a weird (bad) T + * junction + */ + + /* Check if corners are near each other, where + * 'near' is based in the frames' minimum side + * length */ + dist = len_v3v3(frames[i]->co[j], frames[k]->co[l]); + if (dist < thresh) { + mid_v3_v3v3(mid, frames[i]->co[j], frames[k]->co[l]); + + copy_v3_v3(frames[i]->co[j], mid); + copy_v3_v3(frames[k]->co[l], mid); + + frames[k]->merge[l].frame = frames[i]; + frames[k]->merge[l].corner = j; + frames[i]->merge[j].is_target = true; + + /* Can't merge another corner into the same + * frame corner, so move on to frame k+1 */ + break; + } + } + } + } + } } static Frame **collect_hull_frames( - int v, SkinNode *frames, - const MeshElemMap *emap, const MEdge *medge, - int *tothullframe) + int v, SkinNode *frames, const MeshElemMap *emap, const MEdge *medge, int *tothullframe) { - SkinNode *f; - Frame **hull_frames; - int nbr, i; - - (*tothullframe) = emap[v].count; - hull_frames = MEM_calloc_arrayN((*tothullframe), sizeof(Frame *), - "hull_from_frames.hull_frames"); - i = 0; - for (nbr = 0; nbr < emap[v].count; nbr++) { - const MEdge *e = &medge[emap[v].indices[nbr]]; - f = &frames[BKE_mesh_edge_other_vert(e, v)]; - /* Can't have adjacent branch nodes yet */ - if (f->totframe) - hull_frames[i++] = &f->frames[0]; - else - (*tothullframe)--; - } - - return hull_frames; + SkinNode *f; + Frame **hull_frames; + int nbr, i; + + (*tothullframe) = emap[v].count; + hull_frames = MEM_calloc_arrayN( + (*tothullframe), sizeof(Frame *), "hull_from_frames.hull_frames"); + i = 0; + for (nbr = 0; nbr < emap[v].count; nbr++) { + const MEdge *e = &medge[emap[v].indices[nbr]]; + f = &frames[BKE_mesh_edge_other_vert(e, v)]; + /* Can't have adjacent branch nodes yet */ + if (f->totframe) + hull_frames[i++] = &f->frames[0]; + else + (*tothullframe)--; + } + + return hull_frames; } - /**************************** Create Frames ***************************/ static void node_frames_init(SkinNode *nf, int totframe) { - int i; + int i; - nf->totframe = totframe; - memset(nf->frames, 0, sizeof(nf->frames)); + nf->totframe = totframe; + memset(nf->frames, 0, sizeof(nf->frames)); - nf->flag = 0; - for (i = 0; i < 2; i++) - nf->seam_edges[i] = -1; + nf->flag = 0; + for (i = 0; i < 2; i++) + nf->seam_edges[i] = -1; } static void create_frame( - Frame *frame, const float co[3], - const float radius[2], - float mat[3][3], float offset) + Frame *frame, const float co[3], const float radius[2], float mat[3][3], float offset) { - float rx[3], ry[3], rz[3]; - int i; + float rx[3], ry[3], rz[3]; + int i; - mul_v3_v3fl(ry, mat[1], radius[0]); - mul_v3_v3fl(rz, mat[2], radius[1]); + mul_v3_v3fl(ry, mat[1], radius[0]); + mul_v3_v3fl(rz, mat[2], radius[1]); - add_v3_v3v3(frame->co[3], co, ry); - add_v3_v3v3(frame->co[3], frame->co[3], rz); + add_v3_v3v3(frame->co[3], co, ry); + add_v3_v3v3(frame->co[3], frame->co[3], rz); - sub_v3_v3v3(frame->co[2], co, ry); - add_v3_v3v3(frame->co[2], frame->co[2], rz); + sub_v3_v3v3(frame->co[2], co, ry); + add_v3_v3v3(frame->co[2], frame->co[2], rz); - sub_v3_v3v3(frame->co[1], co, ry); - sub_v3_v3v3(frame->co[1], frame->co[1], rz); + sub_v3_v3v3(frame->co[1], co, ry); + sub_v3_v3v3(frame->co[1], frame->co[1], rz); - add_v3_v3v3(frame->co[0], co, ry); - sub_v3_v3v3(frame->co[0], frame->co[0], rz); + add_v3_v3v3(frame->co[0], co, ry); + sub_v3_v3v3(frame->co[0], frame->co[0], rz); - mul_v3_v3fl(rx, mat[0], offset); - for (i = 0; i < 4; i++) - add_v3_v3v3(frame->co[i], frame->co[i], rx); + mul_v3_v3fl(rx, mat[0], offset); + for (i = 0; i < 4; i++) + add_v3_v3v3(frame->co[i], frame->co[i], rx); } static float half_v2(const float v[2]) { - return (v[0] + v[1]) * 0.5f; + return (v[0] + v[1]) * 0.5f; } -static void end_node_frames( - int v, SkinNode *skin_nodes, const MVert *mvert, - const MVertSkin *nodes, const MeshElemMap *emap, - EMat *emat) +static void end_node_frames(int v, + SkinNode *skin_nodes, + const MVert *mvert, + const MVertSkin *nodes, + const MeshElemMap *emap, + EMat *emat) { - const float *rad = nodes[v].radius; - float mat[3][3]; - - if (emap[v].count == 0) { - float avg = half_v2(rad); - - /* For solitary nodes, just build a box (two frames) */ - node_frames_init(&skin_nodes[v], 2); - skin_nodes[v].flag |= (CAP_START | CAP_END); - - /* Hardcoded basis */ - zero_m3(mat); - mat[0][2] = mat[1][0] = mat[2][1] = 1; - - /* Caps */ - create_frame(&skin_nodes[v].frames[0], mvert[v].co, rad, mat, avg); - create_frame(&skin_nodes[v].frames[1], mvert[v].co, rad, mat, -avg); - } - else { - /* For nodes with an incoming edge, create a single (capped) frame */ - node_frames_init(&skin_nodes[v], 1); - skin_nodes[v].flag |= CAP_START; - - /* Use incoming edge for orientation */ - copy_m3_m3(mat, emat[emap[v].indices[0]].mat); - if (emat[emap[v].indices[0]].origin != v) - negate_v3(mat[0]); - - /* End frame */ - create_frame(&skin_nodes[v].frames[0], mvert[v].co, rad, mat, 0); - } - - if (nodes[v].flag & MVERT_SKIN_ROOT) - skin_nodes[v].flag |= ROOT; + const float *rad = nodes[v].radius; + float mat[3][3]; + + if (emap[v].count == 0) { + float avg = half_v2(rad); + + /* For solitary nodes, just build a box (two frames) */ + node_frames_init(&skin_nodes[v], 2); + skin_nodes[v].flag |= (CAP_START | CAP_END); + + /* Hardcoded basis */ + zero_m3(mat); + mat[0][2] = mat[1][0] = mat[2][1] = 1; + + /* Caps */ + create_frame(&skin_nodes[v].frames[0], mvert[v].co, rad, mat, avg); + create_frame(&skin_nodes[v].frames[1], mvert[v].co, rad, mat, -avg); + } + else { + /* For nodes with an incoming edge, create a single (capped) frame */ + node_frames_init(&skin_nodes[v], 1); + skin_nodes[v].flag |= CAP_START; + + /* Use incoming edge for orientation */ + copy_m3_m3(mat, emat[emap[v].indices[0]].mat); + if (emat[emap[v].indices[0]].origin != v) + negate_v3(mat[0]); + + /* End frame */ + create_frame(&skin_nodes[v].frames[0], mvert[v].co, rad, mat, 0); + } + + if (nodes[v].flag & MVERT_SKIN_ROOT) + skin_nodes[v].flag |= ROOT; } /* Returns 1 for seam, 0 otherwise */ static int connection_node_mat(float mat[3][3], int v, const MeshElemMap *emap, EMat *emat) { - float axis[3], angle, ine[3][3], oute[3][3]; - EMat *e1, *e2; - - e1 = &emat[emap[v].indices[0]]; - e2 = &emat[emap[v].indices[1]]; - - if (e1->origin != v && e2->origin == v) { - copy_m3_m3(ine, e1->mat); - copy_m3_m3(oute, e2->mat); - } - else if (e1->origin == v && e2->origin != v) { - copy_m3_m3(ine, e2->mat); - copy_m3_m3(oute, e1->mat); - } - else - return 1; - - /* Get axis and angle to rotate frame by */ - angle = angle_normalized_v3v3(ine[0], oute[0]) / 2.0f; - cross_v3_v3v3(axis, ine[0], oute[0]); - normalize_v3(axis); - - /* Build frame matrix (don't care about X axis here) */ - copy_v3_v3(mat[0], ine[0]); - rotate_normalized_v3_v3v3fl(mat[1], ine[1], axis, angle); - rotate_normalized_v3_v3v3fl(mat[2], ine[2], axis, angle); - - return 0; + float axis[3], angle, ine[3][3], oute[3][3]; + EMat *e1, *e2; + + e1 = &emat[emap[v].indices[0]]; + e2 = &emat[emap[v].indices[1]]; + + if (e1->origin != v && e2->origin == v) { + copy_m3_m3(ine, e1->mat); + copy_m3_m3(oute, e2->mat); + } + else if (e1->origin == v && e2->origin != v) { + copy_m3_m3(ine, e2->mat); + copy_m3_m3(oute, e1->mat); + } + else + return 1; + + /* Get axis and angle to rotate frame by */ + angle = angle_normalized_v3v3(ine[0], oute[0]) / 2.0f; + cross_v3_v3v3(axis, ine[0], oute[0]); + normalize_v3(axis); + + /* Build frame matrix (don't care about X axis here) */ + copy_v3_v3(mat[0], ine[0]); + rotate_normalized_v3_v3v3fl(mat[1], ine[1], axis, angle); + rotate_normalized_v3_v3v3fl(mat[2], ine[2], axis, angle); + + return 0; } -static void connection_node_frames( - int v, SkinNode *skin_nodes, const MVert *mvert, - const MVertSkin *nodes, const MeshElemMap *emap, - EMat *emat) +static void connection_node_frames(int v, + SkinNode *skin_nodes, + const MVert *mvert, + const MVertSkin *nodes, + const MeshElemMap *emap, + EMat *emat) { - const float *rad = nodes[v].radius; - float mat[3][3]; - EMat *e1, *e2; - - if (connection_node_mat(mat, v, emap, emat)) { - float avg = half_v2(rad); - - /* Get edges */ - e1 = &emat[emap[v].indices[0]]; - e2 = &emat[emap[v].indices[1]]; - - /* Handle seam separately to avoid twisting */ - /* Create two frames, will be hulled to neighbors later */ - node_frames_init(&skin_nodes[v], 2); - skin_nodes[v].flag |= SEAM_FRAME; - - copy_m3_m3(mat, e1->mat); - if (e1->origin != v) negate_v3(mat[0]); - create_frame(&skin_nodes[v].frames[0], mvert[v].co, rad, mat, avg); - skin_nodes[v].seam_edges[0] = emap[v].indices[0]; - - copy_m3_m3(mat, e2->mat); - if (e2->origin != v) negate_v3(mat[0]); - create_frame(&skin_nodes[v].frames[1], mvert[v].co, rad, mat, avg); - skin_nodes[v].seam_edges[1] = emap[v].indices[1]; - - return; - } - - /* Build regular frame */ - node_frames_init(&skin_nodes[v], 1); - create_frame(&skin_nodes[v].frames[0], mvert[v].co, rad, mat, 0); + const float *rad = nodes[v].radius; + float mat[3][3]; + EMat *e1, *e2; + + if (connection_node_mat(mat, v, emap, emat)) { + float avg = half_v2(rad); + + /* Get edges */ + e1 = &emat[emap[v].indices[0]]; + e2 = &emat[emap[v].indices[1]]; + + /* Handle seam separately to avoid twisting */ + /* Create two frames, will be hulled to neighbors later */ + node_frames_init(&skin_nodes[v], 2); + skin_nodes[v].flag |= SEAM_FRAME; + + copy_m3_m3(mat, e1->mat); + if (e1->origin != v) + negate_v3(mat[0]); + create_frame(&skin_nodes[v].frames[0], mvert[v].co, rad, mat, avg); + skin_nodes[v].seam_edges[0] = emap[v].indices[0]; + + copy_m3_m3(mat, e2->mat); + if (e2->origin != v) + negate_v3(mat[0]); + create_frame(&skin_nodes[v].frames[1], mvert[v].co, rad, mat, avg); + skin_nodes[v].seam_edges[1] = emap[v].indices[1]; + + return; + } + + /* Build regular frame */ + node_frames_init(&skin_nodes[v], 1); + create_frame(&skin_nodes[v].frames[0], mvert[v].co, rad, mat, 0); } static SkinNode *build_frames( - const MVert *mvert, int totvert, - const MVertSkin *nodes, const MeshElemMap *emap, - EMat *emat) + const MVert *mvert, int totvert, const MVertSkin *nodes, const MeshElemMap *emap, EMat *emat) { - SkinNode *skin_nodes; - int v; - - skin_nodes = MEM_calloc_arrayN(totvert, sizeof(SkinNode), "build_frames.skin_nodes"); - - for (v = 0; v < totvert; v++) { - if (emap[v].count <= 1) - end_node_frames(v, skin_nodes, mvert, nodes, emap, emat); - else if (emap[v].count == 2) - connection_node_frames(v, skin_nodes, mvert, nodes, emap, emat); - else { - /* Branch node generates no frames */ - } - } - - return skin_nodes; + SkinNode *skin_nodes; + int v; + + skin_nodes = MEM_calloc_arrayN(totvert, sizeof(SkinNode), "build_frames.skin_nodes"); + + for (v = 0; v < totvert; v++) { + if (emap[v].count <= 1) + end_node_frames(v, skin_nodes, mvert, nodes, emap, emat); + else if (emap[v].count == 2) + connection_node_frames(v, skin_nodes, mvert, nodes, emap, emat); + else { + /* Branch node generates no frames */ + } + } + + return skin_nodes; } /**************************** Edge Matrices ***************************/ static void calc_edge_mat(float mat[3][3], const float a[3], const float b[3]) { - const float z_up[3] = {0, 0, 1}; - float dot; - - /* X = edge direction */ - sub_v3_v3v3(mat[0], b, a); - normalize_v3(mat[0]); - - dot = dot_v3v3(mat[0], z_up); - if (dot > -1 + FLT_EPSILON && dot < 1 - FLT_EPSILON) { - /* Y = Z cross x */ - cross_v3_v3v3(mat[1], z_up, mat[0]); - normalize_v3(mat[1]); - - /* Z = x cross y */ - cross_v3_v3v3(mat[2], mat[0], mat[1]); - normalize_v3(mat[2]); - } - else { - mat[1][0] = 1; - mat[1][1] = 0; - mat[1][2] = 0; - mat[2][0] = 0; - mat[2][1] = 1; - mat[2][2] = 0; - } + const float z_up[3] = {0, 0, 1}; + float dot; + + /* X = edge direction */ + sub_v3_v3v3(mat[0], b, a); + normalize_v3(mat[0]); + + dot = dot_v3v3(mat[0], z_up); + if (dot > -1 + FLT_EPSILON && dot < 1 - FLT_EPSILON) { + /* Y = Z cross x */ + cross_v3_v3v3(mat[1], z_up, mat[0]); + normalize_v3(mat[1]); + + /* Z = x cross y */ + cross_v3_v3v3(mat[2], mat[0], mat[1]); + normalize_v3(mat[2]); + } + else { + mat[1][0] = 1; + mat[1][1] = 0; + mat[1][2] = 0; + mat[2][0] = 0; + mat[2][1] = 1; + mat[2][2] = 0; + } } typedef struct { - float mat[3][3]; - int parent_v; - int e; + float mat[3][3]; + int parent_v; + int e; } EdgeStackElem; -static void build_emats_stack( - BLI_Stack *stack, BLI_bitmap *visited_e, EMat *emat, - const MeshElemMap *emap, const MEdge *medge, - const MVertSkin *vs, const MVert *mvert) +static void build_emats_stack(BLI_Stack *stack, + BLI_bitmap *visited_e, + EMat *emat, + const MeshElemMap *emap, + const MEdge *medge, + const MVertSkin *vs, + const MVert *mvert) { - EdgeStackElem stack_elem; - float axis[3], angle; - int i, e, v, parent_v, parent_is_branch; - - BLI_stack_pop(stack, &stack_elem); - parent_v = stack_elem.parent_v; - e = stack_elem.e; - - /* Skip if edge already visited */ - if (BLI_BITMAP_TEST(visited_e, e)) - return; - - /* Mark edge as visited */ - BLI_BITMAP_ENABLE(visited_e, e); - - /* Process edge */ - - parent_is_branch = ((emap[parent_v].count > 2) || - (vs[parent_v].flag & MVERT_SKIN_ROOT)); - - v = BKE_mesh_edge_other_vert(&medge[e], parent_v); - emat[e].origin = parent_v; - - /* If parent is a branch node, start a new edge chain */ - if (parent_is_branch) { - calc_edge_mat(emat[e].mat, mvert[parent_v].co, - mvert[v].co); - } - else { - /* Build edge matrix guided by parent matrix */ - sub_v3_v3v3(emat[e].mat[0], mvert[v].co, mvert[parent_v].co); - normalize_v3(emat[e].mat[0]); - angle = angle_normalized_v3v3(stack_elem.mat[0], emat[e].mat[0]); - cross_v3_v3v3(axis, stack_elem.mat[0], emat[e].mat[0]); - normalize_v3(axis); - rotate_normalized_v3_v3v3fl(emat[e].mat[1], stack_elem.mat[1], axis, angle); - rotate_normalized_v3_v3v3fl(emat[e].mat[2], stack_elem.mat[2], axis, angle); - } - - /* Add neighbors to stack */ - for (i = 0; i < emap[v].count; i++) { - /* Add neighbors to stack */ - copy_m3_m3(stack_elem.mat, emat[e].mat); - stack_elem.e = emap[v].indices[i]; - stack_elem.parent_v = v; - BLI_stack_push(stack, &stack_elem); - } + EdgeStackElem stack_elem; + float axis[3], angle; + int i, e, v, parent_v, parent_is_branch; + + BLI_stack_pop(stack, &stack_elem); + parent_v = stack_elem.parent_v; + e = stack_elem.e; + + /* Skip if edge already visited */ + if (BLI_BITMAP_TEST(visited_e, e)) + return; + + /* Mark edge as visited */ + BLI_BITMAP_ENABLE(visited_e, e); + + /* Process edge */ + + parent_is_branch = ((emap[parent_v].count > 2) || (vs[parent_v].flag & MVERT_SKIN_ROOT)); + + v = BKE_mesh_edge_other_vert(&medge[e], parent_v); + emat[e].origin = parent_v; + + /* If parent is a branch node, start a new edge chain */ + if (parent_is_branch) { + calc_edge_mat(emat[e].mat, mvert[parent_v].co, mvert[v].co); + } + else { + /* Build edge matrix guided by parent matrix */ + sub_v3_v3v3(emat[e].mat[0], mvert[v].co, mvert[parent_v].co); + normalize_v3(emat[e].mat[0]); + angle = angle_normalized_v3v3(stack_elem.mat[0], emat[e].mat[0]); + cross_v3_v3v3(axis, stack_elem.mat[0], emat[e].mat[0]); + normalize_v3(axis); + rotate_normalized_v3_v3v3fl(emat[e].mat[1], stack_elem.mat[1], axis, angle); + rotate_normalized_v3_v3v3fl(emat[e].mat[2], stack_elem.mat[2], axis, angle); + } + + /* Add neighbors to stack */ + for (i = 0; i < emap[v].count; i++) { + /* Add neighbors to stack */ + copy_m3_m3(stack_elem.mat, emat[e].mat); + stack_elem.e = emap[v].indices[i]; + stack_elem.parent_v = v; + BLI_stack_push(stack, &stack_elem); + } } -static EMat *build_edge_mats( - const MVertSkin *vs, - const MVert *mvert, - int totvert, - const MEdge *medge, - const MeshElemMap *emap, - int totedge, - bool *has_valid_root) +static EMat *build_edge_mats(const MVertSkin *vs, + const MVert *mvert, + int totvert, + const MEdge *medge, + const MeshElemMap *emap, + int totedge, + bool *has_valid_root) { - BLI_Stack *stack; - EMat *emat; - EdgeStackElem stack_elem; - BLI_bitmap *visited_e; - int i, v; - - stack = BLI_stack_new(sizeof(stack_elem), "build_edge_mats.stack"); - - visited_e = BLI_BITMAP_NEW(totedge, "build_edge_mats.visited_e"); - emat = MEM_calloc_arrayN(totedge, sizeof(EMat), "build_edge_mats.emat"); - - /* Edge matrices are built from the root nodes, add all roots with - * children to the stack */ - for (v = 0; v < totvert; v++) { - if (vs[v].flag & MVERT_SKIN_ROOT) { - if (emap[v].count >= 1) { - const MEdge *e = &medge[emap[v].indices[0]]; - calc_edge_mat(stack_elem.mat, mvert[v].co, - mvert[BKE_mesh_edge_other_vert(e, v)].co); - stack_elem.parent_v = v; - - /* Add adjacent edges to stack */ - for (i = 0; i < emap[v].count; i++) { - stack_elem.e = emap[v].indices[i]; - BLI_stack_push(stack, &stack_elem); - } - - *has_valid_root = true; - } - } - } - - while (!BLI_stack_is_empty(stack)) { - build_emats_stack(stack, visited_e, emat, emap, medge, vs, mvert); - } - - MEM_freeN(visited_e); - BLI_stack_free(stack); - - return emat; + BLI_Stack *stack; + EMat *emat; + EdgeStackElem stack_elem; + BLI_bitmap *visited_e; + int i, v; + + stack = BLI_stack_new(sizeof(stack_elem), "build_edge_mats.stack"); + + visited_e = BLI_BITMAP_NEW(totedge, "build_edge_mats.visited_e"); + emat = MEM_calloc_arrayN(totedge, sizeof(EMat), "build_edge_mats.emat"); + + /* Edge matrices are built from the root nodes, add all roots with + * children to the stack */ + for (v = 0; v < totvert; v++) { + if (vs[v].flag & MVERT_SKIN_ROOT) { + if (emap[v].count >= 1) { + const MEdge *e = &medge[emap[v].indices[0]]; + calc_edge_mat(stack_elem.mat, mvert[v].co, mvert[BKE_mesh_edge_other_vert(e, v)].co); + stack_elem.parent_v = v; + + /* Add adjacent edges to stack */ + for (i = 0; i < emap[v].count; i++) { + stack_elem.e = emap[v].indices[i]; + BLI_stack_push(stack, &stack_elem); + } + + *has_valid_root = true; + } + } + } + + while (!BLI_stack_is_empty(stack)) { + build_emats_stack(stack, visited_e, emat, emap, medge, vs, mvert); + } + + MEM_freeN(visited_e); + BLI_stack_free(stack); + + return emat; } - /************************** Input Subdivision *************************/ /* Returns number of edge subdivisions, taking into account the radius @@ -768,54 +748,54 @@ static EMat *build_edge_mats( * nodes, at least two intermediate frames are required. (This avoids * having any special cases for dealing with sharing a frame between * two hulls.) */ -static int calc_edge_subdivisions( - const MVert *mvert, const MVertSkin *nodes, - const MEdge *e, const int *degree) +static int calc_edge_subdivisions(const MVert *mvert, + const MVertSkin *nodes, + const MEdge *e, + const int *degree) { - /* prevent memory errors [#38003] */ + /* prevent memory errors [#38003] */ #define NUM_SUBDIVISIONS_MAX 128 - const MVertSkin *evs[2] = {&nodes[e->v1], &nodes[e->v2]}; - float avg_radius; - const bool v1_branch = degree[e->v1] > 2; - const bool v2_branch = degree[e->v2] > 2; - int num_subdivisions; - - /* If either end is a branch node marked 'loose', don't subdivide - * the edge (or subdivide just twice if both are branches) */ - if ((v1_branch && (evs[0]->flag & MVERT_SKIN_LOOSE)) || - (v2_branch && (evs[1]->flag & MVERT_SKIN_LOOSE))) - { - if (v1_branch && v2_branch) - return 2; - else - return 0; - } - - avg_radius = half_v2(evs[0]->radius) + half_v2(evs[1]->radius); - - if (avg_radius != 0.0f) { - /* possible (but unlikely) that we overflow INT_MAX */ - float num_subdivisions_fl; - const float edge_len = len_v3v3(mvert[e->v1].co, mvert[e->v2].co); - num_subdivisions_fl = (edge_len / avg_radius); - if (num_subdivisions_fl < NUM_SUBDIVISIONS_MAX) { - num_subdivisions = (int)num_subdivisions_fl; - } - else { - num_subdivisions = NUM_SUBDIVISIONS_MAX; - } - } - else { - num_subdivisions = 0; - } - - /* If both ends are branch nodes, two intermediate nodes are - * required */ - if (num_subdivisions < 2 && v1_branch && v2_branch) - num_subdivisions = 2; - - return num_subdivisions; + const MVertSkin *evs[2] = {&nodes[e->v1], &nodes[e->v2]}; + float avg_radius; + const bool v1_branch = degree[e->v1] > 2; + const bool v2_branch = degree[e->v2] > 2; + int num_subdivisions; + + /* If either end is a branch node marked 'loose', don't subdivide + * the edge (or subdivide just twice if both are branches) */ + if ((v1_branch && (evs[0]->flag & MVERT_SKIN_LOOSE)) || + (v2_branch && (evs[1]->flag & MVERT_SKIN_LOOSE))) { + if (v1_branch && v2_branch) + return 2; + else + return 0; + } + + avg_radius = half_v2(evs[0]->radius) + half_v2(evs[1]->radius); + + if (avg_radius != 0.0f) { + /* possible (but unlikely) that we overflow INT_MAX */ + float num_subdivisions_fl; + const float edge_len = len_v3v3(mvert[e->v1].co, mvert[e->v2].co); + num_subdivisions_fl = (edge_len / avg_radius); + if (num_subdivisions_fl < NUM_SUBDIVISIONS_MAX) { + num_subdivisions = (int)num_subdivisions_fl; + } + else { + num_subdivisions = NUM_SUBDIVISIONS_MAX; + } + } + else { + num_subdivisions = 0; + } + + /* If both ends are branch nodes, two intermediate nodes are + * required */ + if (num_subdivisions < 2 && v1_branch && v2_branch) + num_subdivisions = 2; + + return num_subdivisions; #undef NUM_SUBDIVISIONS_MAX } @@ -824,258 +804,235 @@ static int calc_edge_subdivisions( * reasonably close. */ static Mesh *subdivide_base(Mesh *orig) { - Mesh *result; - MVertSkin *orignode, *outnode; - MVert *origvert, *outvert; - MEdge *origedge, *outedge, *e; - MDeformVert *origdvert, *outdvert; - int totorigvert, totorigedge; - int totsubd, *degree, *edge_subd; - int i, j, k, u, v; - float radrat; - - orignode = CustomData_get_layer(&orig->vdata, CD_MVERT_SKIN); - origvert = orig->mvert; - origedge = orig->medge; - origdvert = orig->dvert; - totorigvert = orig->totvert; - totorigedge = orig->totedge; - - /* Get degree of all vertices */ - degree = MEM_calloc_arrayN(totorigvert, sizeof(int), "degree"); - for (i = 0; i < totorigedge; i++) { - degree[origedge[i].v1]++; - degree[origedge[i].v2]++; - } - - /* Per edge, store how many subdivisions are needed */ - edge_subd = MEM_calloc_arrayN(totorigedge, sizeof(int), "edge_subd"); - for (i = 0, totsubd = 0; i < totorigedge; i++) { - edge_subd[i] += calc_edge_subdivisions(origvert, orignode, - &origedge[i], degree); - BLI_assert(edge_subd[i] >= 0); - totsubd += edge_subd[i]; - } - - MEM_freeN(degree); - - /* Allocate output mesh */ - result = BKE_mesh_new_nomain_from_template( - orig, - totorigvert + totsubd, - totorigedge + totsubd, - 0, 0, 0); - - outvert = result->mvert; - outedge = result->medge; - outnode = CustomData_get_layer(&result->vdata, CD_MVERT_SKIN); - outdvert = result->dvert; - - /* Copy original vertex data */ - CustomData_copy_data(&orig->vdata, - &result->vdata, - 0, 0, totorigvert); - - /* Subdivide edges */ - for (i = 0, v = totorigvert; i < totorigedge; i++) { - struct { - /* Vertex group number */ - int def_nr; - float w1, w2; - } *vgroups = NULL, *vg; - int totvgroup = 0; - - e = &origedge[i]; - - if (origdvert) { - const MDeformVert *dv1 = &origdvert[e->v1]; - const MDeformVert *dv2 = &origdvert[e->v2]; - vgroups = MEM_calloc_arrayN(dv1->totweight, sizeof(*vgroups), "vgroup"); - - /* Only want vertex groups used by both vertices */ - for (j = 0; j < dv1->totweight; j++) { - vg = NULL; - for (k = 0; k < dv2->totweight; k++) { - if (dv1->dw[j].def_nr == dv2->dw[k].def_nr) { - vg = &vgroups[totvgroup]; - totvgroup++; - break; - } - } - - if (vg) { - vg->def_nr = dv1->dw[j].def_nr; - vg->w1 = dv1->dw[j].weight; - vg->w2 = dv2->dw[k].weight; - } - } - } - - u = e->v1; - radrat = (half_v2(outnode[e->v2].radius) / - half_v2(outnode[e->v1].radius)); - radrat = (radrat + 1) / 2; - - /* Add vertices and edge segments */ - for (j = 0; j < edge_subd[i]; j++, v++, outedge++) { - float r = (j + 1) / (float)(edge_subd[i] + 1); - float t = powf(r, radrat); - - /* Interpolate vertex coord */ - interp_v3_v3v3(outvert[v].co, outvert[e->v1].co, - outvert[e->v2].co, t); - - /* Interpolate skin radii */ - interp_v3_v3v3(outnode[v].radius, - orignode[e->v1].radius, - orignode[e->v2].radius, t); - - /* Interpolate vertex group weights */ - for (k = 0; k < totvgroup; k++) { - float weight; - - vg = &vgroups[k]; - weight = interpf(vg->w2, vg->w1, t); - - if (weight > 0) - defvert_add_index_notest(&outdvert[v], vg->def_nr, weight); - } - - outedge->v1 = u; - outedge->v2 = v; - u = v; - } - - if (vgroups) - MEM_freeN(vgroups); - - /* Link up to final vertex */ - outedge->v1 = u; - outedge->v2 = e->v2; - outedge++; - } - - MEM_freeN(edge_subd); - - return result; + Mesh *result; + MVertSkin *orignode, *outnode; + MVert *origvert, *outvert; + MEdge *origedge, *outedge, *e; + MDeformVert *origdvert, *outdvert; + int totorigvert, totorigedge; + int totsubd, *degree, *edge_subd; + int i, j, k, u, v; + float radrat; + + orignode = CustomData_get_layer(&orig->vdata, CD_MVERT_SKIN); + origvert = orig->mvert; + origedge = orig->medge; + origdvert = orig->dvert; + totorigvert = orig->totvert; + totorigedge = orig->totedge; + + /* Get degree of all vertices */ + degree = MEM_calloc_arrayN(totorigvert, sizeof(int), "degree"); + for (i = 0; i < totorigedge; i++) { + degree[origedge[i].v1]++; + degree[origedge[i].v2]++; + } + + /* Per edge, store how many subdivisions are needed */ + edge_subd = MEM_calloc_arrayN(totorigedge, sizeof(int), "edge_subd"); + for (i = 0, totsubd = 0; i < totorigedge; i++) { + edge_subd[i] += calc_edge_subdivisions(origvert, orignode, &origedge[i], degree); + BLI_assert(edge_subd[i] >= 0); + totsubd += edge_subd[i]; + } + + MEM_freeN(degree); + + /* Allocate output mesh */ + result = BKE_mesh_new_nomain_from_template( + orig, totorigvert + totsubd, totorigedge + totsubd, 0, 0, 0); + + outvert = result->mvert; + outedge = result->medge; + outnode = CustomData_get_layer(&result->vdata, CD_MVERT_SKIN); + outdvert = result->dvert; + + /* Copy original vertex data */ + CustomData_copy_data(&orig->vdata, &result->vdata, 0, 0, totorigvert); + + /* Subdivide edges */ + for (i = 0, v = totorigvert; i < totorigedge; i++) { + struct { + /* Vertex group number */ + int def_nr; + float w1, w2; + } *vgroups = NULL, *vg; + int totvgroup = 0; + + e = &origedge[i]; + + if (origdvert) { + const MDeformVert *dv1 = &origdvert[e->v1]; + const MDeformVert *dv2 = &origdvert[e->v2]; + vgroups = MEM_calloc_arrayN(dv1->totweight, sizeof(*vgroups), "vgroup"); + + /* Only want vertex groups used by both vertices */ + for (j = 0; j < dv1->totweight; j++) { + vg = NULL; + for (k = 0; k < dv2->totweight; k++) { + if (dv1->dw[j].def_nr == dv2->dw[k].def_nr) { + vg = &vgroups[totvgroup]; + totvgroup++; + break; + } + } + + if (vg) { + vg->def_nr = dv1->dw[j].def_nr; + vg->w1 = dv1->dw[j].weight; + vg->w2 = dv2->dw[k].weight; + } + } + } + + u = e->v1; + radrat = (half_v2(outnode[e->v2].radius) / half_v2(outnode[e->v1].radius)); + radrat = (radrat + 1) / 2; + + /* Add vertices and edge segments */ + for (j = 0; j < edge_subd[i]; j++, v++, outedge++) { + float r = (j + 1) / (float)(edge_subd[i] + 1); + float t = powf(r, radrat); + + /* Interpolate vertex coord */ + interp_v3_v3v3(outvert[v].co, outvert[e->v1].co, outvert[e->v2].co, t); + + /* Interpolate skin radii */ + interp_v3_v3v3(outnode[v].radius, orignode[e->v1].radius, orignode[e->v2].radius, t); + + /* Interpolate vertex group weights */ + for (k = 0; k < totvgroup; k++) { + float weight; + + vg = &vgroups[k]; + weight = interpf(vg->w2, vg->w1, t); + + if (weight > 0) + defvert_add_index_notest(&outdvert[v], vg->def_nr, weight); + } + + outedge->v1 = u; + outedge->v2 = v; + u = v; + } + + if (vgroups) + MEM_freeN(vgroups); + + /* Link up to final vertex */ + outedge->v1 = u; + outedge->v2 = e->v2; + outedge++; + } + + MEM_freeN(edge_subd); + + return result; } /******************************* Output *******************************/ /* Can be either quad or triangle */ -static void add_poly( - SkinOutput *so, - BMVert *v1, - BMVert *v2, - BMVert *v3, - BMVert *v4) +static void add_poly(SkinOutput *so, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4) { - BMVert *verts[4] = {v1, v2, v3, v4}; - BMFace *f; - - BLI_assert(v1 != v2 && v1 != v3 && v1 != v4); - BLI_assert(v2 != v3 && v2 != v4); - BLI_assert(v3 != v4); - BLI_assert(v1 && v2 && v3); - - f = BM_face_create_verts(so->bm, verts, v4 ? 4 : 3, NULL, BM_CREATE_NO_DOUBLE, true); - BM_face_normal_update(f); - if (so->smd->flag & MOD_SKIN_SMOOTH_SHADING) - BM_elem_flag_enable(f, BM_ELEM_SMOOTH); - f->mat_nr = so->mat_nr; + BMVert *verts[4] = {v1, v2, v3, v4}; + BMFace *f; + + BLI_assert(v1 != v2 && v1 != v3 && v1 != v4); + BLI_assert(v2 != v3 && v2 != v4); + BLI_assert(v3 != v4); + BLI_assert(v1 && v2 && v3); + + f = BM_face_create_verts(so->bm, verts, v4 ? 4 : 3, NULL, BM_CREATE_NO_DOUBLE, true); + BM_face_normal_update(f); + if (so->smd->flag & MOD_SKIN_SMOOTH_SHADING) + BM_elem_flag_enable(f, BM_ELEM_SMOOTH); + f->mat_nr = so->mat_nr; } -static void connect_frames( - SkinOutput *so, - BMVert *frame1[4], - BMVert *frame2[4]) +static void connect_frames(SkinOutput *so, BMVert *frame1[4], BMVert *frame2[4]) { - BMVert *q[4][4] = {{frame2[0], frame2[1], frame1[1], frame1[0]}, - {frame2[1], frame2[2], frame1[2], frame1[1]}, - {frame2[2], frame2[3], frame1[3], frame1[2]}, - {frame2[3], frame2[0], frame1[0], frame1[3]}}; - int i; - bool swap; - - /* Check if frame normals need swap */ + BMVert *q[4][4] = {{frame2[0], frame2[1], frame1[1], frame1[0]}, + {frame2[1], frame2[2], frame1[2], frame1[1]}, + {frame2[2], frame2[3], frame1[3], frame1[2]}, + {frame2[3], frame2[0], frame1[0], frame1[3]}}; + int i; + bool swap; + + /* Check if frame normals need swap */ #if 0 - { - /* simple method, works mostly */ - float p[3], no[3]; - sub_v3_v3v3(p, q[3][0]->co, q[0][0]->co); - normal_quad_v3(no, - q[0][0]->co, q[0][1]->co, - q[0][2]->co, q[0][3]->co); - swap = dot_v3v3(no, p) > 0; - } + { + /* simple method, works mostly */ + float p[3], no[3]; + sub_v3_v3v3(p, q[3][0]->co, q[0][0]->co); + normal_quad_v3(no, + q[0][0]->co, q[0][1]->co, + q[0][2]->co, q[0][3]->co); + swap = dot_v3v3(no, p) > 0; + } #else - { - /* comprehensive method, accumulate flipping of all faces */ - float cent_sides[4][3]; - float cent[3]; - float dot = 0.0f; - - for (i = 0; i < 4; i++) { - mid_v3_v3v3v3v3(cent_sides[i], UNPACK4_EX(, q[i], ->co)); - } - mid_v3_v3v3v3v3(cent, UNPACK4(cent_sides)); - - for (i = 0; i < 4; i++) { - float p[3], no[3]; - normal_quad_v3(no, UNPACK4_EX(, q[i], ->co)); - sub_v3_v3v3(p, cent, cent_sides[i]); - dot += dot_v3v3(no, p); - } - - swap = dot > 0; - } + { + /* comprehensive method, accumulate flipping of all faces */ + float cent_sides[4][3]; + float cent[3]; + float dot = 0.0f; + + for (i = 0; i < 4; i++) { + mid_v3_v3v3v3v3(cent_sides[i], UNPACK4_EX(, q[i], ->co)); + } + mid_v3_v3v3v3v3(cent, UNPACK4(cent_sides)); + + for (i = 0; i < 4; i++) { + float p[3], no[3]; + normal_quad_v3(no, UNPACK4_EX(, q[i], ->co)); + sub_v3_v3v3(p, cent, cent_sides[i]); + dot += dot_v3v3(no, p); + } + + swap = dot > 0; + } #endif - for (i = 0; i < 4; i++) { - if (swap) - add_poly(so, q[i][3], q[i][2], q[i][1], q[i][0]); - else - add_poly(so, q[i][0], q[i][1], q[i][2], q[i][3]); - } + for (i = 0; i < 4; i++) { + if (swap) + add_poly(so, q[i][3], q[i][2], q[i][1], q[i][0]); + else + add_poly(so, q[i][0], q[i][1], q[i][2], q[i][3]); + } } -static void output_frames( - BMesh *bm, - SkinNode *sn, - const MDeformVert *input_dvert) +static void output_frames(BMesh *bm, SkinNode *sn, const MDeformVert *input_dvert) { - Frame *f; - int i, j; - - /* Output all frame verts */ - for (i = 0; i < sn->totframe; i++) { - f = &sn->frames[i]; - for (j = 0; j < 4; j++) { - if (!f->merge[j].frame) { - BMVert *v = f->verts[j] = BM_vert_create(bm, f->co[j], NULL, BM_CREATE_NOP); - - if (input_dvert) { - MDeformVert *dv; - dv = CustomData_bmesh_get(&bm->vdata, - v->head.data, - CD_MDEFORMVERT); - - BLI_assert(dv->totweight == 0); - defvert_copy(dv, input_dvert); - } - } - } - } + Frame *f; + int i, j; + + /* Output all frame verts */ + for (i = 0; i < sn->totframe; i++) { + f = &sn->frames[i]; + for (j = 0; j < 4; j++) { + if (!f->merge[j].frame) { + BMVert *v = f->verts[j] = BM_vert_create(bm, f->co[j], NULL, BM_CREATE_NOP); + + if (input_dvert) { + MDeformVert *dv; + dv = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_MDEFORMVERT); + + BLI_assert(dv->totweight == 0); + defvert_copy(dv, input_dvert); + } + } + } + } } #define PRINT_HOLE_INFO 0 static void calc_frame_center(float center[3], const Frame *frame) { - add_v3_v3v3(center, frame->verts[0]->co, frame->verts[1]->co); - add_v3_v3(center, frame->verts[2]->co); - add_v3_v3(center, frame->verts[3]->co); - mul_v3_fl(center, 0.25f); + add_v3_v3v3(center, frame->verts[0]->co, frame->verts[1]->co); + add_v3_v3(center, frame->verts[2]->co); + add_v3_v3(center, frame->verts[3]->co); + mul_v3_fl(center, 0.25f); } /* Does crappy fan triangulation of poly, may not be so accurate for @@ -1085,32 +1042,30 @@ static int isect_ray_poly(const float ray_start[3], BMFace *f, float *r_lambda) { - BMVert *v, *v_first = NULL, *v_prev = NULL; - BMIter iter; - float best_dist = FLT_MAX; - bool hit = false; - - BM_ITER_ELEM (v, &iter, f, BM_VERTS_OF_FACE) { - if (!v_first) - v_first = v; - else if (v_prev != v_first) { - float dist; - bool curhit; - - curhit = isect_ray_tri_v3(ray_start, ray_dir, - v_first->co, v_prev->co, v->co, - &dist, NULL); - if (curhit && dist < best_dist) { - hit = true; - best_dist = dist; - } - } - - v_prev = v; - } - - *r_lambda = best_dist; - return hit; + BMVert *v, *v_first = NULL, *v_prev = NULL; + BMIter iter; + float best_dist = FLT_MAX; + bool hit = false; + + BM_ITER_ELEM (v, &iter, f, BM_VERTS_OF_FACE) { + if (!v_first) + v_first = v; + else if (v_prev != v_first) { + float dist; + bool curhit; + + curhit = isect_ray_tri_v3(ray_start, ray_dir, v_first->co, v_prev->co, v->co, &dist, NULL); + if (curhit && dist < best_dist) { + hit = true; + best_dist = dist; + } + } + + v_prev = v; + } + + *r_lambda = best_dist; + return hit; } /* Reduce the face down to 'n' corners by collapsing the edges; @@ -1118,237 +1073,238 @@ static int isect_ray_poly(const float ray_start[3], * * The orig_verts should contain the vertices of 'f' */ -static BMFace *collapse_face_corners(BMesh *bm, BMFace *f, int n, - BMVert **orig_verts) +static BMFace *collapse_face_corners(BMesh *bm, BMFace *f, int n, BMVert **orig_verts) { - int orig_len = f->len; - - BLI_assert(n >= 3); - BLI_assert(f->len > n); - if (f->len <= n) - return f; - - /* Collapse shortest edge for now */ - while (f->len > n) { - BMFace *vf; - BMEdge *shortest_edge; - BMVert *v_safe, *v_merge; - BMOperator op; - BMIter iter; - int i; - BMOpSlot *slot_targetmap; - - shortest_edge = BM_face_find_shortest_loop(f)->e; - BMO_op_initf(bm, &op, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), "weld_verts"); - - slot_targetmap = BMO_slot_get(op.slots_in, "targetmap"); - - /* Note: could probably calculate merges in one go to be - * faster */ - - v_safe = shortest_edge->v1; - v_merge = shortest_edge->v2; - mid_v3_v3v3(v_safe->co, v_safe->co, v_merge->co); - BMO_slot_map_elem_insert(&op, slot_targetmap, v_merge, v_safe); - BMO_op_exec(bm, &op); - BMO_op_finish(bm, &op); - - /* Find the new face */ - f = NULL; - BM_ITER_ELEM (vf, &iter, v_safe, BM_FACES_OF_VERT) { - bool wrong_face = false; - - for (i = 0; i < orig_len; i++) { - if (orig_verts[i] == v_merge) { - orig_verts[i] = NULL; - } - else if (orig_verts[i] && - !BM_vert_in_face(orig_verts[i], vf)) - { - wrong_face = true; - break; - } - } - - if (!wrong_face) { - f = vf; - break; - } - } - - BLI_assert(f); - } - - return f; + int orig_len = f->len; + + BLI_assert(n >= 3); + BLI_assert(f->len > n); + if (f->len <= n) + return f; + + /* Collapse shortest edge for now */ + while (f->len > n) { + BMFace *vf; + BMEdge *shortest_edge; + BMVert *v_safe, *v_merge; + BMOperator op; + BMIter iter; + int i; + BMOpSlot *slot_targetmap; + + shortest_edge = BM_face_find_shortest_loop(f)->e; + BMO_op_initf(bm, &op, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), "weld_verts"); + + slot_targetmap = BMO_slot_get(op.slots_in, "targetmap"); + + /* Note: could probably calculate merges in one go to be + * faster */ + + v_safe = shortest_edge->v1; + v_merge = shortest_edge->v2; + mid_v3_v3v3(v_safe->co, v_safe->co, v_merge->co); + BMO_slot_map_elem_insert(&op, slot_targetmap, v_merge, v_safe); + BMO_op_exec(bm, &op); + BMO_op_finish(bm, &op); + + /* Find the new face */ + f = NULL; + BM_ITER_ELEM (vf, &iter, v_safe, BM_FACES_OF_VERT) { + bool wrong_face = false; + + for (i = 0; i < orig_len; i++) { + if (orig_verts[i] == v_merge) { + orig_verts[i] = NULL; + } + else if (orig_verts[i] && !BM_vert_in_face(orig_verts[i], vf)) { + wrong_face = true; + break; + } + } + + if (!wrong_face) { + f = vf; + break; + } + } + + BLI_assert(f); + } + + return f; } /* Choose a good face to merge the frame with, used in case the frame * is completely inside the hull. */ static BMFace *skin_hole_target_face(BMesh *bm, Frame *frame) { - BMFace *f, *isect_target_face, *center_target_face; - BMIter iter; - float frame_center[3]; - float frame_normal[3]; - float best_isect_dist = FLT_MAX; - float best_center_dist = FLT_MAX; - - calc_frame_center(frame_center, frame); - normal_quad_v3(frame_normal, frame->verts[3]->co, - frame->verts[2]->co, frame->verts[1]->co, - frame->verts[0]->co); - - /* Use a line intersection test and nearest center test against - * all faces */ - isect_target_face = center_target_face = NULL; - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - float dist, poly_center[3]; - int hit; - - /* Intersection test */ - hit = isect_ray_poly(frame_center, frame_normal, f, &dist); - if (hit && dist < best_isect_dist) { - isect_target_face = f; - best_isect_dist = dist; - } - - /* Nearest test */ - BM_face_calc_center_median(f, poly_center); - dist = len_v3v3(frame_center, poly_center); - if (dist < best_center_dist) { - center_target_face = f; - best_center_dist = dist; - } - } - - f = isect_target_face; - if (!f || best_center_dist < best_isect_dist / 2) - f = center_target_face; - - /* This case is unlikely now, but could still happen. Should look - * into splitting edges to make new faces. */ + BMFace *f, *isect_target_face, *center_target_face; + BMIter iter; + float frame_center[3]; + float frame_normal[3]; + float best_isect_dist = FLT_MAX; + float best_center_dist = FLT_MAX; + + calc_frame_center(frame_center, frame); + normal_quad_v3(frame_normal, + frame->verts[3]->co, + frame->verts[2]->co, + frame->verts[1]->co, + frame->verts[0]->co); + + /* Use a line intersection test and nearest center test against + * all faces */ + isect_target_face = center_target_face = NULL; + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + float dist, poly_center[3]; + int hit; + + /* Intersection test */ + hit = isect_ray_poly(frame_center, frame_normal, f, &dist); + if (hit && dist < best_isect_dist) { + isect_target_face = f; + best_isect_dist = dist; + } + + /* Nearest test */ + BM_face_calc_center_median(f, poly_center); + dist = len_v3v3(frame_center, poly_center); + if (dist < best_center_dist) { + center_target_face = f; + best_center_dist = dist; + } + } + + f = isect_target_face; + if (!f || best_center_dist < best_isect_dist / 2) + f = center_target_face; + + /* This case is unlikely now, but could still happen. Should look + * into splitting edges to make new faces. */ #if PRINT_HOLE_INFO - if (!f) { - printf("no good face found\n"); - } + if (!f) { + printf("no good face found\n"); + } #endif - return f; + return f; } /* Use edge-length heuristic to choose from eight possible polygon bridges */ -static void skin_choose_quad_bridge_order(BMVert *a[4], BMVert *b[4], - int best_order[4]) +static void skin_choose_quad_bridge_order(BMVert *a[4], BMVert *b[4], int best_order[4]) { - int orders[8][4]; - float shortest_len; - int i, j; - - /* Enumerate all valid orderings */ - for (i = 0; i < 4; i++) { - for (j = 0; j < 4; j++) { - orders[i][j] = (j + i) % 4; - orders[i + 4][j] = 3 - ((j + i) % 4); - } - } - - shortest_len = FLT_MAX; - for (i = 0; i < 8; i++) { - float len = 0; - - /* Get total edge length for this configuration */ - for (j = 0; j < 4; j++) - len += len_squared_v3v3(a[j]->co, b[orders[i][j]]->co); - - if (len < shortest_len) { - shortest_len = len; - memcpy(best_order, orders[i], sizeof(int) * 4); - } - } + int orders[8][4]; + float shortest_len; + int i, j; + + /* Enumerate all valid orderings */ + for (i = 0; i < 4; i++) { + for (j = 0; j < 4; j++) { + orders[i][j] = (j + i) % 4; + orders[i + 4][j] = 3 - ((j + i) % 4); + } + } + + shortest_len = FLT_MAX; + for (i = 0; i < 8; i++) { + float len = 0; + + /* Get total edge length for this configuration */ + for (j = 0; j < 4; j++) + len += len_squared_v3v3(a[j]->co, b[orders[i][j]]->co); + + if (len < shortest_len) { + shortest_len = len; + memcpy(best_order, orders[i], sizeof(int) * 4); + } + } } static void skin_fix_hole_no_good_verts(BMesh *bm, Frame *frame, BMFace *split_face) { - BMFace *f; - BMVert *verts[4]; - BMVert **vert_buf = NULL; - BLI_array_declare(vert_buf); - BMOIter oiter; - BMOperator op; - int i, best_order[4]; - BMOpSlot *slot_targetmap; - - BLI_assert(split_face->len >= 3); - - /* Extrude the split face */ - BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false); - BM_elem_flag_enable(split_face, BM_ELEM_TAG); - BMO_op_initf(bm, &op, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), - "extrude_discrete_faces faces=%hf", BM_ELEM_TAG); - BMO_op_exec(bm, &op); - - /* Update split face (should only be one new face created - * during extrusion) */ - split_face = NULL; - BMO_ITER (f, &oiter, op.slots_out, "faces.out", BM_FACE) { - BLI_assert(!split_face); - split_face = f; - } - - BMO_op_finish(bm, &op); - - if (split_face->len == 3) { - BMEdge *longest_edge; - - /* Need at least four ring edges, so subdivide longest edge if - * face is a triangle */ - longest_edge = BM_face_find_longest_loop(split_face)->e; - - BM_mesh_elem_hflag_disable_all(bm, BM_EDGE, BM_ELEM_TAG, false); - BM_elem_flag_enable(longest_edge, BM_ELEM_TAG); - - BMO_op_callf(bm, BMO_FLAG_DEFAULTS, - "subdivide_edges edges=%he cuts=%i quad_corner_type=%i", - BM_ELEM_TAG, 1, SUBD_CORNER_STRAIGHT_CUT); - } - else if (split_face->len > 4) { - /* Maintain a dynamic vert array containing the split_face's - * vertices, avoids frequent allocs in collapse_face_corners() */ - if (BLI_array_len(vert_buf) < split_face->len) { - BLI_array_grow_items(vert_buf, (split_face->len - - BLI_array_len(vert_buf))); - } - - /* Get split face's verts */ - BM_iter_as_array(bm, BM_VERTS_OF_FACE, split_face, - (void **)vert_buf, split_face->len); - - /* Earlier edge split operations may have turned some quads - * into higher-degree faces */ - split_face = collapse_face_corners(bm, split_face, 4, vert_buf); - } - - /* Done with dynamic array, split_face must now be a quad */ - BLI_array_free(vert_buf); - BLI_assert(split_face->len == 4); - if (split_face->len != 4) - return; - - /* Get split face's verts */ - // BM_iter_as_array(bm, BM_VERTS_OF_FACE, split_face, (void **)verts, 4); - BM_face_as_array_vert_quad(split_face, verts); - skin_choose_quad_bridge_order(verts, frame->verts, best_order); - - /* Delete split face and merge */ - BM_face_kill(bm, split_face); - BMO_op_init(bm, &op, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), - "weld_verts"); - slot_targetmap = BMO_slot_get(op.slots_in, "targetmap"); - for (i = 0; i < 4; i++) { - BMO_slot_map_elem_insert(&op, slot_targetmap, verts[i], frame->verts[best_order[i]]); - } - BMO_op_exec(bm, &op); - BMO_op_finish(bm, &op); + BMFace *f; + BMVert *verts[4]; + BMVert **vert_buf = NULL; + BLI_array_declare(vert_buf); + BMOIter oiter; + BMOperator op; + int i, best_order[4]; + BMOpSlot *slot_targetmap; + + BLI_assert(split_face->len >= 3); + + /* Extrude the split face */ + BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false); + BM_elem_flag_enable(split_face, BM_ELEM_TAG); + BMO_op_initf(bm, + &op, + (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), + "extrude_discrete_faces faces=%hf", + BM_ELEM_TAG); + BMO_op_exec(bm, &op); + + /* Update split face (should only be one new face created + * during extrusion) */ + split_face = NULL; + BMO_ITER (f, &oiter, op.slots_out, "faces.out", BM_FACE) { + BLI_assert(!split_face); + split_face = f; + } + + BMO_op_finish(bm, &op); + + if (split_face->len == 3) { + BMEdge *longest_edge; + + /* Need at least four ring edges, so subdivide longest edge if + * face is a triangle */ + longest_edge = BM_face_find_longest_loop(split_face)->e; + + BM_mesh_elem_hflag_disable_all(bm, BM_EDGE, BM_ELEM_TAG, false); + BM_elem_flag_enable(longest_edge, BM_ELEM_TAG); + + BMO_op_callf(bm, + BMO_FLAG_DEFAULTS, + "subdivide_edges edges=%he cuts=%i quad_corner_type=%i", + BM_ELEM_TAG, + 1, + SUBD_CORNER_STRAIGHT_CUT); + } + else if (split_face->len > 4) { + /* Maintain a dynamic vert array containing the split_face's + * vertices, avoids frequent allocs in collapse_face_corners() */ + if (BLI_array_len(vert_buf) < split_face->len) { + BLI_array_grow_items(vert_buf, (split_face->len - BLI_array_len(vert_buf))); + } + + /* Get split face's verts */ + BM_iter_as_array(bm, BM_VERTS_OF_FACE, split_face, (void **)vert_buf, split_face->len); + + /* Earlier edge split operations may have turned some quads + * into higher-degree faces */ + split_face = collapse_face_corners(bm, split_face, 4, vert_buf); + } + + /* Done with dynamic array, split_face must now be a quad */ + BLI_array_free(vert_buf); + BLI_assert(split_face->len == 4); + if (split_face->len != 4) + return; + + /* Get split face's verts */ + // BM_iter_as_array(bm, BM_VERTS_OF_FACE, split_face, (void **)verts, 4); + BM_face_as_array_vert_quad(split_face, verts); + skin_choose_quad_bridge_order(verts, frame->verts, best_order); + + /* Delete split face and merge */ + BM_face_kill(bm, split_face); + BMO_op_init(bm, &op, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), "weld_verts"); + slot_targetmap = BMO_slot_get(op.slots_in, "targetmap"); + for (i = 0; i < 4; i++) { + BMO_slot_map_elem_insert(&op, slot_targetmap, verts[i], frame->verts[best_order[i]]); + } + BMO_op_exec(bm, &op); + BMO_op_finish(bm, &op); } /* If the frame has some vertices that are inside the hull (detached) @@ -1356,473 +1312,451 @@ static void skin_fix_hole_no_good_verts(BMesh *bm, Frame *frame, BMFace *split_f * whole frame off the hull. */ static void skin_hole_detach_partially_attached_frame(BMesh *bm, Frame *frame) { - int i, attached[4], totattached = 0; - - /* Get/count attached frame corners */ - for (i = 0; i < 4; i++) { - if (!frame->inside_hull[i]) - attached[totattached++] = i; - } - - /* Detach everything */ - for (i = 0; i < totattached; i++) { - BMVert **av = &frame->verts[attached[i]]; - (*av) = BM_vert_create(bm, (*av)->co, *av, BM_CREATE_NOP); - } + int i, attached[4], totattached = 0; + + /* Get/count attached frame corners */ + for (i = 0; i < 4; i++) { + if (!frame->inside_hull[i]) + attached[totattached++] = i; + } + + /* Detach everything */ + for (i = 0; i < totattached; i++) { + BMVert **av = &frame->verts[attached[i]]; + (*av) = BM_vert_create(bm, (*av)->co, *av, BM_CREATE_NOP); + } } - static void quad_from_tris(BMEdge *e, BMFace *adj[2], BMVert *ndx[4]) { - BMVert *tri[2][3]; - BMVert *opp = NULL; - int i, j; + BMVert *tri[2][3]; + BMVert *opp = NULL; + int i, j; - BLI_assert(adj[0]->len == 3 && adj[1]->len == 3); + BLI_assert(adj[0]->len == 3 && adj[1]->len == 3); #if 0 - BM_iter_as_array(bm, BM_VERTS_OF_FACE, adj[0], (void **)tri[0], 3); - BM_iter_as_array(bm, BM_VERTS_OF_FACE, adj[1], (void **)tri[1], 3); + BM_iter_as_array(bm, BM_VERTS_OF_FACE, adj[0], (void **)tri[0], 3); + BM_iter_as_array(bm, BM_VERTS_OF_FACE, adj[1], (void **)tri[1], 3); #else - BM_face_as_array_vert_tri(adj[0], tri[0]); - BM_face_as_array_vert_tri(adj[1], tri[1]); + BM_face_as_array_vert_tri(adj[0], tri[0]); + BM_face_as_array_vert_tri(adj[1], tri[1]); #endif - /* Find what the second tri has that the first doesn't */ - for (i = 0; i < 3; i++) { - if (tri[1][i] != tri[0][0] && - tri[1][i] != tri[0][1] && - tri[1][i] != tri[0][2]) - { - opp = tri[1][i]; - break; - } - } - BLI_assert(opp); - - for (i = 0, j = 0; i < 3; i++, j++) { - ndx[j] = tri[0][i]; - /* When the triangle edge cuts across our quad-to-be, - * throw in the second triangle's vertex */ - if ((tri[0][i] == e->v1 || tri[0][i] == e->v2) && - (tri[0][(i + 1) % 3] == e->v1 || tri[0][(i + 1) % 3] == e->v2)) - { - j++; - ndx[j] = opp; - } - } + /* Find what the second tri has that the first doesn't */ + for (i = 0; i < 3; i++) { + if (tri[1][i] != tri[0][0] && tri[1][i] != tri[0][1] && tri[1][i] != tri[0][2]) { + opp = tri[1][i]; + break; + } + } + BLI_assert(opp); + + for (i = 0, j = 0; i < 3; i++, j++) { + ndx[j] = tri[0][i]; + /* When the triangle edge cuts across our quad-to-be, + * throw in the second triangle's vertex */ + if ((tri[0][i] == e->v1 || tri[0][i] == e->v2) && + (tri[0][(i + 1) % 3] == e->v1 || tri[0][(i + 1) % 3] == e->v2)) { + j++; + ndx[j] = opp; + } + } } static void add_quad_from_tris(SkinOutput *so, BMEdge *e, BMFace *adj[2]) { - BMVert *quad[4]; + BMVert *quad[4]; - quad_from_tris(e, adj, quad); + quad_from_tris(e, adj, quad); - add_poly(so, quad[0], quad[1], quad[2], quad[3]); + add_poly(so, quad[0], quad[1], quad[2], quad[3]); } static void hull_merge_triangles(SkinOutput *so, const SkinModifierData *smd) { - BMIter iter; - BMEdge *e; - HeapSimple *heap; - float score; - - heap = BLI_heapsimple_new(); - - BM_mesh_elem_hflag_disable_all(so->bm, BM_FACE, BM_ELEM_TAG, false); - - /* Build heap */ - BM_ITER_MESH (e, &iter, so->bm, BM_EDGES_OF_MESH) { - BMFace *adj[2]; - - /* Only care if the edge is used by exactly two triangles */ - if (BM_edge_face_pair(e, &adj[0], &adj[1])) { - if (adj[0]->len == 3 && adj[1]->len == 3) { - BMVert *quad[4]; - - BLI_assert(BM_face_is_normal_valid(adj[0])); - BLI_assert(BM_face_is_normal_valid(adj[1])); - - /* Construct quad using the two triangles adjacent to - * the edge */ - quad_from_tris(e, adj, quad); - - /* Calculate a score for the quad, higher score for - * triangles being closer to coplanar */ - score = ((BM_face_calc_area(adj[0]) + - BM_face_calc_area(adj[1])) * - dot_v3v3(adj[0]->no, adj[1]->no)); - - /* Check if quad crosses the axis of symmetry */ - if (quad_crosses_symmetry_plane(quad, smd)) { - /* Increase score if the triangles form a - * symmetric quad, otherwise don't use it */ - if (is_quad_symmetric(quad, smd)) - score *= 10; - else - continue; - } - - /* Don't use the quad if it's concave */ - if (!is_quad_convex_v3(quad[0]->co, quad[1]->co, - quad[2]->co, quad[3]->co)) - { - continue; - } - - BLI_heapsimple_insert(heap, -score, e); - } - } - } - - while (!BLI_heapsimple_is_empty(heap)) { - BMFace *adj[2]; - - e = BLI_heapsimple_pop_min(heap); - - if (BM_edge_face_pair(e, &adj[0], &adj[1])) { - /* If both triangles still free, and if they don't already - * share a border with another face, output as a quad */ - if (!BM_elem_flag_test(adj[0], BM_ELEM_TAG) && - !BM_elem_flag_test(adj[1], BM_ELEM_TAG) && - !BM_face_share_face_check(adj[0], adj[1])) - { - add_quad_from_tris(so, e, adj); - BM_elem_flag_enable(adj[0], BM_ELEM_TAG); - BM_elem_flag_enable(adj[1], BM_ELEM_TAG); - BM_elem_flag_enable(e, BM_ELEM_TAG); - } - } - } - - BLI_heapsimple_free(heap, NULL); - - BM_mesh_delete_hflag_tagged(so->bm, BM_ELEM_TAG, BM_EDGE | BM_FACE); - + BMIter iter; + BMEdge *e; + HeapSimple *heap; + float score; + + heap = BLI_heapsimple_new(); + + BM_mesh_elem_hflag_disable_all(so->bm, BM_FACE, BM_ELEM_TAG, false); + + /* Build heap */ + BM_ITER_MESH (e, &iter, so->bm, BM_EDGES_OF_MESH) { + BMFace *adj[2]; + + /* Only care if the edge is used by exactly two triangles */ + if (BM_edge_face_pair(e, &adj[0], &adj[1])) { + if (adj[0]->len == 3 && adj[1]->len == 3) { + BMVert *quad[4]; + + BLI_assert(BM_face_is_normal_valid(adj[0])); + BLI_assert(BM_face_is_normal_valid(adj[1])); + + /* Construct quad using the two triangles adjacent to + * the edge */ + quad_from_tris(e, adj, quad); + + /* Calculate a score for the quad, higher score for + * triangles being closer to coplanar */ + score = ((BM_face_calc_area(adj[0]) + BM_face_calc_area(adj[1])) * + dot_v3v3(adj[0]->no, adj[1]->no)); + + /* Check if quad crosses the axis of symmetry */ + if (quad_crosses_symmetry_plane(quad, smd)) { + /* Increase score if the triangles form a + * symmetric quad, otherwise don't use it */ + if (is_quad_symmetric(quad, smd)) + score *= 10; + else + continue; + } + + /* Don't use the quad if it's concave */ + if (!is_quad_convex_v3(quad[0]->co, quad[1]->co, quad[2]->co, quad[3]->co)) { + continue; + } + + BLI_heapsimple_insert(heap, -score, e); + } + } + } + + while (!BLI_heapsimple_is_empty(heap)) { + BMFace *adj[2]; + + e = BLI_heapsimple_pop_min(heap); + + if (BM_edge_face_pair(e, &adj[0], &adj[1])) { + /* If both triangles still free, and if they don't already + * share a border with another face, output as a quad */ + if (!BM_elem_flag_test(adj[0], BM_ELEM_TAG) && !BM_elem_flag_test(adj[1], BM_ELEM_TAG) && + !BM_face_share_face_check(adj[0], adj[1])) { + add_quad_from_tris(so, e, adj); + BM_elem_flag_enable(adj[0], BM_ELEM_TAG); + BM_elem_flag_enable(adj[1], BM_ELEM_TAG); + BM_elem_flag_enable(e, BM_ELEM_TAG); + } + } + } + + BLI_heapsimple_free(heap, NULL); + + BM_mesh_delete_hflag_tagged(so->bm, BM_ELEM_TAG, BM_EDGE | BM_FACE); } -static void skin_merge_close_frame_verts(SkinNode *skin_nodes, int totvert, +static void skin_merge_close_frame_verts(SkinNode *skin_nodes, + int totvert, const MeshElemMap *emap, const MEdge *medge) { - Frame **hull_frames; - int v, tothullframe; - - for (v = 0; v < totvert; v++) { - /* Only check branch nodes */ - if (!skin_nodes[v].totframe) { - hull_frames = collect_hull_frames(v, skin_nodes, - emap, medge, - &tothullframe); - merge_frame_corners(hull_frames, tothullframe); - MEM_freeN(hull_frames); - } - } + Frame **hull_frames; + int v, tothullframe; + + for (v = 0; v < totvert; v++) { + /* Only check branch nodes */ + if (!skin_nodes[v].totframe) { + hull_frames = collect_hull_frames(v, skin_nodes, emap, medge, &tothullframe); + merge_frame_corners(hull_frames, tothullframe); + MEM_freeN(hull_frames); + } + } } static void skin_update_merged_vertices(SkinNode *skin_nodes, int totvert) { - int v; + int v; - for (v = 0; v < totvert; ++v) { - SkinNode *sn = &skin_nodes[v]; - int i, j; + for (v = 0; v < totvert; ++v) { + SkinNode *sn = &skin_nodes[v]; + int i, j; - for (i = 0; i < sn->totframe; i++) { - Frame *f = &sn->frames[i]; + for (i = 0; i < sn->totframe; i++) { + Frame *f = &sn->frames[i]; - for (j = 0; j < 4; j++) { - if (f->merge[j].frame) { - /* Merge chaining not allowed */ - BLI_assert(!f->merge[j].frame->merge[f->merge[j].corner].frame); + for (j = 0; j < 4; j++) { + if (f->merge[j].frame) { + /* Merge chaining not allowed */ + BLI_assert(!f->merge[j].frame->merge[f->merge[j].corner].frame); - f->verts[j] = f->merge[j].frame->verts[f->merge[j].corner]; - } - } - } - } + f->verts[j] = f->merge[j].frame->verts[f->merge[j].corner]; + } + } + } + } } -static void skin_fix_hull_topology(BMesh *bm, SkinNode *skin_nodes, - int totvert) +static void skin_fix_hull_topology(BMesh *bm, SkinNode *skin_nodes, int totvert) { - int v; + int v; - for (v = 0; v < totvert; v++) { - SkinNode *sn = &skin_nodes[v]; - int j; + for (v = 0; v < totvert; v++) { + SkinNode *sn = &skin_nodes[v]; + int j; - for (j = 0; j < sn->totframe; j++) { - Frame *f = &sn->frames[j]; + for (j = 0; j < sn->totframe; j++) { + Frame *f = &sn->frames[j]; - if (f->detached) { - BMFace *target_face; + if (f->detached) { + BMFace *target_face; - skin_hole_detach_partially_attached_frame(bm, f); + skin_hole_detach_partially_attached_frame(bm, f); - target_face = skin_hole_target_face(bm, f); - if (target_face) - skin_fix_hole_no_good_verts(bm, f, target_face); - } - } - } + target_face = skin_hole_target_face(bm, f); + if (target_face) + skin_fix_hole_no_good_verts(bm, f, target_face); + } + } + } } -static void skin_output_end_nodes(SkinOutput *so, SkinNode *skin_nodes, - int totvert) +static void skin_output_end_nodes(SkinOutput *so, SkinNode *skin_nodes, int totvert) { - int v; - - for (v = 0; v < totvert; ++v) { - SkinNode *sn = &skin_nodes[v]; - /* Assuming here just two frames */ - if (sn->flag & SEAM_FRAME) { - BMVert *v_order[4]; - int i, order[4]; - - skin_choose_quad_bridge_order(sn->frames[0].verts, - sn->frames[1].verts, - order); - for (i = 0; i < 4; i++) - v_order[i] = sn->frames[1].verts[order[i]]; - connect_frames(so, sn->frames[0].verts, v_order); - } - else if (sn->totframe == 2) { - connect_frames(so, - sn->frames[0].verts, - sn->frames[1].verts); - } - - if (sn->flag & CAP_START) { - if (sn->flag & ROOT) { - add_poly(so, - sn->frames[0].verts[0], - sn->frames[0].verts[1], - sn->frames[0].verts[2], - sn->frames[0].verts[3]); - } - else { - add_poly(so, - sn->frames[0].verts[3], - sn->frames[0].verts[2], - sn->frames[0].verts[1], - sn->frames[0].verts[0]); - } - } - if (sn->flag & CAP_END) { - add_poly(so, - sn->frames[1].verts[0], - sn->frames[1].verts[1], - sn->frames[1].verts[2], - sn->frames[1].verts[3]); - } - } + int v; + + for (v = 0; v < totvert; ++v) { + SkinNode *sn = &skin_nodes[v]; + /* Assuming here just two frames */ + if (sn->flag & SEAM_FRAME) { + BMVert *v_order[4]; + int i, order[4]; + + skin_choose_quad_bridge_order(sn->frames[0].verts, sn->frames[1].verts, order); + for (i = 0; i < 4; i++) + v_order[i] = sn->frames[1].verts[order[i]]; + connect_frames(so, sn->frames[0].verts, v_order); + } + else if (sn->totframe == 2) { + connect_frames(so, sn->frames[0].verts, sn->frames[1].verts); + } + + if (sn->flag & CAP_START) { + if (sn->flag & ROOT) { + add_poly(so, + sn->frames[0].verts[0], + sn->frames[0].verts[1], + sn->frames[0].verts[2], + sn->frames[0].verts[3]); + } + else { + add_poly(so, + sn->frames[0].verts[3], + sn->frames[0].verts[2], + sn->frames[0].verts[1], + sn->frames[0].verts[0]); + } + } + if (sn->flag & CAP_END) { + add_poly(so, + sn->frames[1].verts[0], + sn->frames[1].verts[1], + sn->frames[1].verts[2], + sn->frames[1].verts[3]); + } + } } -static void skin_output_connections(SkinOutput *so, SkinNode *skin_nodes, +static void skin_output_connections(SkinOutput *so, + SkinNode *skin_nodes, const MEdge *medge, int totedge) { - int e; - - for (e = 0; e < totedge; e++) { - SkinNode *a, *b; - a = &skin_nodes[medge[e].v1]; - b = &skin_nodes[medge[e].v2]; - - if (a->totframe && b->totframe) { - if ((a->flag & SEAM_FRAME) || (b->flag & SEAM_FRAME)) { - Frame *fr[2] = {&a->frames[0], &b->frames[0]}; - BMVert *v_order[4]; - int i, order[4]; - - if ((a->flag & SEAM_FRAME) && (e != a->seam_edges[0])) - fr[0]++; - if ((b->flag & SEAM_FRAME) && (e != b->seam_edges[0])) - fr[1]++; - - skin_choose_quad_bridge_order(fr[0]->verts, fr[1]->verts, order); - for (i = 0; i < 4; i++) - v_order[i] = fr[1]->verts[order[i]]; - connect_frames(so, fr[0]->verts, v_order); - } - else { - connect_frames(so, - a->frames[0].verts, - b->frames[0].verts); - } - } - } + int e; + + for (e = 0; e < totedge; e++) { + SkinNode *a, *b; + a = &skin_nodes[medge[e].v1]; + b = &skin_nodes[medge[e].v2]; + + if (a->totframe && b->totframe) { + if ((a->flag & SEAM_FRAME) || (b->flag & SEAM_FRAME)) { + Frame *fr[2] = {&a->frames[0], &b->frames[0]}; + BMVert *v_order[4]; + int i, order[4]; + + if ((a->flag & SEAM_FRAME) && (e != a->seam_edges[0])) + fr[0]++; + if ((b->flag & SEAM_FRAME) && (e != b->seam_edges[0])) + fr[1]++; + + skin_choose_quad_bridge_order(fr[0]->verts, fr[1]->verts, order); + for (i = 0; i < 4; i++) + v_order[i] = fr[1]->verts[order[i]]; + connect_frames(so, fr[0]->verts, v_order); + } + else { + connect_frames(so, a->frames[0].verts, b->frames[0].verts); + } + } + } } -static void skin_smooth_hulls(BMesh *bm, SkinNode *skin_nodes, - int totvert, const SkinModifierData *smd) +static void skin_smooth_hulls(BMesh *bm, + SkinNode *skin_nodes, + int totvert, + const SkinModifierData *smd) { - BMIter iter, eiter; - BMVert *v; - int i, j, k, skey; - - if (smd->branch_smoothing == 0) - return; - - /* Mark all frame vertices */ - BM_mesh_elem_hflag_disable_all(bm, BM_VERT, BM_ELEM_TAG, false); - for (i = 0; i < totvert; i++) { - for (j = 0; j < skin_nodes[i].totframe; j++) { - Frame *frame = &skin_nodes[i].frames[j]; - - for (k = 0; k < 4; k++) - BM_elem_flag_enable(frame->verts[k], BM_ELEM_TAG); - } - } - - /* Add temporary shapekey layer to store original coordinates */ - BM_data_layer_add(bm, &bm->vdata, CD_SHAPEKEY); - skey = CustomData_number_of_layers(&bm->vdata, CD_SHAPEKEY) - 1; - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - copy_v3_v3(CustomData_bmesh_get_n(&bm->vdata, v->head.data, - CD_SHAPEKEY, skey), v->co); - } - - /* Smooth vertices, weight unmarked vertices more strongly (helps - * to smooth frame vertices, but don't want to alter them too - * much) */ - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - BMEdge *e; - float avg[3]; - float weight = smd->branch_smoothing; - int totv = 1; - - if (BM_elem_flag_test(v, BM_ELEM_TAG)) - weight *= 0.5f; - - copy_v3_v3(avg, v->co); - BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - BMVert *other = BM_edge_other_vert(e, v); - - add_v3_v3(avg, CustomData_bmesh_get_n(&bm->vdata, - other->head.data, - CD_SHAPEKEY, skey)); - totv++; - } - - if (totv > 1) { - mul_v3_fl(avg, 1.0f / (float)totv); - interp_v3_v3v3(v->co, v->co, avg, weight); - } - } - - /* Done with original coordinates */ - BM_data_layer_free_n(bm, &bm->vdata, CD_SHAPEKEY, skey); + BMIter iter, eiter; + BMVert *v; + int i, j, k, skey; + + if (smd->branch_smoothing == 0) + return; + + /* Mark all frame vertices */ + BM_mesh_elem_hflag_disable_all(bm, BM_VERT, BM_ELEM_TAG, false); + for (i = 0; i < totvert; i++) { + for (j = 0; j < skin_nodes[i].totframe; j++) { + Frame *frame = &skin_nodes[i].frames[j]; + + for (k = 0; k < 4; k++) + BM_elem_flag_enable(frame->verts[k], BM_ELEM_TAG); + } + } + + /* Add temporary shapekey layer to store original coordinates */ + BM_data_layer_add(bm, &bm->vdata, CD_SHAPEKEY); + skey = CustomData_number_of_layers(&bm->vdata, CD_SHAPEKEY) - 1; + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + copy_v3_v3(CustomData_bmesh_get_n(&bm->vdata, v->head.data, CD_SHAPEKEY, skey), v->co); + } + + /* Smooth vertices, weight unmarked vertices more strongly (helps + * to smooth frame vertices, but don't want to alter them too + * much) */ + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + BMEdge *e; + float avg[3]; + float weight = smd->branch_smoothing; + int totv = 1; + + if (BM_elem_flag_test(v, BM_ELEM_TAG)) + weight *= 0.5f; + + copy_v3_v3(avg, v->co); + BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { + BMVert *other = BM_edge_other_vert(e, v); + + add_v3_v3(avg, CustomData_bmesh_get_n(&bm->vdata, other->head.data, CD_SHAPEKEY, skey)); + totv++; + } + + if (totv > 1) { + mul_v3_fl(avg, 1.0f / (float)totv); + interp_v3_v3v3(v->co, v->co, avg, weight); + } + } + + /* Done with original coordinates */ + BM_data_layer_free_n(bm, &bm->vdata, CD_SHAPEKEY, skey); } /* Returns true if all hulls are successfully built, false otherwise */ -static bool skin_output_branch_hulls(SkinOutput *so, SkinNode *skin_nodes, - int totvert, const MeshElemMap *emap, - const MEdge *medge) +static bool skin_output_branch_hulls( + SkinOutput *so, SkinNode *skin_nodes, int totvert, const MeshElemMap *emap, const MEdge *medge) { - bool result = true; - int v; + bool result = true; + int v; - for (v = 0; v < totvert; v++) { - SkinNode *sn = &skin_nodes[v]; + for (v = 0; v < totvert; v++) { + SkinNode *sn = &skin_nodes[v]; - /* Branch node hulls */ - if (!sn->totframe) { - Frame **hull_frames; - int tothullframe; + /* Branch node hulls */ + if (!sn->totframe) { + Frame **hull_frames; + int tothullframe; - hull_frames = collect_hull_frames(v, skin_nodes, - emap, medge, - &tothullframe); - if (!build_hull(so, hull_frames, tothullframe)) - result = false; + hull_frames = collect_hull_frames(v, skin_nodes, emap, medge, &tothullframe); + if (!build_hull(so, hull_frames, tothullframe)) + result = false; - MEM_freeN(hull_frames); - } - } + MEM_freeN(hull_frames); + } + } - return result; + return result; } static BMesh *build_skin(SkinNode *skin_nodes, - int totvert, const MeshElemMap *emap, - const MEdge *medge, int totedge, + int totvert, + const MeshElemMap *emap, + const MEdge *medge, + int totedge, const MDeformVert *input_dvert, SkinModifierData *smd) { - SkinOutput so; - int v; - - so.smd = smd; - so.bm = BM_mesh_create( - &bm_mesh_allocsize_default, - &((struct BMeshCreateParams){.use_toolflags = true,})); - so.mat_nr = 0; - - /* BMESH_TODO: bumping up the stack level (see MOD_array.c) */ - BM_mesh_elem_toolflags_ensure(so.bm); - BMO_push(so.bm, NULL); - bmesh_edit_begin(so.bm, 0); - - if (input_dvert) - BM_data_layer_add(so.bm, &so.bm->vdata, CD_MDEFORMVERT); - - /* Check for mergeable frame corners around hulls before - * outputting vertices */ - skin_merge_close_frame_verts(skin_nodes, totvert, emap, medge); - - /* Write out all frame vertices to the mesh */ - for (v = 0; v < totvert; ++v) { - if (skin_nodes[v].totframe) - output_frames(so.bm, &skin_nodes[v], - input_dvert ? &input_dvert[v] : NULL); - } - - /* Update vertex pointers for merged frame corners */ - skin_update_merged_vertices(skin_nodes, totvert); - - if (!skin_output_branch_hulls(&so, skin_nodes, totvert, emap, medge)) - modifier_setError(&smd->modifier, "Hull error"); - - /* Merge triangles here in the hope of providing better target - * faces for skin_fix_hull_topology() to connect to */ - hull_merge_triangles(&so, smd); - - /* Using convex hulls may not generate a nice manifold mesh. Two - * problems can occur: an input frame's edges may be inside the - * hull, and/or an input frame's vertices may be inside the hull. - * - * General fix to produce manifold mesh: for any frame that is - * partially detached, first detach it fully, then find a suitable - * existing face to merge with. (Note that we do this after - * creating all hull faces, but before creating any other - * faces. - */ - skin_fix_hull_topology(so.bm, skin_nodes, totvert); - - skin_smooth_hulls(so.bm, skin_nodes, totvert, smd); - - skin_output_end_nodes(&so, skin_nodes, totvert); - skin_output_connections(&so, skin_nodes, medge, totedge); - hull_merge_triangles(&so, smd); - - bmesh_edit_end(so.bm, 0); - BMO_pop(so.bm); - - return so.bm; + SkinOutput so; + int v; + + so.smd = smd; + so.bm = BM_mesh_create(&bm_mesh_allocsize_default, + &((struct BMeshCreateParams){ + .use_toolflags = true, + })); + so.mat_nr = 0; + + /* BMESH_TODO: bumping up the stack level (see MOD_array.c) */ + BM_mesh_elem_toolflags_ensure(so.bm); + BMO_push(so.bm, NULL); + bmesh_edit_begin(so.bm, 0); + + if (input_dvert) + BM_data_layer_add(so.bm, &so.bm->vdata, CD_MDEFORMVERT); + + /* Check for mergeable frame corners around hulls before + * outputting vertices */ + skin_merge_close_frame_verts(skin_nodes, totvert, emap, medge); + + /* Write out all frame vertices to the mesh */ + for (v = 0; v < totvert; ++v) { + if (skin_nodes[v].totframe) + output_frames(so.bm, &skin_nodes[v], input_dvert ? &input_dvert[v] : NULL); + } + + /* Update vertex pointers for merged frame corners */ + skin_update_merged_vertices(skin_nodes, totvert); + + if (!skin_output_branch_hulls(&so, skin_nodes, totvert, emap, medge)) + modifier_setError(&smd->modifier, "Hull error"); + + /* Merge triangles here in the hope of providing better target + * faces for skin_fix_hull_topology() to connect to */ + hull_merge_triangles(&so, smd); + + /* Using convex hulls may not generate a nice manifold mesh. Two + * problems can occur: an input frame's edges may be inside the + * hull, and/or an input frame's vertices may be inside the hull. + * + * General fix to produce manifold mesh: for any frame that is + * partially detached, first detach it fully, then find a suitable + * existing face to merge with. (Note that we do this after + * creating all hull faces, but before creating any other + * faces. + */ + skin_fix_hull_topology(so.bm, skin_nodes, totvert); + + skin_smooth_hulls(so.bm, skin_nodes, totvert, smd); + + skin_output_end_nodes(&so, skin_nodes, totvert); + skin_output_connections(&so, skin_nodes, medge, totedge); + hull_merge_triangles(&so, smd); + + bmesh_edit_end(so.bm, 0); + BMO_pop(so.bm); + + return so.bm; } static void skin_set_orig_indices(Mesh *mesh) { - int *orig, totpoly; + int *orig, totpoly; - totpoly = mesh->totpoly; - orig = CustomData_add_layer(&mesh->pdata, CD_ORIGINDEX, - CD_CALLOC, NULL, totpoly); - copy_vn_i(orig, totpoly, ORIGINDEX_NONE); + totpoly = mesh->totpoly; + orig = CustomData_add_layer(&mesh->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, totpoly); + copy_vn_i(orig, totpoly, ORIGINDEX_NONE); } /* @@ -1831,129 +1765,129 @@ static void skin_set_orig_indices(Mesh *mesh) * 2) Generate node frames * 3) Output vertices and polygons from frames, connections, and hulls */ -static Mesh *base_skin(Mesh *origmesh, - SkinModifierData *smd) +static Mesh *base_skin(Mesh *origmesh, SkinModifierData *smd) { - Mesh *result; - MVertSkin *nodes; - BMesh *bm; - EMat *emat; - SkinNode *skin_nodes; - MeshElemMap *emap; - int *emapmem; - MVert *mvert; - MEdge *medge; - MDeformVert *dvert; - int totvert, totedge; - bool has_valid_root = false; + Mesh *result; + MVertSkin *nodes; + BMesh *bm; + EMat *emat; + SkinNode *skin_nodes; + MeshElemMap *emap; + int *emapmem; + MVert *mvert; + MEdge *medge; + MDeformVert *dvert; + int totvert, totedge; + bool has_valid_root = false; - nodes = CustomData_get_layer(&origmesh->vdata, CD_MVERT_SKIN); + nodes = CustomData_get_layer(&origmesh->vdata, CD_MVERT_SKIN); - mvert = origmesh->mvert; - dvert = origmesh->dvert; - medge = origmesh->medge; - totvert = origmesh->totvert; - totedge = origmesh->totedge; + mvert = origmesh->mvert; + dvert = origmesh->dvert; + medge = origmesh->medge; + totvert = origmesh->totvert; + totedge = origmesh->totedge; - BKE_mesh_vert_edge_map_create(&emap, &emapmem, medge, totvert, totedge); + BKE_mesh_vert_edge_map_create(&emap, &emapmem, medge, totvert, totedge); - emat = build_edge_mats(nodes, mvert, totvert, medge, emap, totedge, &has_valid_root); - skin_nodes = build_frames(mvert, totvert, nodes, emap, emat); - MEM_freeN(emat); - emat = NULL; + emat = build_edge_mats(nodes, mvert, totvert, medge, emap, totedge, &has_valid_root); + skin_nodes = build_frames(mvert, totvert, nodes, emap, emat); + MEM_freeN(emat); + emat = NULL; - bm = build_skin(skin_nodes, totvert, emap, medge, totedge, dvert, smd); + bm = build_skin(skin_nodes, totvert, emap, medge, totedge, dvert, smd); - MEM_freeN(skin_nodes); - MEM_freeN(emap); - MEM_freeN(emapmem); + MEM_freeN(skin_nodes); + MEM_freeN(emap); + MEM_freeN(emapmem); - if (!has_valid_root) { - modifier_setError(&smd->modifier, "No valid root vertex found (you need one per mesh island you want to skin)"); - } + if (!has_valid_root) { + modifier_setError( + &smd->modifier, + "No valid root vertex found (you need one per mesh island you want to skin)"); + } - if (!bm) - return NULL; + if (!bm) + return NULL; - result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL); - BM_mesh_free(bm); + result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL); + BM_mesh_free(bm); - result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; - skin_set_orig_indices(result); + skin_set_orig_indices(result); - return result; + return result; } static Mesh *final_skin(SkinModifierData *smd, Mesh *mesh) { - Mesh *result; + Mesh *result; - /* Skin node layer is required */ - if (!CustomData_get_layer(&mesh->vdata, CD_MVERT_SKIN)) - return mesh; + /* Skin node layer is required */ + if (!CustomData_get_layer(&mesh->vdata, CD_MVERT_SKIN)) + return mesh; - mesh = subdivide_base(mesh); - result = base_skin(mesh, smd); + mesh = subdivide_base(mesh); + result = base_skin(mesh, smd); - BKE_id_free(NULL, mesh); - return result; + BKE_id_free(NULL, mesh); + return result; } - /**************************** Skin Modifier ***************************/ static void initData(ModifierData *md) { - SkinModifierData *smd = (SkinModifierData *) md; + SkinModifierData *smd = (SkinModifierData *)md; - /* Enable in editmode by default */ - md->mode |= eModifierMode_Editmode; + /* Enable in editmode by default */ + md->mode |= eModifierMode_Editmode; - smd->branch_smoothing = 0; - smd->flag = 0; - smd->symmetry_axes = MOD_SKIN_SYMM_X; + smd->branch_smoothing = 0; + smd->flag = 0; + smd->symmetry_axes = MOD_SKIN_SYMM_X; } -static Mesh *applyModifier(ModifierData *md, - const ModifierEvalContext *UNUSED(ctx), - Mesh *mesh) +static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *UNUSED(ctx), Mesh *mesh) { - Mesh *result; + Mesh *result; - if (!(result = final_skin((SkinModifierData *)md, mesh))) - return mesh; - return result; + if (!(result = final_skin((SkinModifierData *)md, mesh))) + return mesh; + return result; } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *UNUSED(md), CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *UNUSED(md), + CustomData_MeshMasks *r_cddata_masks) { - r_cddata_masks->vmask |= CD_MASK_MVERT_SKIN | CD_MASK_MDEFORMVERT; + r_cddata_masks->vmask |= CD_MASK_MVERT_SKIN | CD_MASK_MDEFORMVERT; } ModifierTypeInfo modifierType_Skin = { - /* name */ "Skin", - /* structName */ "SkinModifierData", - /* structSize */ sizeof(SkinModifierData), - /* type */ eModifierTypeType_Constructive, - /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsEditmode, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ NULL, - /* isDisabled */ NULL, - /* updateDepsgraph */ NULL, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ NULL, - /* foreachIDLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Skin", + /* structName */ "SkinModifierData", + /* structSize */ sizeof(SkinModifierData), + /* type */ eModifierTypeType_Constructive, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsEditmode, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_smoke.c b/source/blender/modifiers/intern/MOD_smoke.c index 8a0a8e227ae..60d4c1a01c3 100644 --- a/source/blender/modifiers/intern/MOD_smoke.c +++ b/source/blender/modifiers/intern/MOD_smoke.c @@ -21,7 +21,6 @@ * \ingroup modifiers */ - #include #include "MEM_guardedalloc.h" @@ -50,136 +49,148 @@ static void initData(ModifierData *md) { - SmokeModifierData *smd = (SmokeModifierData *) md; + SmokeModifierData *smd = (SmokeModifierData *)md; - smd->domain = NULL; - smd->flow = NULL; - smd->coll = NULL; - smd->type = 0; - smd->time = -1; + smd->domain = NULL; + smd->flow = NULL; + smd->coll = NULL; + smd->type = 0; + smd->time = -1; } static void copyData(const ModifierData *md, ModifierData *target, const int flag) { - const SmokeModifierData *smd = (const SmokeModifierData *)md; - SmokeModifierData *tsmd = (SmokeModifierData *)target; + const SmokeModifierData *smd = (const SmokeModifierData *)md; + SmokeModifierData *tsmd = (SmokeModifierData *)target; - smokeModifier_free(tsmd); - smokeModifier_copy(smd, tsmd, flag); + smokeModifier_free(tsmd); + smokeModifier_copy(smd, tsmd, flag); } static void freeData(ModifierData *md) { - SmokeModifierData *smd = (SmokeModifierData *) md; + SmokeModifierData *smd = (SmokeModifierData *)md; - smokeModifier_free(smd); + smokeModifier_free(smd); } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - SmokeModifierData *smd = (SmokeModifierData *)md; - - if (smd && (smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) { - if (smd->flow->source == MOD_SMOKE_FLOW_SOURCE_MESH) { - /* vertex groups */ - if (smd->flow->vgroup_density) - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; - /* uv layer */ - if (smd->flow->texture_type == MOD_SMOKE_FLOW_TEXTURE_MAP_UV) - r_cddata_masks->fmask |= CD_MASK_MTFACE; - } - } + SmokeModifierData *smd = (SmokeModifierData *)md; + + if (smd && (smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) { + if (smd->flow->source == MOD_SMOKE_FLOW_SOURCE_MESH) { + /* vertex groups */ + if (smd->flow->vgroup_density) + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + /* uv layer */ + if (smd->flow->texture_type == MOD_SMOKE_FLOW_TEXTURE_MAP_UV) + r_cddata_masks->fmask |= CD_MASK_MTFACE; + } + } } -static Mesh *applyModifier( - ModifierData *md, const ModifierEvalContext *ctx, - Mesh *me) +static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *me) { - SmokeModifierData *smd = (SmokeModifierData *) md; + SmokeModifierData *smd = (SmokeModifierData *)md; - if (ctx->flag & MOD_APPLY_ORCO) { - return me; - } + if (ctx->flag & MOD_APPLY_ORCO) { + return me; + } - Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); - return smokeModifier_do(smd, ctx->depsgraph, scene, ctx->object, me); + Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); + return smokeModifier_do(smd, ctx->depsgraph, scene, ctx->object, me); } static bool dependsOnTime(ModifierData *UNUSED(md)) { - return true; + return true; } static bool is_flow_cb(Object *UNUSED(ob), ModifierData *md) { - SmokeModifierData *smd = (SmokeModifierData *) md; - return (smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow; + SmokeModifierData *smd = (SmokeModifierData *)md; + return (smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow; } static bool is_coll_cb(Object *UNUSED(ob), ModifierData *md) { - SmokeModifierData *smd = (SmokeModifierData *) md; - return (smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll; + SmokeModifierData *smd = (SmokeModifierData *)md; + return (smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll; } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { - SmokeModifierData *smd = (SmokeModifierData *)md; - - if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) { - DEG_add_collision_relations(ctx->node, ctx->object, smd->domain->fluid_group, eModifierType_Smoke, is_flow_cb, "Smoke Flow"); - DEG_add_collision_relations(ctx->node, ctx->object, smd->domain->coll_group, eModifierType_Smoke, is_coll_cb, "Smoke Coll"); - DEG_add_forcefield_relations(ctx->node, ctx->object, smd->domain->effector_weights, true, PFIELD_SMOKEFLOW, "Smoke Force Field"); - } + SmokeModifierData *smd = (SmokeModifierData *)md; + + if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) { + DEG_add_collision_relations(ctx->node, + ctx->object, + smd->domain->fluid_group, + eModifierType_Smoke, + is_flow_cb, + "Smoke Flow"); + DEG_add_collision_relations(ctx->node, + ctx->object, + smd->domain->coll_group, + eModifierType_Smoke, + is_coll_cb, + "Smoke Coll"); + DEG_add_forcefield_relations(ctx->node, + ctx->object, + smd->domain->effector_weights, + true, + PFIELD_SMOKEFLOW, + "Smoke Force Field"); + } } -static void foreachIDLink( - ModifierData *md, Object *ob, - IDWalkFunc walk, void *userData) +static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData) { - SmokeModifierData *smd = (SmokeModifierData *) md; + SmokeModifierData *smd = (SmokeModifierData *)md; - if (smd->type == MOD_SMOKE_TYPE_DOMAIN && smd->domain) { - walk(userData, ob, (ID **)&smd->domain->coll_group, IDWALK_CB_NOP); - walk(userData, ob, (ID **)&smd->domain->fluid_group, IDWALK_CB_NOP); - walk(userData, ob, (ID **)&smd->domain->eff_group, IDWALK_CB_NOP); + if (smd->type == MOD_SMOKE_TYPE_DOMAIN && smd->domain) { + walk(userData, ob, (ID **)&smd->domain->coll_group, IDWALK_CB_NOP); + walk(userData, ob, (ID **)&smd->domain->fluid_group, IDWALK_CB_NOP); + walk(userData, ob, (ID **)&smd->domain->eff_group, IDWALK_CB_NOP); - if (smd->domain->effector_weights) { - walk(userData, ob, (ID **)&smd->domain->effector_weights->group, IDWALK_CB_NOP); - } - } + if (smd->domain->effector_weights) { + walk(userData, ob, (ID **)&smd->domain->effector_weights->group, IDWALK_CB_NOP); + } + } - if (smd->type == MOD_SMOKE_TYPE_FLOW && smd->flow) { - walk(userData, ob, (ID **)&smd->flow->noise_texture, IDWALK_CB_USER); - } + if (smd->type == MOD_SMOKE_TYPE_FLOW && smd->flow) { + walk(userData, ob, (ID **)&smd->flow->noise_texture, IDWALK_CB_USER); + } } ModifierTypeInfo modifierType_Smoke = { - /* name */ "Smoke", - /* structName */ "SmokeModifierData", - /* structSize */ sizeof(SmokeModifierData), - /* type */ eModifierTypeType_Constructive, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_UsesPointCache | - eModifierTypeFlag_Single, - - /* copyData */ copyData, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ freeData, - /* isDisabled */ NULL, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ dependsOnTime, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ NULL, - /* foreachIDLink */ foreachIDLink, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Smoke", + /* structName */ "SmokeModifierData", + /* structSize */ sizeof(SmokeModifierData), + /* type */ eModifierTypeType_Constructive, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_UsesPointCache | + eModifierTypeFlag_Single, + + /* copyData */ copyData, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ freeData, + /* isDisabled */ NULL, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ dependsOnTime, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ foreachIDLink, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_smooth.c b/source/blender/modifiers/intern/MOD_smooth.c index 685a4837d32..08430d0e8f1 100644 --- a/source/blender/modifiers/intern/MOD_smooth.c +++ b/source/blender/modifiers/intern/MOD_smooth.c @@ -21,7 +21,6 @@ * \ingroup modifiers */ - #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" @@ -40,225 +39,230 @@ #include "MOD_modifiertypes.h" #include "MOD_util.h" - static void initData(ModifierData *md) { - SmoothModifierData *smd = (SmoothModifierData *) md; + SmoothModifierData *smd = (SmoothModifierData *)md; - smd->fac = 0.5f; - smd->repeat = 1; - smd->flag = MOD_SMOOTH_X | MOD_SMOOTH_Y | MOD_SMOOTH_Z; - smd->defgrp_name[0] = '\0'; + smd->fac = 0.5f; + smd->repeat = 1; + smd->flag = MOD_SMOOTH_X | MOD_SMOOTH_Y | MOD_SMOOTH_Z; + smd->defgrp_name[0] = '\0'; } -static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams)) +static bool isDisabled(const struct Scene *UNUSED(scene), + ModifierData *md, + bool UNUSED(useRenderParams)) { - SmoothModifierData *smd = (SmoothModifierData *) md; - short flag; + SmoothModifierData *smd = (SmoothModifierData *)md; + short flag; - flag = smd->flag & (MOD_SMOOTH_X | MOD_SMOOTH_Y | MOD_SMOOTH_Z); + flag = smd->flag & (MOD_SMOOTH_X | MOD_SMOOTH_Y | MOD_SMOOTH_Z); - /* disable if modifier is off for X, Y and Z or if factor is 0 */ - if ((smd->fac == 0.0f) || flag == 0) return 1; + /* disable if modifier is off for X, Y and Z or if factor is 0 */ + if ((smd->fac == 0.0f) || flag == 0) + return 1; - return 0; + return 0; } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - SmoothModifierData *smd = (SmoothModifierData *)md; + SmoothModifierData *smd = (SmoothModifierData *)md; - /* ask for vertexgroups if we need them */ - if (smd->defgrp_name[0] != '\0') { - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; - } + /* ask for vertexgroups if we need them */ + if (smd->defgrp_name[0] != '\0') { + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + } } static void smoothModifier_do( - SmoothModifierData *smd, Object *ob, Mesh *mesh, - float (*vertexCos)[3], int numVerts) + SmoothModifierData *smd, Object *ob, Mesh *mesh, 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_calloc_arrayN(numVerts, 3 * sizeof(float), - "smoothmodifier_f"); - if (!ftmp) return; - uctmp = (unsigned char *)MEM_calloc_arrayN(numVerts, sizeof(unsigned char), - "smoothmodifier_uc"); - if (!uctmp) { - if (ftmp) MEM_freeN(ftmp); - return; - } - - fac = smd->fac; - facm = 1 - fac; - - if (mesh != NULL) { - medges = mesh->medge; - numDMEdges = mesh->totedge; - } - else { - medges = NULL; - numDMEdges = 0; - } - - MOD_get_vgroup(ob, mesh, smd->defgrp_name, &dvert, &defgrp_index); - - /* 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]; - - mid_v3_v3v3(fvec, v1, v2); - - 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) { - MDeformVert *dv = dvert; - for (i = 0; i < numVerts; i++, dv++) { - float f, fm, facw, *fp, *v; - short flag = smd->flag; - - v = vertexCos[i]; - fp = &ftmp[i * 3]; - - - f = defvert_find_weight(dv, defgrp_index); - if (f <= 0.0f) continue; - - f *= fac; - 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); + MDeformVert *dvert = NULL; + MEdge *medges = NULL; + + int i, j, numDMEdges, defgrp_index; + unsigned char *uctmp; + float *ftmp, fac, facm; + + ftmp = (float *)MEM_calloc_arrayN(numVerts, 3 * sizeof(float), "smoothmodifier_f"); + if (!ftmp) + return; + uctmp = (unsigned char *)MEM_calloc_arrayN(numVerts, sizeof(unsigned char), "smoothmodifier_uc"); + if (!uctmp) { + if (ftmp) + MEM_freeN(ftmp); + return; + } + + fac = smd->fac; + facm = 1 - fac; + + if (mesh != NULL) { + medges = mesh->medge; + numDMEdges = mesh->totedge; + } + else { + medges = NULL; + numDMEdges = 0; + } + + MOD_get_vgroup(ob, mesh, smd->defgrp_name, &dvert, &defgrp_index); + + /* 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]; + + mid_v3_v3v3(fvec, v1, v2); + + 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) { + MDeformVert *dv = dvert; + for (i = 0; i < numVerts; i++, dv++) { + float f, fm, facw, *fp, *v; + short flag = smd->flag; + + v = vertexCos[i]; + fp = &ftmp[i * 3]; + + f = defvert_find_weight(dv, defgrp_index); + if (f <= 0.0f) + continue; + + f *= fac; + 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 void deformVerts( - ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh, - float (*vertexCos)[3], int numVerts) +static void deformVerts(ModifierData *md, + const ModifierEvalContext *ctx, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - SmoothModifierData *smd = (SmoothModifierData *)md; - Mesh *mesh_src = NULL; + SmoothModifierData *smd = (SmoothModifierData *)md; + Mesh *mesh_src = NULL; - /* mesh_src is needed for vgroups, and taking edges into account. */ - mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); + /* mesh_src is needed for vgroups, and taking edges into account. */ + mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); - smoothModifier_do(smd, ctx->object, mesh_src, vertexCos, numVerts); + smoothModifier_do(smd, ctx->object, mesh_src, vertexCos, numVerts); - if (!ELEM(mesh_src, NULL, mesh)) { - BKE_id_free(NULL, mesh_src); - } + if (!ELEM(mesh_src, NULL, mesh)) { + BKE_id_free(NULL, mesh_src); + } } -static void deformVertsEM( - ModifierData *md, const ModifierEvalContext *ctx, struct BMEditMesh *editData, - Mesh *mesh, float (*vertexCos)[3], int numVerts) +static void deformVertsEM(ModifierData *md, + const ModifierEvalContext *ctx, + struct BMEditMesh *editData, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - SmoothModifierData *smd = (SmoothModifierData *)md; - Mesh *mesh_src = NULL; + SmoothModifierData *smd = (SmoothModifierData *)md; + Mesh *mesh_src = NULL; - /* mesh_src is needed for vgroups, and taking edges into account. */ - mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false); + /* mesh_src is needed for vgroups, and taking edges into account. */ + mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false); - smoothModifier_do(smd, ctx->object, mesh_src, vertexCos, numVerts); + smoothModifier_do(smd, ctx->object, mesh_src, vertexCos, numVerts); - if (!ELEM(mesh_src, NULL, mesh)) { - BKE_id_free(NULL, mesh_src); - } + if (!ELEM(mesh_src, NULL, mesh)) { + BKE_id_free(NULL, mesh_src); + } } - ModifierTypeInfo modifierType_Smooth = { - /* name */ "Smooth", - /* structName */ "SmoothModifierData", - /* structSize */ sizeof(SmoothModifierData), - /* type */ eModifierTypeType_OnlyDeform, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_AcceptsCVs | - eModifierTypeFlag_SupportsEditmode, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ deformVerts, - /* deformMatrices */ NULL, - /* deformVertsEM */ deformVertsEM, - /* deformMatricesEM */ NULL, - /* applyModifier */ NULL, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ NULL, - /* isDisabled */ isDisabled, - /* updateDepsgraph */ NULL, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ NULL, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Smooth", + /* structName */ "SmoothModifierData", + /* structSize */ sizeof(SmoothModifierData), + /* type */ eModifierTypeType_OnlyDeform, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs | + eModifierTypeFlag_SupportsEditmode, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ deformVerts, + /* deformMatrices */ NULL, + /* deformVertsEM */ deformVertsEM, + /* deformMatricesEM */ NULL, + /* applyModifier */ NULL, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ NULL, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_softbody.c b/source/blender/modifiers/intern/MOD_softbody.c index 2ff50ee3977..48ccd9b83ed 100644 --- a/source/blender/modifiers/intern/MOD_softbody.c +++ b/source/blender/modifiers/intern/MOD_softbody.c @@ -40,57 +40,62 @@ #include "MOD_modifiertypes.h" -static void deformVerts( - ModifierData *UNUSED(md), const ModifierEvalContext *ctx, - Mesh *UNUSED(derivedData), - float (*vertexCos)[3], - int numVerts) +static void deformVerts(ModifierData *UNUSED(md), + const ModifierEvalContext *ctx, + Mesh *UNUSED(derivedData), + float (*vertexCos)[3], + int numVerts) { - Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); - sbObjectStep(ctx->depsgraph, scene, ctx->object, DEG_get_ctime(ctx->depsgraph), vertexCos, numVerts); + Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); + sbObjectStep( + ctx->depsgraph, scene, ctx->object, DEG_get_ctime(ctx->depsgraph), vertexCos, numVerts); } static bool dependsOnTime(ModifierData *UNUSED(md)) { - return true; + return true; } static void updateDepsgraph(ModifierData *UNUSED(md), const ModifierUpdateDepsgraphContext *ctx) { - if (ctx->object->soft) { - /* Actual code uses ccd_build_deflector_hash */ - DEG_add_collision_relations(ctx->node, ctx->object, ctx->object->soft->collision_group, eModifierType_Collision, NULL, "Softbody Collision"); - DEG_add_forcefield_relations(ctx->node, ctx->object, ctx->object->soft->effector_weights, true, 0, "Softbody Field"); - } + if (ctx->object->soft) { + /* Actual code uses ccd_build_deflector_hash */ + DEG_add_collision_relations(ctx->node, + ctx->object, + ctx->object->soft->collision_group, + eModifierType_Collision, + NULL, + "Softbody Collision"); + DEG_add_forcefield_relations( + ctx->node, ctx->object, ctx->object->soft->effector_weights, true, 0, "Softbody Field"); + } } ModifierTypeInfo modifierType_Softbody = { - /* name */ "Softbody", - /* structName */ "SoftbodyModifierData", - /* structSize */ sizeof(SoftbodyModifierData), - /* type */ eModifierTypeType_OnlyDeform, - /* flags */ eModifierTypeFlag_AcceptsCVs | - eModifierTypeFlag_AcceptsLattice | - eModifierTypeFlag_RequiresOriginalData | - eModifierTypeFlag_Single, + /* name */ "Softbody", + /* structName */ "SoftbodyModifierData", + /* structSize */ sizeof(SoftbodyModifierData), + /* type */ eModifierTypeType_OnlyDeform, + /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice | + eModifierTypeFlag_RequiresOriginalData | eModifierTypeFlag_Single, - /* copyData */ NULL, + /* copyData */ NULL, - /* deformVerts */ deformVerts, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ NULL, + /* deformVerts */ deformVerts, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ NULL, - /* initData */ NULL, - /* requiredDataMask */ NULL, - /* freeData */ NULL, - /* isDisabled */ NULL, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ dependsOnTime, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ NULL, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* initData */ NULL, + /* requiredDataMask */ NULL, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ dependsOnTime, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c index e8a7d8217ed..9fb2e728dd9 100644 --- a/source/blender/modifiers/intern/MOD_solidify.c +++ b/source/blender/modifiers/intern/MOD_solidify.c @@ -50,13 +50,13 @@ /* could be exposed for other functions to use */ typedef struct EdgeFaceRef { - int p1; /* init as -1 */ - int p2; + int p1; /* init as -1 */ + int p2; } EdgeFaceRef; BLI_INLINE bool edgeref_is_init(const EdgeFaceRef *edge_ref) { - return !((edge_ref->p1 == 0) && (edge_ref->p2 == 0)); + return !((edge_ref->p1 == 0) && (edge_ref->p2 == 0)); } /** @@ -66,912 +66,934 @@ BLI_INLINE bool edgeref_is_init(const EdgeFaceRef *edge_ref) */ static void mesh_calc_hq_normal(Mesh *mesh, float (*poly_nors)[3], float (*r_vert_nors)[3]) { - int i, numVerts, numEdges, numPolys; - MPoly *mpoly, *mp; - MLoop *mloop, *ml; - MEdge *medge, *ed; - MVert *mvert, *mv; - - numVerts = mesh->totvert; - numEdges = mesh->totedge; - numPolys = mesh->totpoly; - mpoly = mesh->mpoly; - medge = mesh->medge; - mvert = mesh->mvert; - mloop = mesh->mloop; - - /* we don't want to overwrite any referenced layers */ - - /* Doesn't work here! */ + int i, numVerts, numEdges, numPolys; + MPoly *mpoly, *mp; + MLoop *mloop, *ml; + MEdge *medge, *ed; + MVert *mvert, *mv; + + numVerts = mesh->totvert; + numEdges = mesh->totedge; + numPolys = mesh->totpoly; + mpoly = mesh->mpoly; + medge = mesh->medge; + mvert = mesh->mvert; + mloop = mesh->mloop; + + /* we don't want to overwrite any referenced layers */ + + /* Doesn't work here! */ #if 0 - mv = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, numVerts); - cddm->mvert = mv; + mv = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, numVerts); + cddm->mvert = mv; #endif - mv = mvert; - mp = mpoly; - - { - EdgeFaceRef *edge_ref_array = MEM_calloc_arrayN((size_t)numEdges, sizeof(EdgeFaceRef), "Edge Connectivity"); - EdgeFaceRef *edge_ref; - float edge_normal[3]; - - /* Add an edge reference if it's not there, pointing back to the face index. */ - for (i = 0; i < numPolys; i++, mp++) { - int j; - - ml = mloop + mp->loopstart; - - for (j = 0; j < mp->totloop; j++, ml++) { - /* --- add edge ref to face --- */ - edge_ref = &edge_ref_array[ml->e]; - if (!edgeref_is_init(edge_ref)) { - edge_ref->p1 = i; - edge_ref->p2 = -1; - } - else if ((edge_ref->p1 != -1) && (edge_ref->p2 == -1)) { - edge_ref->p2 = i; - } - else { - /* 3+ faces using an edge, we can't handle this usefully */ - edge_ref->p1 = edge_ref->p2 = -1; + mv = mvert; + mp = mpoly; + + { + EdgeFaceRef *edge_ref_array = MEM_calloc_arrayN( + (size_t)numEdges, sizeof(EdgeFaceRef), "Edge Connectivity"); + EdgeFaceRef *edge_ref; + float edge_normal[3]; + + /* Add an edge reference if it's not there, pointing back to the face index. */ + for (i = 0; i < numPolys; i++, mp++) { + int j; + + ml = mloop + mp->loopstart; + + for (j = 0; j < mp->totloop; j++, ml++) { + /* --- add edge ref to face --- */ + edge_ref = &edge_ref_array[ml->e]; + if (!edgeref_is_init(edge_ref)) { + edge_ref->p1 = i; + edge_ref->p2 = -1; + } + else if ((edge_ref->p1 != -1) && (edge_ref->p2 == -1)) { + edge_ref->p2 = i; + } + else { + /* 3+ faces using an edge, we can't handle this usefully */ + edge_ref->p1 = edge_ref->p2 = -1; #ifdef USE_NONMANIFOLD_WORKAROUND - medge[ml->e].flag |= ME_EDGE_TMP_TAG; + medge[ml->e].flag |= ME_EDGE_TMP_TAG; #endif - } - /* --- done --- */ - } - } - - for (i = 0, ed = medge, edge_ref = edge_ref_array; i < numEdges; i++, ed++, edge_ref++) { - /* Get the edge vert indices, and edge value (the face indices that use it) */ - - if (edgeref_is_init(edge_ref) && (edge_ref->p1 != -1)) { - if (edge_ref->p2 != -1) { - /* We have 2 faces using this edge, calculate the edges normal - * using the angle between the 2 faces as a weighting */ + } + /* --- done --- */ + } + } + + for (i = 0, ed = medge, edge_ref = edge_ref_array; i < numEdges; i++, ed++, edge_ref++) { + /* Get the edge vert indices, and edge value (the face indices that use it) */ + + if (edgeref_is_init(edge_ref) && (edge_ref->p1 != -1)) { + if (edge_ref->p2 != -1) { + /* We have 2 faces using this edge, calculate the edges normal + * using the angle between the 2 faces as a weighting */ #if 0 - add_v3_v3v3(edge_normal, face_nors[edge_ref->f1], face_nors[edge_ref->f2]); - normalize_v3_length( - edge_normal, - angle_normalized_v3v3(face_nors[edge_ref->f1], face_nors[edge_ref->f2])); + add_v3_v3v3(edge_normal, face_nors[edge_ref->f1], face_nors[edge_ref->f2]); + normalize_v3_length( + edge_normal, + angle_normalized_v3v3(face_nors[edge_ref->f1], face_nors[edge_ref->f2])); #else - mid_v3_v3v3_angle_weighted(edge_normal, poly_nors[edge_ref->p1], poly_nors[edge_ref->p2]); + mid_v3_v3v3_angle_weighted( + edge_normal, poly_nors[edge_ref->p1], poly_nors[edge_ref->p2]); #endif - } - else { - /* only one face attached to that edge */ - /* an edge without another attached- the weight on this is undefined */ - copy_v3_v3(edge_normal, poly_nors[edge_ref->p1]); - } - add_v3_v3(r_vert_nors[ed->v1], edge_normal); - add_v3_v3(r_vert_nors[ed->v2], edge_normal); - } - } - MEM_freeN(edge_ref_array); - } - - /* normalize vertex normals and assign */ - for (i = 0; i < numVerts; i++, mv++) { - if (normalize_v3(r_vert_nors[i]) == 0.0f) { - normal_short_to_float_v3(r_vert_nors[i], mv->no); - } - } + } + else { + /* only one face attached to that edge */ + /* an edge without another attached- the weight on this is undefined */ + copy_v3_v3(edge_normal, poly_nors[edge_ref->p1]); + } + add_v3_v3(r_vert_nors[ed->v1], edge_normal); + add_v3_v3(r_vert_nors[ed->v2], edge_normal); + } + } + MEM_freeN(edge_ref_array); + } + + /* normalize vertex normals and assign */ + for (i = 0; i < numVerts; i++, mv++) { + if (normalize_v3(r_vert_nors[i]) == 0.0f) { + normal_short_to_float_v3(r_vert_nors[i], mv->no); + } + } } static void initData(ModifierData *md) { - SolidifyModifierData *smd = (SolidifyModifierData *) md; - smd->offset = 0.01f; - smd->offset_fac = -1.0f; - smd->flag = MOD_SOLIDIFY_RIM; + SolidifyModifierData *smd = (SolidifyModifierData *)md; + smd->offset = 0.01f; + smd->offset_fac = -1.0f; + smd->flag = MOD_SOLIDIFY_RIM; } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - SolidifyModifierData *smd = (SolidifyModifierData *) md; + SolidifyModifierData *smd = (SolidifyModifierData *)md; - /* ask for vertexgroups if we need them */ - if (smd->defgrp_name[0] != '\0') { - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; - } + /* ask for vertexgroups if we need them */ + if (smd->defgrp_name[0] != '\0') { + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + } } /* specific function for solidify - define locally */ BLI_INLINE void madd_v3v3short_fl(float r[3], const short a[3], const float f) { - r[0] += (float)a[0] * f; - r[1] += (float)a[1] * f; - r[2] += (float)a[2] * f; + r[0] += (float)a[0] * f; + r[1] += (float)a[1] * f; + r[2] += (float)a[2] * f; } -static Mesh *applyModifier( - ModifierData *md, const ModifierEvalContext *ctx, - Mesh *mesh) +static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) { - Mesh *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)mesh->totvert; - const unsigned int numEdges = (unsigned int)mesh->totedge; - const unsigned int numPolys = (unsigned int)mesh->totpoly; - const unsigned int numLoops = (unsigned int)mesh->totloop; - unsigned int newLoops = 0, newPolys = 0, newEdges = 0, newVerts = 0, rimVerts = 0; - - /* only use material offsets if we have 2 or more materials */ - const short mat_nr_max = ctx->object->totcol > 1 ? ctx->object->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_calloc_arrayN(numVerts, sizeof(*old_vert_arr), "old_vert_arr in solidify"); - - unsigned int *edge_users = NULL; - char *edge_order = NULL; - - float (*vert_nors)[3] = NULL; - float (*poly_nors)[3] = NULL; - - const bool need_poly_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; - - MOD_get_vgroup(ctx->object, mesh, smd->defgrp_name, &dvert, &defgrp_index); - - orig_mvert = mesh->mvert; - orig_medge = mesh->medge; - orig_mloop = mesh->mloop; - orig_mpoly = mesh->mpoly; - - if (need_poly_normals) { - /* calculate only face normals */ - poly_nors = MEM_malloc_arrayN(numPolys, sizeof(*poly_nors), __func__); - BKE_mesh_calc_normals_poly( - orig_mvert, NULL, (int)numVerts, - orig_mloop, orig_mpoly, - (int)numLoops, (int)numPolys, - poly_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; + Mesh *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)mesh->totvert; + const unsigned int numEdges = (unsigned int)mesh->totedge; + const unsigned int numPolys = (unsigned int)mesh->totpoly; + const unsigned int numLoops = (unsigned int)mesh->totloop; + unsigned int newLoops = 0, newPolys = 0, newEdges = 0, newVerts = 0, rimVerts = 0; + + /* only use material offsets if we have 2 or more materials */ + const short mat_nr_max = ctx->object->totcol > 1 ? ctx->object->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_calloc_arrayN( + numVerts, sizeof(*old_vert_arr), "old_vert_arr in solidify"); + + unsigned int *edge_users = NULL; + char *edge_order = NULL; + + float(*vert_nors)[3] = NULL; + float(*poly_nors)[3] = NULL; + + const bool need_poly_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; + + MOD_get_vgroup(ctx->object, mesh, smd->defgrp_name, &dvert, &defgrp_index); + + orig_mvert = mesh->mvert; + orig_medge = mesh->medge; + orig_mloop = mesh->mloop; + orig_mpoly = mesh->mpoly; + + if (need_poly_normals) { + /* calculate only face normals */ + poly_nors = MEM_malloc_arrayN(numPolys, sizeof(*poly_nors), __func__); + BKE_mesh_calc_normals_poly(orig_mvert, + NULL, + (int)numVerts, + orig_mloop, + orig_mpoly, + (int)numLoops, + (int)numPolys, + poly_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_malloc_arrayN(numVerts, 2 * sizeof(*new_vert_arr), __func__); - new_edge_arr = MEM_malloc_arrayN(((numEdges * 2) + numVerts), sizeof(*new_edge_arr), __func__); + new_vert_arr = MEM_malloc_arrayN(numVerts, 2 * sizeof(*new_vert_arr), __func__); + new_edge_arr = MEM_malloc_arrayN(((numEdges * 2) + numVerts), sizeof(*new_edge_arr), __func__); - edge_users = MEM_malloc_arrayN(numEdges, sizeof(*edge_users), "solid_mod edges"); - edge_order = MEM_malloc_arrayN(numEdges, sizeof(*edge_order), "solid_mod eorder"); + edge_users = MEM_malloc_arrayN(numEdges, sizeof(*edge_users), "solid_mod edges"); + edge_order = MEM_malloc_arrayN(numEdges, sizeof(*edge_order), "solid_mod eorder"); - - /* save doing 2 loops here... */ + /* save doing 2 loops here... */ #if 0 - copy_vn_i(edge_users, numEdges, INVALID_UNUSED); + 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 < numPolys; 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 + numPolys); - 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); - newPolys++; - 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 = newPolys; - } - 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_calloc_arrayN(numVerts, 3 * sizeof(float), "mod_solid_vno_hq"); - mesh_calc_hq_normal(mesh, poly_nors, vert_nors); - } - - result = BKE_mesh_new_nomain_from_template( - mesh, - (int)((numVerts * stride) + newVerts), - (int)((numEdges * stride) + newEdges + rimVerts), 0, - (int)((numLoops * stride) + newLoops), - (int)((numPolys * stride) + newPolys)); - - mpoly = result->mpoly; - mloop = result->mloop; - medge = result->medge; - mvert = result->mvert; - - if (do_shell) { - CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, (int)numVerts); - CustomData_copy_data(&mesh->vdata, &result->vdata, 0, (int)numVerts, (int)numVerts); - - CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, (int)numEdges); - CustomData_copy_data(&mesh->edata, &result->edata, 0, (int)numEdges, (int)numEdges); - - CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, (int)numLoops); - /* DO NOT copy here the 'copied' part of loop data, we want to reverse loops - * (so that winding of copied face get reversed, so that normals get reversed - * and point in expected direction...). - * If we also copy data here, then this data get overwritten (and allocated memory becomes memleak). */ - - CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, (int)numPolys); - CustomData_copy_data(&mesh->pdata, &result->pdata, 0, (int)numPolys, (int)numPolys); - } - else { - int i, j; - CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, (int)numVerts); - for (i = 0, j = (int)numVerts; i < numVerts; i++) { - if (old_vert_arr[i] != INVALID_UNUSED) { - CustomData_copy_data(&mesh->vdata, &result->vdata, i, j, 1); - j++; - } - } - - CustomData_copy_data(&mesh->edata, &result->edata, 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; - CustomData_copy_data(&mesh->edata, &result->edata, 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 */ - CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, (int)numLoops); - CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, (int)numPolys); - } + for (eidx = 0, ed = orig_medge; eidx < numEdges; eidx++, ed++) { + edge_users[eidx] = INVALID_UNUSED; + } + + for (i = 0, mp = orig_mpoly; i < numPolys; 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 + numPolys); + 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); + newPolys++; + 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 = newPolys; + } + 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_calloc_arrayN(numVerts, 3 * sizeof(float), "mod_solid_vno_hq"); + mesh_calc_hq_normal(mesh, poly_nors, vert_nors); + } + + result = BKE_mesh_new_nomain_from_template(mesh, + (int)((numVerts * stride) + newVerts), + (int)((numEdges * stride) + newEdges + rimVerts), + 0, + (int)((numLoops * stride) + newLoops), + (int)((numPolys * stride) + newPolys)); + + mpoly = result->mpoly; + mloop = result->mloop; + medge = result->medge; + mvert = result->mvert; + + if (do_shell) { + CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, (int)numVerts); + CustomData_copy_data(&mesh->vdata, &result->vdata, 0, (int)numVerts, (int)numVerts); + + CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, (int)numEdges); + CustomData_copy_data(&mesh->edata, &result->edata, 0, (int)numEdges, (int)numEdges); + + CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, (int)numLoops); + /* DO NOT copy here the 'copied' part of loop data, we want to reverse loops + * (so that winding of copied face get reversed, so that normals get reversed + * and point in expected direction...). + * If we also copy data here, then this data get overwritten (and allocated memory becomes memleak). */ + + CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, (int)numPolys); + CustomData_copy_data(&mesh->pdata, &result->pdata, 0, (int)numPolys, (int)numPolys); + } + else { + int i, j; + CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, (int)numVerts); + for (i = 0, j = (int)numVerts; i < numVerts; i++) { + if (old_vert_arr[i] != INVALID_UNUSED) { + CustomData_copy_data(&mesh->vdata, &result->vdata, i, j, 1); + j++; + } + } + + CustomData_copy_data(&mesh->edata, &result->edata, 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; + CustomData_copy_data(&mesh->edata, &result->edata, 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 */ + CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, (int)numLoops); + CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, (int)numPolys); + } #undef INVALID_UNUSED #undef INVALID_PAIR - - /* initializes: (i_end, do_shell_align, mv) */ + /* 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 + numPolys; - for (i = 0; i < mesh->totpoly; i++, mp++) { - const int loop_end = mp->totloop - 1; - 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 + mesh->totloop; + 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 + numPolys; + for (i = 0; i < mesh->totpoly; i++, mp++) { + const int loop_end = mp->totloop - 1; + 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 + mesh->totloop; #if 0 - for (j = 0; j < mp->totloop; j++) { - CustomData_copy_data(&mesh->ldata, &result->ldata, mp->loopstart + j, - mp->loopstart + (loop_end - j) + mesh->totloop, 1); - } + for (j = 0; j < mp->totloop; j++) { + CustomData_copy_data(&mesh->ldata, &result->ldata, mp->loopstart + j, + mp->loopstart + (loop_end - j) + mesh->totloop, 1); + } #else - /* slightly more involved, keep the first vertex the same for the copy, - * ensures the diagonals in the new face match the original. */ - j = 0; - for (int j_prev = loop_end; j < mp->totloop; j_prev = j++) { - CustomData_copy_data(&mesh->ldata, &result->ldata, mp->loopstart + j, - mp->loopstart + (loop_end - j_prev) + mesh->totloop, 1); - } + /* slightly more involved, keep the first vertex the same for the copy, + * ensures the diagonals in the new face match the original. */ + j = 0; + for (int j_prev = loop_end; j < mp->totloop; j_prev = j++) { + CustomData_copy_data(&mesh->ldata, + &result->ldata, + mp->loopstart + j, + mp->loopstart + (loop_end - j_prev) + mesh->totloop, + 1); + } #endif - if (mat_ofs) { - mp->mat_nr += mat_ofs; - CLAMP(mp->mat_nr, 0, mat_nr_max); - } - - e = ml2[0].e; - for (j = 0; j < loop_end; j++) { - ml2[j].e = ml2[j + 1].e; - } - ml2[loop_end].e = e; - - mp->loopstart += mesh->totloop; - - 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_malloc_arrayN(numVerts, sizeof(float), "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 { + if (mat_ofs) { + mp->mat_nr += mat_ofs; + CLAMP(mp->mat_nr, 0, mat_nr_max); + } + + e = ml2[0].e; + for (j = 0; j < loop_end; j++) { + ml2[j].e = ml2[j + 1].e; + } + ml2[loop_end].e = e; + + mp->loopstart += mesh->totloop; + + 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_malloc_arrayN(numVerts, sizeof(float), "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; + 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_calloc_arrayN(numVerts, 2 * sizeof(float), "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_malloc_arrayN(numVerts, 3 * sizeof(float), "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 < numPolys; 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; + /* same as EM_solidify() in editmesh_lib.c */ + float *vert_angles = MEM_calloc_arrayN( + numVerts, 2 * sizeof(float), "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_malloc_arrayN(numVerts, 3 * sizeof(float), "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 < numPolys; 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], poly_nors[i]) * angle; - } - else { - vert_angles[vidx] += angle; - } + /* 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], poly_nors[i]) * + angle; + } + else { + vert_angles[vidx] += angle; + } #else - vert_angles[vidx] += shell_v3v3_normalized_to_dist(vert_nors[vidx], poly_nors[i]) * angle; + vert_angles[vidx] += shell_v3v3_normalized_to_dist(vert_nors[vidx], poly_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_malloc_arrayN(numVerts, sizeof(float), "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 ((mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) || (smd->flag & MOD_SOLIDIFY_RIM) || dvert) { - result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; - } - 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 - */ + /* --- 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_malloc_arrayN(numVerts, sizeof(float), "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 ((mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) || (smd->flag & MOD_SOLIDIFY_RIM) || dvert) { + result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + } + 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 - /* Note that, due to the code setting cd_dirty_vert a few lines above, - * do_side_normals is always false. - Sybren */ - const bool do_side_normals = !(result->runtime.cd_dirty_vert & CD_MASK_NORMAL); - /* annoying to allocate these since we only need the edge verts, */ - float (*edge_vert_nos)[3] = do_side_normals ? MEM_calloc_arrayN(numVerts, 3 * sizeof(float), __func__) : NULL; - float nor[3]; + /* Note that, due to the code setting cd_dirty_vert a few lines above, + * do_side_normals is always false. - Sybren */ + const bool do_side_normals = !(result->runtime.cd_dirty_vert & CD_MASK_NORMAL); + /* annoying to allocate these since we only need the edge verts, */ + float(*edge_vert_nos)[3] = do_side_normals ? + MEM_calloc_arrayN(numVerts, 3 * sizeof(float), __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 = CustomData_get_layer(&result->edata, CD_ORIGINDEX); - orig_ed = (origindex_edge) ? &origindex_edge[(numEdges * stride) + newEdges] : NULL; - ed = &medge[(numEdges * stride) + newEdges]; /* start after copied edges */ - for (i = 0; i < rimVerts; i++, ed++) { - ed->v1 = new_vert_arr[i]; - ed->v2 = (do_shell ? new_vert_arr[i] : i) + numVerts; - ed->flag |= ME_EDGEDRAW | ME_EDGERENDER; - - if (orig_ed) { - *orig_ed = ORIGINDEX_NONE; - orig_ed++; - } - - if (crease_rim) { - ed->crease = crease_rim; - } - } - - /* faces */ - mp = mpoly + (numPolys * stride); - ml = mloop + (numLoops * stride); - j = 0; - for (i = 0; i < newPolys; i++, mp++) { - unsigned int eidx = new_edge_arr[i]; - unsigned int pidx = edge_users[eidx]; - int k1, k2; - bool flip; - - if (pidx >= numPolys) { - pidx -= numPolys; - flip = true; - } - else { - flip = false; - } - - ed = medge + eidx; - - /* copy most of the face settings */ - CustomData_copy_data(&mesh->pdata, &result->pdata, (int)pidx, (int)((numPolys * stride) + i), 1); - mp->loopstart = (int)(j + (numLoops * stride)); - mp->flag = mpoly[pidx].flag; - - /* notice we use 'mp->totloop' which is later overwritten, - * we could lookup the original face but there's no point since this is a copy - * and will have the same value, just take care when changing order of assignment */ - k1 = mpoly[pidx].loopstart + (((edge_order[eidx] - 1) + mp->totloop) % mp->totloop); /* prev loop */ - k2 = mpoly[pidx].loopstart + (edge_order[eidx]); - - mp->totloop = 4; - - CustomData_copy_data(&mesh->ldata, &result->ldata, k2, (int)((numLoops * stride) + j + 0), 1); - CustomData_copy_data(&mesh->ldata, &result->ldata, k1, (int)((numLoops * stride) + j + 1), 1); - CustomData_copy_data(&mesh->ldata, &result->ldata, k1, (int)((numLoops * stride) + j + 2), 1); - CustomData_copy_data(&mesh->ldata, &result->ldata, 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; - } - - if (origindex_edge) { - 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; - } + 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 = CustomData_get_layer(&result->edata, CD_ORIGINDEX); + orig_ed = (origindex_edge) ? &origindex_edge[(numEdges * stride) + newEdges] : NULL; + ed = &medge[(numEdges * stride) + newEdges]; /* start after copied edges */ + for (i = 0; i < rimVerts; i++, ed++) { + ed->v1 = new_vert_arr[i]; + ed->v2 = (do_shell ? new_vert_arr[i] : i) + numVerts; + ed->flag |= ME_EDGEDRAW | ME_EDGERENDER; + + if (orig_ed) { + *orig_ed = ORIGINDEX_NONE; + orig_ed++; + } + + if (crease_rim) { + ed->crease = crease_rim; + } + } + + /* faces */ + mp = mpoly + (numPolys * stride); + ml = mloop + (numLoops * stride); + j = 0; + for (i = 0; i < newPolys; i++, mp++) { + unsigned int eidx = new_edge_arr[i]; + unsigned int pidx = edge_users[eidx]; + int k1, k2; + bool flip; + + if (pidx >= numPolys) { + pidx -= numPolys; + flip = true; + } + else { + flip = false; + } + + ed = medge + eidx; + + /* copy most of the face settings */ + CustomData_copy_data( + &mesh->pdata, &result->pdata, (int)pidx, (int)((numPolys * stride) + i), 1); + mp->loopstart = (int)(j + (numLoops * stride)); + mp->flag = mpoly[pidx].flag; + + /* notice we use 'mp->totloop' which is later overwritten, + * we could lookup the original face but there's no point since this is a copy + * and will have the same value, just take care when changing order of assignment */ + k1 = mpoly[pidx].loopstart + + (((edge_order[eidx] - 1) + mp->totloop) % mp->totloop); /* prev loop */ + k2 = mpoly[pidx].loopstart + (edge_order[eidx]); + + mp->totloop = 4; + + CustomData_copy_data( + &mesh->ldata, &result->ldata, k2, (int)((numLoops * stride) + j + 0), 1); + CustomData_copy_data( + &mesh->ldata, &result->ldata, k1, (int)((numLoops * stride) + j + 1), 1); + CustomData_copy_data( + &mesh->ldata, &result->ldata, k1, (int)((numLoops * stride) + j + 2), 1); + CustomData_copy_data( + &mesh->ldata, &result->ldata, 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; + } + + if (origindex_edge) { + 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); - } + 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) { - const MEdge *ed_orig = medge; - ed = medge + (numEdges * stride); - for (i = 0; i < rimVerts; i++, ed++, ed_orig++) { - float nor_cpy[3]; - short *nor_short; - int k; - - /* note, only the first vertex (lower half of the index) is calculated */ - BLI_assert(ed->v1 < numVerts); - normalize_v3_v3(nor_cpy, edge_vert_nos[ed_orig->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); - } + if (do_side_normals) { + const MEdge *ed_orig = medge; + ed = medge + (numEdges * stride); + for (i = 0; i < rimVerts; i++, ed++, ed_orig++) { + float nor_cpy[3]; + short *nor_short; + int k; + + /* note, only the first vertex (lower half of the index) is calculated */ + BLI_assert(ed->v1 < numVerts); + normalize_v3_v3(nor_cpy, edge_vert_nos[ed_orig->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(new_vert_arr); + MEM_freeN(new_edge_arr); - MEM_freeN(edge_users); - MEM_freeN(edge_order); - } + MEM_freeN(edge_users); + MEM_freeN(edge_order); + } - if (old_vert_arr) - MEM_freeN(old_vert_arr); + if (old_vert_arr) + MEM_freeN(old_vert_arr); - if (poly_nors) - MEM_freeN(poly_nors); + if (poly_nors) + MEM_freeN(poly_nors); - if (numPolys == 0 && numEdges != 0) { - modifier_setError(md, "Faces needed for useful output"); - } + if (numPolys == 0 && numEdges != 0) { + modifier_setError(md, "Faces needed for useful output"); + } - return result; + return result; } #undef SOLIDIFY_SIDE_NORMALS static bool dependsOnNormals(ModifierData *UNUSED(md)) { - /* even when we calculate our own normals, - * the vertex normals are used as a fallback */ - return true; + /* even when we calculate our own normals, + * the vertex normals are used as a fallback */ + return true; } ModifierTypeInfo modifierType_Solidify = { - /* name */ "Solidify", - /* structName */ "SolidifyModifierData", - /* structSize */ sizeof(SolidifyModifierData), - /* type */ eModifierTypeType_Constructive, - - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_AcceptsCVs | - eModifierTypeFlag_SupportsMapping | - eModifierTypeFlag_SupportsEditmode | - eModifierTypeFlag_EnableInEditmode, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ NULL, - /* isDisabled */ NULL, - /* updateDepsgraph */ NULL, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ dependsOnNormals, - /* foreachObjectLink */ NULL, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Solidify", + /* structName */ "SolidifyModifierData", + /* structSize */ sizeof(SolidifyModifierData), + /* type */ eModifierTypeType_Constructive, + + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs | + eModifierTypeFlag_SupportsMapping | eModifierTypeFlag_SupportsEditmode | + eModifierTypeFlag_EnableInEditmode, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ dependsOnNormals, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c index 74bf6b7e976..c03b1761251 100644 --- a/source/blender/modifiers/intern/MOD_subsurf.c +++ b/source/blender/modifiers/intern/MOD_subsurf.c @@ -21,7 +21,6 @@ * \ingroup modifiers */ - #include #include "MEM_guardedalloc.h" @@ -47,90 +46,86 @@ #include "intern/CCGSubSurf.h" typedef struct SubsurfRuntimeData { - /* Cached subdivision surface descriptor, with topology and settings. */ - struct Subdiv *subdiv; + /* Cached subdivision surface descriptor, with topology and settings. */ + struct Subdiv *subdiv; } SubsurfRuntimeData; static void initData(ModifierData *md) { - SubsurfModifierData *smd = (SubsurfModifierData *) md; + SubsurfModifierData *smd = (SubsurfModifierData *)md; - smd->levels = 1; - smd->renderLevels = 2; - smd->uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS; - smd->quality = 3; - smd->flags |= eSubsurfModifierFlag_UseCrease; + smd->levels = 1; + smd->renderLevels = 2; + smd->uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS; + smd->quality = 3; + smd->flags |= eSubsurfModifierFlag_UseCrease; } static void copyData(const ModifierData *md, ModifierData *target, const int flag) { #if 0 - const SubsurfModifierData *smd = (const SubsurfModifierData *) md; + const SubsurfModifierData *smd = (const SubsurfModifierData *) md; #endif - SubsurfModifierData *tsmd = (SubsurfModifierData *) target; + SubsurfModifierData *tsmd = (SubsurfModifierData *)target; - modifier_copyData_generic(md, target, flag); + modifier_copyData_generic(md, target, flag); - tsmd->emCache = tsmd->mCache = NULL; + tsmd->emCache = tsmd->mCache = NULL; } static void freeRuntimeData(void *runtime_data_v) { - if (runtime_data_v == NULL) { - return; - } - SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)runtime_data_v; - if (runtime_data->subdiv != NULL) { - BKE_subdiv_free(runtime_data->subdiv); - } - MEM_freeN(runtime_data); + if (runtime_data_v == NULL) { + return; + } + SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)runtime_data_v; + if (runtime_data->subdiv != NULL) { + BKE_subdiv_free(runtime_data->subdiv); + } + MEM_freeN(runtime_data); } static void freeData(ModifierData *md) { - SubsurfModifierData *smd = (SubsurfModifierData *) md; - - if (smd->mCache) { - ccgSubSurf_free(smd->mCache); - smd->mCache = NULL; - } - if (smd->emCache) { - ccgSubSurf_free(smd->emCache); - smd->emCache = NULL; - } - freeRuntimeData(smd->modifier.runtime); + SubsurfModifierData *smd = (SubsurfModifierData *)md; + + if (smd->mCache) { + ccgSubSurf_free(smd->mCache); + smd->mCache = NULL; + } + if (smd->emCache) { + ccgSubSurf_free(smd->emCache); + smd->emCache = NULL; + } + freeRuntimeData(smd->modifier.runtime); } static bool isDisabled(const Scene *scene, ModifierData *md, bool useRenderParams) { - SubsurfModifierData *smd = (SubsurfModifierData *) md; - int levels = (useRenderParams) ? smd->renderLevels : smd->levels; + SubsurfModifierData *smd = (SubsurfModifierData *)md; + int levels = (useRenderParams) ? smd->renderLevels : smd->levels; - return get_render_subsurf_level(&scene->r, levels, useRenderParams != 0) == 0; + return get_render_subsurf_level(&scene->r, levels, useRenderParams != 0) == 0; } static int subdiv_levels_for_modifier_get(const SubsurfModifierData *smd, const ModifierEvalContext *ctx) { - Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); - const bool use_render_params = (ctx->flag & MOD_APPLY_RENDER); - const int requested_levels = (use_render_params) ? smd->renderLevels - : smd->levels; - return get_render_subsurf_level(&scene->r, - requested_levels, - use_render_params); + Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); + const bool use_render_params = (ctx->flag & MOD_APPLY_RENDER); + const int requested_levels = (use_render_params) ? smd->renderLevels : smd->levels; + return get_render_subsurf_level(&scene->r, requested_levels, use_render_params); } -static void subdiv_settings_init(SubdivSettings *settings, - const SubsurfModifierData *smd) +static void subdiv_settings_init(SubdivSettings *settings, const SubsurfModifierData *smd) { - settings->is_simple = (smd->subdivType == SUBSURF_TYPE_SIMPLE); - settings->is_adaptive = true; - settings->level = settings->is_simple ? 1 : smd->quality; - settings->use_creases = (smd->flags & eSubsurfModifierFlag_UseCrease); - settings->vtx_boundary_interpolation = SUBDIV_VTX_BOUNDARY_EDGE_ONLY; - settings->fvar_linear_interpolation = - BKE_subdiv_fvar_interpolation_from_uv_smooth(smd->uv_smooth); + settings->is_simple = (smd->subdivType == SUBSURF_TYPE_SIMPLE); + settings->is_adaptive = true; + settings->level = settings->is_simple ? 1 : smd->quality; + settings->use_creases = (smd->flags & eSubsurfModifierFlag_UseCrease); + settings->vtx_boundary_interpolation = SUBDIV_VTX_BOUNDARY_EDGE_ONLY; + settings->fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth( + smd->uv_smooth); } /* Main goal of this function is to give usable subdivision surface descriptor @@ -139,12 +134,10 @@ static Subdiv *subdiv_descriptor_ensure(SubsurfModifierData *smd, const SubdivSettings *subdiv_settings, const Mesh *mesh) { - SubsurfRuntimeData *runtime_data = - (SubsurfRuntimeData *)smd->modifier.runtime; - Subdiv *subdiv = BKE_subdiv_update_from_mesh( - runtime_data->subdiv, subdiv_settings, mesh); - runtime_data->subdiv = subdiv; - return subdiv; + SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime; + Subdiv *subdiv = BKE_subdiv_update_from_mesh(runtime_data->subdiv, subdiv_settings, mesh); + runtime_data->subdiv = subdiv; + return subdiv; } /* Subdivide into fully qualified mesh. */ @@ -153,10 +146,9 @@ static void subdiv_mesh_settings_init(SubdivToMeshSettings *settings, const SubsurfModifierData *smd, const ModifierEvalContext *ctx) { - const int level = subdiv_levels_for_modifier_get(smd, ctx); - settings->resolution = (1 << level) + 1; - settings->use_optimal_display = - (smd->flags & eSubsurfModifierFlag_ControlEdges); + const int level = subdiv_levels_for_modifier_get(smd, ctx); + settings->resolution = (1 << level) + 1; + settings->use_optimal_display = (smd->flags & eSubsurfModifierFlag_ControlEdges); } static Mesh *subdiv_as_mesh(SubsurfModifierData *smd, @@ -164,14 +156,14 @@ static Mesh *subdiv_as_mesh(SubsurfModifierData *smd, Mesh *mesh, Subdiv *subdiv) { - Mesh *result = mesh; - SubdivToMeshSettings mesh_settings; - subdiv_mesh_settings_init(&mesh_settings, smd, ctx); - if (mesh_settings.resolution < 3) { - return result; - } - result = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh); - return result; + Mesh *result = mesh; + SubdivToMeshSettings mesh_settings; + subdiv_mesh_settings_init(&mesh_settings, smd, ctx); + if (mesh_settings.resolution < 3) { + return result; + } + result = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh); + return result; } /* Subdivide into CCG. */ @@ -180,101 +172,96 @@ static void subdiv_ccg_settings_init(SubdivToCCGSettings *settings, const SubsurfModifierData *smd, const ModifierEvalContext *ctx) { - const int level = subdiv_levels_for_modifier_get(smd, ctx); - settings->resolution = (1 << level) + 1; - settings->need_normal = true; - settings->need_mask = false; + const int level = subdiv_levels_for_modifier_get(smd, ctx); + settings->resolution = (1 << level) + 1; + settings->need_normal = true; + settings->need_mask = false; } static Mesh *subdiv_as_ccg(SubsurfModifierData *smd, - const ModifierEvalContext *ctx, - Mesh *mesh, - Subdiv *subdiv) + const ModifierEvalContext *ctx, + Mesh *mesh, + Subdiv *subdiv) { - Mesh *result = mesh; - SubdivToCCGSettings ccg_settings; - subdiv_ccg_settings_init(&ccg_settings, smd, ctx); - if (ccg_settings.resolution < 3) { - return result; - } - result = BKE_subdiv_to_ccg_mesh(subdiv, &ccg_settings, mesh); - return result; + Mesh *result = mesh; + SubdivToCCGSettings ccg_settings; + subdiv_ccg_settings_init(&ccg_settings, smd, ctx); + if (ccg_settings.resolution < 3) { + return result; + } + result = BKE_subdiv_to_ccg_mesh(subdiv, &ccg_settings, mesh); + return result; } static SubsurfRuntimeData *subsurf_ensure_runtime(SubsurfModifierData *smd) { - SubsurfRuntimeData *runtime_data = - (SubsurfRuntimeData *)smd->modifier.runtime; - if (runtime_data == NULL) { - runtime_data = MEM_callocN(sizeof(*runtime_data), "subsurf runtime"); - smd->modifier.runtime = runtime_data; - } - return runtime_data; + SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime; + if (runtime_data == NULL) { + runtime_data = MEM_callocN(sizeof(*runtime_data), "subsurf runtime"); + smd->modifier.runtime = runtime_data; + } + return runtime_data; } /* Modifier itself. */ -static Mesh *applyModifier(ModifierData *md, - const ModifierEvalContext *ctx, - Mesh *mesh) +static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) { - Mesh *result = mesh; - SubsurfModifierData *smd = (SubsurfModifierData *) md; - SubdivSettings subdiv_settings; - subdiv_settings_init(&subdiv_settings, smd); - if (subdiv_settings.level == 0) { - return result; - } - BKE_subdiv_settings_validate_for_mesh(&subdiv_settings, mesh); - SubsurfRuntimeData *runtime_data = subsurf_ensure_runtime(smd); - Subdiv *subdiv = subdiv_descriptor_ensure(smd, &subdiv_settings, mesh); - if (subdiv == NULL) { - /* Happens on bad topology, but also on empty input mesh. */ - return result; - } - /* TODO(sergey): Decide whether we ever want to use CCG for subsurf, - * maybe when it is a last modifier in the stack? */ - if (true) { - result = subdiv_as_mesh(smd, ctx, mesh, subdiv); - } - else { - result = subdiv_as_ccg(smd, ctx, mesh, subdiv); - } - // BKE_subdiv_stats_print(&subdiv->stats); - if (subdiv != runtime_data->subdiv) { - BKE_subdiv_free(subdiv); - } - return result; + Mesh *result = mesh; + SubsurfModifierData *smd = (SubsurfModifierData *)md; + SubdivSettings subdiv_settings; + subdiv_settings_init(&subdiv_settings, smd); + if (subdiv_settings.level == 0) { + return result; + } + BKE_subdiv_settings_validate_for_mesh(&subdiv_settings, mesh); + SubsurfRuntimeData *runtime_data = subsurf_ensure_runtime(smd); + Subdiv *subdiv = subdiv_descriptor_ensure(smd, &subdiv_settings, mesh); + if (subdiv == NULL) { + /* Happens on bad topology, but also on empty input mesh. */ + return result; + } + /* TODO(sergey): Decide whether we ever want to use CCG for subsurf, + * maybe when it is a last modifier in the stack? */ + if (true) { + result = subdiv_as_mesh(smd, ctx, mesh, subdiv); + } + else { + result = subdiv_as_ccg(smd, ctx, mesh, subdiv); + } + // BKE_subdiv_stats_print(&subdiv->stats); + if (subdiv != runtime_data->subdiv) { + BKE_subdiv_free(subdiv); + } + return result; } ModifierTypeInfo modifierType_Subsurf = { - /* name */ "Subdivision", - /* structName */ "SubsurfModifierData", - /* structSize */ sizeof(SubsurfModifierData), - /* type */ eModifierTypeType_Constructive, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_SupportsMapping | - eModifierTypeFlag_SupportsEditmode | - eModifierTypeFlag_EnableInEditmode | - eModifierTypeFlag_AcceptsCVs, - - /* copyData */ copyData, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ initData, - /* requiredDataMask */ NULL, - /* freeData */ freeData, - /* isDisabled */ isDisabled, - /* updateDepsgraph */ NULL, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ NULL, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ freeRuntimeData, + /* name */ "Subdivision", + /* structName */ "SubsurfModifierData", + /* structSize */ sizeof(SubsurfModifierData), + /* type */ eModifierTypeType_Constructive, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping | + eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode | + eModifierTypeFlag_AcceptsCVs, + + /* copyData */ copyData, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ initData, + /* requiredDataMask */ NULL, + /* freeData */ freeData, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ freeRuntimeData, }; diff --git a/source/blender/modifiers/intern/MOD_surface.c b/source/blender/modifiers/intern/MOD_surface.c index c0fbb4d9ac3..02678879e89 100644 --- a/source/blender/modifiers/intern/MOD_surface.c +++ b/source/blender/modifiers/intern/MOD_surface.c @@ -21,7 +21,6 @@ * \ingroup modifiers */ - #include "BLI_utildefines.h" #include "BLI_math.h" @@ -43,173 +42,167 @@ #include "MEM_guardedalloc.h" - static void initData(ModifierData *md) { - SurfaceModifierData *surmd = (SurfaceModifierData *) md; + SurfaceModifierData *surmd = (SurfaceModifierData *)md; - surmd->bvhtree = NULL; - surmd->mesh = NULL; - surmd->x = NULL; - surmd->v = NULL; + surmd->bvhtree = NULL; + surmd->mesh = NULL; + surmd->x = NULL; + surmd->v = NULL; } static void copyData(const ModifierData *md_src, ModifierData *md_dst, const int flag) { - SurfaceModifierData *surmd_dst = (SurfaceModifierData *)md_dst; + SurfaceModifierData *surmd_dst = (SurfaceModifierData *)md_dst; - modifier_copyData_generic(md_src, md_dst, flag); + modifier_copyData_generic(md_src, md_dst, flag); - surmd_dst->bvhtree = NULL; - surmd_dst->mesh = NULL; - surmd_dst->x = NULL; - surmd_dst->v = NULL; + surmd_dst->bvhtree = NULL; + surmd_dst->mesh = NULL; + surmd_dst->x = NULL; + surmd_dst->v = NULL; } static void freeData(ModifierData *md) { - SurfaceModifierData *surmd = (SurfaceModifierData *) md; + SurfaceModifierData *surmd = (SurfaceModifierData *)md; - if (surmd) { - if (surmd->bvhtree) { - free_bvhtree_from_mesh(surmd->bvhtree); - MEM_SAFE_FREE(surmd->bvhtree); - } + if (surmd) { + if (surmd->bvhtree) { + free_bvhtree_from_mesh(surmd->bvhtree); + MEM_SAFE_FREE(surmd->bvhtree); + } - if (surmd->mesh) { - BKE_id_free(NULL, surmd->mesh); - surmd->mesh = NULL; - } + if (surmd->mesh) { + BKE_id_free(NULL, surmd->mesh); + surmd->mesh = NULL; + } - MEM_SAFE_FREE(surmd->x); + MEM_SAFE_FREE(surmd->x); - MEM_SAFE_FREE(surmd->v); - } + MEM_SAFE_FREE(surmd->v); + } } static bool dependsOnTime(ModifierData *UNUSED(md)) { - return true; + return true; } -static void deformVerts( - ModifierData *md, const ModifierEvalContext *ctx, - Mesh *mesh, - float (*vertexCos)[3], - int numVerts) +static void deformVerts(ModifierData *md, + const ModifierEvalContext *ctx, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - SurfaceModifierData *surmd = (SurfaceModifierData *) md; - const int cfra = (int)DEG_get_ctime(ctx->depsgraph); - - /* Free mesh and BVH cache. */ - if (surmd->bvhtree) { - free_bvhtree_from_mesh(surmd->bvhtree); - MEM_SAFE_FREE(surmd->bvhtree); - } - - if (surmd->mesh) { - BKE_id_free(NULL, surmd->mesh); - surmd->mesh = NULL; - } - - if (mesh) { - /* Not possible to use get_mesh() in this case as we'll modify its vertices - * and get_mesh() would return 'mesh' directly. */ - BKE_id_copy_ex(NULL, (ID *)mesh, (ID **)&surmd->mesh, LIB_ID_COPY_LOCALIZE); - } - else { - surmd->mesh = MOD_deform_mesh_eval_get(ctx->object, NULL, NULL, NULL, numVerts, false, false); - } - - if (!ctx->object->pd) { - printf("SurfaceModifier deformVerts: Should not happen!\n"); - return; - } - - if (surmd->mesh) { - unsigned int numverts = 0, i = 0; - int init = 0; - float *vec; - MVert *x, *v; - - BKE_mesh_apply_vert_coords(surmd->mesh, vertexCos); - BKE_mesh_calc_normals(surmd->mesh); - - numverts = surmd->mesh->totvert; - - if (numverts != surmd->numverts || - surmd->x == NULL || - surmd->v == NULL || - cfra != surmd->cfra + 1) - { - if (surmd->x) { - MEM_freeN(surmd->x); - surmd->x = NULL; - } - if (surmd->v) { - MEM_freeN(surmd->v); - surmd->v = NULL; - } - - surmd->x = MEM_calloc_arrayN(numverts, sizeof(MVert), "MVert"); - surmd->v = MEM_calloc_arrayN(numverts, sizeof(MVert), "MVert"); - - surmd->numverts = numverts; - - init = 1; - } - - /* convert to global coordinates and calculate velocity */ - for (i = 0, x = surmd->x, v = surmd->v; i < numverts; i++, x++, v++) { - vec = surmd->mesh->mvert[i].co; - mul_m4_v3(ctx->object->obmat, vec); - - if (init) - v->co[0] = v->co[1] = v->co[2] = 0.0f; - else - sub_v3_v3v3(v->co, vec, x->co); - - copy_v3_v3(x->co, vec); - } - - surmd->cfra = cfra; - - surmd->bvhtree = MEM_callocN(sizeof(BVHTreeFromMesh), "BVHTreeFromMesh"); - - if (surmd->mesh->totpoly) - BKE_bvhtree_from_mesh_get(surmd->bvhtree, surmd->mesh, BVHTREE_FROM_LOOPTRI, 2); - else - BKE_bvhtree_from_mesh_get(surmd->bvhtree, surmd->mesh, BVHTREE_FROM_EDGES, 2); - } + SurfaceModifierData *surmd = (SurfaceModifierData *)md; + const int cfra = (int)DEG_get_ctime(ctx->depsgraph); + + /* Free mesh and BVH cache. */ + if (surmd->bvhtree) { + free_bvhtree_from_mesh(surmd->bvhtree); + MEM_SAFE_FREE(surmd->bvhtree); + } + + if (surmd->mesh) { + BKE_id_free(NULL, surmd->mesh); + surmd->mesh = NULL; + } + + if (mesh) { + /* Not possible to use get_mesh() in this case as we'll modify its vertices + * and get_mesh() would return 'mesh' directly. */ + BKE_id_copy_ex(NULL, (ID *)mesh, (ID **)&surmd->mesh, LIB_ID_COPY_LOCALIZE); + } + else { + surmd->mesh = MOD_deform_mesh_eval_get(ctx->object, NULL, NULL, NULL, numVerts, false, false); + } + + if (!ctx->object->pd) { + printf("SurfaceModifier deformVerts: Should not happen!\n"); + return; + } + + if (surmd->mesh) { + unsigned int numverts = 0, i = 0; + int init = 0; + float *vec; + MVert *x, *v; + + BKE_mesh_apply_vert_coords(surmd->mesh, vertexCos); + BKE_mesh_calc_normals(surmd->mesh); + + numverts = surmd->mesh->totvert; + + if (numverts != surmd->numverts || surmd->x == NULL || surmd->v == NULL || + cfra != surmd->cfra + 1) { + if (surmd->x) { + MEM_freeN(surmd->x); + surmd->x = NULL; + } + if (surmd->v) { + MEM_freeN(surmd->v); + surmd->v = NULL; + } + + surmd->x = MEM_calloc_arrayN(numverts, sizeof(MVert), "MVert"); + surmd->v = MEM_calloc_arrayN(numverts, sizeof(MVert), "MVert"); + + surmd->numverts = numverts; + + init = 1; + } + + /* convert to global coordinates and calculate velocity */ + for (i = 0, x = surmd->x, v = surmd->v; i < numverts; i++, x++, v++) { + vec = surmd->mesh->mvert[i].co; + mul_m4_v3(ctx->object->obmat, vec); + + if (init) + v->co[0] = v->co[1] = v->co[2] = 0.0f; + else + sub_v3_v3v3(v->co, vec, x->co); + + copy_v3_v3(x->co, vec); + } + + surmd->cfra = cfra; + + surmd->bvhtree = MEM_callocN(sizeof(BVHTreeFromMesh), "BVHTreeFromMesh"); + + if (surmd->mesh->totpoly) + BKE_bvhtree_from_mesh_get(surmd->bvhtree, surmd->mesh, BVHTREE_FROM_LOOPTRI, 2); + else + BKE_bvhtree_from_mesh_get(surmd->bvhtree, surmd->mesh, BVHTREE_FROM_EDGES, 2); + } } - ModifierTypeInfo modifierType_Surface = { - /* name */ "Surface", - /* structName */ "SurfaceModifierData", - /* structSize */ sizeof(SurfaceModifierData), - /* type */ eModifierTypeType_OnlyDeform, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_AcceptsCVs | - eModifierTypeFlag_NoUserAdd, - - /* copyData */ copyData, - - /* deformVerts */ deformVerts, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ NULL, - - /* initData */ initData, - /* requiredDataMask */ NULL, - /* freeData */ freeData, - /* isDisabled */ NULL, - /* updateDepsgraph */ NULL, - /* dependsOnTime */ dependsOnTime, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ NULL, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Surface", + /* structName */ "SurfaceModifierData", + /* structSize */ sizeof(SurfaceModifierData), + /* type */ eModifierTypeType_OnlyDeform, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs | + eModifierTypeFlag_NoUserAdd, + + /* copyData */ copyData, + + /* deformVerts */ deformVerts, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ NULL, + + /* initData */ initData, + /* requiredDataMask */ NULL, + /* freeData */ freeData, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ dependsOnTime, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c index 46f4f9c78e9..2a9fff47e5d 100644 --- a/source/blender/modifiers/intern/MOD_surfacedeform.c +++ b/source/blender/modifiers/intern/MOD_surfacedeform.c @@ -44,1221 +44,1266 @@ #include "MOD_util.h" typedef struct SDefAdjacency { - struct SDefAdjacency *next; - unsigned int index; + struct SDefAdjacency *next; + unsigned int index; } SDefAdjacency; typedef struct SDefAdjacencyArray { - SDefAdjacency *first; - unsigned int num; /* Careful, this is twice the number of polygons (avoids an extra loop) */ + SDefAdjacency *first; + unsigned int num; /* Careful, this is twice the number of polygons (avoids an extra loop) */ } SDefAdjacencyArray; typedef struct SDefEdgePolys { - unsigned int polys[2], num; + unsigned int polys[2], num; } SDefEdgePolys; typedef struct SDefBindCalcData { - BVHTreeFromMesh * const treeData; - const SDefAdjacencyArray * const vert_edges; - const SDefEdgePolys * const edge_polys; - SDefVert * const bind_verts; - const MLoopTri * const looptri; - const MPoly * const mpoly; - const MEdge * const medge; - const MLoop * const mloop; - float (* const targetCos)[3]; - float (* const vertexCos)[3]; - float imat[4][4]; - const float falloff; - int success; + BVHTreeFromMesh *const treeData; + const SDefAdjacencyArray *const vert_edges; + const SDefEdgePolys *const edge_polys; + SDefVert *const bind_verts; + const MLoopTri *const looptri; + const MPoly *const mpoly; + const MEdge *const medge; + const MLoop *const mloop; + float (*const targetCos)[3]; + float (*const vertexCos)[3]; + float imat[4][4]; + const float falloff; + int success; } SDefBindCalcData; typedef struct SDefBindPoly { - float (*coords)[3]; - float (*coords_v2)[2]; - float point_v2[2]; - float weight_angular; - float weight_dist_proj; - float weight_dist; - float weight; - float scales[2]; - float centroid[3]; - float centroid_v2[2]; - float normal[3]; - float cent_edgemid_vecs_v2[2][2]; - float edgemid_angle; - float point_edgemid_angles[2]; - float corner_edgemid_angles[2]; - float dominant_angle_weight; - unsigned int index; - unsigned int numverts; - unsigned int loopstart; - unsigned int edge_inds[2]; - unsigned int edge_vert_inds[2]; - unsigned int corner_ind; - unsigned int dominant_edge; - bool inside; + float (*coords)[3]; + float (*coords_v2)[2]; + float point_v2[2]; + float weight_angular; + float weight_dist_proj; + float weight_dist; + float weight; + float scales[2]; + float centroid[3]; + float centroid_v2[2]; + float normal[3]; + float cent_edgemid_vecs_v2[2][2]; + float edgemid_angle; + float point_edgemid_angles[2]; + float corner_edgemid_angles[2]; + float dominant_angle_weight; + unsigned int index; + unsigned int numverts; + unsigned int loopstart; + unsigned int edge_inds[2]; + unsigned int edge_vert_inds[2]; + unsigned int corner_ind; + unsigned int dominant_edge; + bool inside; } SDefBindPoly; typedef struct SDefBindWeightData { - SDefBindPoly *bind_polys; - unsigned int numpoly; - unsigned int numbinds; + SDefBindPoly *bind_polys; + unsigned int numpoly; + unsigned int numbinds; } SDefBindWeightData; typedef struct SDefDeformData { - const SDefVert * const bind_verts; - float (* const targetCos)[3]; - float (* const vertexCos)[3]; + const SDefVert *const bind_verts; + float (*const targetCos)[3]; + float (*const vertexCos)[3]; } SDefDeformData; /* Bind result values */ enum { - MOD_SDEF_BIND_RESULT_SUCCESS = 1, - MOD_SDEF_BIND_RESULT_GENERIC_ERR = 0, - MOD_SDEF_BIND_RESULT_MEM_ERR = -1, - MOD_SDEF_BIND_RESULT_NONMANY_ERR = -2, - MOD_SDEF_BIND_RESULT_CONCAVE_ERR = -3, - MOD_SDEF_BIND_RESULT_OVERLAP_ERR = -4, + MOD_SDEF_BIND_RESULT_SUCCESS = 1, + MOD_SDEF_BIND_RESULT_GENERIC_ERR = 0, + MOD_SDEF_BIND_RESULT_MEM_ERR = -1, + MOD_SDEF_BIND_RESULT_NONMANY_ERR = -2, + MOD_SDEF_BIND_RESULT_CONCAVE_ERR = -3, + MOD_SDEF_BIND_RESULT_OVERLAP_ERR = -4, }; /* Infinite weight flags */ enum { - MOD_SDEF_INFINITE_WEIGHT_ANGULAR = (1 << 0), - MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ = (1 << 1), - MOD_SDEF_INFINITE_WEIGHT_DIST = (1 << 2), + MOD_SDEF_INFINITE_WEIGHT_ANGULAR = (1 << 0), + MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ = (1 << 1), + MOD_SDEF_INFINITE_WEIGHT_DIST = (1 << 2), }; static void initData(ModifierData *md) { - SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md; - smd->target = NULL; - smd->verts = NULL; - smd->flags = 0; - smd->falloff = 4.0f; + SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md; + smd->target = NULL; + smd->verts = NULL; + smd->flags = 0; + smd->falloff = 4.0f; } static void freeData(ModifierData *md) { - SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md; - - if (smd->verts) { - for (int i = 0; i < smd->numverts; i++) { - if (smd->verts[i].binds) { - for (int j = 0; j < smd->verts[i].numbinds; j++) { - MEM_SAFE_FREE(smd->verts[i].binds[j].vert_inds); - MEM_SAFE_FREE(smd->verts[i].binds[j].vert_weights); - } - - MEM_SAFE_FREE(smd->verts[i].binds); - } - } - - MEM_SAFE_FREE(smd->verts); - } + SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md; + + if (smd->verts) { + for (int i = 0; i < smd->numverts; i++) { + if (smd->verts[i].binds) { + for (int j = 0; j < smd->verts[i].numbinds; j++) { + MEM_SAFE_FREE(smd->verts[i].binds[j].vert_inds); + MEM_SAFE_FREE(smd->verts[i].binds[j].vert_weights); + } + + MEM_SAFE_FREE(smd->verts[i].binds); + } + } + + MEM_SAFE_FREE(smd->verts); + } } static void copyData(const ModifierData *md, ModifierData *target, const int flag) { - const SurfaceDeformModifierData *smd = (const SurfaceDeformModifierData *)md; - SurfaceDeformModifierData *tsmd = (SurfaceDeformModifierData *)target; - - modifier_copyData_generic(md, target, flag); - - if (smd->verts) { - tsmd->verts = MEM_dupallocN(smd->verts); - - for (int i = 0; i < smd->numverts; i++) { - if (smd->verts[i].binds) { - tsmd->verts[i].binds = MEM_dupallocN(smd->verts[i].binds); - - for (int j = 0; j < smd->verts[i].numbinds; j++) { - if (smd->verts[i].binds[j].vert_inds) { - tsmd->verts[i].binds[j].vert_inds = MEM_dupallocN(smd->verts[i].binds[j].vert_inds); - } - - if (smd->verts[i].binds[j].vert_weights) { - tsmd->verts[i].binds[j].vert_weights = MEM_dupallocN(smd->verts[i].binds[j].vert_weights); - } - } - } - } - } + const SurfaceDeformModifierData *smd = (const SurfaceDeformModifierData *)md; + SurfaceDeformModifierData *tsmd = (SurfaceDeformModifierData *)target; + + modifier_copyData_generic(md, target, flag); + + if (smd->verts) { + tsmd->verts = MEM_dupallocN(smd->verts); + + for (int i = 0; i < smd->numverts; i++) { + if (smd->verts[i].binds) { + tsmd->verts[i].binds = MEM_dupallocN(smd->verts[i].binds); + + for (int j = 0; j < smd->verts[i].numbinds; j++) { + if (smd->verts[i].binds[j].vert_inds) { + tsmd->verts[i].binds[j].vert_inds = MEM_dupallocN(smd->verts[i].binds[j].vert_inds); + } + + if (smd->verts[i].binds[j].vert_weights) { + tsmd->verts[i].binds[j].vert_weights = MEM_dupallocN( + smd->verts[i].binds[j].vert_weights); + } + } + } + } + } } static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) { - SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md; + SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md; - walk(userData, ob, &smd->target, IDWALK_NOP); + walk(userData, ob, &smd->target, IDWALK_NOP); } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { - SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md; - if (smd->target != NULL) { - DEG_add_object_relation(ctx->node, smd->target, DEG_OB_COMP_GEOMETRY, "Surface Deform Modifier"); - } + SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md; + if (smd->target != NULL) { + DEG_add_object_relation( + ctx->node, smd->target, DEG_OB_COMP_GEOMETRY, "Surface Deform Modifier"); + } } -static void freeAdjacencyMap(SDefAdjacencyArray * const vert_edges, SDefAdjacency * const adj_ref, SDefEdgePolys * const edge_polys) +static void freeAdjacencyMap(SDefAdjacencyArray *const vert_edges, + SDefAdjacency *const adj_ref, + SDefEdgePolys *const edge_polys) { - MEM_freeN(edge_polys); + MEM_freeN(edge_polys); - MEM_freeN(adj_ref); + MEM_freeN(adj_ref); - MEM_freeN(vert_edges); + MEM_freeN(vert_edges); } -static int buildAdjacencyMap( - const MPoly *poly, const MEdge *edge, const MLoop * const mloop, const unsigned int numpoly, const unsigned int numedges, - SDefAdjacencyArray * const vert_edges, SDefAdjacency *adj, SDefEdgePolys * const edge_polys) +static int buildAdjacencyMap(const MPoly *poly, + const MEdge *edge, + const MLoop *const mloop, + const unsigned int numpoly, + const unsigned int numedges, + SDefAdjacencyArray *const vert_edges, + SDefAdjacency *adj, + SDefEdgePolys *const edge_polys) { - const MLoop *loop; - - /* Fing polygons adjacent to edges */ - for (int i = 0; i < numpoly; i++, poly++) { - loop = &mloop[poly->loopstart]; - - for (int j = 0; j < poly->totloop; j++, loop++) { - if (edge_polys[loop->e].num == 0) { - edge_polys[loop->e].polys[0] = i; - edge_polys[loop->e].polys[1] = -1; - edge_polys[loop->e].num++; - } - else if (edge_polys[loop->e].num == 1) { - edge_polys[loop->e].polys[1] = i; - edge_polys[loop->e].num++; - } - else { - return MOD_SDEF_BIND_RESULT_NONMANY_ERR; - } - } - } - - /* Find edges adjacent to vertices */ - for (int i = 0; i < numedges; i++, edge++) { - adj->next = vert_edges[edge->v1].first; - adj->index = i; - vert_edges[edge->v1].first = adj; - vert_edges[edge->v1].num += edge_polys[i].num; - adj++; - - adj->next = vert_edges[edge->v2].first; - adj->index = i; - vert_edges[edge->v2].first = adj; - vert_edges[edge->v2].num += edge_polys[i].num; - adj++; - } - - return MOD_SDEF_BIND_RESULT_SUCCESS; + const MLoop *loop; + + /* Fing polygons adjacent to edges */ + for (int i = 0; i < numpoly; i++, poly++) { + loop = &mloop[poly->loopstart]; + + for (int j = 0; j < poly->totloop; j++, loop++) { + if (edge_polys[loop->e].num == 0) { + edge_polys[loop->e].polys[0] = i; + edge_polys[loop->e].polys[1] = -1; + edge_polys[loop->e].num++; + } + else if (edge_polys[loop->e].num == 1) { + edge_polys[loop->e].polys[1] = i; + edge_polys[loop->e].num++; + } + else { + return MOD_SDEF_BIND_RESULT_NONMANY_ERR; + } + } + } + + /* Find edges adjacent to vertices */ + for (int i = 0; i < numedges; i++, edge++) { + adj->next = vert_edges[edge->v1].first; + adj->index = i; + vert_edges[edge->v1].first = adj; + vert_edges[edge->v1].num += edge_polys[i].num; + adj++; + + adj->next = vert_edges[edge->v2].first; + adj->index = i; + vert_edges[edge->v2].first = adj; + vert_edges[edge->v2].num += edge_polys[i].num; + adj++; + } + + return MOD_SDEF_BIND_RESULT_SUCCESS; } -BLI_INLINE void sortPolyVertsEdge(unsigned int *indices, const MLoop * const mloop, const unsigned int edge, const unsigned int num) +BLI_INLINE void sortPolyVertsEdge(unsigned int *indices, + const MLoop *const mloop, + const unsigned int edge, + const unsigned int num) { - bool found = false; - - for (int i = 0; i < num; i++) { - if (mloop[i].e == edge) { - found = true; - } - if (found) { - *indices = mloop[i].v; - indices++; - } - } - - /* Fill in remaining vertex indices that occur before the edge */ - for (int i = 0; mloop[i].e != edge; i++) { - *indices = mloop[i].v; - indices++; - } + bool found = false; + + for (int i = 0; i < num; i++) { + if (mloop[i].e == edge) { + found = true; + } + if (found) { + *indices = mloop[i].v; + indices++; + } + } + + /* Fill in remaining vertex indices that occur before the edge */ + for (int i = 0; mloop[i].e != edge; i++) { + *indices = mloop[i].v; + indices++; + } } -BLI_INLINE void sortPolyVertsTri(unsigned int *indices, const MLoop * const mloop, const unsigned int loopstart, const unsigned int num) +BLI_INLINE void sortPolyVertsTri(unsigned int *indices, + const MLoop *const mloop, + const unsigned int loopstart, + const unsigned int num) { - for (int i = loopstart; i < num; i++) { - *indices = mloop[i].v; - indices++; - } - - for (int i = 0; i < loopstart; i++) { - *indices = mloop[i].v; - indices++; - } + for (int i = loopstart; i < num; i++) { + *indices = mloop[i].v; + indices++; + } + + for (int i = 0; i < loopstart; i++) { + *indices = mloop[i].v; + indices++; + } } -BLI_INLINE unsigned int nearestVert(SDefBindCalcData * const data, const float point_co[3]) +BLI_INLINE unsigned int nearestVert(SDefBindCalcData *const data, const float point_co[3]) { - BVHTreeNearest nearest = { .dist_sq = FLT_MAX, .index = -1, }; - const MPoly *poly; - const MEdge *edge; - const MLoop *loop; - float t_point[3]; - float max_dist = FLT_MAX; - float dist; - unsigned int index = 0; - - mul_v3_m4v3(t_point, data->imat, point_co); - - BLI_bvhtree_find_nearest(data->treeData->tree, t_point, &nearest, data->treeData->nearest_callback, data->treeData); - - poly = &data->mpoly[data->looptri[nearest.index].poly]; - loop = &data->mloop[poly->loopstart]; - - for (int i = 0; i < poly->totloop; i++, loop++) { - edge = &data->medge[loop->e]; - dist = dist_squared_to_line_segment_v3(point_co, data->targetCos[edge->v1], data->targetCos[edge->v2]); - - if (dist < max_dist) { - max_dist = dist; - index = loop->e; - } - } - - edge = &data->medge[index]; - if (len_squared_v3v3(point_co, data->targetCos[edge->v1]) < len_squared_v3v3(point_co, data->targetCos[edge->v2])) { - return edge->v1; - } - else { - return edge->v2; - } + BVHTreeNearest nearest = { + .dist_sq = FLT_MAX, + .index = -1, + }; + const MPoly *poly; + const MEdge *edge; + const MLoop *loop; + float t_point[3]; + float max_dist = FLT_MAX; + float dist; + unsigned int index = 0; + + mul_v3_m4v3(t_point, data->imat, point_co); + + BLI_bvhtree_find_nearest( + data->treeData->tree, t_point, &nearest, data->treeData->nearest_callback, data->treeData); + + poly = &data->mpoly[data->looptri[nearest.index].poly]; + loop = &data->mloop[poly->loopstart]; + + for (int i = 0; i < poly->totloop; i++, loop++) { + edge = &data->medge[loop->e]; + dist = dist_squared_to_line_segment_v3( + point_co, data->targetCos[edge->v1], data->targetCos[edge->v2]); + + if (dist < max_dist) { + max_dist = dist; + index = loop->e; + } + } + + edge = &data->medge[index]; + if (len_squared_v3v3(point_co, data->targetCos[edge->v1]) < + len_squared_v3v3(point_co, data->targetCos[edge->v2])) { + return edge->v1; + } + else { + return edge->v2; + } } BLI_INLINE int isPolyValid(const float coords[][2], const unsigned int nr) { - float prev_co[2]; - float curr_vec[2], prev_vec[2]; + float prev_co[2]; + float curr_vec[2], prev_vec[2]; - if (!is_poly_convex_v2(coords, nr)) { - return MOD_SDEF_BIND_RESULT_CONCAVE_ERR; - } + if (!is_poly_convex_v2(coords, nr)) { + return MOD_SDEF_BIND_RESULT_CONCAVE_ERR; + } - copy_v2_v2(prev_co, coords[nr - 1]); - sub_v2_v2v2(prev_vec, prev_co, coords[nr - 2]); - normalize_v2(prev_vec); + copy_v2_v2(prev_co, coords[nr - 1]); + sub_v2_v2v2(prev_vec, prev_co, coords[nr - 2]); + normalize_v2(prev_vec); - for (int i = 0; i < nr; i++) { - sub_v2_v2v2(curr_vec, coords[i], prev_co); + for (int i = 0; i < nr; i++) { + sub_v2_v2v2(curr_vec, coords[i], prev_co); - const float curr_len = normalize_v2(curr_vec); - if (curr_len < FLT_EPSILON) { - return MOD_SDEF_BIND_RESULT_OVERLAP_ERR; - } + const float curr_len = normalize_v2(curr_vec); + if (curr_len < FLT_EPSILON) { + return MOD_SDEF_BIND_RESULT_OVERLAP_ERR; + } - if (1.0f - dot_v2v2(prev_vec, curr_vec) < FLT_EPSILON) { - return MOD_SDEF_BIND_RESULT_CONCAVE_ERR; - } + if (1.0f - dot_v2v2(prev_vec, curr_vec) < FLT_EPSILON) { + return MOD_SDEF_BIND_RESULT_CONCAVE_ERR; + } - copy_v2_v2(prev_co, coords[i]); - copy_v2_v2(prev_vec, curr_vec); - } + copy_v2_v2(prev_co, coords[i]); + copy_v2_v2(prev_vec, curr_vec); + } - return MOD_SDEF_BIND_RESULT_SUCCESS; + return MOD_SDEF_BIND_RESULT_SUCCESS; } -static void freeBindData(SDefBindWeightData * const bwdata) +static void freeBindData(SDefBindWeightData *const bwdata) { - SDefBindPoly *bpoly = bwdata->bind_polys; + SDefBindPoly *bpoly = bwdata->bind_polys; - if (bwdata->bind_polys) { - for (int i = 0; i < bwdata->numpoly; bpoly++, i++) { - MEM_SAFE_FREE(bpoly->coords); - MEM_SAFE_FREE(bpoly->coords_v2); - } + if (bwdata->bind_polys) { + for (int i = 0; i < bwdata->numpoly; bpoly++, i++) { + MEM_SAFE_FREE(bpoly->coords); + MEM_SAFE_FREE(bpoly->coords_v2); + } - MEM_freeN(bwdata->bind_polys); - } + MEM_freeN(bwdata->bind_polys); + } - MEM_freeN(bwdata); + MEM_freeN(bwdata); } BLI_INLINE float computeAngularWeight(const float point_angle, const float edgemid_angle) { - float weight; + float weight; - weight = point_angle; - weight /= edgemid_angle; - weight *= M_PI_2; + weight = point_angle; + weight /= edgemid_angle; + weight *= M_PI_2; - return sinf(weight); + return sinf(weight); } -BLI_INLINE SDefBindWeightData *computeBindWeights(SDefBindCalcData * const data, const float point_co[3]) +BLI_INLINE SDefBindWeightData *computeBindWeights(SDefBindCalcData *const data, + const float point_co[3]) { - const unsigned int nearest = nearestVert(data, point_co); - const SDefAdjacency * const vert_edges = data->vert_edges[nearest].first; - const SDefEdgePolys * const edge_polys = data->edge_polys; - - const SDefAdjacency *vedge; - const MPoly *poly; - const MLoop *loop; - - SDefBindWeightData *bwdata; - SDefBindPoly *bpoly; - - float world[3] = {0.0f, 0.0f, 1.0f}; - float avg_point_dist = 0.0f; - float tot_weight = 0.0f; - int inf_weight_flags = 0; - - bwdata = MEM_callocN(sizeof(*bwdata), "SDefBindWeightData"); - if (bwdata == NULL) { - data->success = MOD_SDEF_BIND_RESULT_MEM_ERR; - return NULL; - } - - bwdata->numpoly = data->vert_edges[nearest].num / 2; - - bpoly = MEM_calloc_arrayN(bwdata->numpoly, sizeof(*bpoly), "SDefBindPoly"); - if (bpoly == NULL) { - freeBindData(bwdata); - data->success = MOD_SDEF_BIND_RESULT_MEM_ERR; - return NULL; - } - - bwdata->bind_polys = bpoly; - - /* Loop over all adjacent edges, and build the SDefBindPoly data for each poly adjacent to those */ - for (vedge = vert_edges; vedge; vedge = vedge->next) { - unsigned int edge_ind = vedge->index; - - for (int i = 0; i < edge_polys[edge_ind].num; i++) { - { - bpoly = bwdata->bind_polys; - - for (int j = 0; j < bwdata->numpoly; bpoly++, j++) { - /* If coords isn't allocated, we have reached the first uninitialized bpoly */ - if ((bpoly->index == edge_polys[edge_ind].polys[i]) || (!bpoly->coords)) { - break; - } - } - } - - /* Check if poly was already created by another edge or still has to be initialized */ - if (!bpoly->coords) { - float angle; - float axis[3]; - float tmp_vec_v2[2]; - int is_poly_valid; - - bpoly->index = edge_polys[edge_ind].polys[i]; - bpoly->coords = NULL; - bpoly->coords_v2 = NULL; - - /* Copy poly data */ - poly = &data->mpoly[bpoly->index]; - loop = &data->mloop[poly->loopstart]; - - bpoly->numverts = poly->totloop; - bpoly->loopstart = poly->loopstart; - - bpoly->coords = MEM_malloc_arrayN(poly->totloop, sizeof(*bpoly->coords), "SDefBindPolyCoords"); - if (bpoly->coords == NULL) { - freeBindData(bwdata); - data->success = MOD_SDEF_BIND_RESULT_MEM_ERR; - return NULL; - } - - bpoly->coords_v2 = MEM_malloc_arrayN(poly->totloop, sizeof(*bpoly->coords_v2), "SDefBindPolyCoords_v2"); - if (bpoly->coords_v2 == NULL) { - freeBindData(bwdata); - data->success = MOD_SDEF_BIND_RESULT_MEM_ERR; - return NULL; - } - - for (int j = 0; j < poly->totloop; j++, loop++) { - copy_v3_v3(bpoly->coords[j], data->targetCos[loop->v]); - - /* Find corner and edge indices within poly loop array */ - if (loop->v == nearest) { - bpoly->corner_ind = j; - bpoly->edge_vert_inds[0] = (j == 0) ? (poly->totloop - 1) : (j - 1); - bpoly->edge_vert_inds[1] = (j == poly->totloop - 1) ? (0) : (j + 1); - - bpoly->edge_inds[0] = data->mloop[poly->loopstart + bpoly->edge_vert_inds[0]].e; - bpoly->edge_inds[1] = loop->e; - } - } - - /* Compute poly's parametric data */ - mid_v3_v3_array(bpoly->centroid, bpoly->coords, poly->totloop); - normal_poly_v3(bpoly->normal, bpoly->coords, poly->totloop); - - /* Compute poly skew angle and axis */ - angle = angle_normalized_v3v3(bpoly->normal, world); - - cross_v3_v3v3(axis, bpoly->normal, world); - normalize_v3(axis); - - /* Map coords onto 2d normal plane */ - map_to_plane_axis_angle_v2_v3v3fl(bpoly->point_v2, point_co, axis, angle); - - zero_v2(bpoly->centroid_v2); - for (int j = 0; j < poly->totloop; j++) { - map_to_plane_axis_angle_v2_v3v3fl(bpoly->coords_v2[j], bpoly->coords[j], axis, angle); - madd_v2_v2fl(bpoly->centroid_v2, bpoly->coords_v2[j], 1.0f / poly->totloop); - } - - is_poly_valid = isPolyValid(bpoly->coords_v2, poly->totloop); - - if (is_poly_valid != MOD_SDEF_BIND_RESULT_SUCCESS) { - freeBindData(bwdata); - data->success = is_poly_valid; - return NULL; - } - - bpoly->inside = isect_point_poly_v2(bpoly->point_v2, bpoly->coords_v2, poly->totloop, false); - - /* Initialize weight components */ - bpoly->weight_angular = 1.0f; - bpoly->weight_dist_proj = len_v2v2(bpoly->centroid_v2, bpoly->point_v2); - bpoly->weight_dist = len_v3v3(bpoly->centroid, point_co); - - avg_point_dist += bpoly->weight_dist; - - /* Compute centroid to mid-edge vectors */ - mid_v2_v2v2(bpoly->cent_edgemid_vecs_v2[0], - bpoly->coords_v2[bpoly->edge_vert_inds[0]], - bpoly->coords_v2[bpoly->corner_ind]); - - mid_v2_v2v2(bpoly->cent_edgemid_vecs_v2[1], - bpoly->coords_v2[bpoly->edge_vert_inds[1]], - bpoly->coords_v2[bpoly->corner_ind]); - - sub_v2_v2(bpoly->cent_edgemid_vecs_v2[0], bpoly->centroid_v2); - sub_v2_v2(bpoly->cent_edgemid_vecs_v2[1], bpoly->centroid_v2); - - /* Compute poly scales with respect to mid-edges, and normalize the vectors */ - bpoly->scales[0] = normalize_v2(bpoly->cent_edgemid_vecs_v2[0]); - bpoly->scales[1] = normalize_v2(bpoly->cent_edgemid_vecs_v2[1]); - - /* Compute the required polygon angles */ - bpoly->edgemid_angle = angle_normalized_v2v2(bpoly->cent_edgemid_vecs_v2[0], bpoly->cent_edgemid_vecs_v2[1]); - - sub_v2_v2v2(tmp_vec_v2, bpoly->coords_v2[bpoly->corner_ind], bpoly->centroid_v2); - normalize_v2(tmp_vec_v2); - - bpoly->corner_edgemid_angles[0] = angle_normalized_v2v2(tmp_vec_v2, bpoly->cent_edgemid_vecs_v2[0]); - bpoly->corner_edgemid_angles[1] = angle_normalized_v2v2(tmp_vec_v2, bpoly->cent_edgemid_vecs_v2[1]); - - /* Check for inifnite weights, and compute angular data otherwise */ - if (bpoly->weight_dist < FLT_EPSILON) { - inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ; - inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST; - } - else if (bpoly->weight_dist_proj < FLT_EPSILON) { - inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ; - } - else { - float cent_point_vec[2]; - - sub_v2_v2v2(cent_point_vec, bpoly->point_v2, bpoly->centroid_v2); - normalize_v2(cent_point_vec); - - bpoly->point_edgemid_angles[0] = angle_normalized_v2v2(cent_point_vec, bpoly->cent_edgemid_vecs_v2[0]); - bpoly->point_edgemid_angles[1] = angle_normalized_v2v2(cent_point_vec, bpoly->cent_edgemid_vecs_v2[1]); - } - } - } - } - - avg_point_dist /= bwdata->numpoly; - - /* If weights 1 and 2 are not infinite, loop over all adjacent edges again, - * and build adjacency dependent angle data (depends on all polygons having been computed) */ - if (!inf_weight_flags) { - for (vedge = vert_edges; vedge; vedge = vedge->next) { - SDefBindPoly *bpolys[2]; - const SDefEdgePolys *epolys; - float ang_weights[2]; - unsigned int edge_ind = vedge->index; - unsigned int edge_on_poly[2]; - - epolys = &edge_polys[edge_ind]; - - /* Find bind polys corresponding to the edge's adjacent polys */ - bpoly = bwdata->bind_polys; - - for (int i = 0, j = 0; (i < bwdata->numpoly) && (j < epolys->num); bpoly++, i++) { - if (ELEM(bpoly->index, epolys->polys[0], epolys->polys[1])) { - bpolys[j] = bpoly; - - if (bpoly->edge_inds[0] == edge_ind) { - edge_on_poly[j] = 0; - } - else { - edge_on_poly[j] = 1; - } - - j++; - } - } - - /* Compute angular weight component */ - if (epolys->num == 1) { - ang_weights[0] = computeAngularWeight(bpolys[0]->point_edgemid_angles[edge_on_poly[0]], bpolys[0]->edgemid_angle); - bpolys[0]->weight_angular *= ang_weights[0] * ang_weights[0]; - } - else if (epolys->num == 2) { - ang_weights[0] = computeAngularWeight(bpolys[0]->point_edgemid_angles[edge_on_poly[0]], bpolys[0]->edgemid_angle); - ang_weights[1] = computeAngularWeight(bpolys[1]->point_edgemid_angles[edge_on_poly[1]], bpolys[1]->edgemid_angle); - - bpolys[0]->weight_angular *= ang_weights[0] * ang_weights[1]; - bpolys[1]->weight_angular *= ang_weights[0] * ang_weights[1]; - } - } - } - - /* Compute scalings and falloff. - * Scale all weights if no infinite weight is found, - * scale only unprojected weight if projected weight is infinite, - * scale none if both are infinite. */ - if (!inf_weight_flags) { - bpoly = bwdata->bind_polys; - - for (int i = 0; i < bwdata->numpoly; bpoly++, i++) { - float corner_angle_weights[2]; - float scale_weight, sqr, inv_sqr; - - corner_angle_weights[0] = bpoly->point_edgemid_angles[0] / bpoly->corner_edgemid_angles[0]; - corner_angle_weights[1] = bpoly->point_edgemid_angles[1] / bpoly->corner_edgemid_angles[1]; - - if (isnan(corner_angle_weights[0]) || isnan(corner_angle_weights[1])) { - freeBindData(bwdata); - data->success = MOD_SDEF_BIND_RESULT_GENERIC_ERR; - return NULL; - } - - /* Find which edge the point is closer to */ - if (corner_angle_weights[0] < corner_angle_weights[1]) { - bpoly->dominant_edge = 0; - bpoly->dominant_angle_weight = corner_angle_weights[0]; - } - else { - bpoly->dominant_edge = 1; - bpoly->dominant_angle_weight = corner_angle_weights[1]; - } - - bpoly->dominant_angle_weight = sinf(bpoly->dominant_angle_weight * M_PI_2); - - /* Compute quadratic angular scale interpolation weight */ - scale_weight = bpoly->point_edgemid_angles[bpoly->dominant_edge] / bpoly->edgemid_angle; - scale_weight /= scale_weight + (bpoly->point_edgemid_angles[!bpoly->dominant_edge] / bpoly->edgemid_angle); - - sqr = scale_weight * scale_weight; - inv_sqr = 1.0f - scale_weight; - inv_sqr *= inv_sqr; - scale_weight = sqr / (sqr + inv_sqr); - - /* Compute interpolated scale (no longer need the individual scales, - * so simply storing the result over the scale in index zero) */ - bpoly->scales[0] = bpoly->scales[bpoly->dominant_edge] * (1.0f - scale_weight) + - bpoly->scales[!bpoly->dominant_edge] * scale_weight; - - /* Scale the point distance weights, and introduce falloff */ - bpoly->weight_dist_proj /= bpoly->scales[0]; - bpoly->weight_dist_proj = powf(bpoly->weight_dist_proj, data->falloff); - - bpoly->weight_dist /= avg_point_dist; - bpoly->weight_dist = powf(bpoly->weight_dist, data->falloff); - - /* Re-check for infinite weights, now that all scalings and interpolations are computed */ - if (bpoly->weight_dist < FLT_EPSILON) { - inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ; - inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST; - } - else if (bpoly->weight_dist_proj < FLT_EPSILON) { - inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ; - } - else if (bpoly->weight_angular < FLT_EPSILON) { - inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_ANGULAR; - } - } - } - else if (!(inf_weight_flags & MOD_SDEF_INFINITE_WEIGHT_DIST)) { - bpoly = bwdata->bind_polys; - - for (int i = 0; i < bwdata->numpoly; bpoly++, i++) { - /* Scale the point distance weight by average point distance, and introduce falloff */ - bpoly->weight_dist /= avg_point_dist; - bpoly->weight_dist = powf(bpoly->weight_dist, data->falloff); - - /* Re-check for infinite weights, now that all scalings and interpolations are computed */ - if (bpoly->weight_dist < FLT_EPSILON) { - inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST; - } - } - } - - /* Final loop, to compute actual weights */ - bpoly = bwdata->bind_polys; - - for (int i = 0; i < bwdata->numpoly; bpoly++, i++) { - /* Weight computation from components */ - if (inf_weight_flags & MOD_SDEF_INFINITE_WEIGHT_DIST) { - bpoly->weight = bpoly->weight_dist < FLT_EPSILON ? 1.0f : 0.0f; - } - else if (inf_weight_flags & MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ) { - bpoly->weight = bpoly->weight_dist_proj < FLT_EPSILON ? - 1.0f / bpoly->weight_dist : 0.0f; - } - else if (inf_weight_flags & MOD_SDEF_INFINITE_WEIGHT_ANGULAR) { - bpoly->weight = bpoly->weight_angular < FLT_EPSILON ? - 1.0f / bpoly->weight_dist_proj / bpoly->weight_dist : 0.0f; - } - else { - bpoly->weight = 1.0f / bpoly->weight_angular / - bpoly->weight_dist_proj / - bpoly->weight_dist; - } - - tot_weight += bpoly->weight; - } - - bpoly = bwdata->bind_polys; - - for (int i = 0; i < bwdata->numpoly; bpoly++, i++) { - bpoly->weight /= tot_weight; - - /* Evaluate if this poly is relevant to bind */ - /* Even though the weights should add up to 1.0, - * the losses of weights smaller than epsilon here - * should be negligible... */ - if (bpoly->weight >= FLT_EPSILON) { - if (bpoly->inside) { - bwdata->numbinds += 1; - } - else { - if (bpoly->dominant_angle_weight < FLT_EPSILON || 1.0f - bpoly->dominant_angle_weight < FLT_EPSILON) { - bwdata->numbinds += 1; - } - else { - bwdata->numbinds += 2; - } - } - } - } - - return bwdata; + const unsigned int nearest = nearestVert(data, point_co); + const SDefAdjacency *const vert_edges = data->vert_edges[nearest].first; + const SDefEdgePolys *const edge_polys = data->edge_polys; + + const SDefAdjacency *vedge; + const MPoly *poly; + const MLoop *loop; + + SDefBindWeightData *bwdata; + SDefBindPoly *bpoly; + + float world[3] = {0.0f, 0.0f, 1.0f}; + float avg_point_dist = 0.0f; + float tot_weight = 0.0f; + int inf_weight_flags = 0; + + bwdata = MEM_callocN(sizeof(*bwdata), "SDefBindWeightData"); + if (bwdata == NULL) { + data->success = MOD_SDEF_BIND_RESULT_MEM_ERR; + return NULL; + } + + bwdata->numpoly = data->vert_edges[nearest].num / 2; + + bpoly = MEM_calloc_arrayN(bwdata->numpoly, sizeof(*bpoly), "SDefBindPoly"); + if (bpoly == NULL) { + freeBindData(bwdata); + data->success = MOD_SDEF_BIND_RESULT_MEM_ERR; + return NULL; + } + + bwdata->bind_polys = bpoly; + + /* Loop over all adjacent edges, and build the SDefBindPoly data for each poly adjacent to those */ + for (vedge = vert_edges; vedge; vedge = vedge->next) { + unsigned int edge_ind = vedge->index; + + for (int i = 0; i < edge_polys[edge_ind].num; i++) { + { + bpoly = bwdata->bind_polys; + + for (int j = 0; j < bwdata->numpoly; bpoly++, j++) { + /* If coords isn't allocated, we have reached the first uninitialized bpoly */ + if ((bpoly->index == edge_polys[edge_ind].polys[i]) || (!bpoly->coords)) { + break; + } + } + } + + /* Check if poly was already created by another edge or still has to be initialized */ + if (!bpoly->coords) { + float angle; + float axis[3]; + float tmp_vec_v2[2]; + int is_poly_valid; + + bpoly->index = edge_polys[edge_ind].polys[i]; + bpoly->coords = NULL; + bpoly->coords_v2 = NULL; + + /* Copy poly data */ + poly = &data->mpoly[bpoly->index]; + loop = &data->mloop[poly->loopstart]; + + bpoly->numverts = poly->totloop; + bpoly->loopstart = poly->loopstart; + + bpoly->coords = MEM_malloc_arrayN( + poly->totloop, sizeof(*bpoly->coords), "SDefBindPolyCoords"); + if (bpoly->coords == NULL) { + freeBindData(bwdata); + data->success = MOD_SDEF_BIND_RESULT_MEM_ERR; + return NULL; + } + + bpoly->coords_v2 = MEM_malloc_arrayN( + poly->totloop, sizeof(*bpoly->coords_v2), "SDefBindPolyCoords_v2"); + if (bpoly->coords_v2 == NULL) { + freeBindData(bwdata); + data->success = MOD_SDEF_BIND_RESULT_MEM_ERR; + return NULL; + } + + for (int j = 0; j < poly->totloop; j++, loop++) { + copy_v3_v3(bpoly->coords[j], data->targetCos[loop->v]); + + /* Find corner and edge indices within poly loop array */ + if (loop->v == nearest) { + bpoly->corner_ind = j; + bpoly->edge_vert_inds[0] = (j == 0) ? (poly->totloop - 1) : (j - 1); + bpoly->edge_vert_inds[1] = (j == poly->totloop - 1) ? (0) : (j + 1); + + bpoly->edge_inds[0] = data->mloop[poly->loopstart + bpoly->edge_vert_inds[0]].e; + bpoly->edge_inds[1] = loop->e; + } + } + + /* Compute poly's parametric data */ + mid_v3_v3_array(bpoly->centroid, bpoly->coords, poly->totloop); + normal_poly_v3(bpoly->normal, bpoly->coords, poly->totloop); + + /* Compute poly skew angle and axis */ + angle = angle_normalized_v3v3(bpoly->normal, world); + + cross_v3_v3v3(axis, bpoly->normal, world); + normalize_v3(axis); + + /* Map coords onto 2d normal plane */ + map_to_plane_axis_angle_v2_v3v3fl(bpoly->point_v2, point_co, axis, angle); + + zero_v2(bpoly->centroid_v2); + for (int j = 0; j < poly->totloop; j++) { + map_to_plane_axis_angle_v2_v3v3fl(bpoly->coords_v2[j], bpoly->coords[j], axis, angle); + madd_v2_v2fl(bpoly->centroid_v2, bpoly->coords_v2[j], 1.0f / poly->totloop); + } + + is_poly_valid = isPolyValid(bpoly->coords_v2, poly->totloop); + + if (is_poly_valid != MOD_SDEF_BIND_RESULT_SUCCESS) { + freeBindData(bwdata); + data->success = is_poly_valid; + return NULL; + } + + bpoly->inside = isect_point_poly_v2( + bpoly->point_v2, bpoly->coords_v2, poly->totloop, false); + + /* Initialize weight components */ + bpoly->weight_angular = 1.0f; + bpoly->weight_dist_proj = len_v2v2(bpoly->centroid_v2, bpoly->point_v2); + bpoly->weight_dist = len_v3v3(bpoly->centroid, point_co); + + avg_point_dist += bpoly->weight_dist; + + /* Compute centroid to mid-edge vectors */ + mid_v2_v2v2(bpoly->cent_edgemid_vecs_v2[0], + bpoly->coords_v2[bpoly->edge_vert_inds[0]], + bpoly->coords_v2[bpoly->corner_ind]); + + mid_v2_v2v2(bpoly->cent_edgemid_vecs_v2[1], + bpoly->coords_v2[bpoly->edge_vert_inds[1]], + bpoly->coords_v2[bpoly->corner_ind]); + + sub_v2_v2(bpoly->cent_edgemid_vecs_v2[0], bpoly->centroid_v2); + sub_v2_v2(bpoly->cent_edgemid_vecs_v2[1], bpoly->centroid_v2); + + /* Compute poly scales with respect to mid-edges, and normalize the vectors */ + bpoly->scales[0] = normalize_v2(bpoly->cent_edgemid_vecs_v2[0]); + bpoly->scales[1] = normalize_v2(bpoly->cent_edgemid_vecs_v2[1]); + + /* Compute the required polygon angles */ + bpoly->edgemid_angle = angle_normalized_v2v2(bpoly->cent_edgemid_vecs_v2[0], + bpoly->cent_edgemid_vecs_v2[1]); + + sub_v2_v2v2(tmp_vec_v2, bpoly->coords_v2[bpoly->corner_ind], bpoly->centroid_v2); + normalize_v2(tmp_vec_v2); + + bpoly->corner_edgemid_angles[0] = angle_normalized_v2v2(tmp_vec_v2, + bpoly->cent_edgemid_vecs_v2[0]); + bpoly->corner_edgemid_angles[1] = angle_normalized_v2v2(tmp_vec_v2, + bpoly->cent_edgemid_vecs_v2[1]); + + /* Check for inifnite weights, and compute angular data otherwise */ + if (bpoly->weight_dist < FLT_EPSILON) { + inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ; + inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST; + } + else if (bpoly->weight_dist_proj < FLT_EPSILON) { + inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ; + } + else { + float cent_point_vec[2]; + + sub_v2_v2v2(cent_point_vec, bpoly->point_v2, bpoly->centroid_v2); + normalize_v2(cent_point_vec); + + bpoly->point_edgemid_angles[0] = angle_normalized_v2v2(cent_point_vec, + bpoly->cent_edgemid_vecs_v2[0]); + bpoly->point_edgemid_angles[1] = angle_normalized_v2v2(cent_point_vec, + bpoly->cent_edgemid_vecs_v2[1]); + } + } + } + } + + avg_point_dist /= bwdata->numpoly; + + /* If weights 1 and 2 are not infinite, loop over all adjacent edges again, + * and build adjacency dependent angle data (depends on all polygons having been computed) */ + if (!inf_weight_flags) { + for (vedge = vert_edges; vedge; vedge = vedge->next) { + SDefBindPoly *bpolys[2]; + const SDefEdgePolys *epolys; + float ang_weights[2]; + unsigned int edge_ind = vedge->index; + unsigned int edge_on_poly[2]; + + epolys = &edge_polys[edge_ind]; + + /* Find bind polys corresponding to the edge's adjacent polys */ + bpoly = bwdata->bind_polys; + + for (int i = 0, j = 0; (i < bwdata->numpoly) && (j < epolys->num); bpoly++, i++) { + if (ELEM(bpoly->index, epolys->polys[0], epolys->polys[1])) { + bpolys[j] = bpoly; + + if (bpoly->edge_inds[0] == edge_ind) { + edge_on_poly[j] = 0; + } + else { + edge_on_poly[j] = 1; + } + + j++; + } + } + + /* Compute angular weight component */ + if (epolys->num == 1) { + ang_weights[0] = computeAngularWeight(bpolys[0]->point_edgemid_angles[edge_on_poly[0]], + bpolys[0]->edgemid_angle); + bpolys[0]->weight_angular *= ang_weights[0] * ang_weights[0]; + } + else if (epolys->num == 2) { + ang_weights[0] = computeAngularWeight(bpolys[0]->point_edgemid_angles[edge_on_poly[0]], + bpolys[0]->edgemid_angle); + ang_weights[1] = computeAngularWeight(bpolys[1]->point_edgemid_angles[edge_on_poly[1]], + bpolys[1]->edgemid_angle); + + bpolys[0]->weight_angular *= ang_weights[0] * ang_weights[1]; + bpolys[1]->weight_angular *= ang_weights[0] * ang_weights[1]; + } + } + } + + /* Compute scalings and falloff. + * Scale all weights if no infinite weight is found, + * scale only unprojected weight if projected weight is infinite, + * scale none if both are infinite. */ + if (!inf_weight_flags) { + bpoly = bwdata->bind_polys; + + for (int i = 0; i < bwdata->numpoly; bpoly++, i++) { + float corner_angle_weights[2]; + float scale_weight, sqr, inv_sqr; + + corner_angle_weights[0] = bpoly->point_edgemid_angles[0] / bpoly->corner_edgemid_angles[0]; + corner_angle_weights[1] = bpoly->point_edgemid_angles[1] / bpoly->corner_edgemid_angles[1]; + + if (isnan(corner_angle_weights[0]) || isnan(corner_angle_weights[1])) { + freeBindData(bwdata); + data->success = MOD_SDEF_BIND_RESULT_GENERIC_ERR; + return NULL; + } + + /* Find which edge the point is closer to */ + if (corner_angle_weights[0] < corner_angle_weights[1]) { + bpoly->dominant_edge = 0; + bpoly->dominant_angle_weight = corner_angle_weights[0]; + } + else { + bpoly->dominant_edge = 1; + bpoly->dominant_angle_weight = corner_angle_weights[1]; + } + + bpoly->dominant_angle_weight = sinf(bpoly->dominant_angle_weight * M_PI_2); + + /* Compute quadratic angular scale interpolation weight */ + scale_weight = bpoly->point_edgemid_angles[bpoly->dominant_edge] / bpoly->edgemid_angle; + scale_weight /= scale_weight + + (bpoly->point_edgemid_angles[!bpoly->dominant_edge] / bpoly->edgemid_angle); + + sqr = scale_weight * scale_weight; + inv_sqr = 1.0f - scale_weight; + inv_sqr *= inv_sqr; + scale_weight = sqr / (sqr + inv_sqr); + + /* Compute interpolated scale (no longer need the individual scales, + * so simply storing the result over the scale in index zero) */ + bpoly->scales[0] = bpoly->scales[bpoly->dominant_edge] * (1.0f - scale_weight) + + bpoly->scales[!bpoly->dominant_edge] * scale_weight; + + /* Scale the point distance weights, and introduce falloff */ + bpoly->weight_dist_proj /= bpoly->scales[0]; + bpoly->weight_dist_proj = powf(bpoly->weight_dist_proj, data->falloff); + + bpoly->weight_dist /= avg_point_dist; + bpoly->weight_dist = powf(bpoly->weight_dist, data->falloff); + + /* Re-check for infinite weights, now that all scalings and interpolations are computed */ + if (bpoly->weight_dist < FLT_EPSILON) { + inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ; + inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST; + } + else if (bpoly->weight_dist_proj < FLT_EPSILON) { + inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ; + } + else if (bpoly->weight_angular < FLT_EPSILON) { + inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_ANGULAR; + } + } + } + else if (!(inf_weight_flags & MOD_SDEF_INFINITE_WEIGHT_DIST)) { + bpoly = bwdata->bind_polys; + + for (int i = 0; i < bwdata->numpoly; bpoly++, i++) { + /* Scale the point distance weight by average point distance, and introduce falloff */ + bpoly->weight_dist /= avg_point_dist; + bpoly->weight_dist = powf(bpoly->weight_dist, data->falloff); + + /* Re-check for infinite weights, now that all scalings and interpolations are computed */ + if (bpoly->weight_dist < FLT_EPSILON) { + inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST; + } + } + } + + /* Final loop, to compute actual weights */ + bpoly = bwdata->bind_polys; + + for (int i = 0; i < bwdata->numpoly; bpoly++, i++) { + /* Weight computation from components */ + if (inf_weight_flags & MOD_SDEF_INFINITE_WEIGHT_DIST) { + bpoly->weight = bpoly->weight_dist < FLT_EPSILON ? 1.0f : 0.0f; + } + else if (inf_weight_flags & MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ) { + bpoly->weight = bpoly->weight_dist_proj < FLT_EPSILON ? 1.0f / bpoly->weight_dist : 0.0f; + } + else if (inf_weight_flags & MOD_SDEF_INFINITE_WEIGHT_ANGULAR) { + bpoly->weight = bpoly->weight_angular < FLT_EPSILON ? + 1.0f / bpoly->weight_dist_proj / bpoly->weight_dist : + 0.0f; + } + else { + bpoly->weight = 1.0f / bpoly->weight_angular / bpoly->weight_dist_proj / bpoly->weight_dist; + } + + tot_weight += bpoly->weight; + } + + bpoly = bwdata->bind_polys; + + for (int i = 0; i < bwdata->numpoly; bpoly++, i++) { + bpoly->weight /= tot_weight; + + /* Evaluate if this poly is relevant to bind */ + /* Even though the weights should add up to 1.0, + * the losses of weights smaller than epsilon here + * should be negligible... */ + if (bpoly->weight >= FLT_EPSILON) { + if (bpoly->inside) { + bwdata->numbinds += 1; + } + else { + if (bpoly->dominant_angle_weight < FLT_EPSILON || + 1.0f - bpoly->dominant_angle_weight < FLT_EPSILON) { + bwdata->numbinds += 1; + } + else { + bwdata->numbinds += 2; + } + } + } + } + + return bwdata; } -BLI_INLINE float computeNormalDisplacement(const float point_co[3], const float point_co_proj[3], const float normal[3]) +BLI_INLINE float computeNormalDisplacement(const float point_co[3], + const float point_co_proj[3], + const float normal[3]) { - float disp_vec[3]; - float normal_dist; + float disp_vec[3]; + float normal_dist; - sub_v3_v3v3(disp_vec, point_co, point_co_proj); - normal_dist = len_v3(disp_vec); + sub_v3_v3v3(disp_vec, point_co, point_co_proj); + normal_dist = len_v3(disp_vec); - if (dot_v3v3(disp_vec, normal) < 0) { - normal_dist *= -1; - } + if (dot_v3v3(disp_vec, normal) < 0) { + normal_dist *= -1; + } - return normal_dist; + return normal_dist; } -static void bindVert( - void *__restrict userdata, - const int index, - const ParallelRangeTLS *__restrict UNUSED(tls)) +static void bindVert(void *__restrict userdata, + const int index, + const ParallelRangeTLS *__restrict UNUSED(tls)) { - SDefBindCalcData * const data = (SDefBindCalcData *)userdata; - float point_co[3]; - float point_co_proj[3]; - - SDefBindWeightData *bwdata; - SDefVert *sdvert = data->bind_verts + index; - SDefBindPoly *bpoly; - SDefBind *sdbind; - - if (data->success != MOD_SDEF_BIND_RESULT_SUCCESS) { - sdvert->binds = NULL; - sdvert->numbinds = 0; - return; - } - - copy_v3_v3(point_co, data->vertexCos[index]); - bwdata = computeBindWeights(data, point_co); - - if (bwdata == NULL) { - sdvert->binds = NULL; - sdvert->numbinds = 0; - return; - } - - sdvert->binds = MEM_calloc_arrayN(bwdata->numbinds, sizeof(*sdvert->binds), "SDefVertBindData"); - if (sdvert->binds == NULL) { - data->success = MOD_SDEF_BIND_RESULT_MEM_ERR; - sdvert->numbinds = 0; - return; - } - - sdvert->numbinds = bwdata->numbinds; - - sdbind = sdvert->binds; - - bpoly = bwdata->bind_polys; - - for (int i = 0; i < bwdata->numbinds; bpoly++) { - if (bpoly->weight >= FLT_EPSILON) { - if (bpoly->inside) { - const MLoop *loop = &data->mloop[bpoly->loopstart]; - - sdbind->influence = bpoly->weight; - sdbind->numverts = bpoly->numverts; - - sdbind->mode = MOD_SDEF_MODE_NGON; - sdbind->vert_weights = MEM_malloc_arrayN(bpoly->numverts, sizeof(*sdbind->vert_weights), "SDefNgonVertWeights"); - if (sdbind->vert_weights == NULL) { - data->success = MOD_SDEF_BIND_RESULT_MEM_ERR; - return; - } - - sdbind->vert_inds = MEM_malloc_arrayN(bpoly->numverts, sizeof(*sdbind->vert_inds), "SDefNgonVertInds"); - if (sdbind->vert_inds == NULL) { - data->success = MOD_SDEF_BIND_RESULT_MEM_ERR; - return; - } - - interp_weights_poly_v2(sdbind->vert_weights, bpoly->coords_v2, bpoly->numverts, bpoly->point_v2); - - /* Reproject vert based on weights and original poly verts, to reintroduce poly non-planarity */ - zero_v3(point_co_proj); - for (int j = 0; j < bpoly->numverts; j++, loop++) { - madd_v3_v3fl(point_co_proj, bpoly->coords[j], sdbind->vert_weights[j]); - sdbind->vert_inds[j] = loop->v; - } - - sdbind->normal_dist = computeNormalDisplacement(point_co, point_co_proj, bpoly->normal); - - sdbind++; - i++; - } - else { - float tmp_vec[3]; - float cent[3], norm[3]; - float v1[3], v2[3], v3[3]; - - if (1.0f - bpoly->dominant_angle_weight >= FLT_EPSILON) { - sdbind->influence = bpoly->weight * (1.0f - bpoly->dominant_angle_weight); - sdbind->numverts = bpoly->numverts; - - sdbind->mode = MOD_SDEF_MODE_CENTROID; - sdbind->vert_weights = MEM_malloc_arrayN(3, sizeof(*sdbind->vert_weights), "SDefCentVertWeights"); - if (sdbind->vert_weights == NULL) { - data->success = MOD_SDEF_BIND_RESULT_MEM_ERR; - return; - } - - sdbind->vert_inds = MEM_malloc_arrayN(bpoly->numverts, sizeof(*sdbind->vert_inds), "SDefCentVertInds"); - if (sdbind->vert_inds == NULL) { - data->success = MOD_SDEF_BIND_RESULT_MEM_ERR; - return; - } - - sortPolyVertsEdge(sdbind->vert_inds, &data->mloop[bpoly->loopstart], - bpoly->edge_inds[bpoly->dominant_edge], bpoly->numverts); - - copy_v3_v3(v1, data->targetCos[sdbind->vert_inds[0]]); - copy_v3_v3(v2, data->targetCos[sdbind->vert_inds[1]]); - copy_v3_v3(v3, bpoly->centroid); - - mid_v3_v3v3v3(cent, v1, v2, v3); - normal_tri_v3(norm, v1, v2, v3); - - add_v3_v3v3(tmp_vec, point_co, bpoly->normal); - - /* We are sure the line is not parallel to the plane. - * Checking return value just to avoid warning... */ - if (!isect_line_plane_v3(point_co_proj, point_co, tmp_vec, cent, norm)) { - BLI_assert(false); - } - - interp_weights_tri_v3(sdbind->vert_weights, v1, v2, v3, point_co_proj); - - sdbind->normal_dist = computeNormalDisplacement(point_co, point_co_proj, bpoly->normal); - - sdbind++; - i++; - } - - if (bpoly->dominant_angle_weight >= FLT_EPSILON) { - sdbind->influence = bpoly->weight * bpoly->dominant_angle_weight; - sdbind->numverts = bpoly->numverts; - - sdbind->mode = MOD_SDEF_MODE_LOOPTRI; - sdbind->vert_weights = MEM_malloc_arrayN(3, sizeof(*sdbind->vert_weights), "SDefTriVertWeights"); - if (sdbind->vert_weights == NULL) { - data->success = MOD_SDEF_BIND_RESULT_MEM_ERR; - return; - } - - sdbind->vert_inds = MEM_malloc_arrayN(bpoly->numverts, sizeof(*sdbind->vert_inds), "SDefTriVertInds"); - if (sdbind->vert_inds == NULL) { - data->success = MOD_SDEF_BIND_RESULT_MEM_ERR; - return; - } - - sortPolyVertsTri(sdbind->vert_inds, &data->mloop[bpoly->loopstart], bpoly->edge_vert_inds[0], bpoly->numverts); - - copy_v3_v3(v1, data->targetCos[sdbind->vert_inds[0]]); - copy_v3_v3(v2, data->targetCos[sdbind->vert_inds[1]]); - copy_v3_v3(v3, data->targetCos[sdbind->vert_inds[2]]); - - mid_v3_v3v3v3(cent, v1, v2, v3); - normal_tri_v3(norm, v1, v2, v3); - - add_v3_v3v3(tmp_vec, point_co, bpoly->normal); - - /* We are sure the line is not parallel to the plane. - * Checking return value just to avoid warning... */ - if (!isect_line_plane_v3(point_co_proj, point_co, tmp_vec, cent, norm)) { - BLI_assert(false); - } - - interp_weights_tri_v3(sdbind->vert_weights, v1, v2, v3, point_co_proj); - - sdbind->normal_dist = computeNormalDisplacement(point_co, point_co_proj, bpoly->normal); - - sdbind++; - i++; - } - } - } - } - - freeBindData(bwdata); + SDefBindCalcData *const data = (SDefBindCalcData *)userdata; + float point_co[3]; + float point_co_proj[3]; + + SDefBindWeightData *bwdata; + SDefVert *sdvert = data->bind_verts + index; + SDefBindPoly *bpoly; + SDefBind *sdbind; + + if (data->success != MOD_SDEF_BIND_RESULT_SUCCESS) { + sdvert->binds = NULL; + sdvert->numbinds = 0; + return; + } + + copy_v3_v3(point_co, data->vertexCos[index]); + bwdata = computeBindWeights(data, point_co); + + if (bwdata == NULL) { + sdvert->binds = NULL; + sdvert->numbinds = 0; + return; + } + + sdvert->binds = MEM_calloc_arrayN(bwdata->numbinds, sizeof(*sdvert->binds), "SDefVertBindData"); + if (sdvert->binds == NULL) { + data->success = MOD_SDEF_BIND_RESULT_MEM_ERR; + sdvert->numbinds = 0; + return; + } + + sdvert->numbinds = bwdata->numbinds; + + sdbind = sdvert->binds; + + bpoly = bwdata->bind_polys; + + for (int i = 0; i < bwdata->numbinds; bpoly++) { + if (bpoly->weight >= FLT_EPSILON) { + if (bpoly->inside) { + const MLoop *loop = &data->mloop[bpoly->loopstart]; + + sdbind->influence = bpoly->weight; + sdbind->numverts = bpoly->numverts; + + sdbind->mode = MOD_SDEF_MODE_NGON; + sdbind->vert_weights = MEM_malloc_arrayN( + bpoly->numverts, sizeof(*sdbind->vert_weights), "SDefNgonVertWeights"); + if (sdbind->vert_weights == NULL) { + data->success = MOD_SDEF_BIND_RESULT_MEM_ERR; + return; + } + + sdbind->vert_inds = MEM_malloc_arrayN( + bpoly->numverts, sizeof(*sdbind->vert_inds), "SDefNgonVertInds"); + if (sdbind->vert_inds == NULL) { + data->success = MOD_SDEF_BIND_RESULT_MEM_ERR; + return; + } + + interp_weights_poly_v2( + sdbind->vert_weights, bpoly->coords_v2, bpoly->numverts, bpoly->point_v2); + + /* Reproject vert based on weights and original poly verts, to reintroduce poly non-planarity */ + zero_v3(point_co_proj); + for (int j = 0; j < bpoly->numverts; j++, loop++) { + madd_v3_v3fl(point_co_proj, bpoly->coords[j], sdbind->vert_weights[j]); + sdbind->vert_inds[j] = loop->v; + } + + sdbind->normal_dist = computeNormalDisplacement(point_co, point_co_proj, bpoly->normal); + + sdbind++; + i++; + } + else { + float tmp_vec[3]; + float cent[3], norm[3]; + float v1[3], v2[3], v3[3]; + + if (1.0f - bpoly->dominant_angle_weight >= FLT_EPSILON) { + sdbind->influence = bpoly->weight * (1.0f - bpoly->dominant_angle_weight); + sdbind->numverts = bpoly->numverts; + + sdbind->mode = MOD_SDEF_MODE_CENTROID; + sdbind->vert_weights = MEM_malloc_arrayN( + 3, sizeof(*sdbind->vert_weights), "SDefCentVertWeights"); + if (sdbind->vert_weights == NULL) { + data->success = MOD_SDEF_BIND_RESULT_MEM_ERR; + return; + } + + sdbind->vert_inds = MEM_malloc_arrayN( + bpoly->numverts, sizeof(*sdbind->vert_inds), "SDefCentVertInds"); + if (sdbind->vert_inds == NULL) { + data->success = MOD_SDEF_BIND_RESULT_MEM_ERR; + return; + } + + sortPolyVertsEdge(sdbind->vert_inds, + &data->mloop[bpoly->loopstart], + bpoly->edge_inds[bpoly->dominant_edge], + bpoly->numverts); + + copy_v3_v3(v1, data->targetCos[sdbind->vert_inds[0]]); + copy_v3_v3(v2, data->targetCos[sdbind->vert_inds[1]]); + copy_v3_v3(v3, bpoly->centroid); + + mid_v3_v3v3v3(cent, v1, v2, v3); + normal_tri_v3(norm, v1, v2, v3); + + add_v3_v3v3(tmp_vec, point_co, bpoly->normal); + + /* We are sure the line is not parallel to the plane. + * Checking return value just to avoid warning... */ + if (!isect_line_plane_v3(point_co_proj, point_co, tmp_vec, cent, norm)) { + BLI_assert(false); + } + + interp_weights_tri_v3(sdbind->vert_weights, v1, v2, v3, point_co_proj); + + sdbind->normal_dist = computeNormalDisplacement(point_co, point_co_proj, bpoly->normal); + + sdbind++; + i++; + } + + if (bpoly->dominant_angle_weight >= FLT_EPSILON) { + sdbind->influence = bpoly->weight * bpoly->dominant_angle_weight; + sdbind->numverts = bpoly->numverts; + + sdbind->mode = MOD_SDEF_MODE_LOOPTRI; + sdbind->vert_weights = MEM_malloc_arrayN( + 3, sizeof(*sdbind->vert_weights), "SDefTriVertWeights"); + if (sdbind->vert_weights == NULL) { + data->success = MOD_SDEF_BIND_RESULT_MEM_ERR; + return; + } + + sdbind->vert_inds = MEM_malloc_arrayN( + bpoly->numverts, sizeof(*sdbind->vert_inds), "SDefTriVertInds"); + if (sdbind->vert_inds == NULL) { + data->success = MOD_SDEF_BIND_RESULT_MEM_ERR; + return; + } + + sortPolyVertsTri(sdbind->vert_inds, + &data->mloop[bpoly->loopstart], + bpoly->edge_vert_inds[0], + bpoly->numverts); + + copy_v3_v3(v1, data->targetCos[sdbind->vert_inds[0]]); + copy_v3_v3(v2, data->targetCos[sdbind->vert_inds[1]]); + copy_v3_v3(v3, data->targetCos[sdbind->vert_inds[2]]); + + mid_v3_v3v3v3(cent, v1, v2, v3); + normal_tri_v3(norm, v1, v2, v3); + + add_v3_v3v3(tmp_vec, point_co, bpoly->normal); + + /* We are sure the line is not parallel to the plane. + * Checking return value just to avoid warning... */ + if (!isect_line_plane_v3(point_co_proj, point_co, tmp_vec, cent, norm)) { + BLI_assert(false); + } + + interp_weights_tri_v3(sdbind->vert_weights, v1, v2, v3, point_co_proj); + + sdbind->normal_dist = computeNormalDisplacement(point_co, point_co_proj, bpoly->normal); + + sdbind++; + i++; + } + } + } + } + + freeBindData(bwdata); } -static bool surfacedeformBind( - SurfaceDeformModifierData *smd, float (*vertexCos)[3], - unsigned int numverts, unsigned int tnumpoly, unsigned int tnumverts, Mesh *target) +static bool surfacedeformBind(SurfaceDeformModifierData *smd, + float (*vertexCos)[3], + unsigned int numverts, + unsigned int tnumpoly, + unsigned int tnumverts, + Mesh *target) { - BVHTreeFromMesh treeData = {NULL}; - const MVert *mvert = target->mvert; - const MPoly *mpoly = target->mpoly; - const MEdge *medge = target->medge; - const MLoop *mloop = target->mloop; - unsigned int tnumedges = target->totedge; - int adj_result; - SDefAdjacencyArray *vert_edges; - SDefAdjacency *adj_array; - SDefEdgePolys *edge_polys; - - vert_edges = MEM_calloc_arrayN(tnumverts, sizeof(*vert_edges), "SDefVertEdgeMap"); - if (vert_edges == NULL) { - modifier_setError((ModifierData *)smd, "Out of memory"); - return false; - } - - adj_array = MEM_malloc_arrayN(tnumedges, 2 * sizeof(*adj_array), "SDefVertEdge"); - if (adj_array == NULL) { - modifier_setError((ModifierData *)smd, "Out of memory"); - MEM_freeN(vert_edges); - return false; - } - - edge_polys = MEM_calloc_arrayN(tnumedges, sizeof(*edge_polys), "SDefEdgeFaceMap"); - if (edge_polys == NULL) { - modifier_setError((ModifierData *)smd, "Out of memory"); - MEM_freeN(vert_edges); - MEM_freeN(adj_array); - return false; - } - - smd->verts = MEM_malloc_arrayN(numverts, sizeof(*smd->verts), "SDefBindVerts"); - if (smd->verts == NULL) { - modifier_setError((ModifierData *)smd, "Out of memory"); - freeAdjacencyMap(vert_edges, adj_array, edge_polys); - return false; - } - - BKE_bvhtree_from_mesh_get(&treeData, target, BVHTREE_FROM_LOOPTRI, 2); - if (treeData.tree == NULL) { - modifier_setError((ModifierData *)smd, "Out of memory"); - freeAdjacencyMap(vert_edges, adj_array, edge_polys); - MEM_freeN(smd->verts); - smd->verts = NULL; - return false; - } - - adj_result = buildAdjacencyMap(mpoly, medge, mloop, tnumpoly, tnumedges, vert_edges, adj_array, edge_polys); - - if (adj_result == MOD_SDEF_BIND_RESULT_NONMANY_ERR) { - modifier_setError((ModifierData *)smd, "Target has edges with more than two polygons"); - freeAdjacencyMap(vert_edges, adj_array, edge_polys); - free_bvhtree_from_mesh(&treeData); - MEM_freeN(smd->verts); - smd->verts = NULL; - return false; - } - - smd->numverts = numverts; - smd->numpoly = tnumpoly; - - SDefBindCalcData data = { - .treeData = &treeData, - .vert_edges = vert_edges, - .edge_polys = edge_polys, - .mpoly = mpoly, - .medge = medge, - .mloop = mloop, - .looptri = BKE_mesh_runtime_looptri_ensure(target), - .targetCos = MEM_malloc_arrayN(tnumverts, sizeof(float[3]), "SDefTargetBindVertArray"), - .bind_verts = smd->verts, - .vertexCos = vertexCos, - .falloff = smd->falloff, - .success = MOD_SDEF_BIND_RESULT_SUCCESS, - }; - - if (data.targetCos == NULL) { - modifier_setError((ModifierData *)smd, "Out of memory"); - freeData((ModifierData *)smd); - return false; - } - - invert_m4_m4(data.imat, smd->mat); - - for (int i = 0; i < tnumverts; i++) { - mul_v3_m4v3(data.targetCos[i], smd->mat, mvert[i].co); - } - - ParallelRangeSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = (numverts > 10000); - BLI_task_parallel_range(0, numverts, - &data, - bindVert, - &settings); - - MEM_freeN(data.targetCos); - - if (data.success == MOD_SDEF_BIND_RESULT_MEM_ERR) { - modifier_setError((ModifierData *)smd, "Out of memory"); - freeData((ModifierData *)smd); - } - else if (data.success == MOD_SDEF_BIND_RESULT_NONMANY_ERR) { - modifier_setError((ModifierData *)smd, "Target has edges with more than two polygons"); - freeData((ModifierData *)smd); - } - else if (data.success == MOD_SDEF_BIND_RESULT_CONCAVE_ERR) { - modifier_setError((ModifierData *)smd, "Target contains concave polygons"); - freeData((ModifierData *)smd); - } - else if (data.success == MOD_SDEF_BIND_RESULT_OVERLAP_ERR) { - modifier_setError((ModifierData *)smd, "Target contains overlapping verts"); - freeData((ModifierData *)smd); - } - else if (data.success == MOD_SDEF_BIND_RESULT_GENERIC_ERR) { - /* I know this message is vague, but I could not think of a way - * to explain this with a reasonably sized message. - * Though it shouldn't really matter all that much, - * because this is very unlikely to occur */ - modifier_setError((ModifierData *)smd, "Target contains invalid polygons"); - freeData((ModifierData *)smd); - } - - freeAdjacencyMap(vert_edges, adj_array, edge_polys); - free_bvhtree_from_mesh(&treeData); - - return data.success == 1; + BVHTreeFromMesh treeData = {NULL}; + const MVert *mvert = target->mvert; + const MPoly *mpoly = target->mpoly; + const MEdge *medge = target->medge; + const MLoop *mloop = target->mloop; + unsigned int tnumedges = target->totedge; + int adj_result; + SDefAdjacencyArray *vert_edges; + SDefAdjacency *adj_array; + SDefEdgePolys *edge_polys; + + vert_edges = MEM_calloc_arrayN(tnumverts, sizeof(*vert_edges), "SDefVertEdgeMap"); + if (vert_edges == NULL) { + modifier_setError((ModifierData *)smd, "Out of memory"); + return false; + } + + adj_array = MEM_malloc_arrayN(tnumedges, 2 * sizeof(*adj_array), "SDefVertEdge"); + if (adj_array == NULL) { + modifier_setError((ModifierData *)smd, "Out of memory"); + MEM_freeN(vert_edges); + return false; + } + + edge_polys = MEM_calloc_arrayN(tnumedges, sizeof(*edge_polys), "SDefEdgeFaceMap"); + if (edge_polys == NULL) { + modifier_setError((ModifierData *)smd, "Out of memory"); + MEM_freeN(vert_edges); + MEM_freeN(adj_array); + return false; + } + + smd->verts = MEM_malloc_arrayN(numverts, sizeof(*smd->verts), "SDefBindVerts"); + if (smd->verts == NULL) { + modifier_setError((ModifierData *)smd, "Out of memory"); + freeAdjacencyMap(vert_edges, adj_array, edge_polys); + return false; + } + + BKE_bvhtree_from_mesh_get(&treeData, target, BVHTREE_FROM_LOOPTRI, 2); + if (treeData.tree == NULL) { + modifier_setError((ModifierData *)smd, "Out of memory"); + freeAdjacencyMap(vert_edges, adj_array, edge_polys); + MEM_freeN(smd->verts); + smd->verts = NULL; + return false; + } + + adj_result = buildAdjacencyMap( + mpoly, medge, mloop, tnumpoly, tnumedges, vert_edges, adj_array, edge_polys); + + if (adj_result == MOD_SDEF_BIND_RESULT_NONMANY_ERR) { + modifier_setError((ModifierData *)smd, "Target has edges with more than two polygons"); + freeAdjacencyMap(vert_edges, adj_array, edge_polys); + free_bvhtree_from_mesh(&treeData); + MEM_freeN(smd->verts); + smd->verts = NULL; + return false; + } + + smd->numverts = numverts; + smd->numpoly = tnumpoly; + + SDefBindCalcData data = { + .treeData = &treeData, + .vert_edges = vert_edges, + .edge_polys = edge_polys, + .mpoly = mpoly, + .medge = medge, + .mloop = mloop, + .looptri = BKE_mesh_runtime_looptri_ensure(target), + .targetCos = MEM_malloc_arrayN(tnumverts, sizeof(float[3]), "SDefTargetBindVertArray"), + .bind_verts = smd->verts, + .vertexCos = vertexCos, + .falloff = smd->falloff, + .success = MOD_SDEF_BIND_RESULT_SUCCESS, + }; + + if (data.targetCos == NULL) { + modifier_setError((ModifierData *)smd, "Out of memory"); + freeData((ModifierData *)smd); + return false; + } + + invert_m4_m4(data.imat, smd->mat); + + for (int i = 0; i < tnumverts; i++) { + mul_v3_m4v3(data.targetCos[i], smd->mat, mvert[i].co); + } + + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (numverts > 10000); + BLI_task_parallel_range(0, numverts, &data, bindVert, &settings); + + MEM_freeN(data.targetCos); + + if (data.success == MOD_SDEF_BIND_RESULT_MEM_ERR) { + modifier_setError((ModifierData *)smd, "Out of memory"); + freeData((ModifierData *)smd); + } + else if (data.success == MOD_SDEF_BIND_RESULT_NONMANY_ERR) { + modifier_setError((ModifierData *)smd, "Target has edges with more than two polygons"); + freeData((ModifierData *)smd); + } + else if (data.success == MOD_SDEF_BIND_RESULT_CONCAVE_ERR) { + modifier_setError((ModifierData *)smd, "Target contains concave polygons"); + freeData((ModifierData *)smd); + } + else if (data.success == MOD_SDEF_BIND_RESULT_OVERLAP_ERR) { + modifier_setError((ModifierData *)smd, "Target contains overlapping verts"); + freeData((ModifierData *)smd); + } + else if (data.success == MOD_SDEF_BIND_RESULT_GENERIC_ERR) { + /* I know this message is vague, but I could not think of a way + * to explain this with a reasonably sized message. + * Though it shouldn't really matter all that much, + * because this is very unlikely to occur */ + modifier_setError((ModifierData *)smd, "Target contains invalid polygons"); + freeData((ModifierData *)smd); + } + + freeAdjacencyMap(vert_edges, adj_array, edge_polys); + free_bvhtree_from_mesh(&treeData); + + return data.success == 1; } -static void deformVert( - void *__restrict userdata, - const int index, - const ParallelRangeTLS *__restrict UNUSED(tls)) +static void deformVert(void *__restrict userdata, + const int index, + const ParallelRangeTLS *__restrict UNUSED(tls)) { - const SDefDeformData * const data = (SDefDeformData *)userdata; - const SDefBind *sdbind = data->bind_verts[index].binds; - float * const vertexCos = data->vertexCos[index]; - float norm[3], temp[3]; - - zero_v3(vertexCos); - - for (int j = 0; j < data->bind_verts[index].numbinds; j++, sdbind++) { - /* Mode-generic operations (allocate poly coordinates) */ - float (*coords)[3] = MEM_malloc_arrayN(sdbind->numverts, sizeof(*coords), "SDefDoPolyCoords"); - - for (int k = 0; k < sdbind->numverts; k++) { - copy_v3_v3(coords[k], data->targetCos[sdbind->vert_inds[k]]); - } - - normal_poly_v3(norm, coords, sdbind->numverts); - zero_v3(temp); - - /* ---------- looptri mode ---------- */ - if (sdbind->mode == MOD_SDEF_MODE_LOOPTRI) { - madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[0]], sdbind->vert_weights[0]); - madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[1]], sdbind->vert_weights[1]); - madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[2]], sdbind->vert_weights[2]); - } - else { - /* ---------- ngon mode ---------- */ - if (sdbind->mode == MOD_SDEF_MODE_NGON) { - for (int k = 0; k < sdbind->numverts; k++) { - madd_v3_v3fl(temp, coords[k], sdbind->vert_weights[k]); - } - } - - /* ---------- centroid mode ---------- */ - else if (sdbind->mode == MOD_SDEF_MODE_CENTROID) { - float cent[3]; - mid_v3_v3_array(cent, coords, sdbind->numverts); - - madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[0]], sdbind->vert_weights[0]); - madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[1]], sdbind->vert_weights[1]); - madd_v3_v3fl(temp, cent, sdbind->vert_weights[2]); - } - } - - MEM_freeN(coords); - - /* Apply normal offset (generic for all modes) */ - madd_v3_v3fl(temp, norm, sdbind->normal_dist); - - madd_v3_v3fl(vertexCos, temp, sdbind->influence); - } + const SDefDeformData *const data = (SDefDeformData *)userdata; + const SDefBind *sdbind = data->bind_verts[index].binds; + float *const vertexCos = data->vertexCos[index]; + float norm[3], temp[3]; + + zero_v3(vertexCos); + + for (int j = 0; j < data->bind_verts[index].numbinds; j++, sdbind++) { + /* Mode-generic operations (allocate poly coordinates) */ + float(*coords)[3] = MEM_malloc_arrayN(sdbind->numverts, sizeof(*coords), "SDefDoPolyCoords"); + + for (int k = 0; k < sdbind->numverts; k++) { + copy_v3_v3(coords[k], data->targetCos[sdbind->vert_inds[k]]); + } + + normal_poly_v3(norm, coords, sdbind->numverts); + zero_v3(temp); + + /* ---------- looptri mode ---------- */ + if (sdbind->mode == MOD_SDEF_MODE_LOOPTRI) { + madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[0]], sdbind->vert_weights[0]); + madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[1]], sdbind->vert_weights[1]); + madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[2]], sdbind->vert_weights[2]); + } + else { + /* ---------- ngon mode ---------- */ + if (sdbind->mode == MOD_SDEF_MODE_NGON) { + for (int k = 0; k < sdbind->numverts; k++) { + madd_v3_v3fl(temp, coords[k], sdbind->vert_weights[k]); + } + } + + /* ---------- centroid mode ---------- */ + else if (sdbind->mode == MOD_SDEF_MODE_CENTROID) { + float cent[3]; + mid_v3_v3_array(cent, coords, sdbind->numverts); + + madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[0]], sdbind->vert_weights[0]); + madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[1]], sdbind->vert_weights[1]); + madd_v3_v3fl(temp, cent, sdbind->vert_weights[2]); + } + } + + MEM_freeN(coords); + + /* Apply normal offset (generic for all modes) */ + madd_v3_v3fl(temp, norm, sdbind->normal_dist); + + madd_v3_v3fl(vertexCos, temp, sdbind->influence); + } } -static void surfacedeformModifier_do( - ModifierData *md, - const ModifierEvalContext *ctx, - float (*vertexCos)[3], unsigned int numverts, Object *ob) +static void surfacedeformModifier_do(ModifierData *md, + const ModifierEvalContext *ctx, + float (*vertexCos)[3], + unsigned int numverts, + Object *ob) { - SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md; - Mesh *target; - unsigned int tnumverts, tnumpoly; - - /* Exit function if bind flag is not set (free bind data if any). */ - if (!(smd->flags & MOD_SDEF_BIND)) { - if (smd->verts != NULL) { - if (!DEG_is_active(ctx->depsgraph)) { - modifier_setError(md, "Attempt to bind from inactive dependency graph"); - return; - } - ModifierData *md_orig = modifier_get_original(md); - freeData(md_orig); - } - return; - } - - Object *ob_target = smd->target; - target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target, false); - if (!target) { - modifier_setError(md, "No valid target mesh"); - return; - } - - tnumverts = target->totvert; - tnumpoly = target->totpoly; - - /* If not bound, execute bind. */ - if (smd->verts == NULL) { - if (!DEG_is_active(ctx->depsgraph)) { - modifier_setError(md, "Attempt to unbind from inactive dependency graph"); - return; - } - - SurfaceDeformModifierData *smd_orig = (SurfaceDeformModifierData *)modifier_get_original(md); - float tmp_mat[4][4]; - - invert_m4_m4(tmp_mat, ob->obmat); - mul_m4_m4m4(smd_orig->mat, tmp_mat, ob_target->obmat); - - if (!surfacedeformBind(smd_orig, vertexCos, numverts, tnumpoly, tnumverts, target)) { - smd->flags &= ~MOD_SDEF_BIND; - } - /* Early abort, this is binding 'call', no need to perform whole evaluation. */ - return; - } - - /* Poly count checks */ - if (smd->numverts != numverts) { - modifier_setError(md, "Verts changed from %u to %u", smd->numverts, numverts); - return; - } - else if (smd->numpoly != tnumpoly) { - modifier_setError(md, "Target polygons changed from %u to %u", smd->numpoly, tnumpoly); - return; - } - - /* Actual vertex location update starts here */ - SDefDeformData data = { - .bind_verts = smd->verts, - .targetCos = MEM_malloc_arrayN(tnumverts, sizeof(float[3]), "SDefTargetVertArray"), - .vertexCos = vertexCos, - }; - - if (data.targetCos != NULL) { - const MVert * const mvert = target->mvert; - - for (int i = 0; i < tnumverts; i++) { - mul_v3_m4v3(data.targetCos[i], smd->mat, mvert[i].co); - } - - ParallelRangeSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = (numverts > 10000); - BLI_task_parallel_range(0, numverts, - &data, - deformVert, - &settings); - - MEM_freeN(data.targetCos); - } + SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md; + Mesh *target; + unsigned int tnumverts, tnumpoly; + + /* Exit function if bind flag is not set (free bind data if any). */ + if (!(smd->flags & MOD_SDEF_BIND)) { + if (smd->verts != NULL) { + if (!DEG_is_active(ctx->depsgraph)) { + modifier_setError(md, "Attempt to bind from inactive dependency graph"); + return; + } + ModifierData *md_orig = modifier_get_original(md); + freeData(md_orig); + } + return; + } + + Object *ob_target = smd->target; + target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target, false); + if (!target) { + modifier_setError(md, "No valid target mesh"); + return; + } + + tnumverts = target->totvert; + tnumpoly = target->totpoly; + + /* If not bound, execute bind. */ + if (smd->verts == NULL) { + if (!DEG_is_active(ctx->depsgraph)) { + modifier_setError(md, "Attempt to unbind from inactive dependency graph"); + return; + } + + SurfaceDeformModifierData *smd_orig = (SurfaceDeformModifierData *)modifier_get_original(md); + float tmp_mat[4][4]; + + invert_m4_m4(tmp_mat, ob->obmat); + mul_m4_m4m4(smd_orig->mat, tmp_mat, ob_target->obmat); + + if (!surfacedeformBind(smd_orig, vertexCos, numverts, tnumpoly, tnumverts, target)) { + smd->flags &= ~MOD_SDEF_BIND; + } + /* Early abort, this is binding 'call', no need to perform whole evaluation. */ + return; + } + + /* Poly count checks */ + if (smd->numverts != numverts) { + modifier_setError(md, "Verts changed from %u to %u", smd->numverts, numverts); + return; + } + else if (smd->numpoly != tnumpoly) { + modifier_setError(md, "Target polygons changed from %u to %u", smd->numpoly, tnumpoly); + return; + } + + /* Actual vertex location update starts here */ + SDefDeformData data = { + .bind_verts = smd->verts, + .targetCos = MEM_malloc_arrayN(tnumverts, sizeof(float[3]), "SDefTargetVertArray"), + .vertexCos = vertexCos, + }; + + if (data.targetCos != NULL) { + const MVert *const mvert = target->mvert; + + for (int i = 0; i < tnumverts; i++) { + mul_v3_m4v3(data.targetCos[i], smd->mat, mvert[i].co); + } + + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (numverts > 10000); + BLI_task_parallel_range(0, numverts, &data, deformVert, &settings); + + MEM_freeN(data.targetCos); + } } -static void deformVerts( - ModifierData *md, const ModifierEvalContext *ctx, - Mesh *UNUSED(mesh), - float (*vertexCos)[3], int numVerts) +static void deformVerts(ModifierData *md, + const ModifierEvalContext *ctx, + Mesh *UNUSED(mesh), + float (*vertexCos)[3], + int numVerts) { - surfacedeformModifier_do(md, ctx, vertexCos, numVerts, ctx->object); + surfacedeformModifier_do(md, ctx, vertexCos, numVerts, ctx->object); } -static void deformVertsEM( - ModifierData *md, const ModifierEvalContext *ctx, - struct BMEditMesh *UNUSED(editData), - Mesh *UNUSED(mesh), - float (*vertexCos)[3], int numVerts) +static void deformVertsEM(ModifierData *md, + const ModifierEvalContext *ctx, + struct BMEditMesh *UNUSED(editData), + Mesh *UNUSED(mesh), + float (*vertexCos)[3], + int numVerts) { - surfacedeformModifier_do(md, ctx, vertexCos, numVerts, ctx->object); + surfacedeformModifier_do(md, ctx, vertexCos, numVerts, ctx->object); } static bool isDisabled(const Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams)) { - SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md; + SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md; - return smd->target == NULL && !(smd->verts != NULL && !(smd->flags & MOD_SDEF_BIND)); + return smd->target == NULL && !(smd->verts != NULL && !(smd->flags & MOD_SDEF_BIND)); } ModifierTypeInfo modifierType_SurfaceDeform = { - /* name */ "Surface Deform", - /* structName */ "SurfaceDeformModifierData", - /* structSize */ sizeof(SurfaceDeformModifierData), - /* type */ eModifierTypeType_OnlyDeform, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_SupportsEditmode, - - /* copyData */ copyData, - - /* deformVerts */ deformVerts, - /* deformMatrices */ NULL, - /* deformVertsEM */ deformVertsEM, - /* deformMatricesEM */ NULL, - /* applyModifier */ NULL, - - /* initData */ initData, - /* requiredDataMask */ NULL, - /* freeData */ freeData, - /* isDisabled */ isDisabled, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ foreachObjectLink, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Surface Deform", + /* structName */ "SurfaceDeformModifierData", + /* structSize */ sizeof(SurfaceDeformModifierData), + /* type */ eModifierTypeType_OnlyDeform, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsEditmode, + + /* copyData */ copyData, + + /* deformVerts */ deformVerts, + /* deformMatrices */ NULL, + /* deformVertsEM */ deformVertsEM, + /* deformMatricesEM */ NULL, + /* applyModifier */ NULL, + + /* initData */ initData, + /* requiredDataMask */ NULL, + /* freeData */ freeData, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c index 0b4de9c8d17..7d890b29365 100644 --- a/source/blender/modifiers/intern/MOD_triangulate.c +++ b/source/blender/modifiers/intern/MOD_triangulate.c @@ -34,114 +34,112 @@ #include "MOD_modifiertypes.h" -static Mesh *triangulate_mesh(Mesh *mesh, const int quad_method, const int ngon_method, const int min_vertices, const int flag) +static Mesh *triangulate_mesh(Mesh *mesh, + const int quad_method, + const int ngon_method, + const int min_vertices, + const int flag) { - Mesh *result; - BMesh *bm; - int total_edges, i; - MEdge *me; - CustomData_MeshMasks cddata_masks = {.vmask = CD_MASK_ORIGINDEX, .emask = CD_MASK_ORIGINDEX, .pmask = CD_MASK_ORIGINDEX}; + Mesh *result; + BMesh *bm; + int total_edges, i; + MEdge *me; + CustomData_MeshMasks cddata_masks = { + .vmask = CD_MASK_ORIGINDEX, .emask = CD_MASK_ORIGINDEX, .pmask = CD_MASK_ORIGINDEX}; - bool keep_clnors = (flag & MOD_TRIANGULATE_KEEP_CUSTOMLOOP_NORMALS) != 0; + bool keep_clnors = (flag & MOD_TRIANGULATE_KEEP_CUSTOMLOOP_NORMALS) != 0; - if (keep_clnors) { - BKE_mesh_calc_normals_split(mesh); - /* We need that one to 'survive' to/from BMesh conversions. */ - CustomData_clear_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY); - cddata_masks.lmask |= CD_MASK_NORMAL; - } + if (keep_clnors) { + BKE_mesh_calc_normals_split(mesh); + /* We need that one to 'survive' to/from BMesh conversions. */ + CustomData_clear_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY); + cddata_masks.lmask |= CD_MASK_NORMAL; + } - bm = BKE_mesh_to_bmesh_ex( - mesh, - &((struct BMeshCreateParams){0}), - &((struct BMeshFromMeshParams){ - .calc_face_normal = true, - .cd_mask_extra = cddata_masks, - })); + bm = BKE_mesh_to_bmesh_ex(mesh, + &((struct BMeshCreateParams){0}), + &((struct BMeshFromMeshParams){ + .calc_face_normal = true, + .cd_mask_extra = cddata_masks, + })); - BM_mesh_triangulate(bm, quad_method, ngon_method, min_vertices, false, NULL, NULL, NULL); + BM_mesh_triangulate(bm, quad_method, ngon_method, min_vertices, false, NULL, NULL, NULL); - result = BKE_mesh_from_bmesh_for_eval_nomain(bm, &cddata_masks); - BM_mesh_free(bm); + result = BKE_mesh_from_bmesh_for_eval_nomain(bm, &cddata_masks); + BM_mesh_free(bm); + if (keep_clnors) { + float(*lnors)[3] = CustomData_get_layer(&result->ldata, CD_NORMAL); + BLI_assert(lnors != NULL); - if (keep_clnors) { - float (*lnors)[3] = CustomData_get_layer(&result->ldata, CD_NORMAL); - BLI_assert(lnors != NULL); + BKE_mesh_set_custom_normals(result, lnors); - BKE_mesh_set_custom_normals(result, lnors); + /* Do some cleanup, we do not want those temp data to stay around. */ + CustomData_set_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY); + CustomData_set_layer_flag(&result->ldata, CD_NORMAL, CD_FLAG_TEMPORARY); + } - /* Do some cleanup, we do not want those temp data to stay around. */ - CustomData_set_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY); - CustomData_set_layer_flag(&result->ldata, CD_NORMAL, CD_FLAG_TEMPORARY); - } + total_edges = result->totedge; + me = result->medge; - total_edges = result->totedge; - me = result->medge; + /* force drawing of all edges (seems to be omitted in CDDM_from_bmesh) */ + for (i = 0; i < total_edges; i++, me++) { + me->flag |= ME_EDGEDRAW | ME_EDGERENDER; + } - /* force drawing of all edges (seems to be omitted in CDDM_from_bmesh) */ - for (i = 0; i < total_edges; i++, me++) { - me->flag |= ME_EDGEDRAW | ME_EDGERENDER; - } + result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; - result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; - - return result; + return result; } - static void initData(ModifierData *md) { - TriangulateModifierData *tmd = (TriangulateModifierData *)md; + TriangulateModifierData *tmd = (TriangulateModifierData *)md; - /* Enable in editmode by default */ - md->mode |= eModifierMode_Editmode; - tmd->quad_method = MOD_TRIANGULATE_QUAD_SHORTEDGE; - tmd->ngon_method = MOD_TRIANGULATE_NGON_BEAUTY; - tmd->min_vertices = 4; + /* Enable in editmode by default */ + md->mode |= eModifierMode_Editmode; + tmd->quad_method = MOD_TRIANGULATE_QUAD_SHORTEDGE; + tmd->ngon_method = MOD_TRIANGULATE_NGON_BEAUTY; + tmd->min_vertices = 4; } -static Mesh *applyModifier( - ModifierData *md, - const ModifierEvalContext *UNUSED(ctx), - Mesh *mesh) +static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *UNUSED(ctx), Mesh *mesh) { - TriangulateModifierData *tmd = (TriangulateModifierData *)md; - Mesh *result; - if (!(result = triangulate_mesh(mesh, tmd->quad_method, tmd->ngon_method, tmd->min_vertices, tmd->flag))) { - return mesh; - } - - return result; + TriangulateModifierData *tmd = (TriangulateModifierData *)md; + Mesh *result; + if (!(result = triangulate_mesh( + mesh, tmd->quad_method, tmd->ngon_method, tmd->min_vertices, tmd->flag))) { + return mesh; + } + + return result; } ModifierTypeInfo modifierType_Triangulate = { - /* name */ "Triangulate", - /* structName */ "TriangulateModifierData", - /* structSize */ sizeof(TriangulateModifierData), - /* type */ eModifierTypeType_Constructive, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_SupportsEditmode | - eModifierTypeFlag_SupportsMapping | - eModifierTypeFlag_EnableInEditmode | - eModifierTypeFlag_AcceptsCVs, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ initData, - /* requiredDataMask */ NULL, //requiredDataMask, - /* freeData */ NULL, - /* isDisabled */ NULL, - /* updateDepsgraph */ NULL, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ NULL, - /* foreachIDLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Triangulate", + /* structName */ "TriangulateModifierData", + /* structSize */ sizeof(TriangulateModifierData), + /* type */ eModifierTypeType_Constructive, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsEditmode | + eModifierTypeFlag_SupportsMapping | eModifierTypeFlag_EnableInEditmode | + eModifierTypeFlag_AcceptsCVs, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ initData, + /* requiredDataMask */ NULL, //requiredDataMask, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c index 1bb38001328..b23dff753f8 100644 --- a/source/blender/modifiers/intern/MOD_util.c +++ b/source/blender/modifiers/intern/MOD_util.c @@ -21,7 +21,6 @@ * \ingroup modifiers */ - #include #include "BLI_utildefines.h" @@ -59,245 +58,248 @@ void MOD_init_texture(MappingInfoModifierData *dmd, const ModifierEvalContext *ctx) { - Tex *tex = dmd->texture; + Tex *tex = dmd->texture; - if (tex == NULL) { - return; - } + if (tex == NULL) { + return; + } - if (tex->ima && BKE_image_is_animated(tex->ima)) { - BKE_image_user_frame_calc(&tex->iuser, DEG_get_ctime(ctx->depsgraph)); - } + if (tex->ima && BKE_image_is_animated(tex->ima)) { + BKE_image_user_frame_calc(&tex->iuser, DEG_get_ctime(ctx->depsgraph)); + } } /* TODO to be renamed to get_texture_coords once we are done with moving modifiers to Mesh. */ /** \param cos: may be NULL, in which case we use directly mesh vertices' coordinates. */ -void MOD_get_texture_coords( - MappingInfoModifierData *dmd, - const ModifierEvalContext *UNUSED(ctx), - Object *ob, - Mesh *mesh, - float (*cos)[3], - float (*r_texco)[3]) +void MOD_get_texture_coords(MappingInfoModifierData *dmd, + const ModifierEvalContext *UNUSED(ctx), + Object *ob, + Mesh *mesh, + float (*cos)[3], + float (*r_texco)[3]) { - const int numVerts = mesh->totvert; - int i; - int texmapping = dmd->texmapping; - float mapob_imat[4][4]; - - if (texmapping == MOD_DISP_MAP_OBJECT) { - if (dmd->map_object != NULL) { - Object *map_object = dmd->map_object; - invert_m4_m4(mapob_imat, map_object->obmat); - } - else {/* if there is no map object, default to local */ - texmapping = MOD_DISP_MAP_LOCAL; - } - } - - /* UVs need special handling, since they come from faces */ - if (texmapping == MOD_DISP_MAP_UV) { - if (CustomData_has_layer(&mesh->ldata, CD_MLOOPUV)) { - MPoly *mpoly = mesh->mpoly; - MPoly *mp; - MLoop *mloop = mesh->mloop; - BLI_bitmap *done = BLI_BITMAP_NEW(numVerts, __func__); - const int numPolys = mesh->totpoly; - char uvname[MAX_CUSTOMDATA_LAYER_NAME]; - MLoopUV *mloop_uv; - - CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPUV, dmd->uvlayer_name, uvname); - mloop_uv = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvname); - - /* verts are given the UV from the first face that uses them */ - for (i = 0, mp = mpoly; i < numPolys; ++i, ++mp) { - unsigned int fidx = mp->totloop - 1; - - do { - unsigned int lidx = mp->loopstart + fidx; - unsigned int vidx = mloop[lidx].v; - - if (!BLI_BITMAP_TEST(done, vidx)) { - /* remap UVs from [0, 1] to [-1, 1] */ - r_texco[vidx][0] = (mloop_uv[lidx].uv[0] * 2.0f) - 1.0f; - r_texco[vidx][1] = (mloop_uv[lidx].uv[1] * 2.0f) - 1.0f; - BLI_BITMAP_ENABLE(done, vidx); - } - - } while (fidx--); - } - - MEM_freeN(done); - return; - } - else { - /* if there are no UVs, default to local */ - texmapping = MOD_DISP_MAP_LOCAL; - } - } - - MVert *mv = mesh->mvert; - for (i = 0; i < numVerts; ++i, ++mv, ++r_texco) { - switch (texmapping) { - case MOD_DISP_MAP_LOCAL: - copy_v3_v3(*r_texco, cos != NULL ? *cos : mv->co); - break; - case MOD_DISP_MAP_GLOBAL: - mul_v3_m4v3(*r_texco, ob->obmat, cos != NULL ? *cos : mv->co); - break; - case MOD_DISP_MAP_OBJECT: - mul_v3_m4v3(*r_texco, ob->obmat, cos != NULL ? *cos : mv->co); - mul_m4_v3(mapob_imat, *r_texco); - break; - } - if (cos != NULL) { - cos++; - } - } + const int numVerts = mesh->totvert; + int i; + int texmapping = dmd->texmapping; + float mapob_imat[4][4]; + + if (texmapping == MOD_DISP_MAP_OBJECT) { + if (dmd->map_object != NULL) { + Object *map_object = dmd->map_object; + invert_m4_m4(mapob_imat, map_object->obmat); + } + else { /* if there is no map object, default to local */ + texmapping = MOD_DISP_MAP_LOCAL; + } + } + + /* UVs need special handling, since they come from faces */ + if (texmapping == MOD_DISP_MAP_UV) { + if (CustomData_has_layer(&mesh->ldata, CD_MLOOPUV)) { + MPoly *mpoly = mesh->mpoly; + MPoly *mp; + MLoop *mloop = mesh->mloop; + BLI_bitmap *done = BLI_BITMAP_NEW(numVerts, __func__); + const int numPolys = mesh->totpoly; + char uvname[MAX_CUSTOMDATA_LAYER_NAME]; + MLoopUV *mloop_uv; + + CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPUV, dmd->uvlayer_name, uvname); + mloop_uv = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvname); + + /* verts are given the UV from the first face that uses them */ + for (i = 0, mp = mpoly; i < numPolys; ++i, ++mp) { + unsigned int fidx = mp->totloop - 1; + + do { + unsigned int lidx = mp->loopstart + fidx; + unsigned int vidx = mloop[lidx].v; + + if (!BLI_BITMAP_TEST(done, vidx)) { + /* remap UVs from [0, 1] to [-1, 1] */ + r_texco[vidx][0] = (mloop_uv[lidx].uv[0] * 2.0f) - 1.0f; + r_texco[vidx][1] = (mloop_uv[lidx].uv[1] * 2.0f) - 1.0f; + BLI_BITMAP_ENABLE(done, vidx); + } + + } while (fidx--); + } + + MEM_freeN(done); + return; + } + else { + /* if there are no UVs, default to local */ + texmapping = MOD_DISP_MAP_LOCAL; + } + } + + MVert *mv = mesh->mvert; + for (i = 0; i < numVerts; ++i, ++mv, ++r_texco) { + switch (texmapping) { + case MOD_DISP_MAP_LOCAL: + copy_v3_v3(*r_texco, cos != NULL ? *cos : mv->co); + break; + case MOD_DISP_MAP_GLOBAL: + mul_v3_m4v3(*r_texco, ob->obmat, cos != NULL ? *cos : mv->co); + break; + case MOD_DISP_MAP_OBJECT: + mul_v3_m4v3(*r_texco, ob->obmat, cos != NULL ? *cos : mv->co); + mul_m4_v3(mapob_imat, *r_texco); + break; + } + if (cos != NULL) { + cos++; + } + } } void MOD_previous_vcos_store(ModifierData *md, float (*vertexCos)[3]) { - while ((md = md->next) && md->type == eModifierType_Armature) { - ArmatureModifierData *amd = (ArmatureModifierData *) md; - if (amd->multi && amd->prevCos == NULL) - amd->prevCos = MEM_dupallocN(vertexCos); - else - break; - } - /* lattice/mesh modifier too */ + while ((md = md->next) && md->type == eModifierType_Armature) { + ArmatureModifierData *amd = (ArmatureModifierData *)md; + if (amd->multi && amd->prevCos == NULL) + amd->prevCos = MEM_dupallocN(vertexCos); + else + break; + } + /* lattice/mesh modifier too */ } /* returns a mesh if mesh == NULL, for deforming modifiers that need it */ -Mesh *MOD_deform_mesh_eval_get( - Object *ob, struct BMEditMesh *em, Mesh *mesh, - float (*vertexCos)[3], const int num_verts, - const bool use_normals, const bool use_orco) +Mesh *MOD_deform_mesh_eval_get(Object *ob, + struct BMEditMesh *em, + Mesh *mesh, + float (*vertexCos)[3], + const int num_verts, + const bool use_normals, + const bool use_orco) { - if (mesh != NULL) { - /* pass */ - } - else if (ob->type == OB_MESH) { - if (em) { - mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL); - } - else { - /* TODO(sybren): after modifier conversion of DM to Mesh is done, check whether - * we really need a copy here. Maybe the CoW ob->data can be directly used. */ - Mesh *mesh_prior_modifiers = BKE_object_get_pre_modified_mesh(ob); - BKE_id_copy_ex( - NULL, &mesh_prior_modifiers->id, (ID **)&mesh, - (LIB_ID_COPY_LOCALIZE | - LIB_ID_COPY_CD_REFERENCE)); - mesh->runtime.deformed_only = 1; - } - - /* TODO(sybren): after modifier conversion of DM to Mesh is done, check whether - * we really need vertexCos here. */ - if (vertexCos) { - BKE_mesh_apply_vert_coords(mesh, vertexCos); - mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL; - } - - if (use_orco) { - CustomData_add_layer(&mesh->vdata, CD_ORCO, CD_ASSIGN, BKE_mesh_orco_verts_get(ob), mesh->totvert); - } - } - else if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { - /* TODO(sybren): get evaluated mesh from depsgraph once that's properly generated for curves. */ - mesh = BKE_mesh_new_nomain_from_curve(ob); - - /* Currently, that may not be the case everytime - * (texts e.g. tend to give issues, also when deforming curve points instead of generated curve geometry... ). */ - if (mesh != NULL && mesh->totvert != num_verts) { - BKE_id_free(NULL, mesh); - mesh = NULL; - } - } - - if (use_normals) { - if (LIKELY(mesh)) { - BKE_mesh_ensure_normals(mesh); - } - } - - BLI_assert(mesh == NULL || mesh->totvert == num_verts); - - return mesh; + if (mesh != NULL) { + /* pass */ + } + else if (ob->type == OB_MESH) { + if (em) { + mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL); + } + else { + /* TODO(sybren): after modifier conversion of DM to Mesh is done, check whether + * we really need a copy here. Maybe the CoW ob->data can be directly used. */ + Mesh *mesh_prior_modifiers = BKE_object_get_pre_modified_mesh(ob); + BKE_id_copy_ex(NULL, + &mesh_prior_modifiers->id, + (ID **)&mesh, + (LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_CD_REFERENCE)); + mesh->runtime.deformed_only = 1; + } + + /* TODO(sybren): after modifier conversion of DM to Mesh is done, check whether + * we really need vertexCos here. */ + if (vertexCos) { + BKE_mesh_apply_vert_coords(mesh, vertexCos); + mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + } + + if (use_orco) { + CustomData_add_layer( + &mesh->vdata, CD_ORCO, CD_ASSIGN, BKE_mesh_orco_verts_get(ob), mesh->totvert); + } + } + else if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { + /* TODO(sybren): get evaluated mesh from depsgraph once that's properly generated for curves. */ + mesh = BKE_mesh_new_nomain_from_curve(ob); + + /* Currently, that may not be the case everytime + * (texts e.g. tend to give issues, also when deforming curve points instead of generated curve geometry... ). */ + if (mesh != NULL && mesh->totvert != num_verts) { + BKE_id_free(NULL, mesh); + mesh = NULL; + } + } + + if (use_normals) { + if (LIKELY(mesh)) { + BKE_mesh_ensure_normals(mesh); + } + } + + BLI_assert(mesh == NULL || mesh->totvert == num_verts); + + return mesh; } -void MOD_get_vgroup(Object *ob, struct Mesh *mesh, const char *name, MDeformVert **dvert, int *defgrp_index) +void MOD_get_vgroup( + Object *ob, struct Mesh *mesh, const char *name, MDeformVert **dvert, int *defgrp_index) { - *defgrp_index = defgroup_name_index(ob, name); - *dvert = NULL; - - if (*defgrp_index != -1) { - if (ob->type == OB_LATTICE) - *dvert = BKE_lattice_deform_verts_get(ob); - else if (mesh) - *dvert = mesh->dvert; - } + *defgrp_index = defgroup_name_index(ob, name); + *dvert = NULL; + + if (*defgrp_index != -1) { + if (ob->type == OB_LATTICE) + *dvert = BKE_lattice_deform_verts_get(ob); + else if (mesh) + *dvert = mesh->dvert; + } } - /* only called by BKE_modifier.h/modifier.c */ void modifier_type_init(ModifierTypeInfo *types[]) { #define INIT_TYPE(typeName) (types[eModifierType_##typeName] = &modifierType_##typeName) - INIT_TYPE(None); - INIT_TYPE(Curve); - INIT_TYPE(Lattice); - INIT_TYPE(Subsurf); - INIT_TYPE(Build); - INIT_TYPE(Array); - INIT_TYPE(Mirror); - INIT_TYPE(EdgeSplit); - INIT_TYPE(Bevel); - INIT_TYPE(Displace); - INIT_TYPE(UVProject); - INIT_TYPE(Decimate); - INIT_TYPE(Smooth); - INIT_TYPE(Cast); - INIT_TYPE(Wave); - INIT_TYPE(Armature); - INIT_TYPE(Hook); - INIT_TYPE(Softbody); - INIT_TYPE(Cloth); - INIT_TYPE(Collision); - INIT_TYPE(Boolean); - INIT_TYPE(MeshDeform); - INIT_TYPE(Ocean); - INIT_TYPE(ParticleSystem); - INIT_TYPE(ParticleInstance); - INIT_TYPE(Explode); - INIT_TYPE(Shrinkwrap); - INIT_TYPE(Fluidsim); - INIT_TYPE(Mask); - INIT_TYPE(SimpleDeform); - INIT_TYPE(Multires); - INIT_TYPE(Surface); - INIT_TYPE(Smoke); - INIT_TYPE(ShapeKey); - INIT_TYPE(Solidify); - INIT_TYPE(Screw); - INIT_TYPE(Warp); - INIT_TYPE(WeightVGEdit); - INIT_TYPE(WeightVGMix); - INIT_TYPE(WeightVGProximity); - INIT_TYPE(DynamicPaint); - INIT_TYPE(Remesh); - INIT_TYPE(Skin); - INIT_TYPE(LaplacianSmooth); - INIT_TYPE(Triangulate); - INIT_TYPE(UVWarp); - INIT_TYPE(MeshCache); - INIT_TYPE(LaplacianDeform); - INIT_TYPE(Wireframe); - INIT_TYPE(DataTransfer); - INIT_TYPE(NormalEdit); - INIT_TYPE(CorrectiveSmooth); - INIT_TYPE(MeshSequenceCache); - INIT_TYPE(SurfaceDeform); - INIT_TYPE(WeightedNormal); + INIT_TYPE(None); + INIT_TYPE(Curve); + INIT_TYPE(Lattice); + INIT_TYPE(Subsurf); + INIT_TYPE(Build); + INIT_TYPE(Array); + INIT_TYPE(Mirror); + INIT_TYPE(EdgeSplit); + INIT_TYPE(Bevel); + INIT_TYPE(Displace); + INIT_TYPE(UVProject); + INIT_TYPE(Decimate); + INIT_TYPE(Smooth); + INIT_TYPE(Cast); + INIT_TYPE(Wave); + INIT_TYPE(Armature); + INIT_TYPE(Hook); + INIT_TYPE(Softbody); + INIT_TYPE(Cloth); + INIT_TYPE(Collision); + INIT_TYPE(Boolean); + INIT_TYPE(MeshDeform); + INIT_TYPE(Ocean); + INIT_TYPE(ParticleSystem); + INIT_TYPE(ParticleInstance); + INIT_TYPE(Explode); + INIT_TYPE(Shrinkwrap); + INIT_TYPE(Fluidsim); + INIT_TYPE(Mask); + INIT_TYPE(SimpleDeform); + INIT_TYPE(Multires); + INIT_TYPE(Surface); + INIT_TYPE(Smoke); + INIT_TYPE(ShapeKey); + INIT_TYPE(Solidify); + INIT_TYPE(Screw); + INIT_TYPE(Warp); + INIT_TYPE(WeightVGEdit); + INIT_TYPE(WeightVGMix); + INIT_TYPE(WeightVGProximity); + INIT_TYPE(DynamicPaint); + INIT_TYPE(Remesh); + INIT_TYPE(Skin); + INIT_TYPE(LaplacianSmooth); + INIT_TYPE(Triangulate); + INIT_TYPE(UVWarp); + INIT_TYPE(MeshCache); + INIT_TYPE(LaplacianDeform); + INIT_TYPE(Wireframe); + INIT_TYPE(DataTransfer); + INIT_TYPE(NormalEdit); + INIT_TYPE(CorrectiveSmooth); + INIT_TYPE(MeshSequenceCache); + INIT_TYPE(SurfaceDeform); + INIT_TYPE(WeightedNormal); #undef INIT_TYPE } diff --git a/source/blender/modifiers/intern/MOD_util.h b/source/blender/modifiers/intern/MOD_util.h index 2325f865d6a..ba3ca44c026 100644 --- a/source/blender/modifiers/intern/MOD_util.h +++ b/source/blender/modifiers/intern/MOD_util.h @@ -18,7 +18,6 @@ * \ingroup modifiers */ - #ifndef __MOD_UTIL_H__ #define __MOD_UTIL_H__ @@ -36,23 +35,27 @@ struct Scene; struct Tex; void MOD_init_texture(struct MappingInfoModifierData *dmd, const struct ModifierEvalContext *ctx); -void MOD_get_texture_coords( - struct MappingInfoModifierData *dmd, - const struct ModifierEvalContext *ctx, - struct Object *ob, - struct Mesh *mesh, - float (*cos)[3], - float (*r_texco)[3]); +void MOD_get_texture_coords(struct MappingInfoModifierData *dmd, + const struct ModifierEvalContext *ctx, + struct Object *ob, + struct Mesh *mesh, + float (*cos)[3], + float (*r_texco)[3]); void MOD_previous_vcos_store(struct ModifierData *md, float (*vertexCos)[3]); -struct Mesh *MOD_deform_mesh_eval_get( - struct Object *ob, struct BMEditMesh *em, struct Mesh *mesh, - float (*vertexCos)[3], const int num_verts, - const bool use_normals, const bool use_orco); - -void MOD_get_vgroup( - struct Object *ob, struct Mesh *mesh, - const char *name, struct MDeformVert **dvert, int *defgrp_index); +struct Mesh *MOD_deform_mesh_eval_get(struct Object *ob, + struct BMEditMesh *em, + struct Mesh *mesh, + float (*vertexCos)[3], + const int num_verts, + const bool use_normals, + const bool use_orco); + +void MOD_get_vgroup(struct Object *ob, + struct Mesh *mesh, + const char *name, + struct MDeformVert **dvert, + int *defgrp_index); #endif /* __MOD_UTIL_H__ */ diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c index 06cd7a80494..5a9c115dc12 100644 --- a/source/blender/modifiers/intern/MOD_uvproject.c +++ b/source/blender/modifiers/intern/MOD_uvproject.c @@ -21,7 +21,6 @@ * \ingroup modifiers */ - /* UV Project modifier: Generates UVs projected from an object */ #include "BLI_utildefines.h" @@ -49,295 +48,290 @@ static void initData(ModifierData *md) { - UVProjectModifierData *umd = (UVProjectModifierData *) md; - + UVProjectModifierData *umd = (UVProjectModifierData *)md; - umd->num_projectors = 1; - umd->aspectx = umd->aspecty = 1.0f; - umd->scalex = umd->scaley = 1.0f; + umd->num_projectors = 1; + umd->aspectx = umd->aspecty = 1.0f; + umd->scalex = umd->scaley = 1.0f; } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *UNUSED(md), CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *UNUSED(md), + CustomData_MeshMasks *r_cddata_masks) { - /* ask for UV coordinates */ - r_cddata_masks->lmask |= CD_MLOOPUV; + /* ask for UV coordinates */ + r_cddata_masks->lmask |= CD_MLOOPUV; } -static void foreachObjectLink( - ModifierData *md, Object *ob, - ObjectWalkFunc walk, void *userData) +static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) { - UVProjectModifierData *umd = (UVProjectModifierData *) md; - int i; + UVProjectModifierData *umd = (UVProjectModifierData *)md; + int i; - for (i = 0; i < MOD_UVPROJECT_MAXPROJECTORS; ++i) - walk(userData, ob, &umd->projectors[i], IDWALK_CB_NOP); + for (i = 0; i < MOD_UVPROJECT_MAXPROJECTORS; ++i) + walk(userData, ob, &umd->projectors[i], IDWALK_CB_NOP); } -static void foreachIDLink( - ModifierData *md, Object *ob, - IDWalkFunc walk, void *userData) +static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData) { #if 0 - UVProjectModifierData *umd = (UVProjectModifierData *) md; + UVProjectModifierData *umd = (UVProjectModifierData *) md; #endif - foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData); + foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData); } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { - UVProjectModifierData *umd = (UVProjectModifierData *)md; - bool do_add_own_transform = false; - for (int i = 0; i < umd->num_projectors; ++i) { - if (umd->projectors[i] != NULL) { - DEG_add_object_relation(ctx->node, umd->projectors[i], DEG_OB_COMP_TRANSFORM, "UV Project Modifier"); - do_add_own_transform = true; - } - } - if (do_add_own_transform) { - DEG_add_modifier_to_transform_relation(ctx->node, "UV Project Modifier"); - } + UVProjectModifierData *umd = (UVProjectModifierData *)md; + bool do_add_own_transform = false; + for (int i = 0; i < umd->num_projectors; ++i) { + if (umd->projectors[i] != NULL) { + DEG_add_object_relation( + ctx->node, umd->projectors[i], DEG_OB_COMP_TRANSFORM, "UV Project Modifier"); + do_add_own_transform = true; + } + } + if (do_add_own_transform) { + DEG_add_modifier_to_transform_relation(ctx->node, "UV Project Modifier"); + } } typedef struct Projector { - Object *ob; /* object this projector is derived from */ - float projmat[4][4]; /* projection matrix */ - float normal[3]; /* projector normal in world space */ - void *uci; /* optional uv-project info (panorama projection) */ + Object *ob; /* object this projector is derived from */ + float projmat[4][4]; /* projection matrix */ + float normal[3]; /* projector normal in world space */ + void *uci; /* optional uv-project info (panorama projection) */ } Projector; -static Mesh *uvprojectModifier_do( - UVProjectModifierData *umd, - const ModifierEvalContext *UNUSED(ctx), - Object *ob, Mesh *mesh) +static Mesh *uvprojectModifier_do(UVProjectModifierData *umd, + const ModifierEvalContext *UNUSED(ctx), + Object *ob, + Mesh *mesh) { - float (*coords)[3], (*co)[3]; - MLoopUV *mloop_uv; - int i, numVerts, numPolys, numLoops; - MPoly *mpoly, *mp; - MLoop *mloop; - Projector projectors[MOD_UVPROJECT_MAXPROJECTORS]; - int num_projectors = 0; - char uvname[MAX_CUSTOMDATA_LAYER_NAME]; - float aspx = umd->aspectx ? umd->aspectx : 1.0f; - float aspy = umd->aspecty ? umd->aspecty : 1.0f; - float scax = umd->scalex ? umd->scalex : 1.0f; - float scay = umd->scaley ? umd->scaley : 1.0f; - int free_uci = 0; - - for (i = 0; i < umd->num_projectors; ++i) { - if (umd->projectors[i] != NULL) { - projectors[num_projectors++].ob = umd->projectors[i]; - } - } - - if (num_projectors == 0) - return mesh; - - /* make sure there are UV Maps available */ - - if (!CustomData_has_layer(&mesh->ldata, CD_MLOOPUV)) return mesh; - - /* make sure we're using an existing layer */ - CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPUV, umd->uvlayer_name, uvname); - - /* calculate a projection matrix and normal for each projector */ - for (i = 0; i < num_projectors; ++i) { - float tmpmat[4][4]; - float offsetmat[4][4]; - Camera *cam = NULL; - /* calculate projection matrix */ - invert_m4_m4(projectors[i].projmat, projectors[i].ob->obmat); - - projectors[i].uci = NULL; - - if (projectors[i].ob->type == OB_CAMERA) { - cam = (Camera *)projectors[i].ob->data; - if (cam->type == CAM_PANO) { - projectors[i].uci = BLI_uvproject_camera_info(projectors[i].ob, NULL, aspx, aspy); - BLI_uvproject_camera_info_scale(projectors[i].uci, scax, scay); - free_uci = 1; - } - else { - CameraParams params; - - /* setup parameters */ - BKE_camera_params_init(¶ms); - BKE_camera_params_from_object(¶ms, projectors[i].ob); - - /* compute matrix, viewplane, .. */ - BKE_camera_params_compute_viewplane(¶ms, 1, 1, aspx, aspy); - - /* scale the view-plane */ - params.viewplane.xmin *= scax; - params.viewplane.xmax *= scax; - params.viewplane.ymin *= scay; - params.viewplane.ymax *= scay; - - BKE_camera_params_compute_matrix(¶ms); - mul_m4_m4m4(tmpmat, params.winmat, projectors[i].projmat); - } - } - else { - copy_m4_m4(tmpmat, projectors[i].projmat); - } - - unit_m4(offsetmat); - mul_mat3_m4_fl(offsetmat, 0.5); - offsetmat[3][0] = offsetmat[3][1] = offsetmat[3][2] = 0.5; - - mul_m4_m4m4(projectors[i].projmat, offsetmat, tmpmat); - - /* calculate worldspace projector normal (for best projector test) */ - projectors[i].normal[0] = 0; - projectors[i].normal[1] = 0; - projectors[i].normal[2] = 1; - mul_mat3_m4_v3(projectors[i].ob->obmat, projectors[i].normal); - } - - numPolys = mesh->totpoly; - numLoops = mesh->totloop; - - /* make sure we are not modifying the original UV map */ - mloop_uv = CustomData_duplicate_referenced_layer_named(&mesh->ldata, - CD_MLOOPUV, uvname, numLoops); - - coords = BKE_mesh_vertexCos_get(mesh, &numVerts); - - /* convert coords to world space */ - for (i = 0, co = coords; i < numVerts; ++i, ++co) - mul_m4_v3(ob->obmat, *co); - - /* if only one projector, project coords to UVs */ - if (num_projectors == 1 && projectors[0].uci == NULL) - for (i = 0, co = coords; i < numVerts; ++i, ++co) - mul_project_m4_v3(projectors[0].projmat, *co); - - mpoly = mesh->mpoly; - mloop = mesh->mloop; - - /* apply coords as UVs */ - for (i = 0, mp = mpoly; i < numPolys; ++i, ++mp) { - if (num_projectors == 1) { - if (projectors[0].uci) { - unsigned int fidx = mp->totloop - 1; - do { - unsigned int lidx = mp->loopstart + fidx; - unsigned int vidx = mloop[lidx].v; - BLI_uvproject_from_camera(mloop_uv[lidx].uv, coords[vidx], projectors[0].uci); - } while (fidx--); - } - else { - /* apply transformed coords as UVs */ - unsigned int fidx = mp->totloop - 1; - do { - unsigned int lidx = mp->loopstart + fidx; - unsigned int vidx = mloop[lidx].v; - copy_v2_v2(mloop_uv[lidx].uv, coords[vidx]); - } while (fidx--); - } - } - else { - /* multiple projectors, select the closest to face normal direction */ - float face_no[3]; - int j; - Projector *best_projector; - float best_dot; - - /* get the untransformed face normal */ - BKE_mesh_calc_poly_normal_coords(mp, mloop + mp->loopstart, (const float (*)[3])coords, face_no); - - /* find the projector which the face points at most directly - * (projector normal with largest dot product is best) - */ - best_dot = dot_v3v3(projectors[0].normal, face_no); - best_projector = &projectors[0]; - - for (j = 1; j < num_projectors; ++j) { - float tmp_dot = dot_v3v3(projectors[j].normal, face_no); - if (tmp_dot > best_dot) { - best_dot = tmp_dot; - best_projector = &projectors[j]; - } - } - - if (best_projector->uci) { - unsigned int fidx = mp->totloop - 1; - do { - unsigned int lidx = mp->loopstart + fidx; - unsigned int vidx = mloop[lidx].v; - BLI_uvproject_from_camera(mloop_uv[lidx].uv, coords[vidx], best_projector->uci); - } while (fidx--); - } - else { - unsigned int fidx = mp->totloop - 1; - do { - unsigned int lidx = mp->loopstart + fidx; - unsigned int vidx = mloop[lidx].v; - mul_v2_project_m4_v3(mloop_uv[lidx].uv, best_projector->projmat, coords[vidx]); - } while (fidx--); - } - } - } - - MEM_freeN(coords); - - if (free_uci) { - int j; - for (j = 0; j < num_projectors; ++j) { - if (projectors[j].uci) { - MEM_freeN(projectors[j].uci); - } - } - } - - /* Mark tessellated CD layers as dirty. */ - mesh->runtime.cd_dirty_vert |= CD_MASK_TESSLOOPNORMAL; - - return mesh; + float(*coords)[3], (*co)[3]; + MLoopUV *mloop_uv; + int i, numVerts, numPolys, numLoops; + MPoly *mpoly, *mp; + MLoop *mloop; + Projector projectors[MOD_UVPROJECT_MAXPROJECTORS]; + int num_projectors = 0; + char uvname[MAX_CUSTOMDATA_LAYER_NAME]; + float aspx = umd->aspectx ? umd->aspectx : 1.0f; + float aspy = umd->aspecty ? umd->aspecty : 1.0f; + float scax = umd->scalex ? umd->scalex : 1.0f; + float scay = umd->scaley ? umd->scaley : 1.0f; + int free_uci = 0; + + for (i = 0; i < umd->num_projectors; ++i) { + if (umd->projectors[i] != NULL) { + projectors[num_projectors++].ob = umd->projectors[i]; + } + } + + if (num_projectors == 0) + return mesh; + + /* make sure there are UV Maps available */ + + if (!CustomData_has_layer(&mesh->ldata, CD_MLOOPUV)) + return mesh; + + /* make sure we're using an existing layer */ + CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPUV, umd->uvlayer_name, uvname); + + /* calculate a projection matrix and normal for each projector */ + for (i = 0; i < num_projectors; ++i) { + float tmpmat[4][4]; + float offsetmat[4][4]; + Camera *cam = NULL; + /* calculate projection matrix */ + invert_m4_m4(projectors[i].projmat, projectors[i].ob->obmat); + + projectors[i].uci = NULL; + + if (projectors[i].ob->type == OB_CAMERA) { + cam = (Camera *)projectors[i].ob->data; + if (cam->type == CAM_PANO) { + projectors[i].uci = BLI_uvproject_camera_info(projectors[i].ob, NULL, aspx, aspy); + BLI_uvproject_camera_info_scale(projectors[i].uci, scax, scay); + free_uci = 1; + } + else { + CameraParams params; + + /* setup parameters */ + BKE_camera_params_init(¶ms); + BKE_camera_params_from_object(¶ms, projectors[i].ob); + + /* compute matrix, viewplane, .. */ + BKE_camera_params_compute_viewplane(¶ms, 1, 1, aspx, aspy); + + /* scale the view-plane */ + params.viewplane.xmin *= scax; + params.viewplane.xmax *= scax; + params.viewplane.ymin *= scay; + params.viewplane.ymax *= scay; + + BKE_camera_params_compute_matrix(¶ms); + mul_m4_m4m4(tmpmat, params.winmat, projectors[i].projmat); + } + } + else { + copy_m4_m4(tmpmat, projectors[i].projmat); + } + + unit_m4(offsetmat); + mul_mat3_m4_fl(offsetmat, 0.5); + offsetmat[3][0] = offsetmat[3][1] = offsetmat[3][2] = 0.5; + + mul_m4_m4m4(projectors[i].projmat, offsetmat, tmpmat); + + /* calculate worldspace projector normal (for best projector test) */ + projectors[i].normal[0] = 0; + projectors[i].normal[1] = 0; + projectors[i].normal[2] = 1; + mul_mat3_m4_v3(projectors[i].ob->obmat, projectors[i].normal); + } + + numPolys = mesh->totpoly; + numLoops = mesh->totloop; + + /* make sure we are not modifying the original UV map */ + mloop_uv = CustomData_duplicate_referenced_layer_named( + &mesh->ldata, CD_MLOOPUV, uvname, numLoops); + + coords = BKE_mesh_vertexCos_get(mesh, &numVerts); + + /* convert coords to world space */ + for (i = 0, co = coords; i < numVerts; ++i, ++co) + mul_m4_v3(ob->obmat, *co); + + /* if only one projector, project coords to UVs */ + if (num_projectors == 1 && projectors[0].uci == NULL) + for (i = 0, co = coords; i < numVerts; ++i, ++co) + mul_project_m4_v3(projectors[0].projmat, *co); + + mpoly = mesh->mpoly; + mloop = mesh->mloop; + + /* apply coords as UVs */ + for (i = 0, mp = mpoly; i < numPolys; ++i, ++mp) { + if (num_projectors == 1) { + if (projectors[0].uci) { + unsigned int fidx = mp->totloop - 1; + do { + unsigned int lidx = mp->loopstart + fidx; + unsigned int vidx = mloop[lidx].v; + BLI_uvproject_from_camera(mloop_uv[lidx].uv, coords[vidx], projectors[0].uci); + } while (fidx--); + } + else { + /* apply transformed coords as UVs */ + unsigned int fidx = mp->totloop - 1; + do { + unsigned int lidx = mp->loopstart + fidx; + unsigned int vidx = mloop[lidx].v; + copy_v2_v2(mloop_uv[lidx].uv, coords[vidx]); + } while (fidx--); + } + } + else { + /* multiple projectors, select the closest to face normal direction */ + float face_no[3]; + int j; + Projector *best_projector; + float best_dot; + + /* get the untransformed face normal */ + BKE_mesh_calc_poly_normal_coords( + mp, mloop + mp->loopstart, (const float(*)[3])coords, face_no); + + /* find the projector which the face points at most directly + * (projector normal with largest dot product is best) + */ + best_dot = dot_v3v3(projectors[0].normal, face_no); + best_projector = &projectors[0]; + + for (j = 1; j < num_projectors; ++j) { + float tmp_dot = dot_v3v3(projectors[j].normal, face_no); + if (tmp_dot > best_dot) { + best_dot = tmp_dot; + best_projector = &projectors[j]; + } + } + + if (best_projector->uci) { + unsigned int fidx = mp->totloop - 1; + do { + unsigned int lidx = mp->loopstart + fidx; + unsigned int vidx = mloop[lidx].v; + BLI_uvproject_from_camera(mloop_uv[lidx].uv, coords[vidx], best_projector->uci); + } while (fidx--); + } + else { + unsigned int fidx = mp->totloop - 1; + do { + unsigned int lidx = mp->loopstart + fidx; + unsigned int vidx = mloop[lidx].v; + mul_v2_project_m4_v3(mloop_uv[lidx].uv, best_projector->projmat, coords[vidx]); + } while (fidx--); + } + } + } + + MEM_freeN(coords); + + if (free_uci) { + int j; + for (j = 0; j < num_projectors; ++j) { + if (projectors[j].uci) { + MEM_freeN(projectors[j].uci); + } + } + } + + /* Mark tessellated CD layers as dirty. */ + mesh->runtime.cd_dirty_vert |= CD_MASK_TESSLOOPNORMAL; + + return mesh; } -static Mesh *applyModifier( - ModifierData *md, const ModifierEvalContext *ctx, - Mesh *mesh) +static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) { - Mesh *result; - UVProjectModifierData *umd = (UVProjectModifierData *) md; + Mesh *result; + UVProjectModifierData *umd = (UVProjectModifierData *)md; - result = uvprojectModifier_do(umd, ctx, ctx->object, mesh); + result = uvprojectModifier_do(umd, ctx, ctx->object, mesh); - return result; + return result; } - ModifierTypeInfo modifierType_UVProject = { - /* name */ "UVProject", - /* structName */ "UVProjectModifierData", - /* structSize */ sizeof(UVProjectModifierData), - /* type */ eModifierTypeType_NonGeometrical, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_SupportsMapping | - eModifierTypeFlag_SupportsEditmode | - eModifierTypeFlag_EnableInEditmode, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ NULL, - /* isDisabled */ NULL, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ foreachObjectLink, - /* foreachIDLink */ foreachIDLink, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "UVProject", + /* structName */ "UVProjectModifierData", + /* structSize */ sizeof(UVProjectModifierData), + /* type */ eModifierTypeType_NonGeometrical, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping | + eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ foreachIDLink, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_uvwarp.c b/source/blender/modifiers/intern/MOD_uvwarp.c index a850bb34111..83b9a8e1804 100644 --- a/source/blender/modifiers/intern/MOD_uvwarp.c +++ b/source/blender/modifiers/intern/MOD_uvwarp.c @@ -29,7 +29,7 @@ #include "DNA_meshdata_types.h" #include "DNA_object_types.h" -#include "BKE_action.h" /* BKE_pose_channel_find_name */ +#include "BKE_action.h" /* BKE_pose_channel_find_name */ #include "BKE_deform.h" #include "BKE_library_query.h" #include "BKE_modifier.h" @@ -38,238 +38,236 @@ #include "MOD_util.h" - static void uv_warp_from_mat4_pair( - float uv_dst[2], const float uv_src[2], float warp_mat[4][4], - int axis_u, int axis_v) + float uv_dst[2], const float uv_src[2], float warp_mat[4][4], int axis_u, int axis_v) { - float tuv[3] = {0.0f}; + float tuv[3] = {0.0f}; - tuv[axis_u] = uv_src[0]; - tuv[axis_v] = uv_src[1]; + tuv[axis_u] = uv_src[0]; + tuv[axis_v] = uv_src[1]; - mul_m4_v3(warp_mat, tuv); + mul_m4_v3(warp_mat, tuv); - uv_dst[0] = tuv[axis_u]; - uv_dst[1] = tuv[axis_v]; + uv_dst[0] = tuv[axis_u]; + uv_dst[1] = tuv[axis_v]; } static void initData(ModifierData *md) { - UVWarpModifierData *umd = (UVWarpModifierData *) md; - umd->axis_u = 0; - umd->axis_v = 1; - copy_v2_fl(umd->center, 0.5f); + UVWarpModifierData *umd = (UVWarpModifierData *)md; + umd->axis_u = 0; + umd->axis_v = 1; + copy_v2_fl(umd->center, 0.5f); } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - UVWarpModifierData *umd = (UVWarpModifierData *)md; + UVWarpModifierData *umd = (UVWarpModifierData *)md; - /* ask for vertexgroups if we need them */ - if (umd->vgroup_name[0] != '\0') { - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; - } + /* ask for vertexgroups if we need them */ + if (umd->vgroup_name[0] != '\0') { + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + } } static void matrix_from_obj_pchan(float mat[4][4], Object *ob, const char *bonename) { - bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, bonename); - if (pchan) { - mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat); - } - else { - copy_m4_m4(mat, ob->obmat); - } + bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, bonename); + if (pchan) { + mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat); + } + else { + copy_m4_m4(mat, ob->obmat); + } } typedef struct UVWarpData { - MPoly *mpoly; - MLoop *mloop; - MLoopUV *mloopuv; + MPoly *mpoly; + MLoop *mloop; + MLoopUV *mloopuv; - MDeformVert *dvert; - int defgrp_index; + MDeformVert *dvert; + int defgrp_index; - float (*warp_mat)[4]; - int axis_u; - int axis_v; + float (*warp_mat)[4]; + int axis_u; + int axis_v; } UVWarpData; -static void uv_warp_compute( - void *__restrict userdata, - const int i, - const ParallelRangeTLS *__restrict UNUSED(tls)) +static void uv_warp_compute(void *__restrict userdata, + const int i, + const ParallelRangeTLS *__restrict UNUSED(tls)) { - const UVWarpData *data = userdata; - - const MPoly *mp = &data->mpoly[i]; - const MLoop *ml = &data->mloop[mp->loopstart]; - MLoopUV *mluv = &data->mloopuv[mp->loopstart]; - - const MDeformVert *dvert = data->dvert; - const int defgrp_index = data->defgrp_index; - - float (*warp_mat)[4] = data->warp_mat; - const int axis_u = data->axis_u; - const int axis_v = data->axis_v; - - int l; - - if (dvert) { - for (l = 0; l < mp->totloop; l++, ml++, mluv++) { - float uv[2]; - 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 { - for (l = 0; l < mp->totloop; l++, ml++, mluv++) { - uv_warp_from_mat4_pair(mluv->uv, mluv->uv, warp_mat, axis_u, axis_v); - } - } + const UVWarpData *data = userdata; + + const MPoly *mp = &data->mpoly[i]; + const MLoop *ml = &data->mloop[mp->loopstart]; + MLoopUV *mluv = &data->mloopuv[mp->loopstart]; + + const MDeformVert *dvert = data->dvert; + const int defgrp_index = data->defgrp_index; + + float(*warp_mat)[4] = data->warp_mat; + const int axis_u = data->axis_u; + const int axis_v = data->axis_v; + + int l; + + if (dvert) { + for (l = 0; l < mp->totloop; l++, ml++, mluv++) { + float uv[2]; + 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 { + for (l = 0; l < mp->totloop; l++, ml++, mluv++) { + uv_warp_from_mat4_pair(mluv->uv, mluv->uv, warp_mat, axis_u, axis_v); + } + } } -static Mesh *applyModifier( - ModifierData *md, const ModifierEvalContext *ctx, - Mesh *mesh) +static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) { - 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(&mesh->ldata, CD_MLOOPUV)) { - return mesh; - } - else if (ELEM(NULL, umd->object_src, umd->object_dst)) { - modifier_setError(md, "From/To objects must be set"); - return mesh; - } - - /* 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(&mesh->ldata, CD_MLOOPUV, umd->uvlayer_name, uvname); - - numPolys = mesh->totpoly; - numLoops = mesh->totloop; - - mpoly = mesh->mpoly; - mloop = mesh->mloop; - /* make sure we are not modifying the original UV map */ - mloopuv = CustomData_duplicate_referenced_layer_named(&mesh->ldata, CD_MLOOPUV, uvname, numLoops); - MOD_get_vgroup(ctx->object, mesh, 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, - }; - ParallelRangeSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = (numPolys > 1000); - BLI_task_parallel_range(0, numPolys, - &data, - uv_warp_compute, - &settings); - - /* XXX TODO is this still needed? */ -// me_eval->dirty |= DM_DIRTY_TESS_CDLAYERS; - - return mesh; + 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(&mesh->ldata, CD_MLOOPUV)) { + return mesh; + } + else if (ELEM(NULL, umd->object_src, umd->object_dst)) { + modifier_setError(md, "From/To objects must be set"); + return mesh; + } + + /* 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(&mesh->ldata, CD_MLOOPUV, umd->uvlayer_name, uvname); + + numPolys = mesh->totpoly; + numLoops = mesh->totloop; + + mpoly = mesh->mpoly; + mloop = mesh->mloop; + /* make sure we are not modifying the original UV map */ + mloopuv = CustomData_duplicate_referenced_layer_named( + &mesh->ldata, CD_MLOOPUV, uvname, numLoops); + MOD_get_vgroup(ctx->object, mesh, 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, + }; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (numPolys > 1000); + BLI_task_parallel_range(0, numPolys, &data, uv_warp_compute, &settings); + + /* XXX TODO is this still needed? */ + // me_eval->dirty |= DM_DIRTY_TESS_CDLAYERS; + + return mesh; } static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) { - UVWarpModifierData *umd = (UVWarpModifierData *) md; + UVWarpModifierData *umd = (UVWarpModifierData *)md; - walk(userData, ob, &umd->object_dst, IDWALK_CB_NOP); - walk(userData, ob, &umd->object_src, IDWALK_CB_NOP); + walk(userData, ob, &umd->object_dst, IDWALK_CB_NOP); + walk(userData, ob, &umd->object_src, IDWALK_CB_NOP); } -static void uv_warp_deps_object_bone_new( - struct DepsNodeHandle *node, - Object *object, - const char *bonename) +static void uv_warp_deps_object_bone_new(struct DepsNodeHandle *node, + Object *object, + const char *bonename) { - if (object != NULL) { - if (bonename[0]) - DEG_add_object_relation(node, object, DEG_OB_COMP_EVAL_POSE, "UVWarp Modifier"); - else - DEG_add_object_relation(node, object, DEG_OB_COMP_TRANSFORM, "UVWarp Modifier"); - } + if (object != NULL) { + if (bonename[0]) + DEG_add_object_relation(node, object, DEG_OB_COMP_EVAL_POSE, "UVWarp Modifier"); + else + DEG_add_object_relation(node, object, DEG_OB_COMP_TRANSFORM, "UVWarp Modifier"); + } } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { - UVWarpModifierData *umd = (UVWarpModifierData *) md; + UVWarpModifierData *umd = (UVWarpModifierData *)md; - uv_warp_deps_object_bone_new(ctx->node, umd->object_src, umd->bone_src); - uv_warp_deps_object_bone_new(ctx->node, umd->object_dst, umd->bone_dst); + uv_warp_deps_object_bone_new(ctx->node, umd->object_src, umd->bone_src); + uv_warp_deps_object_bone_new(ctx->node, umd->object_dst, umd->bone_dst); - DEG_add_modifier_to_transform_relation(ctx->node, "UVWarp Modifier"); + DEG_add_modifier_to_transform_relation(ctx->node, "UVWarp Modifier"); } ModifierTypeInfo modifierType_UVWarp = { - /* name */ "UVWarp", - /* structName */ "UVWarpModifierData", - /* structSize */ sizeof(UVWarpModifierData), - /* type */ eModifierTypeType_NonGeometrical, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_SupportsEditmode | - eModifierTypeFlag_EnableInEditmode, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ NULL, - /* isDisabled */ NULL, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ foreachObjectLink, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "UVWarp", + /* structName */ "UVWarpModifierData", + /* structSize */ sizeof(UVWarpModifierData), + /* type */ eModifierTypeType_NonGeometrical, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsEditmode | + eModifierTypeFlag_EnableInEditmode, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c index 30bd391ef84..67b91cfd963 100644 --- a/source/blender/modifiers/intern/MOD_warp.c +++ b/source/blender/modifiers/intern/MOD_warp.c @@ -46,332 +46,338 @@ #include "MOD_util.h" - static void initData(ModifierData *md) { - WarpModifierData *wmd = (WarpModifierData *) md; - - wmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); - wmd->texture = NULL; - wmd->strength = 1.0f; - wmd->falloff_radius = 1.0f; - wmd->falloff_type = eWarp_Falloff_Smooth; - wmd->flag = 0; + WarpModifierData *wmd = (WarpModifierData *)md; + + wmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + wmd->texture = NULL; + wmd->strength = 1.0f; + wmd->falloff_radius = 1.0f; + wmd->falloff_type = eWarp_Falloff_Smooth; + wmd->flag = 0; } static void copyData(const ModifierData *md, ModifierData *target, const int flag) { - const WarpModifierData *wmd = (const WarpModifierData *) md; - WarpModifierData *twmd = (WarpModifierData *) target; + const WarpModifierData *wmd = (const WarpModifierData *)md; + WarpModifierData *twmd = (WarpModifierData *)target; - modifier_copyData_generic(md, target, flag); + modifier_copyData_generic(md, target, flag); - twmd->curfalloff = curvemapping_copy(wmd->curfalloff); + twmd->curfalloff = curvemapping_copy(wmd->curfalloff); } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - WarpModifierData *wmd = (WarpModifierData *)md; + WarpModifierData *wmd = (WarpModifierData *)md; - /* ask for vertexgroups if we need them */ - if (wmd->defgrp_name[0] != '\0') { - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; - } + /* ask for vertexgroups if we need them */ + if (wmd->defgrp_name[0] != '\0') { + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + } - /* ask for UV coordinates if we need them */ - if (wmd->texmapping == MOD_DISP_MAP_UV) { - r_cddata_masks->fmask |= CD_MASK_MTFACE; - } + /* ask for UV coordinates if we need them */ + if (wmd->texmapping == MOD_DISP_MAP_UV) { + r_cddata_masks->fmask |= CD_MASK_MTFACE; + } } static bool dependsOnTime(ModifierData *md) { - WarpModifierData *wmd = (WarpModifierData *)md; - - if (wmd->texture) { - return BKE_texture_dependsOnTime(wmd->texture); - } - else { - return false; - } + WarpModifierData *wmd = (WarpModifierData *)md; + + if (wmd->texture) { + return BKE_texture_dependsOnTime(wmd->texture); + } + else { + return false; + } } static void freeData(ModifierData *md) { - WarpModifierData *wmd = (WarpModifierData *) md; - curvemapping_free(wmd->curfalloff); + WarpModifierData *wmd = (WarpModifierData *)md; + curvemapping_free(wmd->curfalloff); } - -static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(userRenderParams)) +static bool isDisabled(const struct Scene *UNUSED(scene), + ModifierData *md, + bool UNUSED(userRenderParams)) { - WarpModifierData *wmd = (WarpModifierData *) md; + WarpModifierData *wmd = (WarpModifierData *)md; - return !(wmd->object_from && wmd->object_to); + return !(wmd->object_from && wmd->object_to); } static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) { - WarpModifierData *wmd = (WarpModifierData *) md; + WarpModifierData *wmd = (WarpModifierData *)md; - walk(userData, ob, &wmd->object_from, IDWALK_CB_NOP); - walk(userData, ob, &wmd->object_to, IDWALK_CB_NOP); - walk(userData, ob, &wmd->map_object, IDWALK_CB_NOP); + walk(userData, ob, &wmd->object_from, IDWALK_CB_NOP); + walk(userData, ob, &wmd->object_to, IDWALK_CB_NOP); + walk(userData, ob, &wmd->map_object, IDWALK_CB_NOP); } static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData) { - WarpModifierData *wmd = (WarpModifierData *) md; + WarpModifierData *wmd = (WarpModifierData *)md; - walk(userData, ob, (ID **)&wmd->texture, IDWALK_CB_USER); + walk(userData, ob, (ID **)&wmd->texture, IDWALK_CB_USER); - foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData); + foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData); } static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void *userData) { - walk(userData, ob, md, "texture"); + walk(userData, ob, md, "texture"); } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { - WarpModifierData *wmd = (WarpModifierData *) md; - if (wmd->object_from != NULL && wmd->object_to != NULL) { - DEG_add_modifier_to_transform_relation(ctx->node, "Warplace Modifier"); - DEG_add_object_relation(ctx->node, wmd->object_from, DEG_OB_COMP_TRANSFORM, "Warp Modifier from"); - DEG_add_object_relation(ctx->node, wmd->object_to, DEG_OB_COMP_TRANSFORM, "Warp Modifier to"); - } - if ((wmd->texmapping == MOD_DISP_MAP_OBJECT) && wmd->map_object != NULL) { - DEG_add_object_relation(ctx->node, wmd->map_object, DEG_OB_COMP_TRANSFORM, "Warp Modifier map"); - } - if (wmd->texture != NULL) { - DEG_add_generic_id_relation(ctx->node, &wmd->texture->id, "Warp Modifier"); - } + WarpModifierData *wmd = (WarpModifierData *)md; + if (wmd->object_from != NULL && wmd->object_to != NULL) { + DEG_add_modifier_to_transform_relation(ctx->node, "Warplace Modifier"); + DEG_add_object_relation( + ctx->node, wmd->object_from, DEG_OB_COMP_TRANSFORM, "Warp Modifier from"); + DEG_add_object_relation(ctx->node, wmd->object_to, DEG_OB_COMP_TRANSFORM, "Warp Modifier to"); + } + if ((wmd->texmapping == MOD_DISP_MAP_OBJECT) && wmd->map_object != NULL) { + DEG_add_object_relation( + ctx->node, wmd->map_object, DEG_OB_COMP_TRANSFORM, "Warp Modifier map"); + } + if (wmd->texture != NULL) { + DEG_add_generic_id_relation(ctx->node, &wmd->texture->id, "Warp Modifier"); + } } -static void warpModifier_do( - WarpModifierData *wmd, const ModifierEvalContext *ctx, - Mesh *mesh, float (*vertexCos)[3], int numVerts) +static void warpModifier_do(WarpModifierData *wmd, + const ModifierEvalContext *ctx, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - Object *ob = ctx->object; - float obinv[4][4]; - float mat_from[4][4]; - float mat_from_inv[4][4]; - float mat_to[4][4]; - float mat_unit[4][4]; - float mat_final[4][4]; - - float tmat[4][4]; - - const float falloff_radius_sq = SQUARE(wmd->falloff_radius); - float strength = wmd->strength; - float fac = 1.0f, weight; - int i; - int defgrp_index; - MDeformVert *dvert, *dv = NULL; - - float (*tex_co)[3] = NULL; - - if (!(wmd->object_from && wmd->object_to)) - return; - - MOD_get_vgroup(ob, mesh, wmd->defgrp_name, &dvert, &defgrp_index); - if (dvert == NULL) { - defgrp_index = -1; - } - - if (wmd->curfalloff == NULL) /* should never happen, but bad lib linking could cause it */ - wmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); - - if (wmd->curfalloff) { - curvemapping_initialize(wmd->curfalloff); - } - - invert_m4_m4(obinv, ob->obmat); - - mul_m4_m4m4(mat_from, obinv, wmd->object_from->obmat); - mul_m4_m4m4(mat_to, obinv, wmd->object_to->obmat); - - invert_m4_m4(tmat, mat_from); // swap? - mul_m4_m4m4(mat_final, tmat, mat_to); - - invert_m4_m4(mat_from_inv, mat_from); - - unit_m4(mat_unit); - - if (strength < 0.0f) { - float loc[3]; - strength = -strength; - - /* inverted location is not useful, just use the negative */ - copy_v3_v3(loc, mat_final[3]); - invert_m4(mat_final); - negate_v3_v3(mat_final[3], loc); - - } - weight = strength; - - Tex *tex_target = wmd->texture; - if (mesh != NULL && tex_target != NULL) { - tex_co = MEM_malloc_arrayN(numVerts, sizeof(*tex_co), "warpModifier_do tex_co"); - MOD_get_texture_coords((MappingInfoModifierData *)wmd, ctx, ob, mesh, vertexCos, tex_co); - - MOD_init_texture((MappingInfoModifierData *)wmd, ctx); - } - - for (i = 0; i < numVerts; i++) { - float *co = vertexCos[i]; - - if (wmd->falloff_type == eWarp_Falloff_None || - ((fac = len_squared_v3v3(co, mat_from[3])) < falloff_radius_sq && - (fac = (wmd->falloff_radius - sqrtf(fac)) / wmd->falloff_radius))) - { - /* skip if no vert group found */ - if (defgrp_index != -1) { - dv = &dvert[i]; - weight = defvert_find_weight(dv, defgrp_index) * strength; - if (weight <= 0.0f) { - continue; - } - } - - - /* closely match PROP_SMOOTH and similar */ - switch (wmd->falloff_type) { - case eWarp_Falloff_None: - fac = 1.0f; - break; - case eWarp_Falloff_Curve: - fac = curvemapping_evaluateF(wmd->curfalloff, 0, fac); - break; - case eWarp_Falloff_Sharp: - fac = fac * fac; - break; - case eWarp_Falloff_Smooth: - fac = 3.0f * fac * fac - 2.0f * fac * fac * fac; - break; - case eWarp_Falloff_Root: - fac = sqrtf(fac); - break; - case eWarp_Falloff_Linear: - /* pass */ - break; - case eWarp_Falloff_Const: - fac = 1.0f; - break; - case eWarp_Falloff_Sphere: - fac = sqrtf(2 * fac - fac * fac); - break; - case eWarp_Falloff_InvSquare: - fac = fac * (2.0f - fac); - break; - } - - fac *= weight; - - if (tex_co) { - struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); - TexResult texres; - texres.nor = NULL; - BKE_texture_get_value(scene, tex_target, tex_co[i], &texres, false); - fac *= texres.tin; - } - - if (fac != 0.0f) { - /* into the 'from' objects space */ - mul_m4_v3(mat_from_inv, co); - - if (fac == 1.0f) { - mul_m4_v3(mat_final, co); - } - else { - if (wmd->flag & MOD_WARP_VOLUME_PRESERVE) { - /* interpolate the matrix for nicer locations */ - blend_m4_m4m4(tmat, mat_unit, mat_final, fac); - mul_m4_v3(tmat, co); - } - else { - float tvec[3]; - mul_v3_m4v3(tvec, mat_final, co); - interp_v3_v3v3(co, co, tvec, fac); - } - } - - /* out of the 'from' objects space */ - mul_m4_v3(mat_from, co); - } - } - } - - if (tex_co) { - MEM_freeN(tex_co); - } + Object *ob = ctx->object; + float obinv[4][4]; + float mat_from[4][4]; + float mat_from_inv[4][4]; + float mat_to[4][4]; + float mat_unit[4][4]; + float mat_final[4][4]; + + float tmat[4][4]; + + const float falloff_radius_sq = SQUARE(wmd->falloff_radius); + float strength = wmd->strength; + float fac = 1.0f, weight; + int i; + int defgrp_index; + MDeformVert *dvert, *dv = NULL; + + float(*tex_co)[3] = NULL; + + if (!(wmd->object_from && wmd->object_to)) + return; + + MOD_get_vgroup(ob, mesh, wmd->defgrp_name, &dvert, &defgrp_index); + if (dvert == NULL) { + defgrp_index = -1; + } + + if (wmd->curfalloff == NULL) /* should never happen, but bad lib linking could cause it */ + wmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + + if (wmd->curfalloff) { + curvemapping_initialize(wmd->curfalloff); + } + + invert_m4_m4(obinv, ob->obmat); + + mul_m4_m4m4(mat_from, obinv, wmd->object_from->obmat); + mul_m4_m4m4(mat_to, obinv, wmd->object_to->obmat); + + invert_m4_m4(tmat, mat_from); // swap? + mul_m4_m4m4(mat_final, tmat, mat_to); + + invert_m4_m4(mat_from_inv, mat_from); + + unit_m4(mat_unit); + + if (strength < 0.0f) { + float loc[3]; + strength = -strength; + + /* inverted location is not useful, just use the negative */ + copy_v3_v3(loc, mat_final[3]); + invert_m4(mat_final); + negate_v3_v3(mat_final[3], loc); + } + weight = strength; + + Tex *tex_target = wmd->texture; + if (mesh != NULL && tex_target != NULL) { + tex_co = MEM_malloc_arrayN(numVerts, sizeof(*tex_co), "warpModifier_do tex_co"); + MOD_get_texture_coords((MappingInfoModifierData *)wmd, ctx, ob, mesh, vertexCos, tex_co); + + MOD_init_texture((MappingInfoModifierData *)wmd, ctx); + } + + for (i = 0; i < numVerts; i++) { + float *co = vertexCos[i]; + + if (wmd->falloff_type == eWarp_Falloff_None || + ((fac = len_squared_v3v3(co, mat_from[3])) < falloff_radius_sq && + (fac = (wmd->falloff_radius - sqrtf(fac)) / wmd->falloff_radius))) { + /* skip if no vert group found */ + if (defgrp_index != -1) { + dv = &dvert[i]; + weight = defvert_find_weight(dv, defgrp_index) * strength; + if (weight <= 0.0f) { + continue; + } + } + + /* closely match PROP_SMOOTH and similar */ + switch (wmd->falloff_type) { + case eWarp_Falloff_None: + fac = 1.0f; + break; + case eWarp_Falloff_Curve: + fac = curvemapping_evaluateF(wmd->curfalloff, 0, fac); + break; + case eWarp_Falloff_Sharp: + fac = fac * fac; + break; + case eWarp_Falloff_Smooth: + fac = 3.0f * fac * fac - 2.0f * fac * fac * fac; + break; + case eWarp_Falloff_Root: + fac = sqrtf(fac); + break; + case eWarp_Falloff_Linear: + /* pass */ + break; + case eWarp_Falloff_Const: + fac = 1.0f; + break; + case eWarp_Falloff_Sphere: + fac = sqrtf(2 * fac - fac * fac); + break; + case eWarp_Falloff_InvSquare: + fac = fac * (2.0f - fac); + break; + } + + fac *= weight; + + if (tex_co) { + struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); + TexResult texres; + texres.nor = NULL; + BKE_texture_get_value(scene, tex_target, tex_co[i], &texres, false); + fac *= texres.tin; + } + + if (fac != 0.0f) { + /* into the 'from' objects space */ + mul_m4_v3(mat_from_inv, co); + + if (fac == 1.0f) { + mul_m4_v3(mat_final, co); + } + else { + if (wmd->flag & MOD_WARP_VOLUME_PRESERVE) { + /* interpolate the matrix for nicer locations */ + blend_m4_m4m4(tmat, mat_unit, mat_final, fac); + mul_m4_v3(tmat, co); + } + else { + float tvec[3]; + mul_v3_m4v3(tvec, mat_final, co); + interp_v3_v3v3(co, co, tvec, fac); + } + } + + /* out of the 'from' objects space */ + mul_m4_v3(mat_from, co); + } + } + } + + if (tex_co) { + MEM_freeN(tex_co); + } } -static void deformVerts( - ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh, - float (*vertexCos)[3], int numVerts) +static void deformVerts(ModifierData *md, + const ModifierEvalContext *ctx, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - WarpModifierData *wmd = (WarpModifierData *)md; - Mesh *mesh_src = NULL; + WarpModifierData *wmd = (WarpModifierData *)md; + Mesh *mesh_src = NULL; - if (wmd->defgrp_name[0] != '\0' || wmd->texture != NULL) { - /* mesh_src is only needed for vgroups and textures. */ - mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); - } + if (wmd->defgrp_name[0] != '\0' || wmd->texture != NULL) { + /* mesh_src is only needed for vgroups and textures. */ + mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); + } - warpModifier_do(wmd, ctx, mesh_src, vertexCos, numVerts); + warpModifier_do(wmd, ctx, mesh_src, vertexCos, numVerts); - if (!ELEM(mesh_src, NULL, mesh)) { - BKE_id_free(NULL, mesh_src); - } + if (!ELEM(mesh_src, NULL, mesh)) { + BKE_id_free(NULL, mesh_src); + } } -static void deformVertsEM( - ModifierData *md, const ModifierEvalContext *ctx, struct BMEditMesh *em, - Mesh *mesh, float (*vertexCos)[3], int numVerts) +static void deformVertsEM(ModifierData *md, + const ModifierEvalContext *ctx, + struct BMEditMesh *em, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - WarpModifierData *wmd = (WarpModifierData *)md; - Mesh *mesh_src = NULL; + WarpModifierData *wmd = (WarpModifierData *)md; + Mesh *mesh_src = NULL; - if (wmd->defgrp_name[0] != '\0' || wmd->texture != NULL) { - /* mesh_src is only needed for vgroups and textures. */ - mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, numVerts, false, false); - } + if (wmd->defgrp_name[0] != '\0' || wmd->texture != NULL) { + /* mesh_src is only needed for vgroups and textures. */ + mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, numVerts, false, false); + } - warpModifier_do(wmd, ctx, mesh_src, vertexCos, numVerts); + warpModifier_do(wmd, ctx, mesh_src, vertexCos, numVerts); - if (!ELEM(mesh_src, NULL, mesh)) { - BKE_id_free(NULL, mesh_src); - } + if (!ELEM(mesh_src, NULL, mesh)) { + BKE_id_free(NULL, mesh_src); + } } - ModifierTypeInfo modifierType_Warp = { - /* name */ "Warp", - /* structName */ "WarpModifierData", - /* structSize */ sizeof(WarpModifierData), - /* type */ eModifierTypeType_OnlyDeform, - /* flags */ eModifierTypeFlag_AcceptsCVs | - eModifierTypeFlag_AcceptsLattice | - eModifierTypeFlag_SupportsEditmode, - /* copyData */ copyData, - - /* deformVerts */ deformVerts, - /* deformMatrices */ NULL, - /* deformVertsEM */ deformVertsEM, - /* deformMatricesEM */ NULL, - /* applyModifier */ NULL, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ freeData, - /* isDisabled */ isDisabled, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ dependsOnTime, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ foreachObjectLink, - /* foreachIDLink */ foreachIDLink, - /* foreachTexLink */ foreachTexLink, - /* freeRuntimeData */ NULL, + /* name */ "Warp", + /* structName */ "WarpModifierData", + /* structSize */ sizeof(WarpModifierData), + /* type */ eModifierTypeType_OnlyDeform, + /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice | + eModifierTypeFlag_SupportsEditmode, + /* copyData */ copyData, + + /* deformVerts */ deformVerts, + /* deformMatrices */ NULL, + /* deformVertsEM */ deformVertsEM, + /* deformMatricesEM */ NULL, + /* applyModifier */ NULL, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ freeData, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ dependsOnTime, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ foreachIDLink, + /* foreachTexLink */ foreachTexLink, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c index d5c372a2809..c0b686dd098 100644 --- a/source/blender/modifiers/intern/MOD_wave.c +++ b/source/blender/modifiers/intern/MOD_wave.c @@ -21,7 +21,6 @@ * \ingroup modifiers */ - #include "BLI_utildefines.h" #include "BLI_math.h" @@ -50,328 +49,327 @@ static void initData(ModifierData *md) { - WaveModifierData *wmd = (WaveModifierData *) md; // whadya know, moved here from Iraq - - wmd->flag |= (MOD_WAVE_X | MOD_WAVE_Y | MOD_WAVE_CYCL | - MOD_WAVE_NORM_X | MOD_WAVE_NORM_Y | MOD_WAVE_NORM_Z); - - wmd->objectcenter = NULL; - wmd->texture = NULL; - wmd->map_object = NULL; - wmd->height = 0.5f; - wmd->width = 1.5f; - wmd->speed = 0.25f; - wmd->narrow = 1.5f; - wmd->lifetime = 0.0f; - wmd->damp = 10.0f; - wmd->falloff = 0.0f; - wmd->texmapping = MOD_DISP_MAP_LOCAL; - wmd->defgrp_name[0] = 0; + WaveModifierData *wmd = (WaveModifierData *)md; // whadya know, moved here from Iraq + + wmd->flag |= (MOD_WAVE_X | MOD_WAVE_Y | MOD_WAVE_CYCL | MOD_WAVE_NORM_X | MOD_WAVE_NORM_Y | + MOD_WAVE_NORM_Z); + + wmd->objectcenter = NULL; + wmd->texture = NULL; + wmd->map_object = NULL; + wmd->height = 0.5f; + wmd->width = 1.5f; + wmd->speed = 0.25f; + wmd->narrow = 1.5f; + wmd->lifetime = 0.0f; + wmd->damp = 10.0f; + wmd->falloff = 0.0f; + wmd->texmapping = MOD_DISP_MAP_LOCAL; + wmd->defgrp_name[0] = 0; } static bool dependsOnTime(ModifierData *UNUSED(md)) { - return true; + return true; } -static void foreachObjectLink( - ModifierData *md, Object *ob, - ObjectWalkFunc walk, void *userData) +static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) { - WaveModifierData *wmd = (WaveModifierData *) md; + WaveModifierData *wmd = (WaveModifierData *)md; - walk(userData, ob, &wmd->objectcenter, IDWALK_CB_NOP); - walk(userData, ob, &wmd->map_object, IDWALK_CB_NOP); + walk(userData, ob, &wmd->objectcenter, IDWALK_CB_NOP); + walk(userData, ob, &wmd->map_object, IDWALK_CB_NOP); } -static void foreachIDLink( - ModifierData *md, Object *ob, - IDWalkFunc walk, void *userData) +static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData) { - WaveModifierData *wmd = (WaveModifierData *) md; + WaveModifierData *wmd = (WaveModifierData *)md; - walk(userData, ob, (ID **)&wmd->texture, IDWALK_CB_USER); + walk(userData, ob, (ID **)&wmd->texture, IDWALK_CB_USER); - foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData); + foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData); } -static void foreachTexLink( - ModifierData *md, Object *ob, - TexWalkFunc walk, void *userData) +static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void *userData) { - walk(userData, ob, md, "texture"); + walk(userData, ob, md, "texture"); } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { - WaveModifierData *wmd = (WaveModifierData *)md; - if (wmd->objectcenter != NULL) { - DEG_add_object_relation(ctx->node, wmd->objectcenter, DEG_OB_COMP_TRANSFORM, "Wave Modifier"); - } - if (wmd->map_object != NULL) { - DEG_add_object_relation(ctx->node, wmd->map_object, DEG_OB_COMP_TRANSFORM, "Wave Modifier"); - } - if (wmd->objectcenter != NULL || wmd->map_object != NULL) { - DEG_add_modifier_to_transform_relation(ctx->node, "Wave Modifier"); - } - if (wmd->texture != NULL) { - DEG_add_generic_id_relation(ctx->node, &wmd->texture->id, "Wave Modifier"); - } + WaveModifierData *wmd = (WaveModifierData *)md; + if (wmd->objectcenter != NULL) { + DEG_add_object_relation(ctx->node, wmd->objectcenter, DEG_OB_COMP_TRANSFORM, "Wave Modifier"); + } + if (wmd->map_object != NULL) { + DEG_add_object_relation(ctx->node, wmd->map_object, DEG_OB_COMP_TRANSFORM, "Wave Modifier"); + } + if (wmd->objectcenter != NULL || wmd->map_object != NULL) { + DEG_add_modifier_to_transform_relation(ctx->node, "Wave Modifier"); + } + if (wmd->texture != NULL) { + DEG_add_generic_id_relation(ctx->node, &wmd->texture->id, "Wave Modifier"); + } } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - WaveModifierData *wmd = (WaveModifierData *)md; + WaveModifierData *wmd = (WaveModifierData *)md; - /* ask for UV coordinates if we need them */ - if (wmd->texture && wmd->texmapping == MOD_DISP_MAP_UV) { - r_cddata_masks->fmask |= CD_MASK_MTFACE; - } + /* ask for UV coordinates if we need them */ + if (wmd->texture && wmd->texmapping == MOD_DISP_MAP_UV) { + r_cddata_masks->fmask |= CD_MASK_MTFACE; + } - /* ask for vertexgroups if we need them */ - if (wmd->defgrp_name[0] != '\0') { - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; - } + /* ask for vertexgroups if we need them */ + if (wmd->defgrp_name[0] != '\0') { + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + } } static bool dependsOnNormals(ModifierData *md) { - WaveModifierData *wmd = (WaveModifierData *)md; + WaveModifierData *wmd = (WaveModifierData *)md; - return (wmd->flag & MOD_WAVE_NORM) != 0; + return (wmd->flag & MOD_WAVE_NORM) != 0; } -static void waveModifier_do( - WaveModifierData *md, - const ModifierEvalContext *ctx, - Object *ob, Mesh *mesh, - float (*vertexCos)[3], int numVerts) +static void waveModifier_do(WaveModifierData *md, + const ModifierEvalContext *ctx, + Object *ob, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - WaveModifierData *wmd = (WaveModifierData *) md; - MVert *mvert = NULL; - MDeformVert *dvert; - int defgrp_index; - float ctime = DEG_get_ctime(ctx->depsgraph); - float minfac = (float)(1.0 / exp(wmd->width * wmd->narrow * wmd->width * wmd->narrow)); - float lifefac = wmd->height; - float (*tex_co)[3] = NULL; - const int wmd_axis = wmd->flag & (MOD_WAVE_X | MOD_WAVE_Y); - const float falloff = wmd->falloff; - float falloff_fac = 1.0f; /* when falloff == 0.0f this stays at 1.0f */ - - if ((wmd->flag & MOD_WAVE_NORM) && (mesh != NULL)) { - mvert = mesh->mvert; - } - - if (wmd->objectcenter != NULL) { - float mat[4][4]; - /* get the control object's location in local coordinates */ - invert_m4_m4(ob->imat, ob->obmat); - mul_m4_m4m4(mat, ob->imat, wmd->objectcenter->obmat); - - wmd->startx = mat[3][0]; - wmd->starty = mat[3][1]; - } - - /* get the index of the deform group */ - MOD_get_vgroup(ob, mesh, wmd->defgrp_name, &dvert, &defgrp_index); - - if (wmd->damp == 0.0f) { - wmd->damp = 10.0f; - } - - if (wmd->lifetime != 0.0f) { - float x = ctime - wmd->timeoffs; - - if (x > wmd->lifetime) { - lifefac = x - wmd->lifetime; - - if (lifefac > wmd->damp) lifefac = 0.0; - else lifefac = (float)(wmd->height * (1.0f - sqrtf(lifefac / wmd->damp))); - } - } - - Tex *tex_target = wmd->texture; - if (mesh != NULL && tex_target != NULL) { - tex_co = MEM_malloc_arrayN(numVerts, sizeof(*tex_co), "waveModifier_do tex_co"); - MOD_get_texture_coords((MappingInfoModifierData *)wmd, ctx, ob, mesh, vertexCos, tex_co); - - MOD_init_texture((MappingInfoModifierData *)wmd, ctx); - } - - if (lifefac != 0.0f) { - /* avoid divide by zero checks within the loop */ - float falloff_inv = falloff != 0.0f ? 1.0f / falloff : 1.0f; - int i; - - for (i = 0; i < numVerts; i++) { - float *co = vertexCos[i]; - float x = co[0] - wmd->startx; - float y = co[1] - wmd->starty; - float amplit = 0.0f; - float def_weight = 1.0f; - - /* get weights */ - if (dvert) { - def_weight = defvert_find_weight(&dvert[i], defgrp_index); - - /* if this vert isn't in the vgroup, don't deform it */ - if (def_weight == 0.0f) { - continue; - } - } - - switch (wmd_axis) { - case MOD_WAVE_X | MOD_WAVE_Y: - amplit = sqrtf(x * x + y * y); - break; - case MOD_WAVE_X: - amplit = x; - break; - case MOD_WAVE_Y: - amplit = y; - break; - } - - /* this way it makes nice circles */ - amplit -= (ctime - wmd->timeoffs) * wmd->speed; - - if (wmd->flag & MOD_WAVE_CYCL) { - amplit = (float)fmodf(amplit - wmd->width, 2.0f * wmd->width) + - wmd->width; - } - - if (falloff != 0.0f) { - float dist = 0.0f; - - switch (wmd_axis) { - case MOD_WAVE_X | MOD_WAVE_Y: - dist = sqrtf(x * x + y * y); - break; - case MOD_WAVE_X: - dist = fabsf(x); - break; - case MOD_WAVE_Y: - dist = fabsf(y); - break; - } - - falloff_fac = (1.0f - (dist * falloff_inv)); - CLAMP(falloff_fac, 0.0f, 1.0f); - } - - /* GAUSSIAN */ - if ((falloff_fac != 0.0f) && (amplit > -wmd->width) && (amplit < wmd->width)) { - amplit = amplit * wmd->narrow; - amplit = (float)(1.0f / expf(amplit * amplit) - minfac); - - /*apply texture*/ - if (tex_target) { - Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); - TexResult texres; - texres.nor = NULL; - BKE_texture_get_value(scene, tex_target, tex_co[i], &texres, false); - amplit *= texres.tin; - } - - /*apply weight & falloff */ - amplit *= def_weight * falloff_fac; - - if (mvert) { - /* move along normals */ - if (wmd->flag & MOD_WAVE_NORM_X) { - co[0] += (lifefac * amplit) * mvert[i].no[0] / 32767.0f; - } - if (wmd->flag & MOD_WAVE_NORM_Y) { - co[1] += (lifefac * amplit) * mvert[i].no[1] / 32767.0f; - } - if (wmd->flag & MOD_WAVE_NORM_Z) { - co[2] += (lifefac * amplit) * mvert[i].no[2] / 32767.0f; - } - } - else { - /* move along local z axis */ - co[2] += lifefac * amplit; - } - } - } - } - - MEM_SAFE_FREE(tex_co); + WaveModifierData *wmd = (WaveModifierData *)md; + MVert *mvert = NULL; + MDeformVert *dvert; + int defgrp_index; + float ctime = DEG_get_ctime(ctx->depsgraph); + float minfac = (float)(1.0 / exp(wmd->width * wmd->narrow * wmd->width * wmd->narrow)); + float lifefac = wmd->height; + float(*tex_co)[3] = NULL; + const int wmd_axis = wmd->flag & (MOD_WAVE_X | MOD_WAVE_Y); + const float falloff = wmd->falloff; + float falloff_fac = 1.0f; /* when falloff == 0.0f this stays at 1.0f */ + + if ((wmd->flag & MOD_WAVE_NORM) && (mesh != NULL)) { + mvert = mesh->mvert; + } + + if (wmd->objectcenter != NULL) { + float mat[4][4]; + /* get the control object's location in local coordinates */ + invert_m4_m4(ob->imat, ob->obmat); + mul_m4_m4m4(mat, ob->imat, wmd->objectcenter->obmat); + + wmd->startx = mat[3][0]; + wmd->starty = mat[3][1]; + } + + /* get the index of the deform group */ + MOD_get_vgroup(ob, mesh, wmd->defgrp_name, &dvert, &defgrp_index); + + if (wmd->damp == 0.0f) { + wmd->damp = 10.0f; + } + + if (wmd->lifetime != 0.0f) { + float x = ctime - wmd->timeoffs; + + if (x > wmd->lifetime) { + lifefac = x - wmd->lifetime; + + if (lifefac > wmd->damp) + lifefac = 0.0; + else + lifefac = (float)(wmd->height * (1.0f - sqrtf(lifefac / wmd->damp))); + } + } + + Tex *tex_target = wmd->texture; + if (mesh != NULL && tex_target != NULL) { + tex_co = MEM_malloc_arrayN(numVerts, sizeof(*tex_co), "waveModifier_do tex_co"); + MOD_get_texture_coords((MappingInfoModifierData *)wmd, ctx, ob, mesh, vertexCos, tex_co); + + MOD_init_texture((MappingInfoModifierData *)wmd, ctx); + } + + if (lifefac != 0.0f) { + /* avoid divide by zero checks within the loop */ + float falloff_inv = falloff != 0.0f ? 1.0f / falloff : 1.0f; + int i; + + for (i = 0; i < numVerts; i++) { + float *co = vertexCos[i]; + float x = co[0] - wmd->startx; + float y = co[1] - wmd->starty; + float amplit = 0.0f; + float def_weight = 1.0f; + + /* get weights */ + if (dvert) { + def_weight = defvert_find_weight(&dvert[i], defgrp_index); + + /* if this vert isn't in the vgroup, don't deform it */ + if (def_weight == 0.0f) { + continue; + } + } + + switch (wmd_axis) { + case MOD_WAVE_X | MOD_WAVE_Y: + amplit = sqrtf(x * x + y * y); + break; + case MOD_WAVE_X: + amplit = x; + break; + case MOD_WAVE_Y: + amplit = y; + break; + } + + /* this way it makes nice circles */ + amplit -= (ctime - wmd->timeoffs) * wmd->speed; + + if (wmd->flag & MOD_WAVE_CYCL) { + amplit = (float)fmodf(amplit - wmd->width, 2.0f * wmd->width) + wmd->width; + } + + if (falloff != 0.0f) { + float dist = 0.0f; + + switch (wmd_axis) { + case MOD_WAVE_X | MOD_WAVE_Y: + dist = sqrtf(x * x + y * y); + break; + case MOD_WAVE_X: + dist = fabsf(x); + break; + case MOD_WAVE_Y: + dist = fabsf(y); + break; + } + + falloff_fac = (1.0f - (dist * falloff_inv)); + CLAMP(falloff_fac, 0.0f, 1.0f); + } + + /* GAUSSIAN */ + if ((falloff_fac != 0.0f) && (amplit > -wmd->width) && (amplit < wmd->width)) { + amplit = amplit * wmd->narrow; + amplit = (float)(1.0f / expf(amplit * amplit) - minfac); + + /*apply texture*/ + if (tex_target) { + Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); + TexResult texres; + texres.nor = NULL; + BKE_texture_get_value(scene, tex_target, tex_co[i], &texres, false); + amplit *= texres.tin; + } + + /*apply weight & falloff */ + amplit *= def_weight * falloff_fac; + + if (mvert) { + /* move along normals */ + if (wmd->flag & MOD_WAVE_NORM_X) { + co[0] += (lifefac * amplit) * mvert[i].no[0] / 32767.0f; + } + if (wmd->flag & MOD_WAVE_NORM_Y) { + co[1] += (lifefac * amplit) * mvert[i].no[1] / 32767.0f; + } + if (wmd->flag & MOD_WAVE_NORM_Z) { + co[2] += (lifefac * amplit) * mvert[i].no[2] / 32767.0f; + } + } + else { + /* move along local z axis */ + co[2] += lifefac * amplit; + } + } + } + } + + MEM_SAFE_FREE(tex_co); } -static void deformVerts( - ModifierData *md, const ModifierEvalContext *ctx, - Mesh *mesh, - float (*vertexCos)[3], - int numVerts) +static void deformVerts(ModifierData *md, + const ModifierEvalContext *ctx, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - WaveModifierData *wmd = (WaveModifierData *)md; - Mesh *mesh_src = NULL; + WaveModifierData *wmd = (WaveModifierData *)md; + Mesh *mesh_src = NULL; - if (wmd->flag & MOD_WAVE_NORM) { - mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, vertexCos, numVerts, true, false); - } - else if (wmd->texture != NULL || wmd->defgrp_name[0] != '\0') { - mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); - } + if (wmd->flag & MOD_WAVE_NORM) { + mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, vertexCos, numVerts, true, false); + } + else if (wmd->texture != NULL || wmd->defgrp_name[0] != '\0') { + mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); + } - waveModifier_do(wmd, ctx, ctx->object, mesh_src, vertexCos, numVerts); + waveModifier_do(wmd, ctx, ctx->object, mesh_src, vertexCos, numVerts); - if (!ELEM(mesh_src, NULL, mesh)) { - BKE_id_free(NULL, mesh_src); - } + if (!ELEM(mesh_src, NULL, mesh)) { + BKE_id_free(NULL, mesh_src); + } } -static void deformVertsEM( - ModifierData *md, const ModifierEvalContext *ctx, - struct BMEditMesh *editData, - Mesh *mesh, float (*vertexCos)[3], int numVerts) +static void deformVertsEM(ModifierData *md, + const ModifierEvalContext *ctx, + struct BMEditMesh *editData, + Mesh *mesh, + float (*vertexCos)[3], + int numVerts) { - WaveModifierData *wmd = (WaveModifierData *)md; - Mesh *mesh_src = NULL; - - if (wmd->flag & MOD_WAVE_NORM) { - mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, vertexCos, numVerts, true, false); - } - else if (wmd->texture != NULL || wmd->defgrp_name[0] != '\0') { - mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false); - } - - waveModifier_do(wmd, ctx, ctx->object, mesh_src, vertexCos, numVerts); - - if (!ELEM(mesh_src, NULL, mesh)) { - BKE_id_free(NULL, mesh_src); - } + WaveModifierData *wmd = (WaveModifierData *)md; + Mesh *mesh_src = NULL; + + if (wmd->flag & MOD_WAVE_NORM) { + mesh_src = MOD_deform_mesh_eval_get( + ctx->object, editData, mesh, vertexCos, numVerts, true, false); + } + else if (wmd->texture != NULL || wmd->defgrp_name[0] != '\0') { + mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false); + } + + waveModifier_do(wmd, ctx, ctx->object, mesh_src, vertexCos, numVerts); + + if (!ELEM(mesh_src, NULL, mesh)) { + BKE_id_free(NULL, mesh_src); + } } - ModifierTypeInfo modifierType_Wave = { - /* name */ "Wave", - /* structName */ "WaveModifierData", - /* structSize */ sizeof(WaveModifierData), - /* type */ eModifierTypeType_OnlyDeform, - /* flags */ eModifierTypeFlag_AcceptsCVs | - eModifierTypeFlag_AcceptsLattice | - eModifierTypeFlag_SupportsEditmode, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ deformVerts, - /* deformMatrices */ NULL, - /* deformVertsEM */ deformVertsEM, - /* deformMatricesEM */ NULL, - /* applyModifier */ NULL, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ NULL, - /* isDisabled */ NULL, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ dependsOnTime, - /* dependsOnNormals */ dependsOnNormals, - /* foreachObjectLink */ foreachObjectLink, - /* foreachIDLink */ foreachIDLink, - /* foreachTexLink */ foreachTexLink, - /* freeRuntimeData */ NULL, + /* name */ "Wave", + /* structName */ "WaveModifierData", + /* structSize */ sizeof(WaveModifierData), + /* type */ eModifierTypeType_OnlyDeform, + /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice | + eModifierTypeFlag_SupportsEditmode, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ deformVerts, + /* deformMatrices */ NULL, + /* deformVertsEM */ deformVertsEM, + /* deformMatricesEM */ NULL, + /* applyModifier */ NULL, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ dependsOnTime, + /* dependsOnNormals */ dependsOnNormals, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ foreachIDLink, + /* foreachTexLink */ foreachTexLink, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.c b/source/blender/modifiers/intern/MOD_weighted_normal.c index 98b2117e5a3..2162f223b7a 100644 --- a/source/blender/modifiers/intern/MOD_weighted_normal.c +++ b/source/blender/modifiers/intern/MOD_weighted_normal.c @@ -38,616 +38,678 @@ #define CLNORS_VALID_VEC_LEN (1e-6f) typedef struct ModePair { - float val; /* Contains mode based value (face area / corner angle). */ - int index; /* Index value per poly or per loop. */ + float val; /* Contains mode based value (face area / corner angle). */ + int index; /* Index value per poly or per loop. */ } ModePair; /* Sorting function used in modifier, sorts in decreasing order. */ static int modepair_cmp_by_val_inverse(const void *p1, const void *p2) { - ModePair *r1 = (ModePair *)p1; - ModePair *r2 = (ModePair *)p2; + ModePair *r1 = (ModePair *)p1; + ModePair *r2 = (ModePair *)p2; - return (r1->val < r2->val) ? 1 : ((r1->val > r2->val) ? -1 : 0); + return (r1->val < r2->val) ? 1 : ((r1->val > r2->val) ? -1 : 0); } /* There will be one of those per vertex (simple case, computing one normal per vertex), or per smooth fan. */ typedef struct WeightedNormalDataAggregateItem { - float normal[3]; + float normal[3]; - int num_loops; /* Count number of loops using this item so far. */ - float curr_val; /* Current max val for this item. */ - int curr_strength; /* Current max strength encountered for this item. */ + int num_loops; /* Count number of loops using this item so far. */ + float curr_val; /* Current max val for this item. */ + int curr_strength; /* Current max strength encountered for this item. */ } WeightedNormalDataAggregateItem; #define NUM_CACHED_INVERSE_POWERS_OF_WEIGHT 128 typedef struct WeightedNormalData { - const int numVerts; - const int numEdges; - const int numLoops; - const int numPolys; + const int numVerts; + const int numEdges; + const int numLoops; + const int numPolys; - MVert *mvert; - MEdge *medge; + MVert *mvert; + MEdge *medge; - MLoop *mloop; - short (*clnors)[2]; - const bool has_clnors; /* True if clnors already existed, false if we had to create them. */ - const float split_angle; + MLoop *mloop; + short (*clnors)[2]; + const bool has_clnors; /* True if clnors already existed, false if we had to create them. */ + const float split_angle; - MPoly *mpoly; - float (*polynors)[3]; - int *poly_strength; + MPoly *mpoly; + float (*polynors)[3]; + int *poly_strength; - MDeformVert *dvert; - const int defgrp_index; - const bool use_invert_vgroup; + MDeformVert *dvert; + const int defgrp_index; + const bool use_invert_vgroup; - const float weight; - const short mode; + const float weight; + const short mode; - /* Lower-level, internal processing data. */ - float cached_inverse_powers_of_weight[NUM_CACHED_INVERSE_POWERS_OF_WEIGHT]; + /* Lower-level, internal processing data. */ + float cached_inverse_powers_of_weight[NUM_CACHED_INVERSE_POWERS_OF_WEIGHT]; - WeightedNormalDataAggregateItem *items_data; + WeightedNormalDataAggregateItem *items_data; - ModePair *mode_pair; + ModePair *mode_pair; - int *loop_to_poly; + int *loop_to_poly; } WeightedNormalData; /* Check strength of given poly compared to those found so far for that given item (vertex or smooth fan), * and reset matching item_data in case we get a stronger new strength. */ -static bool check_item_poly_strength( - WeightedNormalData *wn_data, WeightedNormalDataAggregateItem *item_data, const int mp_index) +static bool check_item_poly_strength(WeightedNormalData *wn_data, + WeightedNormalDataAggregateItem *item_data, + const int mp_index) { - BLI_assert (wn_data->poly_strength != NULL); + BLI_assert(wn_data->poly_strength != NULL); - const int mp_strength = wn_data->poly_strength[mp_index]; + const int mp_strength = wn_data->poly_strength[mp_index]; - if (mp_strength > item_data->curr_strength) { - item_data->curr_strength = mp_strength; - item_data->curr_val = 0.0f; - item_data->num_loops = 0; - zero_v3(item_data->normal); - } + if (mp_strength > item_data->curr_strength) { + item_data->curr_strength = mp_strength; + item_data->curr_val = 0.0f; + item_data->num_loops = 0; + zero_v3(item_data->normal); + } - return mp_strength == item_data->curr_strength; + return mp_strength == item_data->curr_strength; } -static void aggregate_item_normal( - WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data, - WeightedNormalDataAggregateItem *item_data, - const int mv_index, const int mp_index, - const float curr_val, const bool use_face_influence) +static void aggregate_item_normal(WeightedNormalModifierData *wnmd, + WeightedNormalData *wn_data, + WeightedNormalDataAggregateItem *item_data, + const int mv_index, + const int mp_index, + const float curr_val, + const bool use_face_influence) { - float (*polynors)[3] = wn_data->polynors; - - MDeformVert *dvert = wn_data->dvert; - const int defgrp_index = wn_data->defgrp_index; - const bool use_invert_vgroup = wn_data->use_invert_vgroup; - - const float weight = wn_data->weight; - - float *cached_inverse_powers_of_weight = wn_data->cached_inverse_powers_of_weight; - - const bool has_vgroup = dvert != NULL; - const bool vert_of_group = has_vgroup && defvert_find_index(&dvert[mv_index], defgrp_index) != NULL; - - if (has_vgroup && ((vert_of_group && use_invert_vgroup) || (!vert_of_group && !use_invert_vgroup))) { - return; - } - - if (use_face_influence && !check_item_poly_strength(wn_data, item_data, mp_index)) { - return; - } - - /* If item's curr_val is 0 init it to present value. */ - if (item_data->curr_val == 0.0f) { - item_data->curr_val = curr_val; - } - if (!compare_ff(item_data->curr_val, curr_val, wnmd->thresh)) { - /* item's curr_val and present value differ more than threshold, update. */ - item_data->num_loops++; - item_data->curr_val = curr_val; - } - - /* Exponentially divided weight for each normal (since a few values will be used by most cases, we cache those). */ - const int num_loops = item_data->num_loops; - if (num_loops < NUM_CACHED_INVERSE_POWERS_OF_WEIGHT && cached_inverse_powers_of_weight[num_loops] == 0.0f) { - cached_inverse_powers_of_weight[num_loops] = 1.0f / powf(weight, num_loops); - } - const float inverted_n_weight = num_loops < NUM_CACHED_INVERSE_POWERS_OF_WEIGHT ? - cached_inverse_powers_of_weight[num_loops] : 1.0f / powf(weight, num_loops); - - madd_v3_v3fl(item_data->normal, polynors[mp_index], curr_val * inverted_n_weight); + float(*polynors)[3] = wn_data->polynors; + + MDeformVert *dvert = wn_data->dvert; + const int defgrp_index = wn_data->defgrp_index; + const bool use_invert_vgroup = wn_data->use_invert_vgroup; + + const float weight = wn_data->weight; + + float *cached_inverse_powers_of_weight = wn_data->cached_inverse_powers_of_weight; + + const bool has_vgroup = dvert != NULL; + const bool vert_of_group = has_vgroup && + defvert_find_index(&dvert[mv_index], defgrp_index) != NULL; + + if (has_vgroup && + ((vert_of_group && use_invert_vgroup) || (!vert_of_group && !use_invert_vgroup))) { + return; + } + + if (use_face_influence && !check_item_poly_strength(wn_data, item_data, mp_index)) { + return; + } + + /* If item's curr_val is 0 init it to present value. */ + if (item_data->curr_val == 0.0f) { + item_data->curr_val = curr_val; + } + if (!compare_ff(item_data->curr_val, curr_val, wnmd->thresh)) { + /* item's curr_val and present value differ more than threshold, update. */ + item_data->num_loops++; + item_data->curr_val = curr_val; + } + + /* Exponentially divided weight for each normal (since a few values will be used by most cases, we cache those). */ + const int num_loops = item_data->num_loops; + if (num_loops < NUM_CACHED_INVERSE_POWERS_OF_WEIGHT && + cached_inverse_powers_of_weight[num_loops] == 0.0f) { + cached_inverse_powers_of_weight[num_loops] = 1.0f / powf(weight, num_loops); + } + const float inverted_n_weight = num_loops < NUM_CACHED_INVERSE_POWERS_OF_WEIGHT ? + cached_inverse_powers_of_weight[num_loops] : + 1.0f / powf(weight, num_loops); + + madd_v3_v3fl(item_data->normal, polynors[mp_index], curr_val * inverted_n_weight); } -static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data) +static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, + WeightedNormalData *wn_data) { - const int numVerts = wn_data->numVerts; - const int numEdges = wn_data->numEdges; - const int numLoops = wn_data->numLoops; - const int numPolys = wn_data->numPolys; - - MVert *mvert = wn_data->mvert; - MEdge *medge = wn_data->medge; - - MLoop *mloop = wn_data->mloop; - short (*clnors)[2] = wn_data->clnors; - int *loop_to_poly = wn_data->loop_to_poly; - - MPoly *mpoly = wn_data->mpoly; - float (*polynors)[3] = wn_data->polynors; - int *poly_strength = wn_data->poly_strength; - - MDeformVert *dvert = wn_data->dvert; - - const short mode = wn_data->mode; - ModePair *mode_pair = wn_data->mode_pair; - - const bool has_clnors = wn_data->has_clnors; - const float split_angle = wn_data->split_angle; - MLoopNorSpaceArray lnors_spacearr = {NULL}; - - const bool keep_sharp = (wnmd->flag & MOD_WEIGHTEDNORMAL_KEEP_SHARP) != 0; - const bool use_face_influence = (wnmd->flag & MOD_WEIGHTEDNORMAL_FACE_INFLUENCE) != 0 && poly_strength != NULL; - const bool has_vgroup = dvert != NULL; - - float (*loop_normals)[3] = NULL; - - WeightedNormalDataAggregateItem *items_data = NULL; - int num_items = 0; - if (keep_sharp) { - BLI_bitmap *done_loops = BLI_BITMAP_NEW(numLoops, __func__); - - /* This will give us loop normal spaces, we do not actually care about computed loop_normals for now... */ - loop_normals = MEM_calloc_arrayN((size_t)numLoops, sizeof(*loop_normals), __func__); - BKE_mesh_normals_loop_split(mvert, numVerts, medge, numEdges, - mloop, loop_normals, numLoops, mpoly, polynors, numPolys, - true, split_angle, &lnors_spacearr, has_clnors ? clnors : NULL, loop_to_poly); - - num_items = lnors_spacearr.num_spaces; - items_data = MEM_calloc_arrayN((size_t)num_items, sizeof(*items_data), __func__); - - /* In this first loop, we assign each WeightedNormalDataAggregateItem - * to its smooth fan of loops (aka lnor space). */ - MPoly *mp; - int mp_index; - int item_index; - for (mp = mpoly, mp_index = 0, item_index = 0; mp_index < numPolys; mp++, mp_index++) { - int ml_index = mp->loopstart; - const int ml_end_index = ml_index + mp->totloop; - - for (; ml_index < ml_end_index; ml_index++) { - if (BLI_BITMAP_TEST(done_loops, ml_index)) { - /* Smooth fan of this loop has already been processed, skip it. */ - continue; - } - BLI_assert(item_index < num_items); - - WeightedNormalDataAggregateItem *itdt = &items_data[item_index]; - itdt->curr_strength = FACE_STRENGTH_WEAK; - - MLoopNorSpace *lnor_space = lnors_spacearr.lspacearr[ml_index]; - lnor_space->user_data = itdt; - - if (!(lnor_space->flags & MLNOR_SPACE_IS_SINGLE)) { - for (LinkNode *lnode = lnor_space->loops; lnode; lnode = lnode->next) { - const int ml_fan_index = POINTER_AS_INT(lnode->link); - BLI_BITMAP_ENABLE(done_loops, ml_fan_index); - } - } - else { - BLI_BITMAP_ENABLE(done_loops, ml_index); - } - - item_index++; - } - } - - MEM_freeN(done_loops); - } - else { - num_items = numVerts; - items_data = MEM_calloc_arrayN((size_t)num_items, sizeof(*items_data), __func__); - if (use_face_influence) { - for (int item_index = 0; item_index < num_items; item_index++) { - items_data[item_index].curr_strength = FACE_STRENGTH_WEAK; - } - } - } - wn_data->items_data = items_data; - - switch (mode) { - case MOD_WEIGHTEDNORMAL_MODE_FACE: - for (int i = 0; i < numPolys; i++) { - const int mp_index = mode_pair[i].index; - const float mp_val = mode_pair[i].val; - - int ml_index = mpoly[mp_index].loopstart; - const int ml_index_end = ml_index + mpoly[mp_index].totloop; - for (; ml_index < ml_index_end; ml_index++) { - const int mv_index = mloop[ml_index].v; - WeightedNormalDataAggregateItem *item_data = keep_sharp ? - lnors_spacearr.lspacearr[ml_index]->user_data: - &items_data[mv_index]; - - aggregate_item_normal(wnmd, wn_data, item_data, mv_index, mp_index, mp_val, use_face_influence); - } - } - break; - case MOD_WEIGHTEDNORMAL_MODE_ANGLE: - case MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE: - BLI_assert(loop_to_poly != NULL); - - for (int i = 0; i < numLoops; i++) { - const int ml_index = mode_pair[i].index; - const float ml_val = mode_pair[i].val; - - const int mp_index = loop_to_poly[ml_index]; - const int mv_index = mloop[ml_index].v; - WeightedNormalDataAggregateItem *item_data = keep_sharp ? - lnors_spacearr.lspacearr[ml_index]->user_data: - &items_data[mv_index]; - - aggregate_item_normal(wnmd, wn_data, item_data, mv_index, mp_index, ml_val, use_face_influence); - } - break; - default: - BLI_assert(0); - } - - /* Validate computed weighted normals. */ - for (int item_index = 0; item_index < num_items; item_index++) { - if (normalize_v3(items_data[item_index].normal) < CLNORS_VALID_VEC_LEN) { - zero_v3(items_data[item_index].normal); - } - } - - if (keep_sharp) { - /* Set loop normals for normal computed for each lnor space (smooth fan). - * Note that loop_normals is already populated with clnors (before this modifier is applied, at start of - * this function), so no need to recompute them here. */ - for (int ml_index = 0; ml_index < numLoops; ml_index++) { - WeightedNormalDataAggregateItem *item_data = lnors_spacearr.lspacearr[ml_index]->user_data; - if (!is_zero_v3(item_data->normal)) { - copy_v3_v3(loop_normals[ml_index], item_data->normal); - } - } - - BKE_mesh_normals_loop_custom_set(mvert, numVerts, medge, numEdges, - mloop, loop_normals, numLoops, mpoly, polynors, numPolys, clnors); - } - else { - /* TODO: Ideally, we could add an option to BKE_mesh_normals_loop_custom_[from_vertices_]set() to keep current - * clnors instead of resetting them to default autocomputed ones, when given new custom normal is zero-vec. - * But this is not exactly trivial change, better to keep this optimization for later... - */ - if (!has_vgroup) { - /* Note: in theory, we could avoid this extra allocation & copying... But think we can live with it for now, - * and it makes code simpler & cleaner. */ - float (*vert_normals)[3] = MEM_calloc_arrayN((size_t)numVerts, sizeof(*loop_normals), __func__); - - for (int ml_index = 0; ml_index < numLoops; ml_index++) { - const int mv_index = mloop[ml_index].v; - copy_v3_v3(vert_normals[mv_index], items_data[mv_index].normal); - } - - BKE_mesh_normals_loop_custom_from_vertices_set(mvert, vert_normals, numVerts, medge, numEdges, - mloop, numLoops, mpoly, polynors, numPolys, clnors); - - MEM_freeN(vert_normals); - } - else { - loop_normals = MEM_calloc_arrayN((size_t)numLoops, sizeof(*loop_normals), __func__); - - BKE_mesh_normals_loop_split(mvert, numVerts, medge, numEdges, - mloop, loop_normals, numLoops, mpoly, polynors, numPolys, - true, split_angle, NULL, has_clnors ? clnors : NULL, loop_to_poly); - - for (int ml_index = 0; ml_index < numLoops; ml_index++) { - const int item_index = mloop[ml_index].v; - if (!is_zero_v3(items_data[item_index].normal)) { - copy_v3_v3(loop_normals[ml_index], items_data[item_index].normal); - } - } - - BKE_mesh_normals_loop_custom_set(mvert, numVerts, medge, numEdges, - mloop, loop_normals, numLoops, mpoly, polynors, numPolys, clnors); - } - } - - if (keep_sharp) { - BKE_lnor_spacearr_free(&lnors_spacearr); - } - MEM_SAFE_FREE(loop_normals); + const int numVerts = wn_data->numVerts; + const int numEdges = wn_data->numEdges; + const int numLoops = wn_data->numLoops; + const int numPolys = wn_data->numPolys; + + MVert *mvert = wn_data->mvert; + MEdge *medge = wn_data->medge; + + MLoop *mloop = wn_data->mloop; + short(*clnors)[2] = wn_data->clnors; + int *loop_to_poly = wn_data->loop_to_poly; + + MPoly *mpoly = wn_data->mpoly; + float(*polynors)[3] = wn_data->polynors; + int *poly_strength = wn_data->poly_strength; + + MDeformVert *dvert = wn_data->dvert; + + const short mode = wn_data->mode; + ModePair *mode_pair = wn_data->mode_pair; + + const bool has_clnors = wn_data->has_clnors; + const float split_angle = wn_data->split_angle; + MLoopNorSpaceArray lnors_spacearr = {NULL}; + + const bool keep_sharp = (wnmd->flag & MOD_WEIGHTEDNORMAL_KEEP_SHARP) != 0; + const bool use_face_influence = (wnmd->flag & MOD_WEIGHTEDNORMAL_FACE_INFLUENCE) != 0 && + poly_strength != NULL; + const bool has_vgroup = dvert != NULL; + + float(*loop_normals)[3] = NULL; + + WeightedNormalDataAggregateItem *items_data = NULL; + int num_items = 0; + if (keep_sharp) { + BLI_bitmap *done_loops = BLI_BITMAP_NEW(numLoops, __func__); + + /* This will give us loop normal spaces, we do not actually care about computed loop_normals for now... */ + loop_normals = MEM_calloc_arrayN((size_t)numLoops, sizeof(*loop_normals), __func__); + BKE_mesh_normals_loop_split(mvert, + numVerts, + medge, + numEdges, + mloop, + loop_normals, + numLoops, + mpoly, + polynors, + numPolys, + true, + split_angle, + &lnors_spacearr, + has_clnors ? clnors : NULL, + loop_to_poly); + + num_items = lnors_spacearr.num_spaces; + items_data = MEM_calloc_arrayN((size_t)num_items, sizeof(*items_data), __func__); + + /* In this first loop, we assign each WeightedNormalDataAggregateItem + * to its smooth fan of loops (aka lnor space). */ + MPoly *mp; + int mp_index; + int item_index; + for (mp = mpoly, mp_index = 0, item_index = 0; mp_index < numPolys; mp++, mp_index++) { + int ml_index = mp->loopstart; + const int ml_end_index = ml_index + mp->totloop; + + for (; ml_index < ml_end_index; ml_index++) { + if (BLI_BITMAP_TEST(done_loops, ml_index)) { + /* Smooth fan of this loop has already been processed, skip it. */ + continue; + } + BLI_assert(item_index < num_items); + + WeightedNormalDataAggregateItem *itdt = &items_data[item_index]; + itdt->curr_strength = FACE_STRENGTH_WEAK; + + MLoopNorSpace *lnor_space = lnors_spacearr.lspacearr[ml_index]; + lnor_space->user_data = itdt; + + if (!(lnor_space->flags & MLNOR_SPACE_IS_SINGLE)) { + for (LinkNode *lnode = lnor_space->loops; lnode; lnode = lnode->next) { + const int ml_fan_index = POINTER_AS_INT(lnode->link); + BLI_BITMAP_ENABLE(done_loops, ml_fan_index); + } + } + else { + BLI_BITMAP_ENABLE(done_loops, ml_index); + } + + item_index++; + } + } + + MEM_freeN(done_loops); + } + else { + num_items = numVerts; + items_data = MEM_calloc_arrayN((size_t)num_items, sizeof(*items_data), __func__); + if (use_face_influence) { + for (int item_index = 0; item_index < num_items; item_index++) { + items_data[item_index].curr_strength = FACE_STRENGTH_WEAK; + } + } + } + wn_data->items_data = items_data; + + switch (mode) { + case MOD_WEIGHTEDNORMAL_MODE_FACE: + for (int i = 0; i < numPolys; i++) { + const int mp_index = mode_pair[i].index; + const float mp_val = mode_pair[i].val; + + int ml_index = mpoly[mp_index].loopstart; + const int ml_index_end = ml_index + mpoly[mp_index].totloop; + for (; ml_index < ml_index_end; ml_index++) { + const int mv_index = mloop[ml_index].v; + WeightedNormalDataAggregateItem *item_data = + keep_sharp ? lnors_spacearr.lspacearr[ml_index]->user_data : &items_data[mv_index]; + + aggregate_item_normal( + wnmd, wn_data, item_data, mv_index, mp_index, mp_val, use_face_influence); + } + } + break; + case MOD_WEIGHTEDNORMAL_MODE_ANGLE: + case MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE: + BLI_assert(loop_to_poly != NULL); + + for (int i = 0; i < numLoops; i++) { + const int ml_index = mode_pair[i].index; + const float ml_val = mode_pair[i].val; + + const int mp_index = loop_to_poly[ml_index]; + const int mv_index = mloop[ml_index].v; + WeightedNormalDataAggregateItem *item_data = + keep_sharp ? lnors_spacearr.lspacearr[ml_index]->user_data : &items_data[mv_index]; + + aggregate_item_normal( + wnmd, wn_data, item_data, mv_index, mp_index, ml_val, use_face_influence); + } + break; + default: + BLI_assert(0); + } + + /* Validate computed weighted normals. */ + for (int item_index = 0; item_index < num_items; item_index++) { + if (normalize_v3(items_data[item_index].normal) < CLNORS_VALID_VEC_LEN) { + zero_v3(items_data[item_index].normal); + } + } + + if (keep_sharp) { + /* Set loop normals for normal computed for each lnor space (smooth fan). + * Note that loop_normals is already populated with clnors (before this modifier is applied, at start of + * this function), so no need to recompute them here. */ + for (int ml_index = 0; ml_index < numLoops; ml_index++) { + WeightedNormalDataAggregateItem *item_data = lnors_spacearr.lspacearr[ml_index]->user_data; + if (!is_zero_v3(item_data->normal)) { + copy_v3_v3(loop_normals[ml_index], item_data->normal); + } + } + + BKE_mesh_normals_loop_custom_set(mvert, + numVerts, + medge, + numEdges, + mloop, + loop_normals, + numLoops, + mpoly, + polynors, + numPolys, + clnors); + } + else { + /* TODO: Ideally, we could add an option to BKE_mesh_normals_loop_custom_[from_vertices_]set() to keep current + * clnors instead of resetting them to default autocomputed ones, when given new custom normal is zero-vec. + * But this is not exactly trivial change, better to keep this optimization for later... + */ + if (!has_vgroup) { + /* Note: in theory, we could avoid this extra allocation & copying... But think we can live with it for now, + * and it makes code simpler & cleaner. */ + float(*vert_normals)[3] = MEM_calloc_arrayN( + (size_t)numVerts, sizeof(*loop_normals), __func__); + + for (int ml_index = 0; ml_index < numLoops; ml_index++) { + const int mv_index = mloop[ml_index].v; + copy_v3_v3(vert_normals[mv_index], items_data[mv_index].normal); + } + + BKE_mesh_normals_loop_custom_from_vertices_set(mvert, + vert_normals, + numVerts, + medge, + numEdges, + mloop, + numLoops, + mpoly, + polynors, + numPolys, + clnors); + + MEM_freeN(vert_normals); + } + else { + loop_normals = MEM_calloc_arrayN((size_t)numLoops, sizeof(*loop_normals), __func__); + + BKE_mesh_normals_loop_split(mvert, + numVerts, + medge, + numEdges, + mloop, + loop_normals, + numLoops, + mpoly, + polynors, + numPolys, + true, + split_angle, + NULL, + has_clnors ? clnors : NULL, + loop_to_poly); + + for (int ml_index = 0; ml_index < numLoops; ml_index++) { + const int item_index = mloop[ml_index].v; + if (!is_zero_v3(items_data[item_index].normal)) { + copy_v3_v3(loop_normals[ml_index], items_data[item_index].normal); + } + } + + BKE_mesh_normals_loop_custom_set(mvert, + numVerts, + medge, + numEdges, + mloop, + loop_normals, + numLoops, + mpoly, + polynors, + numPolys, + clnors); + } + } + + if (keep_sharp) { + BKE_lnor_spacearr_free(&lnors_spacearr); + } + MEM_SAFE_FREE(loop_normals); } static void wn_face_area(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data) { - const int numPolys = wn_data->numPolys; + const int numPolys = wn_data->numPolys; - MVert *mvert = wn_data->mvert; - MLoop *mloop = wn_data->mloop; - MPoly *mpoly = wn_data->mpoly; + MVert *mvert = wn_data->mvert; + MLoop *mloop = wn_data->mloop; + MPoly *mpoly = wn_data->mpoly; - MPoly *mp; - int mp_index; + MPoly *mp; + int mp_index; - ModePair *face_area = MEM_malloc_arrayN((size_t)numPolys, sizeof(*face_area), __func__); + ModePair *face_area = MEM_malloc_arrayN((size_t)numPolys, sizeof(*face_area), __func__); - ModePair *f_area = face_area; - for (mp_index = 0, mp = mpoly; mp_index < numPolys; mp_index++, mp++, f_area++) { - f_area->val = BKE_mesh_calc_poly_area(mp, &mloop[mp->loopstart], mvert); - f_area->index = mp_index; - } + ModePair *f_area = face_area; + for (mp_index = 0, mp = mpoly; mp_index < numPolys; mp_index++, mp++, f_area++) { + f_area->val = BKE_mesh_calc_poly_area(mp, &mloop[mp->loopstart], mvert); + f_area->index = mp_index; + } - qsort(face_area, numPolys, sizeof(*face_area), modepair_cmp_by_val_inverse); + qsort(face_area, numPolys, sizeof(*face_area), modepair_cmp_by_val_inverse); - wn_data->mode_pair = face_area; - apply_weights_vertex_normal(wnmd, wn_data); + wn_data->mode_pair = face_area; + apply_weights_vertex_normal(wnmd, wn_data); } static void wn_corner_angle(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data) { - const int numLoops = wn_data->numLoops; - const int numPolys = wn_data->numPolys; + const int numLoops = wn_data->numLoops; + const int numPolys = wn_data->numPolys; - MVert *mvert = wn_data->mvert; - MLoop *mloop = wn_data->mloop; - MPoly *mpoly = wn_data->mpoly; + MVert *mvert = wn_data->mvert; + MLoop *mloop = wn_data->mloop; + MPoly *mpoly = wn_data->mpoly; - MPoly *mp; - int mp_index; + MPoly *mp; + int mp_index; - int *loop_to_poly = MEM_malloc_arrayN((size_t)numLoops, sizeof(*loop_to_poly), __func__); + int *loop_to_poly = MEM_malloc_arrayN((size_t)numLoops, sizeof(*loop_to_poly), __func__); - ModePair *corner_angle = MEM_malloc_arrayN((size_t)numLoops, sizeof(*corner_angle), __func__); + ModePair *corner_angle = MEM_malloc_arrayN((size_t)numLoops, sizeof(*corner_angle), __func__); - for (mp_index = 0, mp = mpoly; mp_index < numPolys; mp_index++, mp++) { - MLoop *ml_start = &mloop[mp->loopstart]; + for (mp_index = 0, mp = mpoly; mp_index < numPolys; mp_index++, mp++) { + MLoop *ml_start = &mloop[mp->loopstart]; - float *index_angle = MEM_malloc_arrayN((size_t)mp->totloop, sizeof(*index_angle), __func__); - BKE_mesh_calc_poly_angles(mp, ml_start, mvert, index_angle); + float *index_angle = MEM_malloc_arrayN((size_t)mp->totloop, sizeof(*index_angle), __func__); + BKE_mesh_calc_poly_angles(mp, ml_start, mvert, index_angle); - ModePair *c_angl = &corner_angle[mp->loopstart]; - float *angl = index_angle; - for (int ml_index = mp->loopstart; ml_index < mp->loopstart + mp->totloop; ml_index++, c_angl++, angl++) { - c_angl->val = (float)M_PI - *angl; - c_angl->index = ml_index; + ModePair *c_angl = &corner_angle[mp->loopstart]; + float *angl = index_angle; + for (int ml_index = mp->loopstart; ml_index < mp->loopstart + mp->totloop; + ml_index++, c_angl++, angl++) { + c_angl->val = (float)M_PI - *angl; + c_angl->index = ml_index; - loop_to_poly[ml_index] = mp_index; - } - MEM_freeN(index_angle); - } + loop_to_poly[ml_index] = mp_index; + } + MEM_freeN(index_angle); + } - qsort(corner_angle, numLoops, sizeof(*corner_angle), modepair_cmp_by_val_inverse); + qsort(corner_angle, numLoops, sizeof(*corner_angle), modepair_cmp_by_val_inverse); - wn_data->loop_to_poly = loop_to_poly; - wn_data->mode_pair = corner_angle; - apply_weights_vertex_normal(wnmd, wn_data); + wn_data->loop_to_poly = loop_to_poly; + wn_data->mode_pair = corner_angle; + apply_weights_vertex_normal(wnmd, wn_data); } static void wn_face_with_angle(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data) { - const int numLoops = wn_data->numLoops; - const int numPolys = wn_data->numPolys; + const int numLoops = wn_data->numLoops; + const int numPolys = wn_data->numPolys; - MVert *mvert = wn_data->mvert; - MLoop *mloop = wn_data->mloop; - MPoly *mpoly = wn_data->mpoly; + MVert *mvert = wn_data->mvert; + MLoop *mloop = wn_data->mloop; + MPoly *mpoly = wn_data->mpoly; - MPoly *mp; - int mp_index; + MPoly *mp; + int mp_index; - int *loop_to_poly = MEM_malloc_arrayN((size_t)numLoops, sizeof(*loop_to_poly), __func__); + int *loop_to_poly = MEM_malloc_arrayN((size_t)numLoops, sizeof(*loop_to_poly), __func__); - ModePair *combined = MEM_malloc_arrayN((size_t)numLoops, sizeof(*combined), __func__); + ModePair *combined = MEM_malloc_arrayN((size_t)numLoops, sizeof(*combined), __func__); - for (mp_index = 0, mp = mpoly; mp_index < numPolys; mp_index++, mp++) { - MLoop *ml_start = &mloop[mp->loopstart]; + for (mp_index = 0, mp = mpoly; mp_index < numPolys; mp_index++, mp++) { + MLoop *ml_start = &mloop[mp->loopstart]; - float face_area = BKE_mesh_calc_poly_area(mp, ml_start, mvert); - float *index_angle = MEM_malloc_arrayN((size_t)mp->totloop, sizeof(*index_angle), __func__); - BKE_mesh_calc_poly_angles(mp, ml_start, mvert, index_angle); + float face_area = BKE_mesh_calc_poly_area(mp, ml_start, mvert); + float *index_angle = MEM_malloc_arrayN((size_t)mp->totloop, sizeof(*index_angle), __func__); + BKE_mesh_calc_poly_angles(mp, ml_start, mvert, index_angle); - ModePair *cmbnd = &combined[mp->loopstart]; - float *angl = index_angle; - for (int ml_index = mp->loopstart; ml_index < mp->loopstart + mp->totloop; ml_index++, cmbnd++, angl++) { - /* In this case val is product of corner angle and face area. */ - cmbnd->val = ((float)M_PI - *angl) * face_area; - cmbnd->index = ml_index; + ModePair *cmbnd = &combined[mp->loopstart]; + float *angl = index_angle; + for (int ml_index = mp->loopstart; ml_index < mp->loopstart + mp->totloop; + ml_index++, cmbnd++, angl++) { + /* In this case val is product of corner angle and face area. */ + cmbnd->val = ((float)M_PI - *angl) * face_area; + cmbnd->index = ml_index; - loop_to_poly[ml_index] = mp_index; - } - MEM_freeN(index_angle); - } + loop_to_poly[ml_index] = mp_index; + } + MEM_freeN(index_angle); + } - qsort(combined, numLoops, sizeof(*combined), modepair_cmp_by_val_inverse); + qsort(combined, numLoops, sizeof(*combined), modepair_cmp_by_val_inverse); - wn_data->loop_to_poly = loop_to_poly; - wn_data->mode_pair = combined; - apply_weights_vertex_normal(wnmd, wn_data); + wn_data->loop_to_poly = loop_to_poly; + wn_data->mode_pair = combined; + apply_weights_vertex_normal(wnmd, wn_data); } static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) { - WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md; - Object *ob = ctx->object; + WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md; + Object *ob = ctx->object; - /* XXX TODO ARG GRRR XYQWNMPRXTYY - * Once we fully switch to Mesh evaluation of modifiers, we can expect to get that flag from the COW copy. - * But for now, it is lost in the DM intermediate step, so we need to directly check orig object's data. */ + /* XXX TODO ARG GRRR XYQWNMPRXTYY + * Once we fully switch to Mesh evaluation of modifiers, we can expect to get that flag from the COW copy. + * But for now, it is lost in the DM intermediate step, so we need to directly check orig object's data. */ #if 0 - if (!(mesh->flag & ME_AUTOSMOOTH)) { + if (!(mesh->flag & ME_AUTOSMOOTH)) { #else - if (!(((Mesh *)ob->data)->flag & ME_AUTOSMOOTH)) { + if (!(((Mesh *)ob->data)->flag & ME_AUTOSMOOTH)) { #endif - modifier_setError((ModifierData *)wnmd, "Enable 'Auto Smooth' option in mesh settings"); - return mesh; - } - - Mesh *result; - BKE_id_copy_ex(NULL, &mesh->id, (ID **)&result, LIB_ID_COPY_LOCALIZE); - - const int numVerts = result->totvert; - const int numEdges = result->totedge; - const int numLoops = result->totloop; - const int numPolys = result->totpoly; - - MEdge *medge = result->medge; - MPoly *mpoly = result->mpoly; - MVert *mvert = result->mvert; - MLoop *mloop = result->mloop; - - /* Right now: - * If weight = 50 then all faces are given equal weight. - * If weight > 50 then more weight given to faces with larger vals (face area / corner angle). - * If weight < 50 then more weight given to faces with lesser vals. However current calculation - * does not converge to min/max. - */ - float weight = ((float)wnmd->weight) / 50.0f; - if (wnmd->weight == 100) { - weight = (float)SHRT_MAX; - } - else if (wnmd->weight == 1) { - weight = 1 / (float)SHRT_MAX; - } - else if ((weight - 1) * 25 > 1) { - weight = (weight - 1) * 25; - } - - CustomData *pdata = &result->pdata; - float (*polynors)[3] = CustomData_get_layer(pdata, CD_NORMAL); - if (!polynors) { - polynors = CustomData_add_layer(pdata, CD_NORMAL, CD_CALLOC, NULL, numPolys); - CustomData_set_layer_flag(pdata, CD_NORMAL, CD_FLAG_TEMPORARY); - } - BKE_mesh_calc_normals_poly(mvert, NULL, numVerts, mloop, mpoly, numLoops, numPolys, polynors, false); - - - const float split_angle = mesh->smoothresh; - short (*clnors)[2]; - CustomData *ldata = &result->ldata; - clnors = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL); - - /* Keep info whether we had clnors, it helps when generating clnor spaces and default normals. */ - const bool has_clnors = clnors != NULL; - if (!clnors) { - clnors = CustomData_add_layer(ldata, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL, numLoops); - } - - MDeformVert *dvert; - int defgrp_index; - MOD_get_vgroup(ctx->object, mesh, wnmd->defgrp_name, &dvert, &defgrp_index); - - WeightedNormalData wn_data = { - .numVerts = numVerts, - .numEdges = numEdges, - .numLoops = numLoops, - .numPolys = numPolys, - - .mvert = mvert, - .medge = medge, - - .mloop = mloop, - .clnors = clnors, - .has_clnors = has_clnors, - .split_angle = split_angle, - - .mpoly = mpoly, - .polynors = polynors, - .poly_strength = CustomData_get_layer_named( - &result->pdata, CD_PROP_INT, - MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID), - - .dvert = dvert, - .defgrp_index = defgrp_index, - .use_invert_vgroup = (wnmd->flag & MOD_WEIGHTEDNORMAL_INVERT_VGROUP) != 0, - - .weight = weight, - .mode = wnmd->mode, - }; - - switch (wnmd->mode) { - case MOD_WEIGHTEDNORMAL_MODE_FACE: - wn_face_area(wnmd, &wn_data); - break; - case MOD_WEIGHTEDNORMAL_MODE_ANGLE: - wn_corner_angle(wnmd, &wn_data); - break; - case MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE: - wn_face_with_angle(wnmd, &wn_data); - break; - } - - MEM_SAFE_FREE(wn_data.loop_to_poly); - MEM_SAFE_FREE(wn_data.mode_pair); - MEM_SAFE_FREE(wn_data.items_data); - - /* Currently Modifier stack assumes there is no poly normal data passed around... */ - CustomData_free_layers(pdata, CD_NORMAL, numPolys); - return result; + modifier_setError((ModifierData *)wnmd, "Enable 'Auto Smooth' option in mesh settings"); + return mesh; +} + +Mesh *result; +BKE_id_copy_ex(NULL, &mesh->id, (ID **)&result, LIB_ID_COPY_LOCALIZE); + +const int numVerts = result->totvert; +const int numEdges = result->totedge; +const int numLoops = result->totloop; +const int numPolys = result->totpoly; + +MEdge *medge = result->medge; +MPoly *mpoly = result->mpoly; +MVert *mvert = result->mvert; +MLoop *mloop = result->mloop; + +/* Right now: + * If weight = 50 then all faces are given equal weight. + * If weight > 50 then more weight given to faces with larger vals (face area / corner angle). + * If weight < 50 then more weight given to faces with lesser vals. However current calculation + * does not converge to min/max. + */ +float weight = ((float)wnmd->weight) / 50.0f; +if (wnmd->weight == 100) { + weight = (float)SHRT_MAX; +} +else if (wnmd->weight == 1) { + weight = 1 / (float)SHRT_MAX; +} +else if ((weight - 1) * 25 > 1) { + weight = (weight - 1) * 25; +} + +CustomData *pdata = &result->pdata; +float (*polynors)[3] = CustomData_get_layer(pdata, CD_NORMAL); +if (!polynors) { + polynors = CustomData_add_layer(pdata, CD_NORMAL, CD_CALLOC, NULL, numPolys); + CustomData_set_layer_flag(pdata, CD_NORMAL, CD_FLAG_TEMPORARY); +} +BKE_mesh_calc_normals_poly( + mvert, NULL, numVerts, mloop, mpoly, numLoops, numPolys, polynors, false); + +const float split_angle = mesh->smoothresh; +short (*clnors)[2]; +CustomData *ldata = &result->ldata; +clnors = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL); + +/* Keep info whether we had clnors, it helps when generating clnor spaces and default normals. */ +const bool has_clnors = clnors != NULL; +if (!clnors) { + clnors = CustomData_add_layer(ldata, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL, numLoops); +} + +MDeformVert *dvert; +int defgrp_index; +MOD_get_vgroup(ctx->object, mesh, wnmd->defgrp_name, &dvert, &defgrp_index); + +WeightedNormalData wn_data = { + .numVerts = numVerts, + .numEdges = numEdges, + .numLoops = numLoops, + .numPolys = numPolys, + + .mvert = mvert, + .medge = medge, + + .mloop = mloop, + .clnors = clnors, + .has_clnors = has_clnors, + .split_angle = split_angle, + + .mpoly = mpoly, + .polynors = polynors, + .poly_strength = CustomData_get_layer_named( + &result->pdata, CD_PROP_INT, MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID), + + .dvert = dvert, + .defgrp_index = defgrp_index, + .use_invert_vgroup = (wnmd->flag & MOD_WEIGHTEDNORMAL_INVERT_VGROUP) != 0, + + .weight = weight, + .mode = wnmd->mode, +}; + +switch (wnmd->mode) { + case MOD_WEIGHTEDNORMAL_MODE_FACE: + wn_face_area(wnmd, &wn_data); + break; + case MOD_WEIGHTEDNORMAL_MODE_ANGLE: + wn_corner_angle(wnmd, &wn_data); + break; + case MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE: + wn_face_with_angle(wnmd, &wn_data); + break; +} + +MEM_SAFE_FREE(wn_data.loop_to_poly); +MEM_SAFE_FREE(wn_data.mode_pair); +MEM_SAFE_FREE(wn_data.items_data); + +/* Currently Modifier stack assumes there is no poly normal data passed around... */ +CustomData_free_layers(pdata, CD_NORMAL, numPolys); +return result; } static void initData(ModifierData *md) { - WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md; - wnmd->mode = MOD_WEIGHTEDNORMAL_MODE_FACE; - wnmd->weight = 50; - wnmd->thresh = 1e-2f; - wnmd->flag = 0; + WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md; + wnmd->mode = MOD_WEIGHTEDNORMAL_MODE_FACE; + wnmd->weight = 50; + wnmd->thresh = 1e-2f; + wnmd->flag = 0; } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md; + WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md; - r_cddata_masks->lmask = CD_MASK_CUSTOMLOOPNORMAL; + r_cddata_masks->lmask = CD_MASK_CUSTOMLOOPNORMAL; - if (wnmd->defgrp_name[0] != '\0') { - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; - } + if (wnmd->defgrp_name[0] != '\0') { + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + } - if (wnmd->flag & MOD_WEIGHTEDNORMAL_FACE_INFLUENCE) { - r_cddata_masks->pmask |= CD_MASK_PROP_INT; - } + if (wnmd->flag & MOD_WEIGHTEDNORMAL_FACE_INFLUENCE) { + r_cddata_masks->pmask |= CD_MASK_PROP_INT; + } } static bool dependsOnNormals(ModifierData *UNUSED(md)) { - return true; + return true; } ModifierTypeInfo modifierType_WeightedNormal = { - /* name */ "Weighted Normal", - /* structName */ "WeightedNormalModifierData", - /* structSize */ sizeof(WeightedNormalModifierData), - /* type */ eModifierTypeType_Constructive, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_SupportsMapping | - eModifierTypeFlag_SupportsEditmode | - eModifierTypeFlag_EnableInEditmode, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ NULL, - /* isDisabled */ NULL, - /* updateDepsgraph */ NULL, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ dependsOnNormals, - /* foreachObjectLink */ NULL, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Weighted Normal", + /* structName */ "WeightedNormalModifierData", + /* structSize */ sizeof(WeightedNormalModifierData), + /* type */ eModifierTypeType_Constructive, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping | + eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ dependsOnNormals, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.c b/source/blender/modifiers/intern/MOD_weightvg_util.c index d0631a0c30b..3e1c2f9bc02 100644 --- a/source/blender/modifiers/intern/MOD_weightvg_util.c +++ b/source/blender/modifiers/intern/MOD_weightvg_util.c @@ -27,18 +27,18 @@ #include "BLI_rand.h" #include "BLI_string.h" -#include "DNA_color_types.h" /* CurveMapping. */ +#include "DNA_color_types.h" /* CurveMapping. */ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" -#include "BKE_colortools.h" /* CurveMapping. */ +#include "BKE_colortools.h" /* CurveMapping. */ #include "BKE_customdata.h" #include "BKE_deform.h" #include "BKE_modifier.h" -#include "BKE_texture.h" /* Texture masking. */ +#include "BKE_texture.h" /* Texture masking. */ #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" @@ -46,7 +46,7 @@ #include "MEM_guardedalloc.h" #include "MOD_util.h" #include "MOD_weightvg_util.h" -#include "RE_shader_ext.h" /* Texture masking. */ +#include "RE_shader_ext.h" /* Texture masking. */ /* Maps new_w weights in place, using either one of the predefined functions, or a custom curve. * Return values are in new_w. @@ -56,54 +56,57 @@ */ void weightvg_do_map(int num, float *new_w, short falloff_type, CurveMapping *cmap, RNG *rng) { - int i; + int i; - /* Return immediately, if we have nothing to do! */ - /* Also security checks... */ - if (((falloff_type == MOD_WVG_MAPPING_CURVE) && (cmap == NULL)) || - !ELEM(falloff_type, MOD_WVG_MAPPING_CURVE, MOD_WVG_MAPPING_SHARP, MOD_WVG_MAPPING_SMOOTH, - MOD_WVG_MAPPING_ROOT, MOD_WVG_MAPPING_SPHERE, MOD_WVG_MAPPING_RANDOM, - MOD_WVG_MAPPING_STEP)) - { - return; - } + /* Return immediately, if we have nothing to do! */ + /* Also security checks... */ + if (((falloff_type == MOD_WVG_MAPPING_CURVE) && (cmap == NULL)) || !ELEM(falloff_type, + MOD_WVG_MAPPING_CURVE, + MOD_WVG_MAPPING_SHARP, + MOD_WVG_MAPPING_SMOOTH, + MOD_WVG_MAPPING_ROOT, + MOD_WVG_MAPPING_SPHERE, + MOD_WVG_MAPPING_RANDOM, + MOD_WVG_MAPPING_STEP)) { + return; + } - if (cmap && falloff_type == MOD_WVG_MAPPING_CURVE) { - curvemapping_initialize(cmap); - } + if (cmap && falloff_type == MOD_WVG_MAPPING_CURVE) { + curvemapping_initialize(cmap); + } - /* Map each weight (vertex) to its new value, accordingly to the chosen mode. */ - for (i = 0; i < num; ++i) { - float fac = new_w[i]; + /* Map each weight (vertex) to its new value, accordingly to the chosen mode. */ + for (i = 0; i < num; ++i) { + float fac = new_w[i]; - /* Code borrowed from the warp modifier. */ - /* Closely matches PROP_SMOOTH and similar. */ - switch (falloff_type) { - case MOD_WVG_MAPPING_CURVE: - fac = curvemapping_evaluateF(cmap, 0, fac); - break; - case MOD_WVG_MAPPING_SHARP: - fac = fac * fac; - break; - case MOD_WVG_MAPPING_SMOOTH: - fac = 3.0f * fac * fac - 2.0f * fac * fac * fac; - break; - case MOD_WVG_MAPPING_ROOT: - fac = sqrtf(fac); - break; - case MOD_WVG_MAPPING_SPHERE: - fac = sqrtf(2 * fac - fac * fac); - break; - case MOD_WVG_MAPPING_RANDOM: - fac = BLI_rng_get_float(rng) * fac; - break; - case MOD_WVG_MAPPING_STEP: - fac = (fac >= 0.5f) ? 1.0f : 0.0f; - break; - } + /* Code borrowed from the warp modifier. */ + /* Closely matches PROP_SMOOTH and similar. */ + switch (falloff_type) { + case MOD_WVG_MAPPING_CURVE: + fac = curvemapping_evaluateF(cmap, 0, fac); + break; + case MOD_WVG_MAPPING_SHARP: + fac = fac * fac; + break; + case MOD_WVG_MAPPING_SMOOTH: + fac = 3.0f * fac * fac - 2.0f * fac * fac * fac; + break; + case MOD_WVG_MAPPING_ROOT: + fac = sqrtf(fac); + break; + case MOD_WVG_MAPPING_SPHERE: + fac = sqrtf(2 * fac - fac * fac); + break; + case MOD_WVG_MAPPING_RANDOM: + fac = BLI_rng_get_float(rng) * fac; + break; + case MOD_WVG_MAPPING_STEP: + fac = (fac >= 0.5f) ? 1.0f : 0.0f; + break; + } - new_w[i] = fac; - } + new_w[i] = fac; + } } /* Applies new_w weights to org_w ones, using either a texture, vgroup or constant value as factor. @@ -112,158 +115,174 @@ void weightvg_do_map(int num, float *new_w, short falloff_type, CurveMapping *cm * 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( - const ModifierEvalContext *ctx, - const int num, const int *indices, float *org_w, const float *new_w, - Object *ob, Mesh *mesh, const float fact, const char defgrp_name[MAX_VGROUP_NAME], - Scene *scene, Tex *texture, const int tex_use_channel, const int tex_mapping, - Object *tex_map_object, const char *tex_uvlayer_name) +void weightvg_do_mask(const ModifierEvalContext *ctx, + const int num, + const int *indices, + float *org_w, + const float *new_w, + Object *ob, + Mesh *mesh, + const float fact, + const char defgrp_name[MAX_VGROUP_NAME], + Scene *scene, + Tex *texture, + const int tex_use_channel, + const int tex_mapping, + Object *tex_map_object, + const char *tex_uvlayer_name) { - int ref_didx; - int i; + int ref_didx; + int i; - /* If influence factor is null, nothing to do! */ - if (fact == 0.0f) return; + /* 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 != NULL) { - /* The texture coordinates. */ - float (*tex_co)[3]; - /* See mapping note below... */ - MappingInfoModifierData t_map; - const int numVerts = mesh->totvert; + /* If we want to mask vgroup weights from a texture. */ + if (texture != NULL) { + /* The texture coordinates. */ + float(*tex_co)[3]; + /* See mapping note below... */ + MappingInfoModifierData t_map; + const int numVerts = mesh->totvert; - /* 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; + /* 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; - tex_co = MEM_calloc_arrayN(numVerts, sizeof(*tex_co), "WeightVG Modifier, TEX mode, tex_co"); - MOD_get_texture_coords(&t_map, ctx, ob, mesh, NULL, tex_co); + tex_co = MEM_calloc_arrayN(numVerts, sizeof(*tex_co), "WeightVG Modifier, TEX mode, tex_co"); + MOD_get_texture_coords(&t_map, ctx, ob, mesh, NULL, tex_co); - MOD_init_texture(&t_map, ctx); + MOD_init_texture(&t_map, ctx); - /* 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; + /* 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; + 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; - } - } + 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; + 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. */ + /* 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 = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT); - /* Proceed only if vgroup is valid, else assume factor = O. */ - if (dvert == NULL) { - return; - } + /* Proceed only if vgroup is valid, else use constant factor. */ + /* Get actual dverts (ie vertex group data). */ + dvert = CustomData_get_layer(&mesh->vdata, 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); - } - } + /* 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); + } + } } - /* Applies weights to given vgroup (defgroup), and optionally add/remove vertices from the group. * If dws is not NULL, it must be an array of MDeformWeight pointers of same length as weights (and * defgrp_idx can then have any value). * If indices is not NULL, it must be an array of same length as weights, mapping to the real * vertex index (in case the weight array does not cover the whole vertices...). */ -void weightvg_update_vg( - MDeformVert *dvert, int defgrp_idx, MDeformWeight **dws, int num, - const int *indices, const float *weights, const bool do_add, - const float add_thresh, const bool do_rem, const float rem_thresh) +void weightvg_update_vg(MDeformVert *dvert, + int defgrp_idx, + MDeformWeight **dws, + int num, + const int *indices, + const float *weights, + const bool do_add, + const float add_thresh, + const bool do_rem, + const float rem_thresh) { - int i; + int i; - for (i = 0; i < num; i++) { - float w = weights[i]; - MDeformVert *dv = &dvert[indices ? indices[i] : i]; - MDeformWeight *dw = dws ? dws[i] : ((defgrp_idx >= 0) ? defvert_find_index(dv, defgrp_idx) : NULL); + for (i = 0; i < num; i++) { + float w = weights[i]; + MDeformVert *dv = &dvert[indices ? indices[i] : i]; + MDeformWeight *dw = dws ? dws[i] : + ((defgrp_idx >= 0) ? defvert_find_index(dv, defgrp_idx) : NULL); - /* Never allow weights out of [0.0, 1.0] range. */ - CLAMP(w, 0.0f, 1.0f); + /* Never allow weights out of [0.0, 1.0] range. */ + CLAMP(w, 0.0f, 1.0f); - /* If the vertex is in this vgroup, remove it if needed, or just update it. */ - if (dw != NULL) { - if (do_rem && w < rem_thresh) { - defvert_remove_group(dv, dw); - } - else { - dw->weight = w; - } - } - /* Else, add it if needed! */ - else if (do_add && w > add_thresh) { - defvert_add_index_notest(dv, defgrp_idx, w); - } - } + /* If the vertex is in this vgroup, remove it if needed, or just update it. */ + if (dw != NULL) { + if (do_rem && w < rem_thresh) { + defvert_remove_group(dv, dw); + } + else { + dw->weight = w; + } + } + /* Else, add it if needed! */ + else if (do_add && w > add_thresh) { + defvert_add_index_notest(dv, defgrp_idx, w); + } + } } diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.h b/source/blender/modifiers/intern/MOD_weightvg_util.h index 8bc56eb61f9..d73cca935d7 100644 --- a/source/blender/modifiers/intern/MOD_weightvg_util.h +++ b/source/blender/modifiers/intern/MOD_weightvg_util.h @@ -50,7 +50,7 @@ struct Tex; * we clamp weightf to this value (or its negative version). * Also used to avoid null power factor. */ -#define MOD_WVG_ZEROFLOOR 1.0e-32f +#define MOD_WVG_ZEROFLOOR 1.0e-32f /* Maps new_w weights in place, using either one of the predefined functions, or a custom curve. * Return values are in new_w. @@ -58,7 +58,8 @@ struct Tex; * vertex index (in case the weight tables do not cover the whole vertices...). * cmap might be NULL, in which case curve mapping mode will return unmodified data. */ -void weightvg_do_map(int num, float *new_w, short mode, struct CurveMapping *cmap, struct RNG *rng); +void weightvg_do_map( + int num, float *new_w, short mode, struct CurveMapping *cmap, struct RNG *rng); /* Applies new_w weights to org_w ones, using either a texture, vgroup or constant value as factor. * Return values are in org_w. @@ -66,20 +67,35 @@ void weightvg_do_map(int num, float *new_w, short mode, struct CurveMapping *cma * 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( - const ModifierEvalContext *ctx, - const int num, const int *indices, float *org_w, const float *new_w, Object *ob, - struct Mesh *mesh, const float fact, const char defgrp_name[MAX_VGROUP_NAME], - struct Scene *scene, Tex *texture, const int tex_use_channel, const int tex_mapping, - Object *tex_map_object, const char *tex_uvlayer_name); +void weightvg_do_mask(const ModifierEvalContext *ctx, + const int num, + const int *indices, + float *org_w, + const float *new_w, + Object *ob, + struct Mesh *mesh, + const float fact, + const char defgrp_name[MAX_VGROUP_NAME], + struct Scene *scene, + Tex *texture, + const int tex_use_channel, + const int tex_mapping, + Object *tex_map_object, + const char *tex_uvlayer_name); /* Applies weights to given vgroup (defgroup), and optionally add/remove vertices from the group. * If indices is not NULL, it must be a table of same length as weights, mapping to the real * vertex index (in case the weight table does not cover the whole vertices...). */ -void weightvg_update_vg( - struct MDeformVert *dvert, int defgrp_idx, struct MDeformWeight **dws, int num, - const int *indices, const float *weights, const bool do_add, - const float add_thresh, const bool do_rem, const float rem_thresh); +void weightvg_update_vg(struct MDeformVert *dvert, + int defgrp_idx, + struct MDeformWeight **dws, + int num, + const int *indices, + const float *weights, + const bool do_add, + const float add_thresh, + const bool do_rem, + const float rem_thresh); #endif /* __MOD_WEIGHTVG_UTIL_H__ */ diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c index 17ccd67dfc9..5f4983af6cc 100644 --- a/source/blender/modifiers/intern/MOD_weightvgedit.c +++ b/source/blender/modifiers/intern/MOD_weightvgedit.c @@ -27,17 +27,17 @@ #include "BLI_listbase.h" #include "BLI_rand.h" -#include "DNA_color_types.h" /* CurveMapping. */ +#include "DNA_color_types.h" /* CurveMapping. */ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" -#include "BKE_colortools.h" /* CurveMapping. */ +#include "BKE_colortools.h" /* CurveMapping. */ #include "BKE_deform.h" #include "BKE_library_query.h" #include "BKE_modifier.h" -#include "BKE_texture.h" /* Texture masking. */ +#include "BKE_texture.h" /* Texture masking. */ #include "DEG_depsgraph_build.h" #include "DEG_depsgraph_query.h" @@ -52,248 +52,266 @@ **************************************/ static void initData(ModifierData *md) { - WeightVGEditModifierData *wmd = (WeightVGEditModifierData *) md; - wmd->edit_flags = 0; - wmd->falloff_type = MOD_WVG_MAPPING_NONE; - wmd->default_weight = 0.0f; + WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md; + wmd->edit_flags = 0; + wmd->falloff_type = MOD_WVG_MAPPING_NONE; + wmd->default_weight = 0.0f; - wmd->cmap_curve = curvemapping_add(1, 0.0, 0.0, 1.0, 1.0); - curvemapping_initialize(wmd->cmap_curve); + wmd->cmap_curve = curvemapping_add(1, 0.0, 0.0, 1.0, 1.0); + curvemapping_initialize(wmd->cmap_curve); - wmd->rem_threshold = 0.01f; - wmd->add_threshold = 0.01f; + wmd->rem_threshold = 0.01f; + wmd->add_threshold = 0.01f; - wmd->mask_constant = 1.0f; - wmd->mask_tex_use_channel = MOD_WVG_MASK_TEX_USE_INT; /* Use intensity by default. */ - wmd->mask_tex_mapping = MOD_DISP_MAP_LOCAL; + wmd->mask_constant = 1.0f; + wmd->mask_tex_use_channel = MOD_WVG_MASK_TEX_USE_INT; /* Use intensity by default. */ + wmd->mask_tex_mapping = MOD_DISP_MAP_LOCAL; } static void freeData(ModifierData *md) { - WeightVGEditModifierData *wmd = (WeightVGEditModifierData *) md; - curvemapping_free(wmd->cmap_curve); + WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md; + curvemapping_free(wmd->cmap_curve); } static void copyData(const ModifierData *md, ModifierData *target, const int flag) { - const WeightVGEditModifierData *wmd = (const WeightVGEditModifierData *) md; - WeightVGEditModifierData *twmd = (WeightVGEditModifierData *) target; + const WeightVGEditModifierData *wmd = (const WeightVGEditModifierData *)md; + WeightVGEditModifierData *twmd = (WeightVGEditModifierData *)target; - modifier_copyData_generic(md, target, flag); + modifier_copyData_generic(md, target, flag); - twmd->cmap_curve = curvemapping_copy(wmd->cmap_curve); + twmd->cmap_curve = curvemapping_copy(wmd->cmap_curve); } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - WeightVGEditModifierData *wmd = (WeightVGEditModifierData *) md; + WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md; - /* We need vertex groups! */ - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + /* We need vertex groups! */ + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; - /* Ask for UV coordinates if we need them. */ - if (wmd->mask_tex_mapping == MOD_DISP_MAP_UV) { - r_cddata_masks->fmask |= CD_MASK_MTFACE; - } + /* Ask for UV coordinates if we need them. */ + if (wmd->mask_tex_mapping == MOD_DISP_MAP_UV) { + r_cddata_masks->fmask |= CD_MASK_MTFACE; + } - /* No need to ask for CD_PREVIEW_MLOOPCOL... */ + /* No need to ask for CD_PREVIEW_MLOOPCOL... */ } static bool dependsOnTime(ModifierData *md) { - WeightVGEditModifierData *wmd = (WeightVGEditModifierData *) md; + WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md; - if (wmd->mask_texture) - return BKE_texture_dependsOnTime(wmd->mask_texture); - return false; + if (wmd->mask_texture) + return BKE_texture_dependsOnTime(wmd->mask_texture); + return false; } static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) { - WeightVGEditModifierData *wmd = (WeightVGEditModifierData *) md; - walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_CB_NOP); + WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md; + walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_CB_NOP); } static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData) { - WeightVGEditModifierData *wmd = (WeightVGEditModifierData *) md; + WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md; - walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_CB_USER); + walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_CB_USER); - foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData); + foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData); } static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void *userData) { - walk(userData, ob, md, "mask_texture"); + walk(userData, ob, md, "mask_texture"); } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { - WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md; - if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) { - DEG_add_object_relation(ctx->node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGEdit Modifier"); - DEG_add_modifier_to_transform_relation(ctx->node, "WeightVGEdit Modifier"); - } - else if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) { - DEG_add_modifier_to_transform_relation(ctx->node, "WeightVGEdit Modifier"); - } - if (wmd->mask_texture != NULL) { - DEG_add_generic_id_relation(ctx->node, &wmd->mask_texture->id, "WeightVGEdit Modifier"); - } + WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md; + if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) { + DEG_add_object_relation( + ctx->node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGEdit Modifier"); + DEG_add_modifier_to_transform_relation(ctx->node, "WeightVGEdit Modifier"); + } + else if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) { + DEG_add_modifier_to_transform_relation(ctx->node, "WeightVGEdit Modifier"); + } + if (wmd->mask_texture != NULL) { + DEG_add_generic_id_relation(ctx->node, &wmd->mask_texture->id, "WeightVGEdit Modifier"); + } } -static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams)) +static bool isDisabled(const struct Scene *UNUSED(scene), + ModifierData *md, + bool UNUSED(useRenderParams)) { - WeightVGEditModifierData *wmd = (WeightVGEditModifierData *) md; - /* If no vertex group, bypass. */ - return (wmd->defgrp_name[0] == '\0'); + WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md; + /* If no vertex group, bypass. */ + return (wmd->defgrp_name[0] == '\0'); } -static Mesh *applyModifier( - ModifierData *md, - const ModifierEvalContext *ctx, - Mesh *mesh) +static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) { - BLI_assert(mesh != NULL); + BLI_assert(mesh != NULL); - WeightVGEditModifierData *wmd = (WeightVGEditModifierData *) md; + WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md; - MDeformVert *dvert = NULL; - MDeformWeight **dw = NULL; - float *org_w; /* Array original weights. */ - float *new_w; /* Array new weights. */ - int i; + MDeformVert *dvert = NULL; + MDeformWeight **dw = NULL; + float *org_w; /* Array original weights. */ + float *new_w; /* Array new weights. */ + 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! */ + /* 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); + const bool do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview); #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); - if (defgrp_index == -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 this modifier is not allowed to add vertices, just return. */ - if (!do_add) { - 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; - - /* Get org weights, assuming 0.0 for vertices not in given vgroup. */ - org_w = MEM_malloc_arrayN(numVerts, sizeof(float), "WeightVGEdit Modifier, org_w"); - new_w = MEM_malloc_arrayN(numVerts, sizeof(float), "WeightVGEdit Modifier, new_w"); - dw = MEM_malloc_arrayN(numVerts, sizeof(MDeformWeight *), "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(ctx->object->id.name + 2)); - } - - weightvg_do_map(numVerts, new_w, wmd->falloff_type, wmd->cmap_curve, rng); - - if (rng) { - BLI_rng_free(rng); - } - } - - /* Do masking. */ - struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); - weightvg_do_mask(ctx, numVerts, NULL, 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/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... */ + /* 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); + if (defgrp_index == -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 this modifier is not allowed to add vertices, just return. */ + if (!do_add) { + 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; + + /* Get org weights, assuming 0.0 for vertices not in given vgroup. */ + org_w = MEM_malloc_arrayN(numVerts, sizeof(float), "WeightVGEdit Modifier, org_w"); + new_w = MEM_malloc_arrayN(numVerts, sizeof(float), "WeightVGEdit Modifier, new_w"); + dw = MEM_malloc_arrayN(numVerts, sizeof(MDeformWeight *), "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(ctx->object->id.name + 2)); + } + + weightvg_do_map(numVerts, new_w, wmd->falloff_type, wmd->cmap_curve, rng); + + if (rng) { + BLI_rng_free(rng); + } + } + + /* Do masking. */ + struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); + weightvg_do_mask(ctx, + numVerts, + NULL, + 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/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); + 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); + /* Freeing stuff. */ + MEM_freeN(org_w); + MEM_freeN(new_w); + MEM_freeN(dw); - /* Return the vgroup-modified mesh. */ - return mesh; + /* Return the vgroup-modified mesh. */ + return mesh; } - ModifierTypeInfo modifierType_WeightVGEdit = { - /* name */ "VertexWeightEdit", - /* structName */ "WeightVGEditModifierData", - /* structSize */ sizeof(WeightVGEditModifierData), - /* type */ eModifierTypeType_NonGeometrical, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_SupportsMapping | - eModifierTypeFlag_SupportsEditmode | - eModifierTypeFlag_UsesPreview, - - /* copyData */ copyData, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ freeData, - /* isDisabled */ isDisabled, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ dependsOnTime, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ foreachObjectLink, - /* foreachIDLink */ foreachIDLink, - /* foreachTexLink */ foreachTexLink, - /* freeRuntimeData */ NULL, + /* name */ "VertexWeightEdit", + /* structName */ "WeightVGEditModifierData", + /* structSize */ sizeof(WeightVGEditModifierData), + /* type */ eModifierTypeType_NonGeometrical, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping | + eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_UsesPreview, + + /* copyData */ copyData, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ freeData, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ dependsOnTime, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ foreachIDLink, + /* foreachTexLink */ foreachTexLink, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c index 0894d30cfc1..ed2c2e5e940 100644 --- a/source/blender/modifiers/intern/MOD_weightvgmix.c +++ b/source/blender/modifiers/intern/MOD_weightvgmix.c @@ -35,7 +35,7 @@ #include "BKE_deform.h" #include "BKE_library_query.h" #include "BKE_modifier.h" -#include "BKE_texture.h" /* Texture masking. */ +#include "BKE_texture.h" /* Texture masking. */ #include "DEG_depsgraph_build.h" #include "DEG_depsgraph_query.h" @@ -51,55 +51,56 @@ static float mix_weight(float weight, float weight2, char mix_mode) { #if 0 - /* - * XXX Don't know why, but the switch version takes many CPU time, - * and produces lag in realtime playback... - */ - switch (mix_mode) - { - case MOD_WVG_MIX_ADD: - return (weight + weight2); - case MOD_WVG_MIX_SUB: - return (weight - weight2); - case MOD_WVG_MIX_MUL: - return (weight * weight2); - case MOD_WVG_MIX_DIV: - /* Avoid dividing by zero (or really small values). */ - if (0.0 <= weight2 < MOD_WVG_ZEROFLOOR) - weight2 = MOD_WVG_ZEROFLOOR; - else if (-MOD_WVG_ZEROFLOOR < weight2) - weight2 = -MOD_WVG_ZEROFLOOR; - return (weight / weight2); - case MOD_WVG_MIX_DIF: - return (weight < weight2 ? weight2 - weight : weight - weight2); - case MOD_WVG_MIX_AVG: - return (weight + weight2) / 2.0; - case MOD_WVG_MIX_SET: - default: - return weight2; - } + /* + * XXX Don't know why, but the switch version takes many CPU time, + * and produces lag in realtime playback... + */ + switch (mix_mode) + { + case MOD_WVG_MIX_ADD: + return (weight + weight2); + case MOD_WVG_MIX_SUB: + return (weight - weight2); + case MOD_WVG_MIX_MUL: + return (weight * weight2); + case MOD_WVG_MIX_DIV: + /* Avoid dividing by zero (or really small values). */ + if (0.0 <= weight2 < MOD_WVG_ZEROFLOOR) + weight2 = MOD_WVG_ZEROFLOOR; + else if (-MOD_WVG_ZEROFLOOR < weight2) + weight2 = -MOD_WVG_ZEROFLOOR; + return (weight / weight2); + case MOD_WVG_MIX_DIF: + return (weight < weight2 ? weight2 - weight : weight - weight2); + case MOD_WVG_MIX_AVG: + return (weight + weight2) / 2.0; + case MOD_WVG_MIX_SET: + default: + return weight2; + } #endif - if (mix_mode == MOD_WVG_MIX_SET) - return weight2; - else if (mix_mode == MOD_WVG_MIX_ADD) - return (weight + weight2); - else if (mix_mode == MOD_WVG_MIX_SUB) - return (weight - weight2); - else if (mix_mode == MOD_WVG_MIX_MUL) - return (weight * weight2); - else if (mix_mode == MOD_WVG_MIX_DIV) { - /* Avoid dividing by zero (or really small values). */ - if (weight2 < 0.0f && weight2 > -MOD_WVG_ZEROFLOOR) - weight2 = -MOD_WVG_ZEROFLOOR; - else if (weight2 >= 0.0f && weight2 < MOD_WVG_ZEROFLOOR) - weight2 = MOD_WVG_ZEROFLOOR; - return (weight / weight2); - } - else if (mix_mode == MOD_WVG_MIX_DIF) - return (weight < weight2 ? weight2 - weight : weight - weight2); - else if (mix_mode == MOD_WVG_MIX_AVG) - return (weight + weight2) * 0.5f; - else return weight2; + if (mix_mode == MOD_WVG_MIX_SET) + return weight2; + else if (mix_mode == MOD_WVG_MIX_ADD) + return (weight + weight2); + else if (mix_mode == MOD_WVG_MIX_SUB) + return (weight - weight2); + else if (mix_mode == MOD_WVG_MIX_MUL) + return (weight * weight2); + else if (mix_mode == MOD_WVG_MIX_DIV) { + /* Avoid dividing by zero (or really small values). */ + if (weight2 < 0.0f && weight2 > -MOD_WVG_ZEROFLOOR) + weight2 = -MOD_WVG_ZEROFLOOR; + else if (weight2 >= 0.0f && weight2 < MOD_WVG_ZEROFLOOR) + weight2 = MOD_WVG_ZEROFLOOR; + return (weight / weight2); + } + else if (mix_mode == MOD_WVG_MIX_DIF) + return (weight < weight2 ? weight2 - weight : weight - weight2); + else if (mix_mode == MOD_WVG_MIX_AVG) + return (weight + weight2) * 0.5f; + else + return weight2; } /************************************** @@ -107,306 +108,330 @@ static float mix_weight(float weight, float weight2, char mix_mode) **************************************/ static void initData(ModifierData *md) { - WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md; + WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md; - wmd->default_weight_a = 0.0f; - wmd->default_weight_b = 0.0f; - wmd->mix_mode = MOD_WVG_MIX_SET; - wmd->mix_set = MOD_WVG_SET_AND; + wmd->default_weight_a = 0.0f; + wmd->default_weight_b = 0.0f; + wmd->mix_mode = MOD_WVG_MIX_SET; + wmd->mix_set = MOD_WVG_SET_AND; - wmd->mask_constant = 1.0f; - wmd->mask_tex_use_channel = MOD_WVG_MASK_TEX_USE_INT; /* Use intensity by default. */ - wmd->mask_tex_mapping = MOD_DISP_MAP_LOCAL; + wmd->mask_constant = 1.0f; + wmd->mask_tex_use_channel = MOD_WVG_MASK_TEX_USE_INT; /* Use intensity by default. */ + wmd->mask_tex_mapping = MOD_DISP_MAP_LOCAL; } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md; + WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md; - /* We need vertex groups! */ - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + /* We need vertex groups! */ + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; - /* Ask for UV coordinates if we need them. */ - if (wmd->mask_tex_mapping == MOD_DISP_MAP_UV) { - r_cddata_masks->fmask |= CD_MASK_MTFACE; - } + /* Ask for UV coordinates if we need them. */ + if (wmd->mask_tex_mapping == MOD_DISP_MAP_UV) { + r_cddata_masks->fmask |= CD_MASK_MTFACE; + } - /* No need to ask for CD_PREVIEW_MLOOPCOL... */ + /* No need to ask for CD_PREVIEW_MLOOPCOL... */ } static bool dependsOnTime(ModifierData *md) { - WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md; + WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md; - if (wmd->mask_texture) - return BKE_texture_dependsOnTime(wmd->mask_texture); - return false; + if (wmd->mask_texture) + return BKE_texture_dependsOnTime(wmd->mask_texture); + return false; } static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) { - WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md; - walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_CB_NOP); + WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md; + walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_CB_NOP); } static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData) { - WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md; + WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md; - walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_CB_USER); + walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_CB_USER); - foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData); + foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData); } static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void *userData) { - walk(userData, ob, md, "mask_texture"); + walk(userData, ob, md, "mask_texture"); } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { - WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md; - if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) { - DEG_add_object_relation(ctx->node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGMix Modifier"); - DEG_add_object_relation(ctx->node, wmd->mask_tex_map_obj, DEG_OB_COMP_GEOMETRY, "WeightVGMix Modifier"); - - DEG_add_modifier_to_transform_relation(ctx->node, "WeightVGMix Modifier"); - } - else if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) { - DEG_add_modifier_to_transform_relation(ctx->node, "WeightVGMix Modifier"); - } - if (wmd->mask_texture != NULL) { - DEG_add_generic_id_relation(ctx->node, &wmd->mask_texture->id, "WeightVGMix Modifier"); - } + WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md; + if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) { + DEG_add_object_relation( + ctx->node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGMix Modifier"); + DEG_add_object_relation( + ctx->node, wmd->mask_tex_map_obj, DEG_OB_COMP_GEOMETRY, "WeightVGMix Modifier"); + + DEG_add_modifier_to_transform_relation(ctx->node, "WeightVGMix Modifier"); + } + else if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) { + DEG_add_modifier_to_transform_relation(ctx->node, "WeightVGMix Modifier"); + } + if (wmd->mask_texture != NULL) { + DEG_add_generic_id_relation(ctx->node, &wmd->mask_texture->id, "WeightVGMix Modifier"); + } } -static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams)) +static bool isDisabled(const struct Scene *UNUSED(scene), + ModifierData *md, + bool UNUSED(useRenderParams)) { - WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md; - /* If no vertex group, bypass. */ - return (wmd->defgrp_name_a[0] == '\0'); + WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md; + /* If no vertex group, bypass. */ + return (wmd->defgrp_name_a[0] == '\0'); } 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. */ + 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; + 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... */ + /* 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); + 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); + /* 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; + /* Return the vgroup-modified mesh. */ + return mesh; } - ModifierTypeInfo modifierType_WeightVGMix = { - /* name */ "VertexWeightMix", - /* structName */ "WeightVGMixModifierData", - /* structSize */ sizeof(WeightVGMixModifierData), - /* type */ eModifierTypeType_NonGeometrical, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_SupportsMapping | - eModifierTypeFlag_SupportsEditmode | - eModifierTypeFlag_UsesPreview, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ NULL, - /* isDisabled */ isDisabled, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ dependsOnTime, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ foreachObjectLink, - /* foreachIDLink */ foreachIDLink, - /* foreachTexLink */ foreachTexLink, - /* freeRuntimeData */ NULL, + /* name */ "VertexWeightMix", + /* structName */ "WeightVGMixModifierData", + /* structSize */ sizeof(WeightVGMixModifierData), + /* type */ eModifierTypeType_NonGeometrical, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping | + eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_UsesPreview, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ NULL, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ dependsOnTime, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ foreachIDLink, + /* foreachTexLink */ foreachTexLink, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c index 89ba5395775..66b7ddb54d6 100644 --- a/source/blender/modifiers/intern/MOD_weightvgproximity.c +++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c @@ -42,7 +42,7 @@ #include "BKE_library_query.h" #include "BKE_mesh.h" #include "BKE_modifier.h" -#include "BKE_texture.h" /* Texture masking. */ +#include "BKE_texture.h" /* Texture masking. */ #include "DEG_depsgraph_build.h" #include "DEG_depsgraph_query.h" @@ -68,135 +68,138 @@ #define OUT_OF_MEMORY() ((void)printf("WeightVGProximity: Out of memory.\n")) typedef struct Vert2GeomData { - /* Read-only data */ - float (*v_cos)[3]; + /* Read-only data */ + float (*v_cos)[3]; - const SpaceTransform *loc2trgt; + const SpaceTransform *loc2trgt; - BVHTreeFromMesh *treeData[3]; + BVHTreeFromMesh *treeData[3]; - /* Write data, but not needing locking (two different threads will never write same index). */ - float *dist[3]; + /* Write data, but not needing locking (two different threads will never write same index). */ + float *dist[3]; } Vert2GeomData; /* Data which is localized to each computed chunk (i.e. thread-safe, and with continuous subset of index range). */ typedef struct Vert2GeomDataChunk { - /* Read-only data */ - float last_hit_co[3][3]; - bool is_init[3]; + /* Read-only data */ + float last_hit_co[3][3]; + bool is_init[3]; } Vert2GeomDataChunk; /** * Callback used by BLI_task 'for loop' helper. */ -static void vert2geom_task_cb_ex( - void *__restrict userdata, - const int iter, - const ParallelRangeTLS *__restrict tls) +static void vert2geom_task_cb_ex(void *__restrict userdata, + const int iter, + const ParallelRangeTLS *__restrict tls) { - Vert2GeomData *data = userdata; - Vert2GeomDataChunk *data_chunk = tls->userdata_chunk; - - float tmp_co[3]; - int i; - - /* Convert the vertex to tree coordinates. */ - copy_v3_v3(tmp_co, data->v_cos[iter]); - BLI_space_transform_apply(data->loc2trgt, tmp_co); - - for (i = 0; i < ARRAY_SIZE(data->dist); i++) { - if (data->dist[i]) { - BVHTreeNearest nearest = {0}; - - /* Note that we use local proximity heuristics (to reduce the nearest search). - * - * If we already had an hit before in same chunk of tasks (i.e. previous vertex by index), - * we assume this vertex is going to have a close hit to that other vertex, so we can initiate - * the "nearest.dist" with the expected value to that last hit. - * This will lead in pruning of the search tree. - */ - nearest.dist_sq = data_chunk->is_init[i] ? len_squared_v3v3(tmp_co, data_chunk->last_hit_co[i]) : FLT_MAX; - nearest.index = -1; - - /* Compute and store result. If invalid (-1 idx), keep FLT_MAX dist. */ - BLI_bvhtree_find_nearest(data->treeData[i]->tree, tmp_co, &nearest, - data->treeData[i]->nearest_callback, data->treeData[i]); - data->dist[i][iter] = sqrtf(nearest.dist_sq); - - if (nearest.index != -1) { - copy_v3_v3(data_chunk->last_hit_co[i], nearest.co); - data_chunk->is_init[i] = true; - } - } - } + Vert2GeomData *data = userdata; + Vert2GeomDataChunk *data_chunk = tls->userdata_chunk; + + float tmp_co[3]; + int i; + + /* Convert the vertex to tree coordinates. */ + copy_v3_v3(tmp_co, data->v_cos[iter]); + BLI_space_transform_apply(data->loc2trgt, tmp_co); + + for (i = 0; i < ARRAY_SIZE(data->dist); i++) { + if (data->dist[i]) { + BVHTreeNearest nearest = {0}; + + /* Note that we use local proximity heuristics (to reduce the nearest search). + * + * If we already had an hit before in same chunk of tasks (i.e. previous vertex by index), + * we assume this vertex is going to have a close hit to that other vertex, so we can initiate + * the "nearest.dist" with the expected value to that last hit. + * This will lead in pruning of the search tree. + */ + nearest.dist_sq = data_chunk->is_init[i] ? + len_squared_v3v3(tmp_co, data_chunk->last_hit_co[i]) : + FLT_MAX; + nearest.index = -1; + + /* Compute and store result. If invalid (-1 idx), keep FLT_MAX dist. */ + BLI_bvhtree_find_nearest(data->treeData[i]->tree, + tmp_co, + &nearest, + data->treeData[i]->nearest_callback, + data->treeData[i]); + data->dist[i][iter] = sqrtf(nearest.dist_sq); + + if (nearest.index != -1) { + copy_v3_v3(data_chunk->last_hit_co[i], nearest.co); + data_chunk->is_init[i] = true; + } + } + } } /** * Find nearest vertex and/or edge and/or face, for each vertex (adapted from shrinkwrap.c). */ -static void get_vert2geom_distance( - int numVerts, float (*v_cos)[3], - float *dist_v, float *dist_e, float *dist_f, - Mesh *target, const SpaceTransform *loc2trgt) +static void get_vert2geom_distance(int numVerts, + float (*v_cos)[3], + float *dist_v, + float *dist_e, + float *dist_f, + Mesh *target, + const SpaceTransform *loc2trgt) { - Vert2GeomData data = {0}; - Vert2GeomDataChunk data_chunk = {{{0}}}; - - BVHTreeFromMesh treeData_v = {NULL}; - BVHTreeFromMesh treeData_e = {NULL}; - BVHTreeFromMesh treeData_f = {NULL}; - - if (dist_v) { - /* Create a bvh-tree of the given target's verts. */ - BKE_bvhtree_from_mesh_get(&treeData_v, target, BVHTREE_FROM_VERTS, 2); - if (treeData_v.tree == NULL) { - OUT_OF_MEMORY(); - return; - } - } - if (dist_e) { - /* Create a bvh-tree of the given target's edges. */ - BKE_bvhtree_from_mesh_get(&treeData_e, target, BVHTREE_FROM_EDGES, 2); - if (treeData_e.tree == NULL) { - OUT_OF_MEMORY(); - return; - } - } - if (dist_f) { - /* Create a bvh-tree of the given target's faces. */ - BKE_bvhtree_from_mesh_get(&treeData_f, target, BVHTREE_FROM_LOOPTRI, 2); - if (treeData_f.tree == NULL) { - OUT_OF_MEMORY(); - return; - } - } - - data.v_cos = v_cos; - data.loc2trgt = loc2trgt; - data.treeData[0] = &treeData_v; - data.treeData[1] = &treeData_e; - data.treeData[2] = &treeData_f; - data.dist[0] = dist_v; - data.dist[1] = dist_e; - data.dist[2] = dist_f; - - ParallelRangeSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = (numVerts > 10000); - settings.userdata_chunk = &data_chunk; - settings.userdata_chunk_size = sizeof(data_chunk); - BLI_task_parallel_range( - 0, numVerts, - &data, - vert2geom_task_cb_ex, - &settings); - - if (dist_v) - free_bvhtree_from_mesh(&treeData_v); - if (dist_e) - free_bvhtree_from_mesh(&treeData_e); - if (dist_f) - free_bvhtree_from_mesh(&treeData_f); + Vert2GeomData data = {0}; + Vert2GeomDataChunk data_chunk = {{{0}}}; + + BVHTreeFromMesh treeData_v = {NULL}; + BVHTreeFromMesh treeData_e = {NULL}; + BVHTreeFromMesh treeData_f = {NULL}; + + if (dist_v) { + /* Create a bvh-tree of the given target's verts. */ + BKE_bvhtree_from_mesh_get(&treeData_v, target, BVHTREE_FROM_VERTS, 2); + if (treeData_v.tree == NULL) { + OUT_OF_MEMORY(); + return; + } + } + if (dist_e) { + /* Create a bvh-tree of the given target's edges. */ + BKE_bvhtree_from_mesh_get(&treeData_e, target, BVHTREE_FROM_EDGES, 2); + if (treeData_e.tree == NULL) { + OUT_OF_MEMORY(); + return; + } + } + if (dist_f) { + /* Create a bvh-tree of the given target's faces. */ + BKE_bvhtree_from_mesh_get(&treeData_f, target, BVHTREE_FROM_LOOPTRI, 2); + if (treeData_f.tree == NULL) { + OUT_OF_MEMORY(); + return; + } + } + + data.v_cos = v_cos; + data.loc2trgt = loc2trgt; + data.treeData[0] = &treeData_v; + data.treeData[1] = &treeData_e; + data.treeData[2] = &treeData_f; + data.dist[0] = dist_v; + data.dist[1] = dist_e; + data.dist[2] = dist_f; + + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (numVerts > 10000); + settings.userdata_chunk = &data_chunk; + settings.userdata_chunk_size = sizeof(data_chunk); + BLI_task_parallel_range(0, numVerts, &data, vert2geom_task_cb_ex, &settings); + + if (dist_v) + free_bvhtree_from_mesh(&treeData_v); + if (dist_e) + free_bvhtree_from_mesh(&treeData_e); + if (dist_f) + free_bvhtree_from_mesh(&treeData_f); } /** @@ -204,19 +207,18 @@ static void get_vert2geom_distance( * Note that it works in final world space (i.e. with constraints etc. applied). */ static void get_vert2ob_distance( - int numVerts, float (*v_cos)[3], float *dist, - Object *ob, Object *obr) + int numVerts, float (*v_cos)[3], float *dist, Object *ob, Object *obr) { - /* Vertex and ref object coordinates. */ - float v_wco[3]; - unsigned int i = numVerts; - - while (i-- > 0) { - /* Get world-coordinates of the vertex (constraints and anim included). */ - mul_v3_m4v3(v_wco, ob->obmat, v_cos[i]); - /* Return distance between both coordinates. */ - dist[i] = len_v3v3(v_wco, obr->obmat[3]); - } + /* Vertex and ref object coordinates. */ + float v_wco[3]; + unsigned int i = numVerts; + + while (i-- > 0) { + /* Get world-coordinates of the vertex (constraints and anim included). */ + mul_v3_m4v3(v_wco, ob->obmat, v_cos[i]); + /* Return distance between both coordinates. */ + dist[i] = len_v3v3(v_wco, obr->obmat[3]); + } } /** @@ -225,49 +227,56 @@ static void get_vert2ob_distance( */ static float get_ob2ob_distance(const Object *ob, const Object *obr) { - return len_v3v3(ob->obmat[3], obr->obmat[3]); + return len_v3v3(ob->obmat[3], obr->obmat[3]); } /** * Maps distances to weights, with an optional "smoothing" mapping. */ -static void do_map(Object *ob, float *weights, const int nidx, const float min_d, const float max_d, short mode) +static void do_map( + Object *ob, float *weights, const int nidx, const float min_d, const float max_d, short mode) { - const float range_inv = 1.0f / (max_d - min_d); /* invert since multiplication is faster */ - unsigned int i = nidx; - if (max_d == min_d) { - while (i-- > 0) { - weights[i] = (weights[i] >= max_d) ? 1.0f : 0.0f; /* "Step" behavior... */ - } - } - else if (max_d > min_d) { - while (i-- > 0) { - if (weights[i] >= max_d) weights[i] = 1.0f; /* most likely case first */ - else if (weights[i] <= min_d) weights[i] = 0.0f; - else weights[i] = (weights[i] - min_d) * range_inv; - } - } - else { - while (i-- > 0) { - if (weights[i] <= max_d) weights[i] = 1.0f; /* most likely case first */ - else if (weights[i] >= min_d) weights[i] = 0.0f; - else weights[i] = (weights[i] - min_d) * range_inv; - } - } - - if (!ELEM(mode, MOD_WVG_MAPPING_NONE, MOD_WVG_MAPPING_CURVE)) { - RNG *rng = NULL; - - if (mode == MOD_WVG_MAPPING_RANDOM) { - rng = BLI_rng_new_srandom(BLI_ghashutil_strhash(ob->id.name + 2)); - } - - weightvg_do_map(nidx, weights, mode, NULL, rng); - - if (rng) { - BLI_rng_free(rng); - } - } + const float range_inv = 1.0f / (max_d - min_d); /* invert since multiplication is faster */ + unsigned int i = nidx; + if (max_d == min_d) { + while (i-- > 0) { + weights[i] = (weights[i] >= max_d) ? 1.0f : 0.0f; /* "Step" behavior... */ + } + } + else if (max_d > min_d) { + while (i-- > 0) { + if (weights[i] >= max_d) + weights[i] = 1.0f; /* most likely case first */ + else if (weights[i] <= min_d) + weights[i] = 0.0f; + else + weights[i] = (weights[i] - min_d) * range_inv; + } + } + else { + while (i-- > 0) { + if (weights[i] <= max_d) + weights[i] = 1.0f; /* most likely case first */ + else if (weights[i] >= min_d) + weights[i] = 0.0f; + else + weights[i] = (weights[i] - min_d) * range_inv; + } + } + + if (!ELEM(mode, MOD_WVG_MAPPING_NONE, MOD_WVG_MAPPING_CURVE)) { + RNG *rng = NULL; + + if (mode == MOD_WVG_MAPPING_RANDOM) { + rng = BLI_rng_new_srandom(BLI_ghashutil_strhash(ob->id.name + 2)); + } + + weightvg_do_map(nidx, weights, mode, NULL, rng); + + if (rng) { + BLI_rng_free(rng); + } + } } /************************************** @@ -275,312 +284,332 @@ static void do_map(Object *ob, float *weights, const int nidx, const float min_d **************************************/ static void initData(ModifierData *md) { - WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md; + WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *)md; - wmd->proximity_mode = MOD_WVG_PROXIMITY_OBJECT; - wmd->proximity_flags = MOD_WVG_PROXIMITY_GEOM_VERTS; + wmd->proximity_mode = MOD_WVG_PROXIMITY_OBJECT; + wmd->proximity_flags = MOD_WVG_PROXIMITY_GEOM_VERTS; - wmd->falloff_type = MOD_WVG_MAPPING_NONE; + wmd->falloff_type = MOD_WVG_MAPPING_NONE; - wmd->mask_constant = 1.0f; - wmd->mask_tex_use_channel = MOD_WVG_MASK_TEX_USE_INT; /* Use intensity by default. */ - wmd->mask_tex_mapping = MOD_DISP_MAP_LOCAL; - wmd->max_dist = 1.0f; /* vert arbitrary distance, but don't use 0 */ + wmd->mask_constant = 1.0f; + wmd->mask_tex_use_channel = MOD_WVG_MASK_TEX_USE_INT; /* Use intensity by default. */ + wmd->mask_tex_mapping = MOD_DISP_MAP_LOCAL; + wmd->max_dist = 1.0f; /* vert arbitrary distance, but don't use 0 */ } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md; + WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *)md; - /* We need vertex groups! */ - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + /* We need vertex groups! */ + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; - /* Ask for UV coordinates if we need them. */ - if (wmd->mask_tex_mapping == MOD_DISP_MAP_UV) { - r_cddata_masks->fmask |= CD_MASK_MTFACE; - } + /* Ask for UV coordinates if we need them. */ + if (wmd->mask_tex_mapping == MOD_DISP_MAP_UV) { + r_cddata_masks->fmask |= CD_MASK_MTFACE; + } - /* No need to ask for CD_PREVIEW_MLOOPCOL... */ + /* No need to ask for CD_PREVIEW_MLOOPCOL... */ } static bool dependsOnTime(ModifierData *md) { - WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md; + WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *)md; - if (wmd->mask_texture) - return BKE_texture_dependsOnTime(wmd->mask_texture); - return 0; + if (wmd->mask_texture) + return BKE_texture_dependsOnTime(wmd->mask_texture); + return 0; } static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) { - WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md; - walk(userData, ob, &wmd->proximity_ob_target, IDWALK_CB_NOP); - walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_CB_NOP); + WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *)md; + walk(userData, ob, &wmd->proximity_ob_target, IDWALK_CB_NOP); + walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_CB_NOP); } static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData) { - WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md; + WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *)md; - walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_CB_USER); + walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_CB_USER); - foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData); + foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData); } static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void *userData) { - walk(userData, ob, md, "mask_texture"); + walk(userData, ob, md, "mask_texture"); } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { - WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *)md; - if (wmd->proximity_ob_target != NULL) { - DEG_add_object_relation(ctx->node, wmd->proximity_ob_target, DEG_OB_COMP_TRANSFORM, "WeightVGProximity Modifier"); - if (wmd->proximity_ob_target->data != NULL && wmd->proximity_mode == MOD_WVG_PROXIMITY_GEOMETRY) { - DEG_add_object_relation(ctx->node, wmd->proximity_ob_target, DEG_OB_COMP_GEOMETRY, "WeightVGProximity Modifier"); - } - } - if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) { - DEG_add_object_relation(ctx->node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGProximity Modifier"); - DEG_add_object_relation(ctx->node, wmd->mask_tex_map_obj, DEG_OB_COMP_GEOMETRY, "WeightVGProximity Modifier"); - } - if (wmd->mask_texture != NULL) { - DEG_add_generic_id_relation(ctx->node, &wmd->mask_texture->id, "WeightVGProximity Modifier"); - } - DEG_add_modifier_to_transform_relation(ctx->node, "WeightVGProximity Modifier"); + WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *)md; + if (wmd->proximity_ob_target != NULL) { + DEG_add_object_relation( + ctx->node, wmd->proximity_ob_target, DEG_OB_COMP_TRANSFORM, "WeightVGProximity Modifier"); + if (wmd->proximity_ob_target->data != NULL && + wmd->proximity_mode == MOD_WVG_PROXIMITY_GEOMETRY) { + DEG_add_object_relation( + ctx->node, wmd->proximity_ob_target, DEG_OB_COMP_GEOMETRY, "WeightVGProximity Modifier"); + } + } + if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) { + DEG_add_object_relation( + ctx->node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGProximity Modifier"); + DEG_add_object_relation( + ctx->node, wmd->mask_tex_map_obj, DEG_OB_COMP_GEOMETRY, "WeightVGProximity Modifier"); + } + if (wmd->mask_texture != NULL) { + DEG_add_generic_id_relation(ctx->node, &wmd->mask_texture->id, "WeightVGProximity Modifier"); + } + DEG_add_modifier_to_transform_relation(ctx->node, "WeightVGProximity Modifier"); } -static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams)) +static bool isDisabled(const struct Scene *UNUSED(scene), + ModifierData *md, + bool UNUSED(useRenderParams)) { - WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md; - /* If no vertex group, bypass. */ - if (wmd->defgrp_name[0] == '\0') return 1; - /* If no target object, bypass. */ - return (wmd->proximity_ob_target == NULL); + WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *)md; + /* If no vertex group, bypass. */ + if (wmd->defgrp_name[0] == '\0') + return 1; + /* If no target object, bypass. */ + return (wmd->proximity_ob_target == NULL); } static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) { - BLI_assert(mesh != NULL); - - WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md; - MDeformVert *dvert = NULL; - MDeformWeight **dw, **tdw; - float (*v_cos)[3] = NULL; /* The vertices coordinates. */ - Object *ob = ctx->object; - 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. */ + BLI_assert(mesh != NULL); + + WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *)md; + MDeformVert *dvert = NULL; + MDeformWeight **dw, **tdw; + float(*v_cos)[3] = NULL; /* The vertices coordinates. */ + Object *ob = ctx->object; + 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; + const bool do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview) != 0; #endif #ifdef USE_TIMEIT - TIMEIT_START(perf); + TIMEIT_START(perf); #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 our target object. */ - obr = wmd->proximity_ob_target; - if (obr == NULL) { - return mesh; - } - - /* Get vgroup idx from its name. */ - defgrp_index = defgroup_name_index(ob, wmd->defgrp_name); - if (defgrp_index == -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. */ - /* As this modifier never add vertices to vgroup, just return. */ - if (!has_mdef) { - return mesh; - } - - dvert = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MDEFORMVERT, numVerts); - /* Ultimate security check. */ - if (!dvert) { - return mesh; - } - mesh->dvert = dvert; - - /* Find out which vertices to work on (all vertices in vgroup), and get their relevant weight. */ - tidx = MEM_malloc_arrayN(numVerts, sizeof(int), "WeightVGProximity Modifier, tidx"); - tw = MEM_malloc_arrayN(numVerts, sizeof(float), "WeightVGProximity Modifier, tw"); - tdw = MEM_malloc_arrayN(numVerts, sizeof(MDeformWeight *), "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 mesh; - } - if (numIdx != numVerts) { - indices = MEM_malloc_arrayN(numIdx, sizeof(int), "WeightVGProximity Modifier, indices"); - memcpy(indices, tidx, sizeof(int) * numIdx); - org_w = MEM_malloc_arrayN(numIdx, sizeof(float), "WeightVGProximity Modifier, org_w"); - memcpy(org_w, tw, sizeof(float) * numIdx); - dw = MEM_malloc_arrayN(numIdx, sizeof(MDeformWeight *), "WeightVGProximity Modifier, dw"); - memcpy(dw, tdw, sizeof(MDeformWeight *) * numIdx); - MEM_freeN(tw); - MEM_freeN(tdw); - } - else { - org_w = tw; - dw = tdw; - } - new_w = MEM_malloc_arrayN(numIdx, sizeof(float), "WeightVGProximity Modifier, new_w"); - MEM_freeN(tidx); - - /* Get our vertex coordinates. */ - if (numIdx != numVerts) { - float (*tv_cos)[3] = BKE_mesh_vertexCos_get(mesh, NULL); - v_cos = MEM_malloc_arrayN(numIdx, sizeof(float[3]), "WeightVGProximity Modifier, v_cos"); - for (i = 0; i < numIdx; i++) { - copy_v3_v3(v_cos[i], tv_cos[indices[i]]); - } - MEM_freeN(tv_cos); - } - else { - v_cos = BKE_mesh_vertexCos_get(mesh, NULL); - } - - /* 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 bool use_trgt_verts = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_VERTS) != 0; - const bool use_trgt_edges = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_EDGES) != 0; - const bool use_trgt_faces = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_FACES) != 0; - - if (use_trgt_verts || use_trgt_edges || use_trgt_faces) { - Mesh *target_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(obr, false); - - /* We must check that we do have a valid target_mesh! */ - if (target_mesh != NULL) { - SpaceTransform loc2trgt; - float *dists_v = use_trgt_verts ? MEM_malloc_arrayN(numIdx, sizeof(float), "dists_v") : NULL; - float *dists_e = use_trgt_edges ? MEM_malloc_arrayN(numIdx, sizeof(float), "dists_e") : NULL; - float *dists_f = use_trgt_faces ? MEM_malloc_arrayN(numIdx, sizeof(float), "dists_f") : NULL; - - BLI_SPACE_TRANSFORM_SETUP(&loc2trgt, ob, obr); - get_vert2geom_distance(numIdx, v_cos, dists_v, dists_e, dists_f, - target_mesh, &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]); - } - - MEM_SAFE_FREE(dists_v); - MEM_SAFE_FREE(dists_e); - MEM_SAFE_FREE(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. */ - struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); - weightvg_do_mask(ctx, numIdx, indices, org_w, new_w, ob, 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 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... */ + /* 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 our target object. */ + obr = wmd->proximity_ob_target; + if (obr == NULL) { + return mesh; + } + + /* Get vgroup idx from its name. */ + defgrp_index = defgroup_name_index(ob, wmd->defgrp_name); + if (defgrp_index == -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. */ + /* As this modifier never add vertices to vgroup, just return. */ + if (!has_mdef) { + return mesh; + } + + dvert = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MDEFORMVERT, numVerts); + /* Ultimate security check. */ + if (!dvert) { + return mesh; + } + mesh->dvert = dvert; + + /* Find out which vertices to work on (all vertices in vgroup), and get their relevant weight. */ + tidx = MEM_malloc_arrayN(numVerts, sizeof(int), "WeightVGProximity Modifier, tidx"); + tw = MEM_malloc_arrayN(numVerts, sizeof(float), "WeightVGProximity Modifier, tw"); + tdw = MEM_malloc_arrayN(numVerts, sizeof(MDeformWeight *), "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 mesh; + } + if (numIdx != numVerts) { + indices = MEM_malloc_arrayN(numIdx, sizeof(int), "WeightVGProximity Modifier, indices"); + memcpy(indices, tidx, sizeof(int) * numIdx); + org_w = MEM_malloc_arrayN(numIdx, sizeof(float), "WeightVGProximity Modifier, org_w"); + memcpy(org_w, tw, sizeof(float) * numIdx); + dw = MEM_malloc_arrayN(numIdx, sizeof(MDeformWeight *), "WeightVGProximity Modifier, dw"); + memcpy(dw, tdw, sizeof(MDeformWeight *) * numIdx); + MEM_freeN(tw); + MEM_freeN(tdw); + } + else { + org_w = tw; + dw = tdw; + } + new_w = MEM_malloc_arrayN(numIdx, sizeof(float), "WeightVGProximity Modifier, new_w"); + MEM_freeN(tidx); + + /* Get our vertex coordinates. */ + if (numIdx != numVerts) { + float(*tv_cos)[3] = BKE_mesh_vertexCos_get(mesh, NULL); + v_cos = MEM_malloc_arrayN(numIdx, sizeof(float[3]), "WeightVGProximity Modifier, v_cos"); + for (i = 0; i < numIdx; i++) { + copy_v3_v3(v_cos[i], tv_cos[indices[i]]); + } + MEM_freeN(tv_cos); + } + else { + v_cos = BKE_mesh_vertexCos_get(mesh, NULL); + } + + /* 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 bool use_trgt_verts = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_VERTS) != 0; + const bool use_trgt_edges = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_EDGES) != 0; + const bool use_trgt_faces = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_FACES) != 0; + + if (use_trgt_verts || use_trgt_edges || use_trgt_faces) { + Mesh *target_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(obr, false); + + /* We must check that we do have a valid target_mesh! */ + if (target_mesh != NULL) { + SpaceTransform loc2trgt; + float *dists_v = use_trgt_verts ? MEM_malloc_arrayN(numIdx, sizeof(float), "dists_v") : + NULL; + float *dists_e = use_trgt_edges ? MEM_malloc_arrayN(numIdx, sizeof(float), "dists_e") : + NULL; + float *dists_f = use_trgt_faces ? MEM_malloc_arrayN(numIdx, sizeof(float), "dists_f") : + NULL; + + BLI_SPACE_TRANSFORM_SETUP(&loc2trgt, ob, obr); + get_vert2geom_distance(numIdx, v_cos, dists_v, dists_e, dists_f, target_mesh, &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]); + } + + MEM_SAFE_FREE(dists_v); + MEM_SAFE_FREE(dists_e); + MEM_SAFE_FREE(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. */ + struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); + weightvg_do_mask(ctx, + numIdx, + indices, + org_w, + new_w, + ob, + 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 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); + 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); - MEM_freeN(v_cos); - MEM_SAFE_FREE(indices); + /* Freeing stuff. */ + MEM_freeN(org_w); + MEM_freeN(new_w); + MEM_freeN(dw); + MEM_freeN(v_cos); + MEM_SAFE_FREE(indices); #ifdef USE_TIMEIT - TIMEIT_END(perf); + TIMEIT_END(perf); #endif - /* Return the vgroup-modified mesh. */ - return mesh; + /* Return the vgroup-modified mesh. */ + return mesh; } - ModifierTypeInfo modifierType_WeightVGProximity = { - /* name */ "VertexWeightProximity", - /* structName */ "WeightVGProximityModifierData", - /* structSize */ sizeof(WeightVGProximityModifierData), - /* type */ eModifierTypeType_NonGeometrical, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_SupportsMapping | - eModifierTypeFlag_SupportsEditmode | - eModifierTypeFlag_UsesPreview, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ NULL, - /* isDisabled */ isDisabled, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ dependsOnTime, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ foreachObjectLink, - /* foreachIDLink */ foreachIDLink, - /* foreachTexLink */ foreachTexLink, - /* freeRuntimeData */ NULL, + /* name */ "VertexWeightProximity", + /* structName */ "WeightVGProximityModifierData", + /* structSize */ sizeof(WeightVGProximityModifierData), + /* type */ eModifierTypeType_NonGeometrical, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping | + eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_UsesPreview, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ NULL, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ dependsOnTime, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ foreachIDLink, + /* foreachTexLink */ foreachTexLink, + /* freeRuntimeData */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c index 74ab0ac3d8c..7af9ef6f5b6 100644 --- a/source/blender/modifiers/intern/MOD_wireframe.c +++ b/source/blender/modifiers/intern/MOD_wireframe.c @@ -33,103 +33,103 @@ static void initData(ModifierData *md) { - WireframeModifierData *wmd = (WireframeModifierData *)md; - wmd->offset = 0.02f; - wmd->flag = MOD_WIREFRAME_REPLACE | MOD_WIREFRAME_OFS_EVEN; - wmd->crease_weight = 1.0f; + WireframeModifierData *wmd = (WireframeModifierData *)md; + wmd->offset = 0.02f; + wmd->flag = MOD_WIREFRAME_REPLACE | MOD_WIREFRAME_OFS_EVEN; + wmd->crease_weight = 1.0f; } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - WireframeModifierData *wmd = (WireframeModifierData *)md; + WireframeModifierData *wmd = (WireframeModifierData *)md; - /* ask for vertexgroups if we need them */ - if (wmd->defgrp_name[0] != '\0') { - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; - } + /* ask for vertexgroups if we need them */ + if (wmd->defgrp_name[0] != '\0') { + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + } } static bool dependsOnNormals(ModifierData *UNUSED(md)) { - return true; + return true; } static Mesh *WireframeModifier_do(WireframeModifierData *wmd, Object *ob, Mesh *mesh) { - Mesh *result; - BMesh *bm; - - const int defgrp_index = defgroup_name_index(ob, wmd->defgrp_name); - - bm = BKE_mesh_to_bmesh_ex( - mesh, - &(struct BMeshCreateParams){0}, - &(struct BMeshFromMeshParams){ - .calc_face_normal = true, - .add_key_index = false, - .use_shapekey = false, - .active_shapekey = 0, - .cd_mask_extra = {.vmask = CD_MASK_ORIGINDEX, .emask = CD_MASK_ORIGINDEX, .pmask = CD_MASK_ORIGINDEX}, - }); - - BM_mesh_wireframe( - bm, - wmd->offset, wmd->offset_fac, wmd->offset_fac_vg, - (wmd->flag & MOD_WIREFRAME_REPLACE) != 0, - (wmd->flag & MOD_WIREFRAME_BOUNDARY) != 0, - (wmd->flag & MOD_WIREFRAME_OFS_EVEN) != 0, - (wmd->flag & MOD_WIREFRAME_OFS_RELATIVE) != 0, - (wmd->flag & MOD_WIREFRAME_CREASE) != 0, - wmd->crease_weight, - defgrp_index, - (wmd->flag & MOD_WIREFRAME_INVERT_VGROUP) != 0, - wmd->mat_ofs, - MAX2(ob->totcol - 1, 0), - false); - - result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL); - BM_mesh_free(bm); - - result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; - - return result; - + Mesh *result; + BMesh *bm; + + const int defgrp_index = defgroup_name_index(ob, wmd->defgrp_name); + + bm = BKE_mesh_to_bmesh_ex(mesh, + &(struct BMeshCreateParams){0}, + &(struct BMeshFromMeshParams){ + .calc_face_normal = true, + .add_key_index = false, + .use_shapekey = false, + .active_shapekey = 0, + .cd_mask_extra = {.vmask = CD_MASK_ORIGINDEX, + .emask = CD_MASK_ORIGINDEX, + .pmask = CD_MASK_ORIGINDEX}, + }); + + BM_mesh_wireframe(bm, + wmd->offset, + wmd->offset_fac, + wmd->offset_fac_vg, + (wmd->flag & MOD_WIREFRAME_REPLACE) != 0, + (wmd->flag & MOD_WIREFRAME_BOUNDARY) != 0, + (wmd->flag & MOD_WIREFRAME_OFS_EVEN) != 0, + (wmd->flag & MOD_WIREFRAME_OFS_RELATIVE) != 0, + (wmd->flag & MOD_WIREFRAME_CREASE) != 0, + wmd->crease_weight, + defgrp_index, + (wmd->flag & MOD_WIREFRAME_INVERT_VGROUP) != 0, + wmd->mat_ofs, + MAX2(ob->totcol - 1, 0), + false); + + result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL); + BM_mesh_free(bm); + + result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + + return result; } -static Mesh *applyModifier( - ModifierData *md, - const struct ModifierEvalContext *ctx, - struct Mesh *mesh) +static Mesh *applyModifier(ModifierData *md, + const struct ModifierEvalContext *ctx, + struct Mesh *mesh) { - return WireframeModifier_do((WireframeModifierData *)md, ctx->object, mesh); + return WireframeModifier_do((WireframeModifierData *)md, ctx->object, mesh); } - ModifierTypeInfo modifierType_Wireframe = { - /* name */ "Wireframe", - /* structName */ "WireframeModifierData", - /* structSize */ sizeof(WireframeModifierData), - /* type */ eModifierTypeType_Constructive, - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_SupportsEditmode, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ NULL, - /* isDisabled */ NULL, - /* updateDepgraph */ NULL, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ dependsOnNormals, - /* foreachObjectLink */ NULL, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Wireframe", + /* structName */ "WireframeModifierData", + /* structSize */ sizeof(WireframeModifierData), + /* type */ eModifierTypeType_Constructive, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsEditmode, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepgraph */ NULL, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ dependsOnNormals, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; -- cgit v1.2.3