Armature CrazySpace Improvement
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Sat, 28 Jul 2007 21:04:30 +0000 (21:04 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Sat, 28 Jul 2007 21:04:30 +0000 (21:04 +0000)
===============================

An improved CrazySpace correction is now used for Armature modifiers that use
vertex groups, and that are the first enabled modifiers in the stack. This is
a a specific case, but also a common one.

http://www.blender.org/development/current-projects/changes-since-244/skinning/

Implementation Notes:

- The quaternion crazyspace correction is still used for modifiers other than
  the armature modifier.
- Modifiers can now provide a deform matrix per vertex to be used for
  crazyspace correction, only the armature modifier implements this now.

source/blender/blenkernel/BKE_DerivedMesh.h
source/blender/blenkernel/BKE_lattice.h
source/blender/blenkernel/BKE_modifier.h
source/blender/blenkernel/intern/DerivedMesh.c
source/blender/blenkernel/intern/armature.c
source/blender/blenkernel/intern/modifier.c
source/blender/blenlib/BLI_arithb.h
source/blender/blenlib/intern/arithb.c
source/blender/makesdna/DNA_modifier_types.h
source/blender/src/transform_conversions.c

index 872717fdb9b27e79139c9005121239ac8db62385..4a19bfb9249e4841041dd0c552b929df51c57044 100644 (file)
@@ -425,6 +425,11 @@ DerivedMesh *editmesh_get_derived_cage(CustomDataMask dataMask);
 DerivedMesh *editmesh_get_derived_cage_and_final(DerivedMesh **final_r,
                                                  CustomDataMask dataMask);
 
+/* returns an array of deform matrices for crazyspace correction, and the
+   number of modifiers left */
+int editmesh_get_first_deform_matrices(float (**deformmats)[3][3],
+                                       float (**deformcos)[3]);
+
 void weight_to_rgb(float input, float *fr, float *fg, float *fb);
 
 /* determines required DerivedMesh data according to view and edit modes */
index 55eb1d27cc027a555ccc9d631c3307f3cd8ffb4e..3dc4b49b52b65cea53580e021f83dfd382345d59 100644 (file)
@@ -64,8 +64,8 @@ void lattice_deform_verts(struct Object *laOb, struct Object *target,
                           int numVerts, char *vgroup);
 void armature_deform_verts(struct Object *armOb, struct Object *target,
                            struct DerivedMesh *dm, float (*vertexCos)[3],
-                           int numVerts, int deformflag,
-                           const char *defgrp_name);
+                           float (*defMats)[3][3], int numVerts,
+                           int deformflag, const char *defgrp_name);
 float (*lattice_getVertexCos(struct Object *ob, int *numVerts_r))[3];
 void lattice_applyVertexCos(struct Object *ob, float (*vertexCos)[3]);
 void lattice_calc_modifiers(struct Object *ob);
index ce3f33bd35c589e8c7d5b155b64d382f4106ae94..297443b883d57b91f24c74eaaece97826d93aec7 100644 (file)
@@ -125,6 +125,11 @@ typedef struct ModifierTypeInfo {
                    struct EditMesh *editData, struct DerivedMesh *derivedData,
                    float (*vertexCos)[3], int numVerts);
 
+       /* Set deform matrix per vertex for crazyspace correction */
+       void (*deformMatricesEM)(
+                   struct ModifierData *md, struct Object *ob,
+                   struct EditMesh *editData, struct DerivedMesh *derivedData,
+                   float (*vertexCos)[3], float (*defMats)[3][3], int numVerts);
 
        /********************* Non-deform modifier functions *********************/
 
@@ -257,6 +262,7 @@ void          modifier_copyData(struct ModifierData *md, struct ModifierData *ta
 int           modifier_dependsOnTime(struct ModifierData *md);
 int           modifier_supportsMapping(struct ModifierData *md);
 int           modifier_couldBeCage(struct ModifierData *md);
+int           modifier_isDeformer(struct ModifierData *md);
 void          modifier_setError(struct ModifierData *md, char *format, ...);
 
 void          modifiers_foreachObjectLink(struct Object *ob,
index 5f8e9c7b207bcdcdbcf776bb7bf36de7d23a0374..be1d39d6c8c2f61f95e761faa739ec6f5c790bdf 100644 (file)
@@ -1887,6 +1887,24 @@ static float (*editmesh_getVertexCos(EditMesh *em, int *numVerts_r))[3]
        return cos;
 }
 
+static int editmesh_modifier_is_enabled(ModifierData *md, DerivedMesh *dm)
+{
+       ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+       int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
+
+       if((md->mode & required_mode) != required_mode) return 0;
+       if((mti->flags & eModifierTypeFlag_RequiresOriginalData) && dm) {
+               modifier_setError(md, "Internal error, modifier requires"
+                                 "original data (bad stack position).");
+               return 0;
+       }
+       if(mti->isDisabled && mti->isDisabled(md)) return 0;
+       if(!(mti->flags & eModifierTypeFlag_SupportsEditmode)) return 0;
+       if(md->mode & eModifierMode_DisableTemporary) return 0;
+       
+       return 1;
+}
+
 static void editmesh_calc_modifiers(DerivedMesh **cage_r,
                                     DerivedMesh **final_r,
                                     CustomDataMask dataMask)
@@ -1897,7 +1915,6 @@ static void editmesh_calc_modifiers(DerivedMesh **cage_r,
        float (*deformedVerts)[3] = NULL;
        DerivedMesh *dm;
        int i, numVerts = 0, cageIndex = modifiers_getCageIndex(ob, NULL);
-       int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
        LinkNode *datamasks, *curr;
 
        modifiers_clearErrors(ob);
@@ -1918,14 +1935,8 @@ static void editmesh_calc_modifiers(DerivedMesh **cage_r,
        for(i = 0; md; i++, md = md->next, curr = curr->next) {
                ModifierTypeInfo *mti = modifierType_getInfo(md->type);
 
-               if((md->mode & required_mode) != required_mode) continue;
-               if((mti->flags & eModifierTypeFlag_RequiresOriginalData) && dm) {
-                       modifier_setError(md, "Internal error, modifier requires"
-                                         "original data (bad stack position).");
+               if(!editmesh_modifier_is_enabled(md, dm))
                        continue;
-               }
-               if(mti->isDisabled && mti->isDisabled(md)) continue;
-               if(!(mti->flags & eModifierTypeFlag_SupportsEditmode)) continue;
 
                /* How to apply modifier depends on (a) what we already have as
                 * a result of previous modifiers (could be a DerivedMesh or just
@@ -2461,6 +2472,61 @@ float *mesh_get_mapped_verts_nors(Object *ob)
        return vertexcosnos;
 }
 
+/* ********* crazyspace *************** */
+
+int editmesh_get_first_deform_matrices(float (**deformmats)[3][3], float (**deformcos)[3])
+{
+       Object *ob = G.obedit;
+       EditMesh *em = G.editMesh;
+       ModifierData *md;
+       DerivedMesh *dm;
+       int i, a, numleft = 0, numVerts = 0;
+       int cageIndex = modifiers_getCageIndex(ob, NULL);
+       float (*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL;
+
+       modifiers_clearErrors(ob);
+
+       dm = NULL;
+       md = ob->modifiers.first;
+
+       /* compute the deformation matrices and coordinates for the first
+          modifiers with on cage editing that are enabled and support computing
+          deform matrices */
+       for(i = 0; md && i <= cageIndex; i++, md = md->next) {
+               ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+               if(!editmesh_modifier_is_enabled(md, dm))
+                       continue;
+
+               if(mti->type==eModifierTypeType_OnlyDeform && mti->deformMatricesEM) {
+                       if(!defmats) {
+                               dm= getEditMeshDerivedMesh(em, ob, NULL);
+                               deformedVerts= editmesh_getVertexCos(em, &numVerts);
+                               defmats= MEM_callocN(sizeof(*defmats)*numVerts, "defmats");
+
+                               for(a=0; a<numVerts; a++)
+                                       Mat3One(defmats[a]);
+                       }
+
+                       mti->deformMatricesEM(md, ob, em, dm, deformedVerts, defmats,
+                               numVerts);
+               }
+               else
+                       break;
+       }
+
+       for(; md && i <= cageIndex; md = md->next, i++)
+               if(editmesh_modifier_is_enabled(md, dm) && modifier_isDeformer(md))
+                       numleft++;
+
+       if(dm)
+               dm->release(dm);
+       
+       *deformmats= defmats;
+       *deformcos= deformedVerts;
+
+       return numleft;
+}
 
 /* ************************* fluidsim bobj file handling **************************** */
 
index b320a7e01065196a06370fc1f8892d1e1da68349..db3841819821ac2a5336dbea47aeaaa4c8874e34 100644 (file)
@@ -504,39 +504,54 @@ static void pchan_b_bone_defmats(bPoseChannel *pchan)
        Bone *bone= pchan->bone;
        Mat4 *b_bone= b_bone_spline_setup(pchan);
        Mat4 *b_bone_mats;
+       float tmat[4][4];
        int a;
        
-       pchan->b_bone_mats=b_bone_mats= MEM_mallocN((1+bone->segments)*sizeof(Mat4), "BBone defmats");
-       
-       /* first matrix is the inverse arm_mat, to bring points in local bone space */
+       /* allocate b_bone matrices and dual quats */
+       b_bone_mats= MEM_mallocN((1+bone->segments)*sizeof(Mat4), "BBone defmats");
+       pchan->b_bone_mats= b_bone_mats;
+
+       /* first matrix is the inverse arm_mat, to bring points in local bone space
+          for finding out which segment it belongs to */
        Mat4Invert(b_bone_mats[0].mat, bone->arm_mat);
-       
-       /* then we multiply the bbone_mats with arm_mat */
+
+       /* then we make the b_bone_mats:
+           - first transform to local bone space
+               - translate over the curve to the bbone mat space
+               - transform with b_bone matrix
+               - transform back into global space */
+       Mat4One(tmat);
+
        for(a=0; a<bone->segments; a++) {
-               Mat4MulMat4(b_bone_mats[a+1].mat, b_bone[a].mat, bone->arm_mat);
+               tmat[3][1] = -a*(bone->length/(float)bone->segments);
+
+               Mat4MulSerie(b_bone_mats[a+1].mat, pchan->chan_mat, bone->arm_mat,
+                       b_bone[a].mat, tmat, b_bone_mats[0].mat, NULL, NULL, NULL);
        }
 }
 
-static void b_bone_deform(bPoseChannel *pchan, Bone *bone, float *defpos)
+static void b_bone_deform(bPoseChannel *pchan, Bone *bone, float *co, float defmat[][3])
 {
        Mat4 *b_bone= pchan->b_bone_mats;
-       float segment;
+       float (*mat)[4]= b_bone[0].mat;
+       float segment, y;
        int a;
        
-       /* need to transform defpos back to bonespace */
-       Mat4MulVecfl(b_bone[0].mat, defpos);
+       /* need to transform co back to bonespace, only need y */
+       y= mat[0][1]*co[0] + mat[1][1]*co[1] + mat[2][1]*co[2] + mat[3][1];
        
        /* now calculate which of the b_bones are deforming this */
        segment= bone->length/((float)bone->segments);
-       a= (int) (defpos[1]/segment);
+       a= (int)(y/segment);
        
-       /* note; by clamping it extends deform at endpoints, goes best with straight joints in restpos. */
+       /* note; by clamping it extends deform at endpoints, goes best with
+          straight joints in restpos. */
        CLAMP(a, 0, bone->segments-1);
 
-       /* since the bbone mats translate from (0.0.0) on the curve, we subtract */
-       defpos[1] -= ((float)a)*segment;
-       
-       Mat4MulVecfl(b_bone[a+1].mat, defpos);
+       Mat4MulVecfl(b_bone[a+1].mat, co);
+
+       if(defmat)
+               Mat3CpyMat4(defmat, b_bone[a+1].mat);
 }
 
 /* using vec with dist to bone b1 - b2 */
@@ -590,12 +605,24 @@ float distfactor_to_bone (float vec[3], float b1[3], float b2[3], float rad1, fl
        }
 }
 
-static float dist_bone_deform(bPoseChannel *pchan, float *vec, float *co)
+static void pchan_deform_mat_add(bPoseChannel *pchan, float weight, float bbonemat[][3], float mat[][3])
+{
+       float wmat[3][3];
+
+       if(pchan->bone->segments>1)
+               Mat3CpyMat3(wmat, bbonemat);
+       else
+               Mat3CpyMat4(wmat, pchan->chan_mat);
+
+       Mat3MulFloat((float*)wmat, weight);
+       Mat3AddMat3(mat, mat, wmat);
+}
+
+static float dist_bone_deform(bPoseChannel *pchan, float *vec, float mat[][3], float *co)
 {
        Bone *bone= pchan->bone;
-       float   fac;
-       float   cop[3];
-       float   contrib=0.0;
+       float fac, contrib=0.0;
+       float cop[3], bbonemat[3][3];
 
        if(bone==NULL) return 0.0f;
        
@@ -603,52 +630,58 @@ static float dist_bone_deform(bPoseChannel *pchan, float *vec, float *co)
 
        fac= distfactor_to_bone(cop, bone->arm_head, bone->arm_tail, bone->rad_head, bone->rad_tail, bone->dist);
        
-       if (fac>0.0){
+       if (fac>0.0) {
                
                fac*=bone->weight;
                contrib= fac;
                if(contrib>0.0) {
-
-                       VECCOPY (cop, co);
-                       
                        if(bone->segments>1)
-                               b_bone_deform(pchan, bone, cop);        // applies on cop
-                       
-                       Mat4MulVecfl(pchan->chan_mat, cop);
-                       
-                       VecSubf (cop, cop, co); //      Make this a delta from the base position
+                               // applies on cop and bbonemat
+                               b_bone_deform(pchan, bone, cop, (mat)?bbonemat:NULL);
+                       else
+                               Mat4MulVecfl(pchan->chan_mat, cop);
+
+                       //      Make this a delta from the base position
+                       VecSubf (cop, cop, co);
                        cop[0]*=fac; cop[1]*=fac; cop[2]*=fac;
                        VecAddf (vec, vec, cop);
+
+                       if(mat)
+                               pchan_deform_mat_add(pchan, fac, bbonemat, mat);
                }
        }
        
        return contrib;
 }
 
-static void pchan_bone_deform(bPoseChannel *pchan, float weight, float *vec, float *co, float *contrib)
+static void pchan_bone_deform(bPoseChannel *pchan, float weight, float *vec, float mat[][3], float *co, float *contrib)
 {
-       float   cop[3];
+       float cop[3], bbonemat[3][3];
 
        if (!weight)
                return;
 
-       VECCOPY (cop, co);
-       
+       VECCOPY(cop, co);
+
        if(pchan->bone->segments>1)
-               b_bone_deform(pchan, pchan->bone, cop); // applies on cop
-       
-       Mat4MulVecfl(pchan->chan_mat, cop);
+               // applies on cop and bbonemat
+               b_bone_deform(pchan, pchan->bone, cop, (mat)?bbonemat:NULL);
+       else
+               Mat4MulVecfl(pchan->chan_mat, cop);
        
        vec[0]+=(cop[0]-co[0])*weight;
        vec[1]+=(cop[1]-co[1])*weight;
        vec[2]+=(cop[2]-co[2])*weight;
 
+       if(mat)
+               pchan_deform_mat_add(pchan, weight, bbonemat, mat);
+
        (*contrib)+=weight;
 }
 
 void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm,
-                           float (*vertexCos)[3], int numVerts, int deformflag,
-                           const char *defgrp_name)
+                           float (*vertexCos)[3], float (*defMats)[3][3],
+                                                  int numVerts, int deformflag, const char *defgrp_name)
 {
        bPoseChannel *pchan, **defnrToPC = NULL;
        MDeformVert *dverts = NULL;
@@ -669,12 +702,11 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm,
 
        /* bone defmats are already in the channels, chan_mat */
        
-       /* initialize B_bone matrices */
-       for(pchan = armOb->pose->chanbase.first; pchan; pchan = pchan->next) {
+       /* initialize B_bone matrices and dual quaternions */
+       for(pchan = armOb->pose->chanbase.first; pchan; pchan = pchan->next)
                if(!(pchan->bone->flag & BONE_NO_DEFORM))
                        if(pchan->bone->segments > 1)
                                pchan_b_bone_defmats(pchan);
-       }
 
        /* get the def_nr for the overall armature vertex group if present */
        for(i = 0, dg = target->defbase.first; dg; i++, dg = dg->next)
@@ -723,6 +755,7 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm,
        for(i = 0; i < numVerts; i++) {
                MDeformVert *dvert;
                float *co = vertexCos[i];
+               float summat[3][3], (*smat)[3] = NULL;
                float vec[3];
                float contrib = 0.0f;
                float armature_weight = 1.0f; /* default to 1 if no overall def group */
@@ -730,6 +763,11 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm,
 
                vec[0] = vec[1] = vec[2] = 0.0f;
 
+               if(defMats) {
+                       Mat3Clr((float*)summat);
+                       smat = summat;
+               }
+
                if(use_dverts || armature_def_nr >= 0) {
                        if(dm) dvert = dm->getVertData(dm, i, CD_MDEFORMVERT);
                        else if(dverts && i < target_totvert) dvert = dverts + i;
@@ -772,7 +810,7 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm,
                                                                             bone->rad_tail,
                                                                             bone->dist);
                                        }
-                                       pchan_bone_deform(pchan, weight, vec, co, &contrib);
+                                       pchan_bone_deform(pchan, weight, vec, smat, co, &contrib);
                                }
                        }
                        /* if there are vertexgroups but not groups with bones
@@ -782,7 +820,7 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm,
                                for(pchan = armOb->pose->chanbase.first; pchan;
                                    pchan = pchan->next) {
                                        if(!(pchan->bone->flag & BONE_NO_DEFORM))
-                                               contrib += dist_bone_deform(pchan, vec, co);
+                                               contrib += dist_bone_deform(pchan, vec, smat, co);
                                }
                        }
                }
@@ -790,15 +828,31 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm,
                        for(pchan = armOb->pose->chanbase.first; pchan;
                            pchan = pchan->next) {
                                if(!(pchan->bone->flag & BONE_NO_DEFORM))
-                                       contrib += dist_bone_deform(pchan, vec, co);
+                                       contrib += dist_bone_deform(pchan, vec, smat, co);
                        }
                }
 
                /* actually should be EPSILON? weight values and contrib can be like 10e-39 small */
                if(contrib > 0.0001f) {
-                       VecMulf(vec, armature_weight / contrib);
+                       float scale = armature_weight/contrib;
+
+                       VecMulf(vec, scale);
                        VecAddf(co, vec, co);
+
+                       if(defMats) {
+                               float pre[3][3], post[3][3], tmpmat[3][3];
+
+                               Mat3CpyMat4(pre, premat);
+                               Mat3CpyMat4(post, postmat);
+                               Mat3CpyMat3(tmpmat, defMats[i]);
+
+                               Mat3MulFloat((float*)smat, scale);
+                               Mat3MulSerie(defMats[i], tmpmat, pre, smat, post,
+                                       NULL, NULL, NULL, NULL);
+                       }
+
                }
+               
                /* always, check above code */
                Mat4MulVecfl(postmat, co);
        }
index dd65eba0df910881bea446194cd10b0ddb8b2918..d6fa8d1d3d6876238a132dcea0d24b1dcab93427 100644 (file)
@@ -4577,8 +4577,8 @@ static void armatureModifier_deformVerts(
 {
        ArmatureModifierData *amd = (ArmatureModifierData*) md;
 
-       armature_deform_verts(amd->object, ob, derivedData, vertexCos, numVerts,
-                             amd->deformflag, amd->defgrp_name);
+       armature_deform_verts(amd->object, ob, derivedData, vertexCos, NULL,
+                             numVerts, amd->deformflag, amd->defgrp_name);
 }
 
 static void armatureModifier_deformVertsEM(
@@ -4590,7 +4590,23 @@ static void armatureModifier_deformVertsEM(
 
        if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data);
 
-       armature_deform_verts(amd->object, ob, dm, vertexCos, numVerts,
+       armature_deform_verts(amd->object, ob, dm, vertexCos, NULL, numVerts,
+                             amd->deformflag, amd->defgrp_name);
+
+       if(!derivedData) dm->release(dm);
+}
+
+static void armatureModifier_deformMatricesEM(
+                               ModifierData *md, Object *ob, EditMesh *editData,
+                               DerivedMesh *derivedData, float (*vertexCos)[3],
+                               float (*defMats)[3][3], int numVerts)
+{
+       ArmatureModifierData *amd = (ArmatureModifierData*) md;
+       DerivedMesh *dm = derivedData;
+
+       if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data);
+
+       armature_deform_verts(amd->object, ob, dm, vertexCos, defMats, numVerts,
                              amd->deformflag, amd->defgrp_name);
 
        if(!derivedData) dm->release(dm);
@@ -5067,6 +5083,7 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type)
                mti->updateDepgraph = armatureModifier_updateDepgraph;
                mti->deformVerts = armatureModifier_deformVerts;
                mti->deformVertsEM = armatureModifier_deformVertsEM;
+               mti->deformMatricesEM = armatureModifier_deformMatricesEM;
 
                mti = INIT_TYPE(Hook);
                mti->type = eModifierTypeType_OnlyDeform;
@@ -5268,6 +5285,7 @@ int modifiers_getCageIndex(Object *ob, int *lastPossibleCageIndex_r)
                if (!(md->mode & eModifierMode_Editmode)) continue;
                if (mti->isDisabled && mti->isDisabled(md)) continue;
                if (!(mti->flags & eModifierTypeFlag_SupportsEditmode)) continue;
+               if (md->mode & eModifierMode_DisableTemporary) continue;
 
                if (!modifier_supportsMapping(md))
                        break;
@@ -5447,20 +5465,26 @@ int modifiers_usesArmature(Object *ob, bArmature *arm)
        return 0;
 }
 
+int modifier_isDeformer(ModifierData *md)
+{
+       if (md->type==eModifierType_Armature)
+               return 1;
+       if (md->type==eModifierType_Curve)
+               return 1;
+       if (md->type==eModifierType_Lattice)
+               return 1;
+       
+       return 0;
+}
+
 int modifiers_isDeformed(Object *ob)
 {
        ModifierData *md = modifiers_getVirtualModifierList(ob);
        
        for (; md; md=md->next) {
                if(ob==G.obedit && (md->mode & eModifierMode_Editmode)==0);
-               else {
-                       if (md->type==eModifierType_Armature)
-                               return 1;
-                       if (md->type==eModifierType_Curve)
-                               return 1;
-                       if (md->type==eModifierType_Lattice)
-                               return 1;
-               }
+               else if(modifier_isDeformer(md))
+                       return 1;
        }
        return 0;
 }
index a732f09ca58fc8f85abd38c64df6415123d0e705..7a1bedf5c14baa0b3f4cd3f9993c397841edf334 100644 (file)
@@ -217,6 +217,8 @@ void Mat3MulVecfl(float mat[][3], float *vec);
 void Mat3MulVecd(float mat[][3], double *vec);
 void Mat3TransMulVecfl(float mat[][3], float *vec);
 
+void Mat3AddMat3(float m1[][3], float m2[][3], float m3[][3]);
+void Mat4AddMat4(float m1[][4], float m2[][4], float m3[][4]);
 
 void VecUpMat3old(float *vec, float mat[][3], short axis);
 void VecUpMat3(float *vec, float mat[][3], short axis);
index e98ce92787faed034191c918efdb2ed6ed09d100..f403be6cd926025167c4e6c0375af6136f04093a 100644 (file)
@@ -952,6 +952,24 @@ void Mat4MulFloat3(float *m, float f)              /* only scale component */
        }
 }
 
+void Mat3AddMat3(float m1[][3], float m2[][3], float m3[][3])
+{
+       int i, j;
+
+       for(i=0;i<3;i++)
+               for(j=0;j<3;j++)
+                       m1[i][j]= m2[i][j] + m3[i][j];
+}
+
+void Mat4AddMat4(float m1[][4], float m2[][4], float m3[][4])
+{
+       int i, j;
+
+       for(i=0;i<4;i++)
+               for(j=0;j<4;j++)
+                       m1[i][j]= m2[i][j] + m3[i][j];
+}
+
 void VecStar(float mat[][3], float *vec)
 {
 
index 2d296ad10fad399ecdb4d2a00745b0e212c838b9..71e850e4368292be98563872db72dfc706b55e3b 100644 (file)
@@ -38,6 +38,7 @@ typedef enum ModifierMode {
        eModifierMode_OnCage = (1<<3),
        eModifierMode_Expanded = (1<<4),
        eModifierMode_Virtual = (1<<5),
+       eModifierMode_DisableTemporary = (1 << 31)
 } ModifierMode;
 
 typedef struct ModifierData {
index 0db4eaaf94fda833917588ea3880f93778579763..65fd406727687d28f231293a26e3d3ad3b0c53ba 100755 (executable)
@@ -1506,43 +1506,33 @@ static void make_vertexcos__mapFunc(void *userData, int index, float *co, float
        VECCOPY(vec, co);
 }
 
-/* hurmf, copy from buttons_editing.c, i have to sort this out what it means... */
-static void modifiers_setOnCage(void *ob_v, void *md_v)
+static int modifiers_disable_subsurf_temporary(Object *ob)
 {
-       Object *ob = ob_v;
        ModifierData *md;
+       int disabled = 0;
        
-       int i, cageIndex = modifiers_getCageIndex(ob, NULL );
+       for(md=ob->modifiers.first; md; md=md->next)
+               if(md->type==eModifierType_Subsurf)
+                       if(md->mode & eModifierMode_OnCage) {
+                               md->mode ^= eModifierMode_DisableTemporary;
+                               disabled= 1;
+                       }
        
-       for( i = 0, md=ob->modifiers.first; md; ++i, md=md->next )
-               if( md == md_v ) {
-                       if( i >= cageIndex )
-                               md->mode ^= eModifierMode_OnCage;
-                       break;
-               }
+       return disabled;
 }
 
-
 /* disable subsurf temporal, get mapped cos, and enable it */
 static float *get_crazy_mapped_editverts(void)
 {
        DerivedMesh *dm;
-       ModifierData *md;
        float *vertexcos;
-       int i;
-       
-       for( i = 0, md=G.obedit->modifiers.first; md; ++i, md=md->next ) {
-               if(md->type==eModifierType_Subsurf)
-                       if(md->mode & eModifierMode_OnCage)
-                               break;
-       }
-       if(md) {
-               /* this call disables subsurf and enables the underlying modifier to deform, apparently */
-               modifiers_setOnCage(G.obedit, md);
-               /* make it all over */
+
+       /* disable subsurf temporal, get mapped cos, and enable it */
+       if(modifiers_disable_subsurf_temporary(G.obedit)) {
+               /* need to make new derivemesh */
                makeDerivedMesh(G.obedit, CD_MASK_BAREMESH);
        }
-       
+
        /* now get the cage */
        dm= editmesh_get_derived_cage(CD_MASK_BAREMESH);
 
@@ -1551,10 +1541,8 @@ static float *get_crazy_mapped_editverts(void)
        
        dm->release(dm);
        
-       if(md) {
-               /* set back the flag, no new cage needs to be built, transform does it */
-               modifiers_setOnCage(G.obedit, md);
-       }
+       /* set back the flag, no new cage needs to be built, transform does it */
+       modifiers_disable_subsurf_temporary(G.obedit);
        
        return vertexcos;
 }
@@ -1577,12 +1565,12 @@ static void set_crazy_vertex_quat(float *quat, float *v1, float *v2, float *v3,
 }
 #undef TAN_MAKE_VEC
 
-static void set_crazyspace_quats(float *mappedcos, float *quats)
+static void set_crazyspace_quats(float *origcos, float *mappedcos, float *quats)
 {
        EditMesh *em = G.editMesh;
        EditVert *eve, *prev;
        EditFace *efa;
-       float *v1, *v2, *v3, *v4;
+       float *v1, *v2, *v3, *v4, *co1, *co2, *co3, *co4;
        long index= 0;
        
        /* two abused locations in vertices */
@@ -1595,43 +1583,48 @@ static void set_crazyspace_quats(float *mappedcos, float *quats)
        for(efa= em->faces.first; efa; efa= efa->next) {
                
                /* retrieve mapped coordinates */
-               v1= mappedcos + 3*( (long)(efa->v1->prev) );
-               v2= mappedcos + 3*( (long)(efa->v2->prev) );
-               v3= mappedcos + 3*( (long)(efa->v3->prev) );
-               
+               v1= mappedcos + 3*(long)(efa->v1->prev);
+               v2= mappedcos + 3*(long)(efa->v2->prev);
+               v3= mappedcos + 3*(long)(efa->v3->prev);
+
+               co1= (origcos)? origcos + 3*(long)(efa->v1->prev): efa->v1->co;
+               co2= (origcos)? origcos + 3*(long)(efa->v2->prev): efa->v2->co;
+               co3= (origcos)? origcos + 3*(long)(efa->v3->prev): efa->v3->co;
+
                if(efa->v2->tmp.fp==NULL && efa->v2->f1) {
-                       set_crazy_vertex_quat(quats, efa->v2->co, efa->v3->co, efa->v1->co, v2, v3, v1);
+                       set_crazy_vertex_quat(quats, co2, co3, co1, v2, v3, v1);
                        efa->v2->tmp.fp= quats;
                        quats+= 4;
                }
                
                if(efa->v4) {
-                       v4= mappedcos + 3*( (long)(efa->v4->prev) );
-                       
+                       v4= mappedcos + 3*(long)(efa->v4->prev);
+                       co4= (origcos)? origcos + 3*(long)(efa->v4->prev): efa->v4->co;
+
                        if(efa->v1->tmp.fp==NULL && efa->v1->f1) {
-                               set_crazy_vertex_quat(quats, efa->v1->co, efa->v2->co, efa->v4->co, v1, v2, v4);
+                               set_crazy_vertex_quat(quats, co1, co2, co4, v1, v2, v4);
                                efa->v1->tmp.fp= quats;
                                quats+= 4;
                        }
                        if(efa->v3->tmp.fp==NULL && efa->v3->f1) {
-                               set_crazy_vertex_quat(quats, efa->v3->co, efa->v4->co, efa->v2->co, v3, v4, v2);
+                               set_crazy_vertex_quat(quats, co3, co4, co2, v3, v4, v2);
                                efa->v3->tmp.fp= quats;
                                quats+= 4;
                        }
                        if(efa->v4->tmp.fp==NULL && efa->v4->f1) {
-                               set_crazy_vertex_quat(quats, efa->v4->co, efa->v1->co, efa->v3->co, v4, v1, v3);
+                               set_crazy_vertex_quat(quats, co4, co1, co3, v4, v1, v3);
                                efa->v4->tmp.fp= quats;
                                quats+= 4;
                        }
                }
                else {
                        if(efa->v1->tmp.fp==NULL && efa->v1->f1) {
-                               set_crazy_vertex_quat(quats, efa->v1->co, efa->v2->co, efa->v3->co, v1, v2, v3);
+                               set_crazy_vertex_quat(quats, co1, co2, co3, v1, v2, v3);
                                efa->v1->tmp.fp= quats;
                                quats+= 4;
                        }
                        if(efa->v3->tmp.fp==NULL && efa->v3->f1) {
-                               set_crazy_vertex_quat(quats, efa->v3->co, efa->v1->co, efa->v2->co, v3, v1, v2);
+                               set_crazy_vertex_quat(quats, co3, co1, co2, v3, v1, v2);
                                efa->v3->tmp.fp= quats;
                                quats+= 4;
                        }
@@ -1651,8 +1644,8 @@ static void createTransEditVerts(TransInfo *t)
        EditVert *eve;
        EditVert **nears = NULL;
        float *vectors = NULL, *mappedcos = NULL, *quats= NULL;
-       float mtx[3][3], smtx[3][3];
-       int count=0, countsel=0;
+       float mtx[3][3], smtx[3][3], (*defmats)[3][3] = NULL, (*defcos)[3] = NULL;
+       int count=0, countsel=0, a, totleft;
        int propmode = t->flag & T_PROP_EDIT;
        int mirror= (G.scene->toolsettings->editbutflag & B_MESH_X_MIRROR);
 
@@ -1714,10 +1707,23 @@ static void createTransEditVerts(TransInfo *t)
        if(propmode==0) {
                if(modifiers_getCageIndex(G.obedit, NULL)>=0) {
                        if(modifiers_isDeformed(G.obedit)) {
-                               /* disable subsurf temporal, get mapped cos, and enable it */
-                               mappedcos= get_crazy_mapped_editverts();
-                               quats= MEM_mallocN( (t->total)*sizeof(float)*4, "crazy quats");
-                               set_crazyspace_quats(mappedcos, quats);
+                               /* check if we can use deform matrices for modifier from the
+                                  start up to stack, they are more accurate than quats */
+                               totleft= editmesh_get_first_deform_matrices(&defmats, &defcos);
+
+                               /* if we still have more modifiers, also do crazyspace
+                                  correction with quats, relative to the coordinates after
+                                  the modifiers that support deform matrices (defcos) */
+                               if(totleft > 0) {
+                                       mappedcos= get_crazy_mapped_editverts();
+                                       quats= MEM_mallocN( (t->total)*sizeof(float)*4, "crazy quats");
+                                       set_crazyspace_quats((float*)defcos, mappedcos, quats);
+                                       if(mappedcos)
+                                               MEM_freeN(mappedcos);
+                               }
+
+                               if(defcos)
+                                       MEM_freeN(defcos);
                        }
                }
        }
@@ -1733,7 +1739,7 @@ static void createTransEditVerts(TransInfo *t)
                }
        }
        
-       for (eve=em->verts.first; eve; eve=eve->next) {
+       for (a=0, eve=em->verts.first; eve; eve=eve->next, a++) {
                if(eve->h==0) {
                        if(propmode || eve->f1) {
                                VertsToTransData(tob, eve);
@@ -1753,11 +1759,22 @@ static void createTransEditVerts(TransInfo *t)
                                }
                                
                                /* CrazySpace */
-                               if(quats && eve->tmp.fp) {
+                               if(defmats || (quats && eve->tmp.fp)) {
                                        float mat[3][3], imat[3][3], qmat[3][3];
                                        
-                                       QuatToMat3(eve->tmp.fp, qmat);
-                                       Mat3MulMat3(mat, mtx, qmat);
+                                       /* use both or either quat and defmat correction */
+                                       if(quats && eve->tmp.f) {
+                                               QuatToMat3(eve->tmp.fp, qmat);
+
+                                               if(defmats)
+                                                       Mat3MulSerie(mat, mtx, qmat, defmats[a],
+                                                               NULL, NULL, NULL, NULL, NULL);
+                                               else
+                                                       Mat3MulMat3(mat, mtx, qmat);
+                                       }
+                                       else
+                                               Mat3MulMat3(mat, mtx, defmats[a]);
+
                                        Mat3Inv(imat, mat);
                                        
                                        Mat3CpyMat3(tob->smtx, imat);
@@ -1782,10 +1799,10 @@ static void createTransEditVerts(TransInfo *t)
                MEM_freeN(nears);
        }
        /* crazy space free */
-       if(mappedcos)
-               MEM_freeN(mappedcos);
        if(quats)
                MEM_freeN(quats);
+       if(defmats)
+               MEM_freeN(defmats);
 }
 
 /* ********************* UV ****************** */