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:
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.
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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. */
|
||||
|
|
Loading…
Reference in New Issue