* New option on modifiers that don't change topology: Apply as Shape
authorMatt Ebb <matt@mke3.net>
Sun, 22 Nov 2009 13:44:09 +0000 (13:44 +0000)
committerMatt Ebb <matt@mke3.net>
Sun, 22 Nov 2009 13:44:09 +0000 (13:44 +0000)
Rather than applying the modifier to the object data, it will create a new shape
with the deformed vertices in there. Only mesh at the moment, other object
types on the todo.

source/blender/blenkernel/BKE_DerivedMesh.h
source/blender/blenkernel/BKE_key.h
source/blender/blenkernel/BKE_modifier.h
source/blender/blenkernel/intern/DerivedMesh.c
source/blender/blenkernel/intern/key.c
source/blender/blenkernel/intern/modifier.c
source/blender/editors/include/ED_object.h
source/blender/editors/interface/interface_templates.c
source/blender/editors/object/object_modifier.c
source/blender/editors/object/object_shapekey.c

index 076747cb8454cf498b1e9fd2f3945ffeb39a2c95..514411e137dfe19d180e4948a915e3691c732f2f 100644 (file)
@@ -54,6 +54,7 @@ struct Object;
 struct Scene;
 struct Mesh;
 struct EditMesh;
+struct KeyBlock;
 struct ModifierData;
 struct MCol;
 struct ColorBand;
@@ -318,6 +319,10 @@ int DM_release(DerivedMesh *dm);
  */
 void DM_to_mesh(DerivedMesh *dm, struct Mesh *me);
 
+/* utility function to convert a DerivedMesh to a shape key block 
+ */
+void DM_to_meshkey(DerivedMesh *dm, struct Mesh *me, struct KeyBlock *kb);
+
 /* set the CD_FLAG_NOCOPY flag in custom data layers where the mask is
  * zero for the layer type, so only layer types specified by the mask
  * will be copied
index c81d837689ff5aac0f4600bc06ba74134d358c95..d5bae00d32e84a1b04641d2c893b16239ad06eef 100644 (file)
@@ -59,6 +59,7 @@ void key_curve_normal_weights(float t, float *data, int type);
 float *do_ob_key(struct Scene *scene, struct Object *ob);
 
 struct Key *ob_get_key(struct Object *ob);
+struct KeyBlock *add_keyblock(struct Scene *scene, struct Key *key);
 struct KeyBlock *ob_get_keyblock(struct Object *ob);
 struct KeyBlock *ob_get_reference_keyblock(struct Object *ob);
 struct KeyBlock *key_get_keyblock(struct Key *key, int index);
index 245db7e35ff6e5c9f4ecb752d1a2976688c6f39b..c30bfa3e24779bb0405b29faf6990df0f601d950 100644 (file)
@@ -281,6 +281,7 @@ int           modifier_dependsOnTime(struct ModifierData *md);
 int           modifier_supportsMapping(struct ModifierData *md);
 int           modifier_couldBeCage(struct ModifierData *md);
 int           modifier_isDeformer(struct ModifierData *md);
+int                      modifier_sameTopology(ModifierData *md);
 int           modifier_isEnabled(struct ModifierData *md, int required_mode);
 void          modifier_setError(struct ModifierData *md, char *format, ...);
 
index f9abaa9da0244108919d9c4e01e799e8b7b783b1..209e4610c6a111758bbf8cca8d09aceb6151d82f 100644 (file)
@@ -277,6 +277,26 @@ void DM_to_mesh(DerivedMesh *dm, Mesh *me)
        *me = tmp;
 }
 
+void DM_to_meshkey(DerivedMesh *dm, Mesh *me, KeyBlock *kb)
+{
+       int a, totvert = dm->getNumVerts(dm);
+       float *fp;
+       MVert *mvert;
+       
+       if(totvert==0 || me->totvert==0 || me->totvert!=totvert) return;
+       
+       if(kb->data) MEM_freeN(kb->data);
+       kb->data= MEM_callocN(me->key->elemsize*me->totvert, "kb->data");
+       kb->totelem= totvert;
+       
+       fp= kb->data;
+       mvert=dm->getVertDataArray(dm, CD_MVERT);
+       
+       for(a=0; a<kb->totelem; a++, fp+=3, mvert++) {
+               VECCOPY(fp, mvert->co);
+       }
+}
+
 void DM_set_only_copy(DerivedMesh *dm, CustomDataMask mask)
 {
        CustomData_set_only_copy(&dm->vertData, mask);
index 3822e0322f76c67d1ddbedc7387a14807f3d9e7c..c7b79756263d49f3b1ce9a3c553edd5776055f46 100644 (file)
@@ -1395,6 +1395,49 @@ Key *ob_get_key(Object *ob)
        return NULL;
 }
 
+KeyBlock *add_keyblock(Scene *scene, Key *key)
+{
+       KeyBlock *kb;
+       float curpos= -0.1;
+       int tot;
+       
+       kb= key->block.last;
+       if(kb) curpos= kb->pos;
+       
+       kb= MEM_callocN(sizeof(KeyBlock), "Keyblock");
+       BLI_addtail(&key->block, kb);
+       kb->type= KEY_CARDINAL;
+       
+       tot= BLI_countlist(&key->block);
+       if(tot==1) strcpy(kb->name, "Basis");
+       else sprintf(kb->name, "Key %d", tot-1);
+       
+       // XXX this is old anim system stuff? (i.e. the 'index' of the shapekey)
+       kb->adrcode= tot-1;
+       
+       key->totkey++;
+       if(key->totkey==1) key->refkey= kb;
+       
+       kb->slidermin= 0.0f;
+       kb->slidermax= 1.0f;
+       
+       // XXX kb->pos is the confusing old horizontal-line RVK crap in old IPO Editor...
+       if(key->type == KEY_RELATIVE) 
+               kb->pos= curpos+0.1;
+       else {
+#if 0 // XXX old animation system
+               curpos= bsystem_time(scene, 0, (float)CFRA, 0.0);
+               if(calc_ipo_spec(key->ipo, KEY_SPEED, &curpos)==0) {
+                       curpos /= 100.0;
+               }
+               kb->pos= curpos;
+               
+               sort_keys(key);
+#endif // XXX old animation system
+       }
+       return kb;
+}
+
 /* only the active keyblock */
 KeyBlock *ob_get_keyblock(Object *ob) 
 {
index ed7fbe58ea4640c04adbae9301bdef7a624e97e6..b5e0ca9ea5cb752a2d15c4c95adc9cbfc27ae154 100644 (file)
@@ -8924,6 +8924,12 @@ int modifier_couldBeCage(ModifierData *md)
                        modifier_supportsMapping(md));  
 }
 
+int modifier_sameTopology(ModifierData *md)
+{
+       ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+       return ( mti->type == eModifierTypeType_OnlyDeform || mti->type == eModifierTypeType_Nonconstructive);
+}
+
 void modifier_setError(ModifierData *md, char *format, ...)
 {
        char buffer[2048];
index 8bc7fc8c4d6d63772c535aff291ced4f99694520..e48a98a65f1e07af4744afdbc1430973cd78977a 100644 (file)
@@ -114,12 +114,17 @@ void key_to_curve(struct KeyBlock *kb, struct Curve  *cu, struct ListBase *nurb)
 void curve_to_key(struct Curve *cu, struct KeyBlock *kb, struct ListBase *nurb);
 
 /* object_modifier.c */
+enum {
+       MODIFIER_APPLY_DATA=1,
+       MODIFIER_APPLY_SHAPE,
+} eModifier_Apply_Mode;
+
 struct ModifierData *ED_object_modifier_add(struct ReportList *reports, struct Scene *scene, struct Object *ob, int type);
 int ED_object_modifier_remove(struct ReportList *reports, struct Scene *scene, struct Object *ob, struct ModifierData *md);
 int ED_object_modifier_move_down(struct ReportList *reports, struct Object *ob, struct ModifierData *md);
 int ED_object_modifier_move_up(struct ReportList *reports, struct Object *ob, struct ModifierData *md);
 int ED_object_modifier_convert(struct ReportList *reports, struct Scene *scene, struct Object *ob, struct ModifierData *md);
-int ED_object_modifier_apply(struct ReportList *reports, struct Scene *scene, struct Object *ob, struct ModifierData *md);
+int ED_object_modifier_apply(struct ReportList *reports, struct Scene *scene, struct Object *ob, struct ModifierData *md, int mode);
 int ED_object_modifier_copy(struct ReportList *reports, struct Object *ob, struct ModifierData *md);
 
 #endif /* ED_OBJECT_H */
index dbf5eb1d0eaf58702b42387044d2459d3f1973dc..c263729f4fee76b75acbdd195bb37ec0bb50e05a 100644 (file)
@@ -656,7 +656,7 @@ static uiLayout *draw_modifier(uiLayout *layout, Object *ob, ModifierData *md, i
                uiLayout *box;
 
                box= uiLayoutBox(column);
-               row= uiLayoutRow(box, 1);
+               row= uiLayoutRow(box, 0);
 
                if(!isVirtual && (md->type!=eModifierType_Collision) && (md->type!=eModifierType_Surface)) {
                        /* only here obdata, the rest of modifiers is ob level */
@@ -669,8 +669,12 @@ static uiLayout *draw_modifier(uiLayout *layout, Object *ob, ModifierData *md, i
                                        if(ELEM3(psys->part->ren_as, PART_DRAW_PATH, PART_DRAW_GR, PART_DRAW_OB) && psys->pathcache)
                                                uiItemO(row, "Convert", 0, "OBJECT_OT_modifier_convert");
                        }
-                       else
-                               uiItemO(row, "Apply", 0, "OBJECT_OT_modifier_apply");
+                       else 
+                               uiItemEnumO(row, "Apply", 0, "OBJECT_OT_modifier_apply", "apply_as", MODIFIER_APPLY_DATA);
+                       
+                       if (modifier_sameTopology(md))
+                               uiItemEnumO(row, "Apply as Shape", 0, "OBJECT_OT_modifier_apply", "apply_as", MODIFIER_APPLY_SHAPE);
+                       
                        
                        uiBlockClearButLock(block);
                        uiBlockSetButLock(block, ob && ob->id.lib, ERROR_LIBDATA_MESSAGE);
index f32d4e7efbd0614f95eddefb31fce8a33b568fe4..58f2ed443ca84a3cce5ad95a727bb76d79e5ad60 100644 (file)
@@ -33,6 +33,7 @@
 
 #include "DNA_action_types.h"
 #include "DNA_curve_types.h"
+#include "DNA_key_types.h"
 #include "DNA_mesh_types.h"
 #include "DNA_meshdata_types.h"
 #include "DNA_modifier_types.h"
@@ -51,6 +52,7 @@
 #include "BKE_DerivedMesh.h"
 #include "BKE_effect.h"
 #include "BKE_global.h"
+#include "BKE_key.h"
 #include "BKE_lattice.h"
 #include "BKE_mesh.h"
 #include "BKE_modifier.h"
@@ -66,6 +68,7 @@
 #include "RNA_enum_types.h"
 
 #include "ED_armature.h"
+#include "ED_object.h"
 #include "ED_screen.h"
 
 #include "WM_api.h"
@@ -328,7 +331,7 @@ int ED_object_modifier_convert(ReportList *reports, Scene *scene, Object *ob, Mo
        return 1;
 }
 
-int ED_object_modifier_apply(ReportList *reports, Scene *scene, Object *ob, ModifierData *md)
+int ED_object_modifier_apply(ReportList *reports, Scene *scene, Object *ob, ModifierData *md, int mode)
 {
        DerivedMesh *dm;
        Mesh *me = ob->data;
@@ -346,27 +349,64 @@ int ED_object_modifier_apply(ReportList *reports, Scene *scene, Object *ob, Modi
                BKE_report(reports, RPT_INFO, "Applied modifier was not first, result may not be as expected.");
 
        if (ob->type==OB_MESH) {
-               if(me->key) {
-                       BKE_report(reports, RPT_ERROR, "Modifier cannot be applied to Mesh with Shape Keys");
-                       return 0;
+               if (mode == MODIFIER_APPLY_SHAPE) {
+                       Key *key=me->key;
+                       KeyBlock *kb;
+                       int newkey=0;
+                       
+                       if(!modifier_sameTopology(md)) {
+                               BKE_report(reports, RPT_ERROR, "Only deforming modifiers can be applied to Shapes");
+                               return 0;
+                       }
+                       mesh_pmv_off(ob, me);
+                       
+                       dm = mesh_create_derived_for_modifier(scene, ob, md);
+                       if (!dm) {
+                               BKE_report(reports, RPT_ERROR, "Modifier is disabled or returned error, skipping apply");
+                               return 0;
+                       }
+                       
+                       if(key == NULL) {
+                               key= me->key= add_key((ID *)me);
+                               key->type= KEY_RELATIVE;
+                               newkey= 1;
+                       }
+                       kb= add_keyblock(scene, key);
+                       
+                       if (newkey) {
+                               /* if that was the first key block added, then it was the basis.
+                                * Initialise it with the mesh, and add another for the modifier */
+                               mesh_to_key(me, kb);
+                               kb= add_keyblock(scene, key);
+                       }
+                       DM_to_meshkey(dm, me, kb);
+                       converted = 1;
+                       
+                       dm->release(dm);
                }
-       
-               mesh_pmv_off(ob, me);
+               else {  /* MODIFIER_APPLY_DATA */
+                       if( me->key) {
+                               BKE_report(reports, RPT_ERROR, "Modifier cannot be applied to Mesh with Shape Keys");
+                               return 0;
+                       }
+                       
+                       mesh_pmv_off(ob, me);
 
-          /* Multires: ensure that recent sculpting is applied */
-          if(md->type == eModifierType_Multires)
-                          multires_force_update(ob);
+                       /* Multires: ensure that recent sculpting is applied */
+                       if(md->type == eModifierType_Multires)
+                                  multires_force_update(ob);
 
-               dm = mesh_create_derived_for_modifier(scene, ob, md);
-               if (!dm) {
-                       BKE_report(reports, RPT_ERROR, "Modifier is disabled or returned error, skipping apply");
-                       return 0;
-               }
+                       dm = mesh_create_derived_for_modifier(scene, ob, md);
+                       if (!dm) {
+                               BKE_report(reports, RPT_ERROR, "Modifier is disabled or returned error, skipping apply");
+                               return 0;
+                       }
 
-               DM_to_mesh(dm, me);
-               converted = 1;
+                       DM_to_mesh(dm, me);
+                       converted = 1;
 
-               dm->release(dm);
+                       dm->release(dm);
+               }
        } 
        else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
                ModifierTypeInfo *mti = modifierType_getInfo(md->type);
@@ -598,8 +638,9 @@ static int modifier_apply_exec(bContext *C, wmOperator *op)
        PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_Modifier);
        Object *ob= ptr.id.data;
        ModifierData *md= ptr.data;
+       int apply_as= RNA_enum_get(op->ptr, "apply_as");
 
-       if(!ob || !md || !ED_object_modifier_apply(op->reports, scene, ob, md))
+       if(!ob || !md || !ED_object_modifier_apply(op->reports, scene, ob, md, apply_as))
                return OPERATOR_CANCELLED;
 
        DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
@@ -608,6 +649,11 @@ static int modifier_apply_exec(bContext *C, wmOperator *op)
        return OPERATOR_FINISHED;
 }
 
+static 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";
@@ -615,11 +661,14 @@ void OBJECT_OT_modifier_apply(wmOperatorType *ot)
        ot->idname= "OBJECT_OT_modifier_apply";
        ot->poll= ED_operator_object_active;
 
+       //ot->invoke= WM_menu_invoke;
        ot->exec= modifier_apply_exec;
        ot->poll= modifier_poll;
        
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       RNA_def_enum(ot->srna, "apply_as", modifier_apply_as_items, MODIFIER_APPLY_DATA, "Apply as", "How to apply the modifier to the geometry");
 }
 
 /************************ convert modifier operator *********************/
index 878c61aac486f28a691e9f2022fa8d609efc645a..f8eff578839fc6a5d1f50de62451edfddc8f833b 100644 (file)
@@ -119,49 +119,6 @@ void key_to_mesh(KeyBlock *kb, Mesh *me)
        }
 }
 
-static KeyBlock *add_keyblock(Scene *scene, Key *key)
-{
-       KeyBlock *kb;
-       float curpos= -0.1;
-       int tot;
-       
-       kb= key->block.last;
-       if(kb) curpos= kb->pos;
-       
-       kb= MEM_callocN(sizeof(KeyBlock), "Keyblock");
-       BLI_addtail(&key->block, kb);
-       kb->type= KEY_CARDINAL;
-       
-       tot= BLI_countlist(&key->block);
-       if(tot==1) strcpy(kb->name, "Basis");
-       else sprintf(kb->name, "Key %d", tot-1);
-       
-               // XXX this is old anim system stuff? (i.e. the 'index' of the shapekey)
-       kb->adrcode= tot-1;
-       
-       key->totkey++;
-       if(key->totkey==1) key->refkey= kb;
-       
-       kb->slidermin= 0.0f;
-       kb->slidermax= 1.0f;
-       
-       // XXX kb->pos is the confusing old horizontal-line RVK crap in old IPO Editor...
-       if(key->type == KEY_RELATIVE) 
-               kb->pos= curpos+0.1;
-       else {
-#if 0 // XXX old animation system
-               curpos= bsystem_time(scene, 0, (float)CFRA, 0.0);
-               if(calc_ipo_spec(key->ipo, KEY_SPEED, &curpos)==0) {
-                       curpos /= 100.0;
-               }
-               kb->pos= curpos;
-               
-               sort_keys(key);
-#endif // XXX old animation system
-       }
-       return kb;
-}
-
 static void insert_meshkey(Scene *scene, Object *ob)
 {
        Mesh *me= ob->data;