Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2015-03-28 20:44:05 +0300
committerCampbell Barton <ideasman42@gmail.com>2015-03-31 02:20:11 +0300
commitc16a8983efba9ecacd8da408d03c37a55483e528 (patch)
treebfeb0f644ac3bd8782bef474329e5a991c82d08c /source
parent660173ed72d9c69f6891d5ad05a8c4a35ece9c7c (diff)
Corrective Smooth Modifier (aka delta-mush)
This modifier can be used to correct bad deformations, Original patch D1183 by @sazerac, with own modifications
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_editmesh.h1
-rw-r--r--source/blender/blenkernel/BKE_mesh.h2
-rw-r--r--source/blender/blenkernel/intern/editmesh.c18
-rw-r--r--source/blender/blenkernel/intern/mesh.c2
-rw-r--r--source/blender/blenloader/intern/readfile.c14
-rw-r--r--source/blender/blenloader/intern/writefile.c7
-rw-r--r--source/blender/editors/object/object_intern.h1
-rw-r--r--source/blender/editors/object/object_modifier.c67
-rw-r--r--source/blender/editors/object/object_ops.c1
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c1
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h43
-rw-r--r--source/blender/makesrna/RNA_access.h1
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c116
-rw-r--r--source/blender/modifiers/CMakeLists.txt1
-rw-r--r--source/blender/modifiers/MOD_modifiertypes.h1
-rw-r--r--source/blender/modifiers/intern/MOD_correctivesmooth.c768
-rw-r--r--source/blender/modifiers/intern/MOD_util.c1
17 files changed, 1043 insertions, 2 deletions
diff --git a/source/blender/blenkernel/BKE_editmesh.h b/source/blender/blenkernel/BKE_editmesh.h
index d0b94117b23..d350eea7ac7 100644
--- a/source/blender/blenkernel/BKE_editmesh.h
+++ b/source/blender/blenkernel/BKE_editmesh.h
@@ -92,6 +92,7 @@ void BKE_editmesh_update_linked_customdata(BMEditMesh *em);
void BKE_editmesh_color_free(BMEditMesh *em);
void BKE_editmesh_color_ensure(BMEditMesh *em, const char htype);
+float (*BKE_editmesh_vertexCos_get_orco(BMEditMesh *em, int *r_numVerts))[3];
/* editderivedmesh.c */
/* should really be defined in editmesh.c, but they use 'EditDerivedBMesh' */
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 5cf557a07e5..05c20410458 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -119,7 +119,7 @@ bool BKE_mesh_uv_cdlayer_rename_index(struct Mesh *me, const int poly_index, con
const char *new_name, const bool do_tessface);
bool BKE_mesh_uv_cdlayer_rename(struct Mesh *me, const char *old_name, const char *new_name, bool do_tessface);
-float (*BKE_mesh_vertexCos_get(struct Mesh *me, int *r_numVerts))[3];
+float (*BKE_mesh_vertexCos_get(const struct Mesh *me, int *r_numVerts))[3];
void BKE_mesh_calc_normals_split(struct Mesh *mesh);
void BKE_mesh_split_faces(struct Mesh *mesh);
diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c
index 2247b91df1d..87a5c6f149f 100644
--- a/source/blender/blenkernel/intern/editmesh.c
+++ b/source/blender/blenkernel/intern/editmesh.c
@@ -246,3 +246,21 @@ void BKE_editmesh_color_ensure(BMEditMesh *em, const char htype)
break;
}
}
+
+float (*BKE_editmesh_vertexCos_get_orco(BMEditMesh *em, int *r_numVerts))[3]
+{
+ BMIter iter;
+ BMVert *eve;
+ float (*orco)[3];
+ int i;
+
+ orco = MEM_mallocN(em->bm->totvert * sizeof(*orco), __func__);
+
+ BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
+ copy_v3_v3(orco[i], eve->co);
+ }
+
+ *r_numVerts = em->bm->totvert;
+
+ return orco;
+}
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index 8ebc318ff9e..adce6e15732 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -1805,7 +1805,7 @@ void BKE_mesh_smooth_flag_set(Object *meshOb, int enableSmooth)
* Return a newly MEM_malloc'd array of all the mesh vertex locations
* \note \a r_numVerts may be NULL
*/
-float (*BKE_mesh_vertexCos_get(Mesh *me, int *r_numVerts))[3]
+float (*BKE_mesh_vertexCos_get(const Mesh *me, int *r_numVerts))[3]
{
int i, numVerts = me->totvert;
float (*cos)[3] = MEM_mallocN(sizeof(*cos) * numVerts, "vertexcos1");
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index b8c3bffae0f..b0aa47787b6 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -4949,6 +4949,20 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
}
lmd->cache_system = NULL;
}
+ else if (md->type == eModifierType_CorrectiveSmooth) {
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData*)md;
+
+ if (csmd->bind_coords) {
+ csmd->bind_coords = newdataadr(fd, csmd->bind_coords);
+ if (fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
+ BLI_endian_switch_float_array((float *)csmd->bind_coords, csmd->bind_coords_num * 3);
+ }
+ }
+
+ /* runtime only */
+ csmd->delta_cache = NULL;
+ csmd->delta_cache_num = 0;
+ }
}
}
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index bc1bc9c7759..afc53f343f1 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -1620,6 +1620,13 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
writedata(wd, DATA, sizeof(float)*lmd->total_verts * 3, lmd->vertexco);
}
+ else if (md->type == eModifierType_CorrectiveSmooth) {
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
+
+ if (csmd->bind_coords) {
+ writedata(wd, DATA, sizeof(float[3]) * csmd->bind_coords_num, csmd->bind_coords);
+ }
+ }
}
}
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index db040bc2017..d535457fc5b 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -174,6 +174,7 @@ void OBJECT_OT_multires_higher_levels_delete(struct wmOperatorType *ot);
void OBJECT_OT_multires_base_apply(struct wmOperatorType *ot);
void OBJECT_OT_multires_external_save(struct wmOperatorType *ot);
void OBJECT_OT_multires_external_pack(struct wmOperatorType *ot);
+void OBJECT_OT_correctivesmooth_bind(struct wmOperatorType *ot);
void OBJECT_OT_meshdeform_bind(struct wmOperatorType *ot);
void OBJECT_OT_explode_refresh(struct wmOperatorType *ot);
void OBJECT_OT_ocean_bake(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index f9315214557..ad02f78e7b6 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -1815,6 +1815,73 @@ void OBJECT_OT_skin_armature_create(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
edit_modifier_properties(ot);
}
+/************************ delta mush bind operator *********************/
+
+static int correctivesmooth_poll(bContext *C)
+{
+ return edit_modifier_poll_generic(C, &RNA_CorrectiveSmoothModifier, 0);
+}
+
+static int correctivesmooth_bind_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = ED_object_active_context(C);
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)edit_modifier_property_get(op, ob, eModifierType_CorrectiveSmooth);
+ bool is_bind;
+
+ if (!csmd) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!modifier_isEnabled(scene, &csmd->modifier, eModifierMode_Realtime)) {
+ BKE_report(op->reports, RPT_ERROR, "Modifier is disabled");
+ return OPERATOR_CANCELLED;
+ }
+
+ is_bind = (csmd->bind_coords != NULL);
+
+ MEM_SAFE_FREE(csmd->bind_coords);
+ MEM_SAFE_FREE(csmd->delta_cache);
+
+ if (is_bind) {
+ /* toggle off */
+ csmd->bind_coords_num = 0;
+ }
+ else {
+ /* signal to modifier to recalculate */
+ csmd->bind_coords_num = (unsigned int)-1;
+ }
+
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int correctivesmooth_bind_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (edit_modifier_invoke_properties(C, op))
+ return correctivesmooth_bind_exec(C, op);
+ else
+ return OPERATOR_CANCELLED;
+}
+
+void OBJECT_OT_correctivesmooth_bind(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Corrective Smooth Bind";
+ ot->description = "Bind base pose in delta mush modifier";
+ ot->idname = "OBJECT_OT_correctivesmooth_bind";
+
+ /* api callbacks */
+ ot->poll = correctivesmooth_poll;
+ ot->invoke = correctivesmooth_bind_invoke;
+ ot->exec = correctivesmooth_bind_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+ edit_modifier_properties(ot);
+}
/************************ mdef bind operator *********************/
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index 15eb9090ce5..422f0c12e51 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -144,6 +144,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_skin_radii_equalize);
WM_operatortype_append(OBJECT_OT_skin_armature_create);
+ WM_operatortype_append(OBJECT_OT_correctivesmooth_bind);
WM_operatortype_append(OBJECT_OT_meshdeform_bind);
WM_operatortype_append(OBJECT_OT_explode_refresh);
WM_operatortype_append(OBJECT_OT_ocean_bake);
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 873b5f5319f..420b73cee86 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -1121,6 +1121,7 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
UI_icon_draw(x, y, ICON_MOD_BEVEL); break;
case eModifierType_Smooth:
case eModifierType_LaplacianSmooth:
+ case eModifierType_CorrectiveSmooth:
UI_icon_draw(x, y, ICON_MOD_SMOOTH); break;
case eModifierType_SimpleDeform:
UI_icon_draw(x, y, ICON_MOD_SIMPLEDEFORM); break;
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index b32b228fda4..f3c61f0ab6c 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -84,6 +84,7 @@ typedef enum ModifierType {
eModifierType_Wireframe = 48,
eModifierType_DataTransfer = 49,
eModifierType_NormalEdit = 50,
+ eModifierType_CorrectiveSmooth = 51,
NUM_MODIFIER_TYPES
} ModifierType;
@@ -1288,6 +1289,48 @@ enum {
MOD_LAPLACIANSMOOTH_NORMALIZED = (1 << 5),
};
+
+typedef struct CorrectiveSmoothModifierData {
+ ModifierData modifier;
+
+ /* positions set during 'bind' operator
+ * use for MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND */
+ float (*bind_coords)[3];
+
+ /* note: -1 is used to bind */
+ unsigned int bind_coords_num;
+
+ float lambda;
+ short repeat, flag;
+ char smooth_type, rest_source;
+ char pad[2];
+
+ char defgrp_name[64]; /* MAX_VGROUP_NAME */
+
+ /* runtime-only cache (delta's between),
+ * delta's between the original positions and the smoothed positions */
+ float (*delta_cache)[3];
+ unsigned int delta_cache_num;
+ char pad2[4];
+} CorrectiveSmoothModifierData;
+
+enum {
+ MOD_CORRECTIVESMOOTH_SMOOTH_SIMPLE = 0,
+ MOD_CORRECTIVESMOOTH_SMOOTH_LENGTH_WEIGHT = 1,
+};
+
+enum {
+ MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO = 0,
+ MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND = 1,
+};
+
+/* Corrective Smooth modifier flags */
+enum {
+ MOD_CORRECTIVESMOOTH_INVERT_VGROUP = (1 << 0),
+ MOD_CORRECTIVESMOOTH_ONLY_SMOOTH = (1 << 1),
+ MOD_CORRECTIVESMOOTH_PIN_BOUNDARY = (1 << 2),
+};
+
typedef struct UVWarpModifierData {
ModifierData modifier;
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 577f27f564e..8aa1bc59b43 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -202,6 +202,7 @@ extern StructRNA RNA_DampedTrackConstraint;
extern StructRNA RNA_DataTransferModifier;
extern StructRNA RNA_DecimateModifier;
extern StructRNA RNA_DelaySensor;
+extern StructRNA RNA_CorrectiveSmoothModifier;
extern StructRNA RNA_DisplaceModifier;
extern StructRNA RNA_DisplaySafeAreas;
extern StructRNA RNA_DistortedNoiseTexture;
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index bde8fd73d85..635336004f9 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -92,6 +92,7 @@ EnumPropertyItem modifier_type_items[] = {
{0, "", 0, N_("Deform"), ""},
{eModifierType_Armature, "ARMATURE", ICON_MOD_ARMATURE, "Armature", ""},
{eModifierType_Cast, "CAST", ICON_MOD_CAST, "Cast", ""},
+ {eModifierType_CorrectiveSmooth, "CORRECTIVE_SMOOTH", ICON_MOD_SMOOTH, "Corrective Smooth", ""},
{eModifierType_Curve, "CURVE", ICON_MOD_CURVE, "Curve", ""},
{eModifierType_Displace, "DISPLACE", ICON_MOD_DISPLACE, "Displace", ""},
{eModifierType_Hook, "HOOK", ICON_HOOK, "Hook", ""},
@@ -377,6 +378,8 @@ static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr)
return &RNA_DataTransferModifier;
case eModifierType_NormalEdit:
return &RNA_NormalEditModifier;
+ case eModifierType_CorrectiveSmooth:
+ return &RNA_CorrectiveSmoothModifier;
/* Default */
case eModifierType_None:
case eModifierType_ShapeKey:
@@ -444,6 +447,7 @@ RNA_MOD_VGROUP_NAME_SET(Cast, defgrp_name);
RNA_MOD_VGROUP_NAME_SET(Curve, name);
RNA_MOD_VGROUP_NAME_SET(DataTransfer, defgrp_name);
RNA_MOD_VGROUP_NAME_SET(Decimate, defgrp_name);
+RNA_MOD_VGROUP_NAME_SET(CorrectiveSmooth, defgrp_name);
RNA_MOD_VGROUP_NAME_SET(Displace, defgrp_name);
RNA_MOD_VGROUP_NAME_SET(Hook, name);
RNA_MOD_VGROUP_NAME_SET(LaplacianDeform, anchor_grp_name);
@@ -1034,6 +1038,33 @@ static EnumPropertyItem *rna_DataTransferModifier_mix_mode_itemf(bContext *C, Po
return item;
}
+static void rna_CorrectiveSmoothModifier_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)ptr->data;
+
+ MEM_SAFE_FREE(csmd->delta_cache);
+
+ rna_Modifier_update(bmain, scene, ptr);
+}
+
+static void rna_CorrectiveSmoothModifier_rest_source_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)ptr->data;
+
+ if (csmd->rest_source != MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
+ MEM_SAFE_FREE(csmd->bind_coords);
+ csmd->bind_coords_num = 0;
+ }
+
+ rna_CorrectiveSmoothModifier_update(bmain, scene, ptr);
+}
+
+static int rna_CorrectiveSmoothModifier_is_bind_get(PointerRNA *ptr)
+{
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)ptr->data;
+ return (csmd->bind_coords != NULL);
+}
+
#else
static PropertyRNA *rna_def_property_subdivision_common(StructRNA *srna, const char type[])
@@ -2111,6 +2142,90 @@ static void rna_def_modifier_smooth(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
+
+static void rna_def_modifier_correctivesmooth(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem modifier_smooth_type_items[] = {
+ {MOD_CORRECTIVESMOOTH_SMOOTH_SIMPLE, "SIMPLE", 0, "Simple",
+ "Use the average of adjacent edge-vertices"},
+ {MOD_CORRECTIVESMOOTH_SMOOTH_LENGTH_WEIGHT, "LENGTH_WEIGHTED", 0, "Length Weight",
+ "Use the average of adjacent edge-vertices weighted by their length"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem modifier_rest_source_items[] = {
+ {MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO, "ORCO", 0, "Original Coords",
+ "Use base mesh vert coords as the rest position"},
+ {MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND, "BIND", 0, "Bind Coords",
+ "Use bind vert coords for rest position"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ srna = RNA_def_struct(brna, "CorrectiveSmoothModifier", "Modifier");
+ RNA_def_struct_ui_text(srna, "Corrective Smooth Modifier", "Correct distortion caused by deformation");
+ RNA_def_struct_sdna(srna, "CorrectiveSmoothModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_SMOOTH);
+
+ prop = RNA_def_property(srna, "lambda_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "lambda");
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0, 1.0, 5, 3);
+ RNA_def_property_ui_text(prop, "Lambda Factor", "Smooth factor effect");
+ RNA_def_property_update(prop, 0, "rna_CorrectiveSmoothModifier_update");
+
+ prop = RNA_def_property(srna, "iterations", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "repeat");
+ RNA_def_property_ui_range(prop, 0, 200, 1, -1);
+ RNA_def_property_ui_text(prop, "Repeat", "");
+ RNA_def_property_update(prop, 0, "rna_CorrectiveSmoothModifier_update");
+
+ prop = RNA_def_property(srna, "rest_source", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "rest_source");
+ RNA_def_property_enum_items(prop, modifier_rest_source_items);
+ RNA_def_property_ui_text(prop, "Rest Source", "Select the source of rest positions");
+ RNA_def_property_update(prop, 0, "rna_CorrectiveSmoothModifier_rest_source_update");
+
+ prop = RNA_def_property(srna, "smooth_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "smooth_type");
+ RNA_def_property_enum_items(prop, modifier_smooth_type_items);
+ RNA_def_property_ui_text(prop, "Smooth Type", "Method used for smoothing");
+ RNA_def_property_update(prop, 0, "rna_CorrectiveSmoothModifier_update");
+
+ prop = RNA_def_property(srna, "invert_vertex_group", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_CORRECTIVESMOOTH_INVERT_VGROUP);
+ RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
+ RNA_def_property_update(prop, 0, "rna_CorrectiveSmoothModifier_update");
+
+ prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "defgrp_name");
+ RNA_def_property_ui_text(prop, "Vertex Group",
+ "Name of Vertex Group which determines influence of modifier per point");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_CorrectiveSmoothModifier_defgrp_name_set");
+ RNA_def_property_update(prop, 0, "rna_CorrectiveSmoothModifier_update");
+
+ prop = RNA_def_property(srna, "is_bind", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Bind current shape", "");
+ RNA_def_property_boolean_funcs(prop, "rna_CorrectiveSmoothModifier_is_bind_get", NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "use_only_smooth", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_CORRECTIVESMOOTH_ONLY_SMOOTH);
+ RNA_def_property_ui_text(prop, "Only Smooth",
+ "Apply smoothing without reconstructing the surface");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "use_pin_boundary", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_CORRECTIVESMOOTH_PIN_BOUNDARY);
+ RNA_def_property_ui_text(prop, "Pin Boundaries",
+ "Excludes boundary vertices from being smoothed");
+ RNA_def_property_update(prop, 0, "rna_CorrectiveSmoothModifier_update");
+}
+
+
static void rna_def_modifier_laplaciansmooth(BlenderRNA *brna)
{
StructRNA *srna;
@@ -4520,6 +4635,7 @@ void RNA_def_modifier(BlenderRNA *brna)
rna_def_modifier_displace(brna);
rna_def_modifier_uvproject(brna);
rna_def_modifier_smooth(brna);
+ rna_def_modifier_correctivesmooth(brna);
rna_def_modifier_cast(brna);
rna_def_modifier_meshdeform(brna);
rna_def_modifier_particlesystem(brna);
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index 57e927fffed..1de3fc9eac0 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -51,6 +51,7 @@ set(SRC
intern/MOD_cast.c
intern/MOD_cloth.c
intern/MOD_collision.c
+ intern/MOD_correctivesmooth.c
intern/MOD_curve.c
intern/MOD_datatransfer.c
intern/MOD_decimate.c
diff --git a/source/blender/modifiers/MOD_modifiertypes.h b/source/blender/modifiers/MOD_modifiertypes.h
index 66e613be68a..a5d96759952 100644
--- a/source/blender/modifiers/MOD_modifiertypes.h
+++ b/source/blender/modifiers/MOD_modifiertypes.h
@@ -83,6 +83,7 @@ extern ModifierTypeInfo modifierType_LaplacianDeform;
extern ModifierTypeInfo modifierType_Wireframe;
extern ModifierTypeInfo modifierType_DataTransfer;
extern ModifierTypeInfo modifierType_NormalEdit;
+extern ModifierTypeInfo modifierType_CorrectiveSmooth;
/* MOD_util.c */
void modifier_type_init(ModifierTypeInfo *types[]);
diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c
new file mode 100644
index 00000000000..82c1d6f2ec8
--- /dev/null
+++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c
@@ -0,0 +1,768 @@
+/*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* The Original Code is Copyright (C) 2015 by the Blender Foundation.
+* All rights reserved.
+*
+* Contributor(s): Jack Simpson,
+* Campbell Barton
+*
+* ***** END GPL LICENSE BLOCK *****
+*
+*/
+
+/** \file blender/modifiers/intern/MOD_correctivesmooth.c
+ * \ingroup modifiers
+ *
+ * Method of smoothing deformation, also known as 'delta-mush'.
+ */
+
+#include "DNA_scene_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BKE_cdderivedmesh.h"
+#include "BKE_deform.h"
+#include "BKE_mesh.h"
+#include "BKE_editmesh.h"
+
+#include "MOD_modifiertypes.h"
+#include "MOD_util.h"
+
+#include "BLI_strict_flags.h"
+
+
+// #define DEBUG_TIME
+
+#include "PIL_time.h"
+#ifdef DEBUG_TIME
+# include "PIL_time_utildefines.h"
+#endif
+
+/* minor optimization, calculate this inline */
+#define USE_TANGENT_CALC_INLINE
+
+static void initData(ModifierData *md)
+{
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
+
+ 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->defgrp_name[0] = '\0';
+
+ csmd->delta_cache = NULL;
+}
+
+
+static void copyData(ModifierData *md, ModifierData *target)
+{
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
+ CorrectiveSmoothModifierData *tcsmd = (CorrectiveSmoothModifierData *)target;
+
+ modifier_copyData_generic(md, target);
+
+ if (csmd->bind_coords) {
+ tcsmd->bind_coords = MEM_dupallocN(csmd->bind_coords);
+ }
+
+ 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);
+
+ csmd->bind_coords_num = 0;
+}
+
+
+static void freeData(ModifierData *md)
+{
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
+ freeBind(csmd);
+}
+
+
+static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
+{
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
+ CustomDataMask dataMask = 0;
+ /* ask for vertex groups if we need them */
+ if (csmd->defgrp_name[0]) {
+ dataMask |= CD_MASK_MDEFORMVERT;
+ }
+ return dataMask;
+}
+
+
+/* check individual weights for changes and cache values */
+static void dm_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;
+ }
+ }
+}
+
+
+static void dm_get_boundaries(DerivedMesh *dm, float *smooth_weights)
+{
+ const MPoly *mpoly = dm->getPolyArray(dm);
+ const MLoop *mloop = dm->getLoopArray(dm);
+ const MEdge *medge = dm->getEdgeArray(dm);
+ unsigned int mpoly_num, medge_num, i;
+ unsigned short *boundaries;
+
+ mpoly_num = (unsigned int)dm->getNumPolys(dm);
+ medge_num = (unsigned int)dm->getNumEdges(dm);
+
+ boundaries = MEM_callocN(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, DerivedMesh *dm,
+ 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)dm->getNumEdges(dm);
+ const MEdge *edges = dm->getEdgeArray(dm);
+ float *vertex_edge_count_div;
+
+ struct SmoothingData_Simple {
+ float delta[3];
+ } *smooth_data = MEM_callocN((size_t)numVerts * sizeof(*smooth_data), __func__);
+
+ vertex_edge_count_div = MEM_callocN((size_t)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, DerivedMesh *dm,
+ 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)dm->getNumEdges(dm);
+ /* 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 = dm->getEdgeArray(dm);
+ float *vertex_edge_count;
+ unsigned int i;
+
+ struct SmoothingData_Weighted {
+ float delta[3];
+ float edge_length_sum;
+ } *smooth_data = MEM_callocN((size_t)numVerts * sizeof(*smooth_data), __func__);
+
+
+ /* calculate as floats to avoid int->float conversion in #smooth_iter */
+ vertex_edge_count = MEM_callocN((size_t)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 neighbours, (mean average) */
+ const float div = sd->edge_length_sum * vertex_edge_count[i];
+ if (div > eps) {
+#if 0
+ /* first calculate the new location */
+ mul_v3_fl(sd->delta, 1.0f / div);
+ /* then interpolate */
+ madd_v3_v3fl(vertexCos[i], sd->delta, lambda);
+#else
+ /* do this in one step */
+ madd_v3_v3fl(vertexCos[i], sd->delta, lambda / div);
+#endif
+ }
+ /* zero for the next iteration (saves memset on entire array) */
+ memset(sd, 0, sizeof(*sd));
+ }
+ }
+ else {
+ for (i = 0; i < numVerts; i++) {
+ struct SmoothingData_Weighted *sd = &smooth_data[i];
+ const float div = sd->edge_length_sum * vertex_edge_count[i];
+ if (div > eps) {
+ const float lambda_w = lambda * smooth_weights[i];
+ madd_v3_v3fl(vertexCos[i], sd->delta, lambda_w / div);
+ }
+
+ memset(sd, 0, sizeof(*sd));
+ }
+ }
+ }
+
+ MEM_freeN(vertex_edge_count);
+ MEM_freeN(smooth_data);
+}
+
+
+static void smooth_iter(
+ CorrectiveSmoothModifierData *csmd, DerivedMesh *dm,
+ 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, dm, vertexCos, numVerts, smooth_weights, iterations);
+ break;
+
+ /* case MOD_CORRECTIVESMOOTH_SMOOTH_SIMPLE: */
+ default:
+ smooth_iter__simple(csmd, dm, vertexCos, numVerts, smooth_weights, iterations);
+ break;
+ }
+}
+
+static void smooth_verts(
+ CorrectiveSmoothModifierData *csmd, DerivedMesh *dm,
+ MDeformVert *dvert, const int defgrp_index,
+ float (*vertexCos)[3], unsigned int numVerts)
+{
+ float *smooth_weights = NULL;
+
+ if (dvert || (csmd->flag & MOD_CORRECTIVESMOOTH_PIN_BOUNDARY)) {
+
+ smooth_weights = MEM_mallocN(numVerts * sizeof(float), __func__);
+
+ if (dvert) {
+ dm_get_weights(
+ dvert, defgrp_index,
+ numVerts, (csmd->flag & MOD_CORRECTIVESMOOTH_INVERT_VGROUP) != 0,
+ smooth_weights);
+ }
+ else {
+ fill_vn_fl(smooth_weights, (int)numVerts, 1.0f);
+ }
+
+ if (csmd->flag & MOD_CORRECTIVESMOOTH_PIN_BOUNDARY) {
+ dm_get_boundaries(dm, smooth_weights);
+ }
+ }
+
+ smooth_iter(csmd, dm, vertexCos, numVerts, smooth_weights, (unsigned int)csmd->repeat);
+
+ if (smooth_weights) {
+ MEM_freeN(smooth_weights);
+ }
+}
+
+/**
+ * finalize after accumulation.
+ */
+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];
+
+ normalize_v3(ts[2]);
+
+ 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);
+
+ /* 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);
+
+ 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])
+{
+ 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];
+
+ cross_v3_v3v3(nor, v_dir_prev, v_dir_next);
+ normalize_v3(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);
+ }
+}
+
+
+static void calc_tangent_spaces(
+ DerivedMesh *dm, float (*vertexCos)[3],
+ float (*r_tangent_spaces)[3][3])
+{
+ const unsigned int mpoly_num = (unsigned int)dm->getNumPolys(dm);
+#ifndef USE_TANGENT_CALC_INLINE
+ const unsigned int mvert_num = (unsigned int)dm->getNumVerts(dm);
+#endif
+ const MPoly *mpoly = dm->getPolyArray(dm);
+ const MLoop *mloop = dm->getLoopArray(dm);
+ 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);
+#endif
+ 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);
+
+ copy_v3_v3(v_dir_prev, v_dir_next);
+ }
+ }
+
+ /* 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);
+ }
+#endif
+}
+
+/**
+ * This calculates #CorrectiveSmoothModifierData.delta_cache
+ * It's not run on every update (during animation for example).
+ */
+static void calc_deltas(
+ CorrectiveSmoothModifierData *csmd, DerivedMesh *dm,
+ MDeformVert *dvert, const int defgrp_index,
+ const float (*rest_coords)[3], unsigned int numVerts)
+{
+ float (*smooth_vertex_coords)[3] = MEM_dupallocN(rest_coords);
+ float (*tangent_spaces)[3][3];
+ unsigned int i;
+
+ tangent_spaces = MEM_callocN((size_t)(numVerts) * sizeof(float[3][3]), __func__);
+
+ if (csmd->delta_cache_num != numVerts) {
+ MEM_SAFE_FREE(csmd->delta_cache);
+ }
+
+ /* allocate deltas if they have not yet been allocated, otheriwse we will just write over them */
+ if (!csmd->delta_cache) {
+ csmd->delta_cache_num = numVerts;
+ csmd->delta_cache = MEM_mallocN((size_t)numVerts * sizeof(float[3]), __func__);
+ }
+
+ smooth_verts(csmd, dm, dvert, defgrp_index, smooth_vertex_coords, numVerts);
+
+ calc_tangent_spaces(dm, smooth_vertex_coords, tangent_spaces);
+
+ for (i = 0; i < numVerts; i++) {
+ float imat[3][3], delta[3];
+
+#ifdef USE_TANGENT_CALC_INLINE
+ calc_tangent_ortho(tangent_spaces[i]);
+#endif
+
+ sub_v3_v3v3(delta, rest_coords[i], smooth_vertex_coords[i]);
+ if (UNLIKELY(!invert_m3_m3(imat, tangent_spaces[i]))) {
+ transpose_m3_m3(imat, tangent_spaces[i]);
+ }
+ mul_v3_m3v3(csmd->delta_cache[i], imat, delta);
+ }
+
+ MEM_freeN(tangent_spaces);
+ MEM_freeN(smooth_vertex_coords);
+}
+
+
+static void correctivesmooth_modifier_do(
+ ModifierData *md, Object *ob, DerivedMesh *dm,
+ float (*vertexCos)[3], unsigned int numVerts,
+ struct BMEditMesh *em)
+{
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
+
+ const bool force_delta_cache_update =
+ /* XXX, take care! if mesh data its self changes we need to forcefully recalculate deltas */
+ ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO) &&
+ (((ID *)ob->data)->flag & LIB_ID_RECALC));
+
+ bool use_only_smooth = (csmd->flag & MOD_CORRECTIVESMOOTH_ONLY_SMOOTH) != 0;
+ MDeformVert *dvert = NULL;
+ int defgrp_index;
+
+ modifier_get_vgroup(ob, dm, csmd->defgrp_name, &dvert, &defgrp_index);
+
+ /* if rest bind_coords not are defined, set them (only run during bind) */
+ if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) &&
+ /* signal to recalculate, whoever sets MUST also free bind coords */
+ (csmd->bind_coords_num == (unsigned int)-1))
+ {
+ BLI_assert(csmd->bind_coords == NULL);
+ csmd->bind_coords = MEM_dupallocN(vertexCos);
+ csmd->bind_coords_num = numVerts;
+ BLI_assert(csmd->bind_coords != NULL);
+ }
+
+ if (UNLIKELY(use_only_smooth)) {
+ smooth_verts(csmd, dm, dvert, defgrp_index, vertexCos, numVerts);
+ return;
+ }
+
+ if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) && (csmd->bind_coords == NULL)) {
+ modifier_setError(md, "Bind data required");
+ goto error;
+ }
+
+ /* If the number of verts has changed, the bind is invalid, so we do nothing */
+ if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
+ if (csmd->bind_coords_num != numVerts) {
+ modifier_setError(md, "Bind vertex count mismatch: %d to %d", 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 {
+ int me_numVerts = (em) ? em->bm->totvert : ((Mesh *)ob->data)->totvert;
+
+ if ((unsigned int)me_numVerts != numVerts) {
+ modifier_setError(md, "Original vertex count mismatch: %d to %d", me_numVerts, numVerts);
+ goto error;
+ }
+ }
+ }
+
+ /* check to see if our deltas are still valid */
+ if (!csmd->delta_cache || (csmd->delta_cache_num != numVerts) || force_delta_cache_update) {
+ const float (*rest_coords)[3];
+ bool is_rest_coords_alloc = false;
+
+ if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
+ /* caller needs to do sanity check here */
+ csmd->bind_coords_num = numVerts;
+ rest_coords = (const float (*)[3])csmd->bind_coords;
+ }
+ else {
+ int me_numVerts;
+ rest_coords = (const float (*)[3]) ((em) ?
+ BKE_editmesh_vertexCos_get_orco(em, &me_numVerts) :
+ BKE_mesh_vertexCos_get(ob->data, &me_numVerts));
+
+ BLI_assert((unsigned int)me_numVerts == numVerts);
+ is_rest_coords_alloc = true;
+ }
+
+#ifdef DEBUG_TIME
+ TIMEIT_START(corrective_smooth_deltas);
+#endif
+
+ calc_deltas(csmd, dm, dvert, defgrp_index, rest_coords, numVerts);
+
+#ifdef DEBUG_TIME
+ TIMEIT_END(corrective_smooth_deltas);
+#endif
+ if (is_rest_coords_alloc) {
+ MEM_freeN((void *)rest_coords);
+ }
+ }
+
+ if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
+ /* this could be a check, but at this point it _must_ be valid */
+ BLI_assert(csmd->bind_coords_num == numVerts && csmd->delta_cache);
+ }
+
+
+#ifdef DEBUG_TIME
+ TIMEIT_START(corrective_smooth);
+#endif
+
+ /* do the actual delta mush */
+ smooth_verts(csmd, dm, dvert, defgrp_index, vertexCos, numVerts);
+
+ {
+ unsigned int i;
+
+ float (*tangent_spaces)[3][3];
+
+ /* calloc, since values are accumulated */
+ tangent_spaces = MEM_callocN((size_t)numVerts * sizeof(float[3][3]), __func__);
+
+ calc_tangent_spaces(dm, vertexCos, tangent_spaces);
+
+ for (i = 0; i < numVerts; i++) {
+ float delta[3];
+
+#ifdef USE_TANGENT_CALC_INLINE
+ calc_tangent_ortho(tangent_spaces[i]);
+#endif
+
+ mul_v3_m3v3(delta, tangent_spaces[i], csmd->delta_cache[i]);
+ add_v3_v3(vertexCos[i], delta);
+ }
+
+ MEM_freeN(tangent_spaces);
+ }
+
+#ifdef DEBUG_TIME
+ TIMEIT_END(corrective_smooth);
+#endif
+
+ return;
+
+ /* when the modifier fails to execute */
+error:
+ MEM_SAFE_FREE(csmd->delta_cache);
+ csmd->delta_cache_num = 0;
+
+}
+
+
+static void deformVerts(
+ ModifierData *md, Object *ob, DerivedMesh *derivedData,
+ float (*vertexCos)[3], int numVerts, ModifierApplyFlag UNUSED(flag))
+{
+ DerivedMesh *dm = get_dm(ob, NULL, derivedData, NULL, false, false);
+
+ correctivesmooth_modifier_do(md, ob, dm, vertexCos, (unsigned int)numVerts, NULL);
+
+ if (dm != derivedData) {
+ dm->release(dm);
+ }
+}
+
+
+static void deformVertsEM(
+ ModifierData *md, Object *ob, struct BMEditMesh *editData,
+ DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+{
+ DerivedMesh *dm = get_dm(ob, editData, derivedData, NULL, false, false);
+
+ correctivesmooth_modifier_do(md, ob, dm, vertexCos, (unsigned int)numVerts, editData);
+
+ if (dm != derivedData) {
+ dm->release(dm);
+ }
+}
+
+
+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,
+ /* applyModifierEM */ NULL,
+ /* initData */ initData,
+ /* requiredDataMask */ requiredDataMask,
+ /* freeData */ freeData,
+ /* isDisabled */ NULL,
+ /* updateDepgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* dependsOnNormals */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index eac2f24d064..be6f7af7791 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -306,5 +306,6 @@ void modifier_type_init(ModifierTypeInfo *types[])
INIT_TYPE(Wireframe);
INIT_TYPE(DataTransfer);
INIT_TYPE(NormalEdit);
+ INIT_TYPE(CorrectiveSmooth);
#undef INIT_TYPE
}