/** * lattice.c * * * $Id$ * * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. The Blender * Foundation also sells licenses for use in proprietary software under * the Blender License. See http://www.blender.org/BL/ for information * about this. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. * * The Original Code is: all of this file. * * Contributor(s): none yet. * * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ #include #include #include #include #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" #include "BLI_arithb.h" #include "DNA_armature_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_lattice_types.h" #include "DNA_curve_types.h" #include "DNA_key_types.h" #include "DNA_ika_types.h" #include "BKE_anim.h" #include "BKE_armature.h" #include "BKE_curve.h" #include "BKE_deform.h" #include "BKE_displist.h" #include "BKE_global.h" #include "BKE_ika.h" #include "BKE_key.h" #include "BKE_lattice.h" #include "BKE_library.h" #include "BKE_main.h" #include "BKE_object.h" #include "BKE_screen.h" #include "BKE_utildefines.h" #ifdef HAVE_CONFIG_H #include #endif #include "blendef.h" Lattice *editLatt=0, *deformLatt=0; float *latticedata=0, latmat[4][4]; void resizelattice(Lattice *lt) { BPoint *bp; int u, v, w; float vec[3], fu, fv, fw, du=0.0, dv=0.0, dw=0.0; MEM_freeN(lt->def); lt->def= MEM_callocN(lt->pntsu*lt->pntsv*lt->pntsw*sizeof(BPoint), "lattice bp"); bp= lt->def; while(lt->pntsu*lt->pntsv*lt->pntsw > 32000) { if( lt->pntsu>=lt->pntsv && lt->pntsu>=lt->pntsw) lt->pntsu--; else if( lt->pntsv>=lt->pntsu && lt->pntsv>=lt->pntsw) lt->pntsv--; else lt->pntsw--; } calc_lat_fudu(lt->flag, lt->pntsu, &fu, &du); calc_lat_fudu(lt->flag, lt->pntsv, &fv, &dv); calc_lat_fudu(lt->flag, lt->pntsw, &fw, &dw); vec[2]= fw; for(w=0; wpntsw; w++) { vec[1]= fv; for(v=0; vpntsv; v++) { vec[0]= fu; for(u=0; upntsu; u++, bp++) { VECCOPY(bp->vec, vec); vec[0]+= du; } vec[1]+= dv; } vec[2]+= dw; } } Lattice *add_lattice() { Lattice *lt; lt= alloc_libblock(&G.main->latt, ID_LT, "Lattice"); lt->pntsu=lt->pntsv=lt->pntsw= 2; lt->flag= LT_GRID; lt->typeu= lt->typev= lt->typew= KEY_BSPLINE; /* temporally */ lt->def= MEM_callocN(sizeof(BPoint), "lattvert"); resizelattice(lt); /* creates a uniform lattice */ return lt; } Lattice *copy_lattice(Lattice *lt) { Lattice *ltn; ltn= copy_libblock(lt); ltn->def= MEM_dupallocN(lt->def); id_us_plus((ID *)ltn->ipo); ltn->key= copy_key(ltn->key); if(ltn->key) ltn->key->from= (ID *)ltn; return ltn; } void free_lattice(Lattice *lt) { if(lt->def) MEM_freeN(lt->def); } void make_local_lattice(Lattice *lt) { Object *ob; Lattice *ltn; int local=0, lib=0; /* - only lib users: do nothing * - only local users: set flag * - mixed: make copy */ if(lt->id.lib==0) return; if(lt->id.us==1) { lt->id.lib= 0; lt->id.flag= LIB_LOCAL; new_id(0, (ID *)lt, 0); return; } ob= G.main->object.first; while(ob) { if(ob->data==lt) { if(ob->id.lib) lib= 1; else local= 1; } ob= ob->id.next; } if(local && lib==0) { lt->id.lib= 0; lt->id.flag= LIB_LOCAL; new_id(0, (ID *)lt, 0); } else if(local && lib) { ltn= copy_lattice(lt); ltn->id.us= 0; ob= G.main->object.first; while(ob) { if(ob->data==lt) { if(ob->id.lib==0) { ob->data= ltn; ltn->id.us++; lt->id.us--; } } ob= ob->id.next; } } } void calc_lat_fudu(int flag, int res, float *fu, float *du) { if(res==1) { *fu= 0.0; *du= 0.0; } else if(flag & LT_GRID) { *fu= -0.5f*(res-1); *du= 1.0f; } else { *fu= -1.0f; *du= 2.0f/(res-1); } } void init_latt_deform(Object *oblatt, Object *ob) { /* we make an array with all differences */ BPoint *bp; float *fp, imat[4][4]; float vec[3], fu, fv, fw, du=0.0, dv=0.0, dw=0.0; int u, v, w; if(oblatt==G.obedit) deformLatt= editLatt; else deformLatt= oblatt->data; fp= latticedata= MEM_mallocN(sizeof(float)*3*deformLatt->pntsu*deformLatt->pntsv*deformLatt->pntsw, "latticedata"); lattice_modifier(oblatt, 's'); bp= deformLatt->def; //if(ob) where_is_object(ob); causes lag here, but why! (ton) /* for example with a particle system: ob==0 */ if(ob==0) { /* in deformspace, calc matrix */ Mat4Invert(latmat, oblatt->obmat); /* back: put in deform array */ Mat4Invert(imat, latmat); } else { /* in deformspace, calc matrix */ Mat4Invert(imat, oblatt->obmat); Mat4MulMat4(latmat, ob->obmat, imat); /* back: put in deform array */ Mat4Invert(imat, latmat); } calc_lat_fudu(deformLatt->flag, deformLatt->pntsu, &fu, &du); calc_lat_fudu(deformLatt->flag, deformLatt->pntsv, &fv, &dv); calc_lat_fudu(deformLatt->flag, deformLatt->pntsw, &fw, &dw); /* we keep calculating the u v w lattice coordinates, not enough reason to store that */ vec[2]= fw; for(w=0; wpntsw; w++) { vec[1]= fv; for(v=0; vpntsv; v++) { vec[0]= fu; for(u=0; upntsu; u++, bp++) { VecSubf(fp, bp->vec, vec); Mat4Mul3Vecfl(imat, fp); vec[0]+= du; fp+= 3; } vec[1]+= dv; } vec[2]+= dw; } lattice_modifier(oblatt, 'e'); } void calc_latt_deform(float *co) { Lattice *lt; float fu, du, u, v, w, tu[4], tv[4], tw[4]; float *fpw, *fpv, *fpu, vec[3]; int ui, vi, wi, uu, vv, ww; if(latticedata==0) return; lt= deformLatt; /* just for shorter notation! */ /* co is in local coords, treat with latmat */ VECCOPY(vec, co); Mat4MulVecfl(latmat, vec); /* u v w coords */ if(lt->pntsu>1) { calc_lat_fudu(lt->flag, lt->pntsu, &fu, &du); u= (vec[0]-fu)/du; ui= (int)floor(u); u -= ui; set_four_ipo(u, tu, lt->typeu); } else { tu[0]= tu[2]= tu[3]= 0.0; tu[1]= 1.0; ui= 0; } if(lt->pntsv>1) { calc_lat_fudu(lt->flag, lt->pntsv, &fu, &du); v= (vec[1]-fu)/du; vi= (int)floor(v); v -= vi; set_four_ipo(v, tv, lt->typev); } else { tv[0]= tv[2]= tv[3]= 0.0; tv[1]= 1.0; vi= 0; } if(lt->pntsw>1) { calc_lat_fudu(lt->flag, lt->pntsw, &fu, &du); w= (vec[2]-fu)/du; wi= (int)floor(w); w -= wi; set_four_ipo(w, tw, lt->typew); } else { tw[0]= tw[2]= tw[3]= 0.0; tw[1]= 1.0; wi= 0; } for(ww= wi-1; ww<=wi+2; ww++) { w= tw[ww-wi+1]; if(w!=0.0) { if(ww>0) { if(wwpntsw) fpw= latticedata + 3*ww*lt->pntsu*lt->pntsv; else fpw= latticedata + 3*(lt->pntsw-1)*lt->pntsu*lt->pntsv; } else fpw= latticedata; for(vv= vi-1; vv<=vi+2; vv++) { v= w*tv[vv-vi+1]; if(v!=0.0) { if(vv>0) { if(vvpntsv) fpv= fpw + 3*vv*lt->pntsu; else fpv= fpw + 3*(lt->pntsv-1)*lt->pntsu; } else fpv= fpw; for(uu= ui-1; uu<=ui+2; uu++) { u= v*tu[uu-ui+1]; if(u!=0.0) { if(uu>0) { if(uupntsu) fpu= fpv + 3*uu; else fpu= fpv + 3*(lt->pntsu-1); } else fpu= fpv; co[0]+= u*fpu[0]; co[1]+= u*fpu[1]; co[2]+= u*fpu[2]; } } } } } } } void end_latt_deform() { MEM_freeN(latticedata); latticedata= 0; } /* calculations is in local space of deformed object so we store in latmat transform from path coord inside object */ typedef struct { float dmin[3], dmax[3], dsize, dloc[3]; float curvespace[4][4], objectspace[4][4]; } CurveDeform; static void init_curve_deform(Object *par, Object *ob, CurveDeform *cd) { Mat4Invert(ob->imat, ob->obmat); Mat4MulMat4(cd->objectspace, par->obmat, ob->imat); Mat4Invert(cd->curvespace, cd->objectspace); // offset vector for 'no smear' Mat4Invert(par->imat, par->obmat); VecMat4MulVecfl(cd->dloc, par->imat, ob->obmat[3]); } /* this makes sure we can extend for non-cyclic. *vec needs 4 items! */ static int where_on_path_deform(Object *ob, float ctime, float *vec, float *dir) /* returns OK */ { Curve *cu= ob->data; BevList *bl; float ctime1; int cycl=0; /* test for cyclic */ bl= cu->bev.first; if(bl && bl->poly> -1) cycl= 1; if(cycl==0) { ctime1= CLAMPIS(ctime, 0.0, 1.0); } else ctime1= ctime; /* vec needs 4 items */ if(where_on_path(ob, ctime1, vec, dir)) { if(cycl==0) { Path *path= cu->path; float dvec[3]; if(ctime < 0.0) { VecSubf(dvec, path->data+4, path->data); VecMulf(dvec, ctime*(float)path->len); VECADD(vec, vec, dvec); } else if(ctime > 1.0) { VecSubf(dvec, path->data+4*path->len-4, path->data+4*path->len-8); VecMulf(dvec, (ctime-1.0)*(float)path->len); VECADD(vec, vec, dvec); } } return 1; } return 0; } /* 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) { Curve *cu= par->data; float fac, loc[4], dir[3], *quat, mat[3][3], cent[3]; short upflag, index; if(axis==OB_POSX || axis==OB_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) { upflag= OB_POSZ; cent[0]= co[0]; cent[1]= 0.0; cent[2]= co[2]; index= 1; } else { upflag= OB_POSY; cent[0]= co[0]; cent[1]= co[1]; cent[2]= 0.0; index= 2; } /* to be sure */ if(cu->path==NULL) { calc_curvepath(par); if(cu->path==NULL) return; // 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( where_on_path_deform(par, fac, loc, dir)) { /* returns OK */ quat= vectoquat(dir, axis, upflag); QuatToMat3(quat, mat); /* local rotation */ Mat3MulVecfl(mat, cent); /* translation */ VECADD(co, cent, loc); } } static int _object_deform(Object *ob, int applyflag) { Mesh *me; Curve *cu; DispList *dl; MVert *mvert; float *fp; int a, tot, flag; if(ob->parent==NULL) return 0; /* always try to do the entire deform in this function: apply! */ if(ob->parent->type==OB_CURVE) { CurveDeform cd; if (ob->partype != PARSKEL){ return 0; } cu= ob->parent->data; flag= cu->flag; cu->flag |= (CU_PATH|CU_FOLLOW); // needed for path & bevlist if(ob->type==OB_MESH) { me= ob->data; if(me->totvert==0) return 0; /* init deform */ init_curve_deform(ob->parent, ob, &cd); /* transformation to curve space, and min max*/ INIT_MINMAX(cd.dmin, cd.dmax); for(a=0, mvert=me->mvert; atotvert; a++, mvert++) { Mat4MulVecfl(cd.curvespace, mvert->co); DO_MINMAX(mvert->co, cd.dmin, cd.dmax); } mvert= me->mvert; for(a=0; atotvert; a++, mvert++) { calc_curve_deform(ob->parent, mvert->co, ob->trackflag, &cd); /* move coord back to objectspace */ Mat4MulVecfl(cd.objectspace, mvert->co); } } /* restore */ cu->flag = flag; return 1; } else if(ob->parent->type==OB_LATTICE) { init_latt_deform(ob->parent, ob); if(ob->type==OB_MESH) { me= ob->data; mvert= me->mvert; for(a=0; atotvert; a++, mvert++) { calc_latt_deform(mvert->co); } } else if(ob->type==OB_MBALL) { dl=ob->disp.first; while(dl) { fp = dl->verts; for(a=0;anr;a++,fp+=3) calc_latt_deform(fp); dl=dl->next; } } else if ELEM(ob->type, OB_CURVE, OB_SURF) { cu= ob->data; if(applyflag) { Nurb *nu; BPoint *bp; BezTriple *bezt; nu= cu->nurb.first; while(nu) { if(nu->bp) { a= nu->pntsu*nu->pntsv; bp= nu->bp; while(a--) { calc_latt_deform(bp->vec); bp++; } } else if(nu->bezt) { a= nu->pntsu; bezt= nu->bezt; while(a--) { calc_latt_deform(bezt->vec[0]); calc_latt_deform(bezt->vec[1]); calc_latt_deform(bezt->vec[2]); bezt++; } test2DNurb(nu); } nu= nu->next; } } else { /* apply deform on displist */ dl= cu->disp.first; while(dl) { fp= dl->verts; if(dl->type==DL_INDEX3) tot=dl->parts; else tot= dl->nr*dl->parts; for(a=0; anext; } } } end_latt_deform(); return 1; } else if(ob->parent->type==OB_ARMATURE) { if (ob->partype != PARSKEL){ return 0; } init_armature_deform (ob->parent, ob); switch (ob->type){ case OB_MESH: me= ob->data; mvert= me->mvert; for(a=0; atotvert; a++, mvert++) { calc_armature_deform(ob->parent, mvert->co, a); } break; case OB_CURVE: case OB_SURF: break; } return 1; } return 0; } int object_deform(Object *ob) { return _object_deform(ob, 0); } BPoint *latt_bp(Lattice *lt, int u, int v, int w) { return lt->def+ u + v*lt->pntsu + w*lt->pntsu*lt->pntsv; } void outside_lattice(Lattice *lt) { BPoint *bp, *bp1, *bp2; int u, v, w; float fac1, du=0.0, dv=0.0, dw=0.0; bp= lt->def; if(lt->pntsu>1) du= 1.0f/((float)lt->pntsu-1); if(lt->pntsv>1) dv= 1.0f/((float)lt->pntsv-1); if(lt->pntsw>1) dw= 1.0f/((float)lt->pntsw-1); for(w=0; wpntsw; w++) { for(v=0; vpntsv; v++) { for(u=0; upntsu; u++, bp++) { if(u==0 || v==0 || w==0 || u==lt->pntsu-1 || v==lt->pntsv-1 || w==lt->pntsw-1); else { bp->hide= 1; bp->f1 &= ~SELECT; /* u extrema */ bp1= latt_bp(lt, 0, v, w); bp2= latt_bp(lt, lt->pntsu-1, v, w); fac1= du*u; bp->vec[0]= (1.0f-fac1)*bp1->vec[0] + fac1*bp2->vec[0]; bp->vec[1]= (1.0f-fac1)*bp1->vec[1] + fac1*bp2->vec[1]; bp->vec[2]= (1.0f-fac1)*bp1->vec[2] + fac1*bp2->vec[2]; /* v extrema */ bp1= latt_bp(lt, u, 0, w); bp2= latt_bp(lt, u, lt->pntsv-1, w); fac1= dv*v; bp->vec[0]+= (1.0f-fac1)*bp1->vec[0] + fac1*bp2->vec[0]; bp->vec[1]+= (1.0f-fac1)*bp1->vec[1] + fac1*bp2->vec[1]; bp->vec[2]+= (1.0f-fac1)*bp1->vec[2] + fac1*bp2->vec[2]; /* w extrema */ bp1= latt_bp(lt, u, v, 0); bp2= latt_bp(lt, u, v, lt->pntsw-1); fac1= dw*w; bp->vec[0]+= (1.0f-fac1)*bp1->vec[0] + fac1*bp2->vec[0]; bp->vec[1]+= (1.0f-fac1)*bp1->vec[1] + fac1*bp2->vec[1]; bp->vec[2]+= (1.0f-fac1)*bp1->vec[2] + fac1*bp2->vec[2]; VecMulf(bp->vec, 0.3333333f); } } } } }