Apply Modifier: support applying as shape key and keeping the modifier.

This can be useful to save the result of a cloth simulation as a
shape key without destroying the simulation, so it's possible to
e.g. re-run it to get other shapes, or simply use the new shape
key to start the simulation already in a draped state.

It also makes sense to allow applying as shape key even when the
mesh is shared, because the operation itself just adds a shape
key. To support this, split the apply operator into Apply and
Apply As Shapekey so that they can have different poll callbacks.

Differential Revision: https://developer.blender.org/D8173
This commit is contained in:
Alexander Gavrilov 2020-07-01 17:38:07 +03:00
parent 7fcb6bc59c
commit 01c8aa12a1
Notes: blender-bot 2023-02-14 18:52:14 +01:00
Referenced by issue blender/blender-addons#78864, Official Modifier Tools addon stopped working in recent 2.90 builds.
5 changed files with 102 additions and 32 deletions

View File

@ -389,7 +389,8 @@ bool ED_object_modifier_apply(struct Main *bmain,
struct Scene *scene,
struct Object *ob,
struct ModifierData *md,
int mode);
int mode,
bool keep_modifier);
int ED_object_modifier_copy(struct ReportList *reports,
struct Object *ob,
struct ModifierData *md);

View File

@ -167,6 +167,7 @@ void OBJECT_OT_modifier_move_up(struct wmOperatorType *ot);
void OBJECT_OT_modifier_move_down(struct wmOperatorType *ot);
void OBJECT_OT_modifier_move_to_index(struct wmOperatorType *ot);
void OBJECT_OT_modifier_apply(struct wmOperatorType *ot);
void OBJECT_OT_modifier_apply_as_shapekey(wmOperatorType *ot);
void OBJECT_OT_modifier_convert(struct wmOperatorType *ot);
void OBJECT_OT_modifier_copy(struct wmOperatorType *ot);
void OBJECT_OT_multires_subdivide(struct wmOperatorType *ot);

View File

@ -822,7 +822,8 @@ bool ED_object_modifier_apply(Main *bmain,
Scene *scene,
Object *ob,
ModifierData *md,
int mode)
int mode,
bool keep_modifier)
{
int prev_mode;
@ -830,7 +831,7 @@ bool ED_object_modifier_apply(Main *bmain,
BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied in edit mode");
return false;
}
if (ID_REAL_USERS(ob->data) > 1) {
if (mode != MODIFIER_APPLY_SHAPE && ID_REAL_USERS(ob->data) > 1) {
BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied to multi-user data");
return false;
}
@ -869,8 +870,11 @@ bool ED_object_modifier_apply(Main *bmain,
}
md_eval->mode = prev_mode;
BLI_remlink(&ob->modifiers, md);
BKE_modifier_free(md);
if (!keep_modifier) {
BLI_remlink(&ob->modifiers, md);
BKE_modifier_free(md);
}
BKE_object_free_derived_caches(ob);
@ -1326,7 +1330,7 @@ void OBJECT_OT_modifier_move_to_index(wmOperatorType *ot)
/** \name Apply Modifier Operator
* \{ */
static bool modifier_apply_poll(bContext *C)
static bool modifier_apply_poll_ex(bContext *C, bool allow_shared)
{
if (!edit_modifier_poll_generic(C, &RNA_Modifier, 0, false)) {
return false;
@ -1341,7 +1345,7 @@ static bool modifier_apply_poll(bContext *C)
CTX_wm_operator_poll_msg_set(C, "Modifiers cannot be applied on override data");
return false;
}
if ((ob->data != NULL) && ID_REAL_USERS(ob->data) > 1) {
if (!allow_shared && (ob->data != NULL) && ID_REAL_USERS(ob->data) > 1) {
CTX_wm_operator_poll_msg_set(C, "Modifiers cannot be applied to multi-user data");
return false;
}
@ -1356,14 +1360,18 @@ static bool modifier_apply_poll(bContext *C)
return true;
}
static int modifier_apply_exec(bContext *C, wmOperator *op)
static bool modifier_apply_poll(bContext *C)
{
return modifier_apply_poll_ex(C, false);
}
static int modifier_apply_exec_ex(bContext *C, wmOperator *op, int apply_as, bool keep_modifier)
{
Main *bmain = CTX_data_main(C);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
Object *ob = ED_object_active_context(C);
ModifierData *md = edit_modifier_property_get(op, ob, 0);
int apply_as = RNA_enum_get(op->ptr, "apply_as");
if (md == NULL) {
return OPERATOR_CANCELLED;
@ -1373,7 +1381,8 @@ static int modifier_apply_exec(bContext *C, wmOperator *op)
char name[MAX_NAME];
strcpy(name, md->name);
if (!ED_object_modifier_apply(bmain, op->reports, depsgraph, scene, ob, md, apply_as)) {
if (!ED_object_modifier_apply(
bmain, op->reports, depsgraph, scene, ob, md, apply_as, keep_modifier)) {
return OPERATOR_CANCELLED;
}
@ -1388,6 +1397,11 @@ static int modifier_apply_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
static int modifier_apply_exec(bContext *C, wmOperator *op)
{
return modifier_apply_exec_ex(C, op, MODIFIER_APPLY_DATA, false);
}
static int modifier_apply_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
int retval;
@ -1397,16 +1411,6 @@ static int modifier_apply_invoke(bContext *C, wmOperator *op, const wmEvent *eve
return retval;
}
static const EnumPropertyItem modifier_apply_as_items[] = {
{MODIFIER_APPLY_DATA, "DATA", 0, "Object Data", "Apply modifier to the object's data"},
{MODIFIER_APPLY_SHAPE,
"SHAPE",
0,
"New Shape",
"Apply deform-only modifier to a new shape on this object"},
{0, NULL, 0, NULL, NULL},
};
void OBJECT_OT_modifier_apply(wmOperatorType *ot)
{
ot->name = "Apply Modifier";
@ -1420,12 +1424,68 @@ void OBJECT_OT_modifier_apply(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
RNA_def_enum(ot->srna,
"apply_as",
modifier_apply_as_items,
MODIFIER_APPLY_DATA,
"Apply as",
"How to apply the modifier to the geometry");
edit_modifier_properties(ot);
edit_modifier_report_property(ot);
}
/** \} */
/* ------------------------------------------------------------------- */
/** \name Apply Modifier As Shapekey Operator
* \{ */
static bool modifier_apply_as_shapekey_poll(bContext *C)
{
return modifier_apply_poll_ex(C, true);
}
static int modifier_apply_as_shapekey_exec(bContext *C, wmOperator *op)
{
bool keep = RNA_boolean_get(op->ptr, "keep_modifier");
return modifier_apply_exec_ex(C, op, MODIFIER_APPLY_SHAPE, keep);
}
static int modifier_apply_as_shapekey_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
int retval;
if (edit_modifier_invoke_properties(C, op, event, &retval)) {
return modifier_apply_as_shapekey_exec(C, op);
}
else {
return retval;
}
}
static char *modifier_apply_as_shapekey_get_description(struct bContext *UNUSED(C),
struct wmOperatorType *UNUSED(op),
struct PointerRNA *values)
{
bool keep = RNA_boolean_get(values, "keep_modifier");
if (keep) {
return BLI_strdup("Apply modifier as a new shapekey and keep it in the stack");
}
return NULL;
}
void OBJECT_OT_modifier_apply_as_shapekey(wmOperatorType *ot)
{
ot->name = "Apply Modifier As Shapekey";
ot->description = "Apply modifier as a new shapekey and remove from the stack";
ot->idname = "OBJECT_OT_modifier_apply_as_shapekey";
ot->invoke = modifier_apply_as_shapekey_invoke;
ot->exec = modifier_apply_as_shapekey_exec;
ot->poll = modifier_apply_as_shapekey_poll;
ot->get_description = modifier_apply_as_shapekey_get_description;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
RNA_def_boolean(
ot->srna, "keep_modifier", false, "Keep Modifier", "Do not remove the modifier from stack");
edit_modifier_properties(ot);
edit_modifier_report_property(ot);
}

View File

@ -130,6 +130,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_modifier_move_down);
WM_operatortype_append(OBJECT_OT_modifier_move_to_index);
WM_operatortype_append(OBJECT_OT_modifier_apply);
WM_operatortype_append(OBJECT_OT_modifier_apply_as_shapekey);
WM_operatortype_append(OBJECT_OT_modifier_convert);
WM_operatortype_append(OBJECT_OT_modifier_copy);
WM_operatortype_append(OBJECT_OT_multires_subdivide);

View File

@ -231,12 +231,19 @@ static void modifier_ops_extra_draw(bContext *C, uiLayout *layout, void *md_v)
/* Apply as shapekey. */
if (BKE_modifier_is_same_topology(md) && !BKE_modifier_is_non_geometrical(md)) {
uiItemEnumO(layout,
"OBJECT_OT_modifier_apply",
CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Apply As Shapekey"),
ICON_SHAPEKEY_DATA,
"apply_as",
MODIFIER_APPLY_SHAPE);
uiItemBooleanO(layout,
CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Apply As Shapekey"),
ICON_SHAPEKEY_DATA,
"OBJECT_OT_modifier_apply_as_shapekey",
"keep_modifier",
false);
uiItemBooleanO(layout,
CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Save As Shapekey"),
ICON_SHAPEKEY_DATA,
"OBJECT_OT_modifier_apply_as_shapekey",
"keep_modifier",
true);
}
/* Duplicate. */