Fix for making vectoquat threadsafe, missed a warning.
[blender.git] / source / blender / blenkernel / intern / lattice.c
index 29325138c152a11d8efa8f53d1e66bf10dd707db..47175a789b166ca64dddf9fb4eb2f5805f646d9c 100644 (file)
@@ -44,6 +44,7 @@
 #include "BLI_arithb.h"
 
 #include "DNA_armature_types.h"
+#include "DNA_ipo_types.h"
 #include "DNA_mesh_types.h"
 #include "DNA_meshdata_types.h"
 #include "DNA_modifier_types.h"
 #include "BKE_anim.h"
 #include "BKE_armature.h"
 #include "BKE_curve.h"
+#include "BKE_cdderivedmesh.h"
+#include "BKE_DerivedMesh.h"
 #include "BKE_deform.h"
 #include "BKE_displist.h"
 #include "BKE_global.h"
+#include "BKE_ipo.h"
 #include "BKE_key.h"
 #include "BKE_lattice.h"
 #include "BKE_library.h"
 #include "BKE_main.h"
+#include "BKE_mesh.h"
 #include "BKE_modifier.h"
 #include "BKE_object.h"
 #include "BKE_screen.h"
@@ -104,6 +109,12 @@ void resizelattice(Lattice *lt, int uNew, int vNew, int wNew, Object *ltOb)
        float fu, fv, fw, uc, vc, wc, du=0.0, dv=0.0, dw=0.0;
        float *co, (*vertexCos)[3] = NULL;
        
+       /* vertex weight groups are just freed all for now */
+       if(lt->dvert) {
+               free_dverts(lt->dvert, lt->pntsu*lt->pntsv*lt->pntsw);
+               lt->dvert= NULL;
+       }
+       
        while(uNew*vNew*wNew > 32000) {
                if( uNew>=vNew && uNew>=wNew) uNew--;
                else if( vNew>=uNew && vNew>=wNew) vNew--;
@@ -161,7 +172,7 @@ void resizelattice(Lattice *lt, int uNew, int vNew, int wNew, Object *ltOb)
 
                Mat4CpyMat4(mat, ltOb->obmat);
                Mat4One(ltOb->obmat);
-               lattice_deform_verts(ltOb, NULL, vertexCos, uNew*vNew*wNew, NULL);
+               lattice_deform_verts(ltOb, NULL, NULL, vertexCos, uNew*vNew*wNew, NULL);
                Mat4CpyMat4(ltOb->obmat, mat);
 
                lt->typeu = typeu;
@@ -192,11 +203,11 @@ void resizelattice(Lattice *lt, int uNew, int vNew, int wNew, Object *ltOb)
        MEM_freeN(vertexCos);
 }
 
-Lattice *add_lattice()
+Lattice *add_lattice(char *name)
 {
        Lattice *lt;
        
-       lt= alloc_libblock(&G.main->latt, ID_LT, "Lattice");
+       lt= alloc_libblock(&G.main->latt, ID_LT, name);
        
        lt->flag= LT_GRID;
        
@@ -220,12 +231,19 @@ Lattice *copy_lattice(Lattice *lt)
        ltn->key= copy_key(ltn->key);
        if(ltn->key) ltn->key->from= (ID *)ltn;
        
+       if(lt->dvert) {
+               int tot= lt->pntsu*lt->pntsv*lt->pntsw;
+               ltn->dvert = MEM_mallocN (sizeof (MDeformVert)*tot, "Lattice MDeformVert");
+               copy_dverts(ltn->dvert, lt->dvert, tot);
+       }
+       
        return ltn;
 }
 
 void free_lattice(Lattice *lt)
 {
        if(lt->def) MEM_freeN(lt->def);
+       if(lt->dvert) free_dverts(lt->dvert, lt->pntsu*lt->pntsv*lt->pntsw);
 }
 
 
@@ -434,19 +452,25 @@ void end_latt_deform()
         */
 typedef struct {
        float dmin[3], dmax[3], dsize, dloc[3];
-       float curvespace[4][4], objectspace[4][4];
+       float curvespace[4][4], objectspace[4][4], objectspace3[3][3];
+       int no_rot_axis;
 } CurveDeform;
 
-static void init_curve_deform(Object *par, Object *ob, CurveDeform *cd)
+static void init_curve_deform(Object *par, Object *ob, CurveDeform *cd, int dloc)
 {
        Mat4Invert(ob->imat, ob->obmat);
        Mat4MulMat4(cd->objectspace, par->obmat, ob->imat);
        Mat4Invert(cd->curvespace, cd->objectspace);
-
+       Mat3CpyMat4(cd->objectspace3, cd->objectspace);
+       
        // offset vector for 'no smear'
-       Mat4Invert(par->imat, par->obmat);
-       VecMat4MulVecfl(cd->dloc, par->imat, ob->obmat[3]);
-
+       if(dloc) {
+               Mat4Invert(par->imat, par->obmat);
+               VecMat4MulVecfl(cd->dloc, par->imat, ob->obmat[3]);
+       }
+       else cd->dloc[0]=cd->dloc[1]=cd->dloc[2]= 0.0f;
+       
+       cd->no_rot_axis= 0;
 }
 
 /* this makes sure we can extend for non-cyclic. *vec needs 4 items! */
@@ -459,6 +483,7 @@ static int where_on_path_deform(Object *ob, float ctime, float *vec, float *dir)
        
        /* test for cyclic */
        bl= cu->bev.first;
+       if (!bl->nr) return 0;
        if(bl && bl->poly> -1) cycl= 1;
 
        if(cycl==0) {
@@ -492,20 +517,22 @@ static int where_on_path_deform(Object *ob, float ctime, float *vec, float *dir)
        /* for each point, rotate & translate to curve */
        /* use path, since it has constant distances */
        /* co: local coord, result local too */
-static void calc_curve_deform(Object *par, float *co, short axis, CurveDeform *cd)
+       /* returns quaternion for rotation, using cd->no_rot_axis */
+       /* axis is using another define!!! */
+static int calc_curve_deform(Object *par, float *co, short axis, CurveDeform *cd, float *quatp)
 {
        Curve *cu= par->data;
-       float fac, loc[4], dir[3], *quat, q[4], mat[3][3], cent[3];
+       float fac, loc[4], dir[3], cent[3];
        short upflag, index;
        
-       if(axis==OB_POSX || axis==OB_NEGX) {
+       if(axis==MOD_CURVE_POSX || axis==MOD_CURVE_NEGX) {
                upflag= OB_POSZ;
                cent[0]= 0.0;
                cent[1]= co[1];
                cent[2]= co[2];
                index= 0;
        }
-       else if(axis==OB_POSY || axis==OB_NEGY) {
+       else if(axis==MOD_CURVE_POSY || axis==MOD_CURVE_NEGY) {
                upflag= OB_POSZ;
                cent[0]= co[0];
                cent[1]= 0.0;
@@ -519,24 +546,46 @@ static void calc_curve_deform(Object *par, float *co, short axis, CurveDeform *c
                cent[2]= 0.0;
                index= 2;
        }
-       /* to be sure */
+       /* to be sure, mostly after file load */
        if(cu->path==NULL) {
-               calc_curvepath(par);
-               if(cu->path==NULL) return;      // happens on append...
+               makeDispListCurveTypes(par, 0);
+               if(cu->path==NULL) return 0;    // happens on append...
        }
+       
        /* options */
-       if(cu->flag & CU_STRETCH)
-               fac= (co[index]-cd->dmin[index])/(cd->dmax[index] - cd->dmin[index]);
-       else
-               fac= (cd->dloc[index])/(cu->path->totdist) + (co[index]-cd->dmin[index])/(cu->path->totdist);
+       if(ELEM3(axis, OB_NEGX, OB_NEGY, OB_NEGZ)) {
+               if(cu->flag & CU_STRETCH)
+                       fac= (-co[index]-cd->dmax[index])/(cd->dmax[index] - cd->dmin[index]);
+               else
+                       fac= (cd->dloc[index])/(cu->path->totdist) - (co[index]-cd->dmax[index])/(cu->path->totdist);
+       }
+       else {
+               if(cu->flag & CU_STRETCH)
+                       fac= (co[index]-cd->dmin[index])/(cd->dmax[index] - cd->dmin[index]);
+               else
+                       fac= (cd->dloc[index])/(cu->path->totdist) + (co[index]-cd->dmin[index])/(cu->path->totdist);
+       }
+       
+       /* we want the ipo to work on the default 100 frame range, because there's no  
+          actual time involved in path position */
+       if(cu->ipo) {
+               fac*= 100.0f;
+               if(calc_ipo_spec(cu->ipo, CU_SPEED, &fac)==0)
+                       fac/= 100.0;
+       }
        
        if( where_on_path_deform(par, fac, loc, dir)) { /* returns OK */
-
-               quat= vectoquat(dir, axis, upflag);
+               float q[4], mat[3][3], quat[4];
+               
+               if(cd->no_rot_axis)     /* set by caller */
+                       dir[cd->no_rot_axis-1]= 0.0f;
+               
+               /* -1 for compatibility with old track defines */
+               vectoquat(dir, axis-1, upflag, quat);
                
                /* the tilt */
                if(loc[3]!=0.0) {
-                       Normalise(dir);
+                       Normalize(dir);
                        q[0]= (float)cos(0.5*loc[3]);
                        fac= (float)sin(0.5*loc[3]);
                        q[1]= -fac*dir[0];
@@ -552,94 +601,175 @@ static void calc_curve_deform(Object *par, float *co, short axis, CurveDeform *c
                /* translation */
                VECADD(co, cent, loc);
                
+               if(quatp)
+                       QUATCOPY(quatp, quat);
+               
+               return 1;
        }
-
+       return 0;
 }
 
-void curve_deform_verts(Object *cuOb, Object *target, float (*vertexCos)[3], int numVerts, char *vgroup)
+void curve_deform_verts(Object *cuOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3], int numVerts, char *vgroup, short defaxis)
 {
        Curve *cu = cuOb->data;
        int a, flag = cu->flag;
        CurveDeform cd;
+       int use_vgroups;
        
        cu->flag |= (CU_PATH|CU_FOLLOW); // needed for path & bevlist
 
-       init_curve_deform(cuOb, target, &cd);
-               
-       INIT_MINMAX(cd.dmin, cd.dmax);
+       init_curve_deform(cuOb, target, &cd, (cu->flag & CU_STRETCH)==0);
                
-       for(a=0; a<numVerts; a++) {
-               Mat4MulVecfl(cd.curvespace, vertexCos[a]);
-               DO_MINMAX(vertexCos[a], cd.dmin, cd.dmax);
-       }
-       
-       if(vgroup && vgroup[0] && target->type==OB_MESH) {
+       /* check whether to use vertex groups (only possible if target is a Mesh)
+        * we want either a Mesh with no derived data, or derived data with
+        * deformverts
+        */
+       if(target && target->type==OB_MESH) {
+               /* if there's derived data without deformverts, don't use vgroups */
+               if(dm && !dm->getVertData(dm, 0, CD_MDEFORMVERT))
+                       use_vgroups = 0;
+               else
+                       use_vgroups = 1;
+       } else
+               use_vgroups = 0;
+       
+       if(vgroup && vgroup[0] && use_vgroups) {
                bDeformGroup *curdef;
                Mesh *me= target->data;
-               int index= 0;
+               int index;
                
                /* find the group (weak loop-in-loop) */
-               for (curdef = target->defbase.first; curdef; curdef=curdef->next, index++)
+               for(index = 0, curdef = target->defbase.first; curdef;
+                   curdef = curdef->next, index++)
                        if (!strcmp(curdef->name, vgroup))
                                break;
-               /* check for numVerts because old files can have modifier over subsurf still */
-               if(curdef && me->dvert && numVerts==me->totvert) {
-                       MDeformVert *dvert= me->dvert;
+
+               if(curdef && (me->dvert || dm)) {
+                       MDeformVert *dvert = me->dvert;
                        float vec[3];
                        int j;
-                       
-                       for(a=0; a<numVerts; a++, dvert++) {
-                               for(j=0; j<dvert->totweight; j++) {
-                                       if (dvert->dw[j].def_nr == index) {
+
+                       INIT_MINMAX(cd.dmin, cd.dmax);
+
+                       for(a = 0; a < numVerts; a++, dvert++) {
+                               if(dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT);
+
+                               for(j = 0; j < dvert->totweight; j++) {
+                                       if(dvert->dw[j].def_nr == index) {
+                                               Mat4MulVecfl(cd.curvespace, vertexCos[a]);
+                                               DO_MINMAX(vertexCos[a], cd.dmin, cd.dmax);
+                                               break;
+                                       }
+                               }
+                       }
+
+                       dvert = me->dvert;
+                       for(a = 0; a < numVerts; a++, dvert++) {
+                               if(dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT);
+
+                               for(j = 0; j < dvert->totweight; j++) {
+                                       if(dvert->dw[j].def_nr == index) {
                                                VECCOPY(vec, vertexCos[a]);
-                                               calc_curve_deform(cuOb, vec, target->trackflag, &cd);
-                                               VecLerpf(vertexCos[a], vertexCos[a], vec, dvert->dw[j].weight);
+                                               calc_curve_deform(cuOb, vec, defaxis, &cd, NULL);
+                                               VecLerpf(vertexCos[a], vertexCos[a], vec,
+                                                        dvert->dw[j].weight);
                                                Mat4MulVecfl(cd.objectspace, vertexCos[a]);
+                                               break;
                                        }
                                }
                        }
                }
-       }
-       else {
-               for(a=0; a<numVerts; a++) {
-                       calc_curve_deform(cuOb, vertexCos[a], target->trackflag, &cd);
+       } else {
+               INIT_MINMAX(cd.dmin, cd.dmax);
+                       
+               for(a = 0; a < numVerts; a++) {
+                       Mat4MulVecfl(cd.curvespace, vertexCos[a]);
+                       DO_MINMAX(vertexCos[a], cd.dmin, cd.dmax);
+               }
+
+               for(a = 0; a < numVerts; a++) {
+                       calc_curve_deform(cuOb, vertexCos[a], defaxis, &cd, NULL);
                        Mat4MulVecfl(cd.objectspace, vertexCos[a]);
                }
        }
        cu->flag = flag;
 }
 
-void lattice_deform_verts(Object *laOb, Object *target, float (*vertexCos)[3], int numVerts, char *vgroup)
+/* input vec and orco = local coord in armature space */
+/* orco is original not-animated or deformed reference point */
+/* result written in vec and mat */
+void curve_deform_vector(Object *cuOb, Object *target, float *orco, float *vec, float mat[][3], int no_rot_axis)
+{
+       CurveDeform cd;
+       float quat[4];
+       
+       init_curve_deform(cuOb, target, &cd, 0);        /* 0 no dloc */
+       cd.no_rot_axis= no_rot_axis;                            /* option to only rotate for XY, for example */
+       
+       VECCOPY(cd.dmin, orco);
+       VECCOPY(cd.dmax, orco);
+
+       Mat4MulVecfl(cd.curvespace, vec);
+       
+       if(calc_curve_deform(cuOb, vec, target->trackflag+1, &cd, quat)) {
+               float qmat[3][3];
+               
+               QuatToMat3(quat, qmat);
+               Mat3MulMat3(mat, qmat, cd.objectspace3);
+       }
+       else
+               Mat3One(mat);
+       
+       Mat4MulVecfl(cd.objectspace, vec);
+
+}
+
+void lattice_deform_verts(Object *laOb, Object *target, DerivedMesh *dm,
+                          float (*vertexCos)[3], int numVerts, char *vgroup)
 {
        int a;
+       int use_vgroups;
 
        init_latt_deform(laOb, target);
-       
-       if(vgroup && vgroup[0] && target->type==OB_MESH) {
+
+       /* check whether to use vertex groups (only possible if target is a Mesh)
+        * we want either a Mesh with no derived data, or derived data with
+        * deformverts
+        */
+       if(target && target->type==OB_MESH) {
+               /* if there's derived data without deformverts, don't use vgroups */
+               if(dm && !dm->getVertData(dm, 0, CD_MDEFORMVERT))
+                       use_vgroups = 0;
+               else
+                       use_vgroups = 1;
+       } else
+               use_vgroups = 0;
+       
+       if(vgroup && vgroup[0] && use_vgroups) {
                bDeformGroup *curdef;
-               Mesh *me= target->data;
-               int index= 0;
+               Mesh *me = target->data;
+               int index = 0;
                
                /* find the group (weak loop-in-loop) */
-               for (curdef = target->defbase.first; curdef; curdef=curdef->next, index++)
-                       if (!strcmp(curdef->name, vgroup))
-                               break;
-               /* check for numVerts because old files can have modifier over subsurf still */
-               if(curdef && me->dvert && numVerts==me->totvert) {
-                       MDeformVert *dvert= me->dvert;
+               for(curdef = target->defbase.first; curdef;
+                   curdef = curdef->next, index++)
+                       if(!strcmp(curdef->name, vgroup)) break;
+
+               if(curdef && (me->dvert || dm)) {
+                       MDeformVert *dvert = me->dvert;
                        int j;
                        
-                       for(a=0; a<numVerts; a++, dvert++) {
-                               for(j=0; j<dvert->totweight; j++) {
+                       for(a = 0; a < numVerts; a++, dvert++) {
+                               if(dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT);
+                               for(j = 0; j < dvert->totweight; j++) {
                                        if (dvert->dw[j].def_nr == index) {
                                                calc_latt_deform(vertexCos[a], dvert->dw[j].weight);
                                        }
                                }
                        }
                }
-       }
-       else {
-               for(a=0; a<numVerts; a++) {
+       } else {
+               for(a = 0; a < numVerts; a++) {
                        calc_latt_deform(vertexCos[a], 1.0f);
                }
        }
@@ -652,7 +782,8 @@ int object_deform_mball(Object *ob)
                DispList *dl;
 
                for (dl=ob->disp.first; dl; dl=dl->next) {
-                       lattice_deform_verts(ob->parent, ob, (float(*)[3]) dl->verts, dl->nr, NULL);
+                       lattice_deform_verts(ob->parent, ob, NULL,
+                                            (float(*)[3]) dl->verts, dl->nr, NULL);
                }
 
                return 1;
@@ -765,7 +896,7 @@ void lattice_calc_modifiers(Object *ob)
        for (; md; md=md->next) {
                ModifierTypeInfo *mti = modifierType_getInfo(md->type);
 
-               if (!(md->mode&(1<<0))) continue;
+               if (!(md->mode&eModifierMode_Realtime)) continue;
                if (editmode && !(md->mode&eModifierMode_Editmode)) continue;
                if (mti->isDisabled && mti->isDisabled(md)) continue;
                if (mti->type!=eModifierTypeType_OnlyDeform) continue;