diff --git a/source/blender/blenkernel/BKE_deform.h b/source/blender/blenkernel/BKE_deform.h
index e7494f28fc446347ba0e3c2825990d2309b617e7..411225b0635054c68624170d9cf9e3ce0822f902 100644
--- a/source/blender/blenkernel/BKE_deform.h
+++ b/source/blender/blenkernel/BKE_deform.h
@@ -1,8 +1,8 @@
 /*  BKE_deform.h   June 2001
  *  
- *  support for deformation groups
+ *  support for deformation groups and hooks
  * 
- *	Reevan McKay
+ *	Reevan McKay et al
  *
  * $Id$
  *
@@ -46,5 +46,12 @@ void copy_defgroups (struct ListBase *lb1, struct ListBase *lb2);
 struct bDeformGroup* copy_defgroup (struct bDeformGroup *ingroup);
 void color_temperature (float input, unsigned char *r, unsigned char *g, unsigned char *b);
 
+void hook_object_deform(struct Object *ob, int index, float *vec);
+
+int curve_modifier(struct Object *ob, char mode);
+int mesh_modifier(struct Object *ob, char mode);
+int lattice_modifier(struct Object *ob, char mode);
+
+
 #endif
 
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 3bd2ff432b9ab17ecdec6c99568de25e04a3f034..a5384ee2ae238a7c73b96faedc8fe3603d879e67 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -93,7 +93,6 @@ void minmax_object(struct Object *ob, float *min, float *max);
 void solve_tracking (struct Object *ob, float targetmat[][4]);
 void solve_constraints (struct Object *ob, short obtype, void *obdata, float ctime);
 
-	
 #ifdef __cplusplus
 }
 #endif
diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c
index fc7953c051d03cf0de47a9043ca4bd607192376a..1cd442a539126a9840d346f29fc91840ea6d2935 100644
--- a/source/blender/blenkernel/intern/anim.c
+++ b/source/blender/blenkernel/intern/anim.c
@@ -97,8 +97,6 @@ void calc_curvepath(Object *ob)
 	if(cu->path) free_path(cu->path);
 	cu->path= 0;
 	
-	if((cu->flag & CU_PATH)==0) return;
-	
 	bl= cu->bev.first;
 	if(bl==0) {
 		makeDispList(ob);
@@ -213,10 +211,13 @@ int where_on_path(Object *ob, float ctime, float *vec, float *dir)	/* returns OK
 	float *fp, *p0, *p1, *p2, *p3, fac;
 	float data[4];
 	int cycl=0, s0, s1, s2, s3;
-	
+
 	if(ob==0 || ob->type != OB_CURVE) return 0;
 	cu= ob->data;
-	if(cu->path==0 || cu->path->data==0) calc_curvepath(ob);
+	if(cu->path==0 || cu->path->data==0) {
+		calc_curvepath(ob);
+		if(cu->path==0 || cu->path->data==0) return 0;
+	}
 	path= cu->path;
 	fp= path->data;
 	
@@ -224,7 +225,6 @@ int where_on_path(Object *ob, float ctime, float *vec, float *dir)	/* returns OK
 	bl= cu->bev.first;
 	if(bl && bl->poly> -1) cycl= 1;
 
-	/* ctime is between 0.0-1.0 */
 	ctime *= (path->len-1);
 	
 	s1= (int)floor(ctime);
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index ae73d7f5059d7b32a9ddb1bbcdf0acdec0ddb487..0c30e53ec16cb54f64fce3a4f91bc3994bb2fcc1 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -1197,9 +1197,13 @@ void make_displists_by_armature (Object *ob)
 		for (base= G.scene->base.first; base; base= base->next){
 			if ((ob==base->object->parent) && (base->lay & G.scene->lay))
 				if ((base->object->partype==PARSKEL) || (base->object->type==OB_MBALL))
-					makeDispList(base->object);		
+					freedisplist(&base->object->disp);		
 		}
 	}
+/*
+(ton) changed this; now a free displist is sufficient, drawobject.c will make disp
+*/
+
 }	
 
 void get_objectspace_bone_matrix (struct Bone* bone, float M_accumulatedMatrix[][4], int root, int posed)
diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c
index f1ba0324fc8c151fe561d2051a5b0e4e78694688..f3eab76a46565ce850826610e78da809ff9f8f0c 100644
--- a/source/blender/blenkernel/intern/deform.c
+++ b/source/blender/blenkernel/intern/deform.c
@@ -36,10 +36,23 @@
  */
 
 #include <string.h>
+
 #include "MEM_guardedalloc.h"
-#include "BLI_blenlib.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
 #include "DNA_object_types.h"
+
+#include "BKE_curve.h"
 #include "BKE_deform.h"
+#include "BKE_displist.h"
+#include "BKE_lattice.h"
+#include "BKE_utildefines.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
@@ -117,3 +130,243 @@ bDeformGroup* copy_defgroup (bDeformGroup *ingroup)
 	return outgroup;
 }
 
+/* *************** HOOK ****************** */
+
+/* vec==NULL: init
+   vec is supposed to be local coord
+*/
+
+void hook_object_deform(Object *ob, int index, float *vec)
+{
+	float totforce;
+	ObHook *hook;
+	float vect[3], vectot[3];
+	
+	if(ob->hooks.first==NULL) return;
+	
+	/* reinitialize if... */
+	if(vec==NULL) {
+		totforce= 0.0;
+		for(hook= ob->hooks.first; hook; hook= hook->next) {
+			if(hook->parent) {
+				hook->curindex= 0;
+				Mat4Invert(ob->imat, ob->obmat);
+				/* apparently this call goes from right to left... */
+				Mat4MulSerie(hook->mat, ob->imat, hook->parent->obmat, hook->parentinv, NULL, 
+							NULL, NULL, NULL, NULL);
+			}
+		}
+		return;
+	}
+
+	totforce= 0.0;
+	vectot[0]= vectot[1]= vectot[2]= 0.0;
+	
+	for(hook= ob->hooks.first; hook; hook= hook->next) {
+		if(hook->parent) {
+			
+			/* is 'index' in hook array? */
+			while(hook->curindex < hook->totindex-1) {
+				if( hook->indexar[hook->curindex] < index ) hook->curindex++;
+				else break;
+			}
+			
+			if( hook->indexar[hook->curindex]==index ) {
+				float fac= hook->force;
+				
+				totforce+= fac;
+				
+				VecMat4MulVecfl(vect, hook->mat, vec);
+				vectot[0]+= fac*vect[0];
+				vectot[1]+= fac*vect[1];
+				vectot[2]+= fac*vect[2];
+			}
+		}
+	}
+
+	/* if totforce < 1.0, we take old position also into account */
+	if(totforce<1.0) {
+		vectot[0]+= (1.0-totforce)*vec[0];
+		vectot[1]+= (1.0-totforce)*vec[1];
+		vectot[2]+= (1.0-totforce)*vec[2];
+	}
+	else VecMulf(vectot, 1.0/totforce);
+	
+	VECCOPY(vec, vectot);
+}
+
+
+/* modifiers: hooks, deform, softbody 
+   mode=='s' is start, 'e' end 
+*/
+
+int mesh_modifier(Object *ob, char mode)
+{
+	static MVert *mvert=NULL;
+	Mesh *me= ob->data;
+	MVert *mv;
+	int a, done=0;
+	
+	/* conditions if it's needed */
+	if(ob->hooks.first);
+	else if(ob->parent && ob->parent->type==OB_LATTICE);
+	else if(ob->parent && ob->partype==PARSKEL); 
+	else return 0;
+	
+	if(me->totvert==0) return 0;
+	
+	if(mode=='s') { // "start"
+		/* copy  */
+		mvert= MEM_dupallocN(me->mvert);
+		
+		/* hooks */
+		if(ob->hooks.first) {
+			done= 1;
+			
+			/* NULL signals initialize */
+			hook_object_deform(ob, 0, NULL);
+			
+			for(a=0, mv= me->mvert; a<me->totvert; a++, mv++) {
+				hook_object_deform(ob, a, mv->co);
+			}
+		}
+		
+		/* deform: input mesh, output ob dl_verts. is used by subsurf */
+		done |= object_deform(ob);	
+		
+		/* put deformed vertices in dl->verts, optional subsurf will replace that */
+		if(done) {
+			DispList *dl= find_displist_create(&ob->disp, DL_VERTS);
+			float *fp;
+			
+			if(dl->verts) MEM_freeN(dl->verts);
+			dl->nr= me->totvert;
+			if(dl->nr) {
+				
+				/* make disp array */
+				dl->verts= fp= MEM_mallocN(3*sizeof(float)*me->totvert, "deform1");
+				mv= me->mvert;
+				for(a=0; a<me->totvert; a++, mv++, fp+=3) {
+					VECCOPY(fp, mv->co);
+				}
+			}
+		}
+	}
+	else { // end
+		if(mvert) {
+			MEM_freeN(me->mvert);
+			me->mvert= mvert;
+			mvert= NULL;
+		}
+	}
+	
+	return done;
+}
+
+int curve_modifier(Object *ob, char mode)
+{
+	static ListBase nurb={NULL, NULL};
+	Curve *cu= ob->data;
+	Nurb *nu, *newnu;
+	BezTriple *bezt;
+	BPoint *bp;
+	int a, index, done= 0;
+	
+	/* conditions if it's needed */
+	if(ob->hooks.first);
+	else if(ob->parent && ob->partype==PARSKEL); 
+	else if(ob->parent && ob->parent->type==OB_LATTICE);
+	else return 0;
+	
+	if(mode=='s') { // "start"
+		/* copy  */
+		nurb.first= nurb.last= NULL;	
+		nu= cu->nurb.first;
+		while(nu) {
+			newnu= duplicateNurb(nu);
+			BLI_addtail(&nurb, newnu);
+			nu= nu->next;
+		}
+		
+		/* hooks */
+		if(ob->hooks.first) {
+			done= 1;
+			
+			/* NULL signals initialize */
+			hook_object_deform(ob, 0, NULL);
+			index= 0;
+			
+			nu= cu->nurb.first;
+			while(nu) {
+				if((nu->type & 7)==CU_BEZIER) {
+					bezt= nu->bezt;
+					a= nu->pntsu;
+					while(a--) {
+						hook_object_deform(ob, index++, bezt->vec[0]);
+						hook_object_deform(ob, index++, bezt->vec[1]);
+						hook_object_deform(ob, index++, bezt->vec[2]);
+						bezt++;
+					}
+				}
+				else {
+					bp= nu->bp;
+					a= nu->pntsu*nu->pntsv;
+					while(a--) {
+						hook_object_deform(ob, index++, bp->vec);
+						bp++;
+					}
+				}
+					
+				nu= nu->next;
+			}
+		}
+	}
+	else {
+		/* paste */
+		freeNurblist(&cu->nurb);
+		cu->nurb= nurb;
+	}
+	
+	return done;
+}
+
+int lattice_modifier(Object *ob, char mode)
+{
+	static BPoint *bpoint;
+	Lattice *lt= ob->data;
+	BPoint *bp;
+	int a, index, done= 0;
+	
+	/* conditions if it's needed */
+	if(ob->hooks.first);
+	else if(ob->parent && ob->partype==PARSKEL); 
+	else return 0;
+	
+	if(mode=='s') { // "start"
+		/* copy  */
+		bpoint= MEM_dupallocN(lt->def);
+		
+		/* hooks */
+		if(ob->hooks.first) {
+			done= 1;
+			
+			/* NULL signals initialize */
+			hook_object_deform(ob, 0, NULL);
+			index= 0;
+			bp= lt->def;
+			a= lt->pntsu*lt->pntsv*lt->pntsw;
+			while(a--) {
+				hook_object_deform(ob, index++, bp->vec);
+				bp++;
+			}
+		}
+	}
+	else { // end
+		MEM_freeN(lt->def);
+		lt->def= bpoint;
+		bpoint= NULL;
+	}
+	
+	return done;
+}
+
diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c
index 821a1a5bd7c1d09939dcb63c8e9a33cfc1e4a855..932eccb23573cccf3cb4cf96a20871de129aa85a 100644
--- a/source/blender/blenkernel/intern/displist.c
+++ b/source/blender/blenkernel/intern/displist.c
@@ -70,6 +70,7 @@
 #include "BKE_utildefines.h"
 #include "BKE_global.h"
 #include "BKE_displist.h"
+#include "BKE_deform.h"
 #include "BKE_object.h"
 #include "BKE_world.h"
 #include "BKE_mesh.h"
@@ -331,6 +332,20 @@ void freedisplist(ListBase *lb)
 	}
 }
 
+static void freedisplist_object(Object *ob)
+{
+	freedisplist(&ob->disp);
+
+	if(ob->type==OB_MESH) {
+		Mesh *me= ob->data;
+		freedisplist(&me->disp);
+	}
+	else if(ob->type==OB_CURVE || ob->type==OB_SURF || ob->type==OB_FONT) {
+		Curve *cu= ob->data;
+		freedisplist(&cu->disp);
+	}
+}
+
 void free_displist_by_type(ListBase *lb, int type) 
 {
 	DispList *dl;
@@ -1740,8 +1755,9 @@ void makeDispList(Object *ob)
 
 		tex_space_mesh(ob->data);
 		
-		/* deform: input mesh, output ob dl_verts. is used by subsurf */
-		object_deform(ob);	
+		if(ob!=G.obedit) {
+			mesh_modifier(ob, 's');
+		}
 		
 		if(ob->effect.first) object_wave(ob);
 		
@@ -1752,7 +1768,7 @@ void makeDispList(Object *ob)
 				dlm= subsurf_make_dispListMesh_from_editmesh(em, me->subdiv, me->flag, me->subsurftype);
 			} else {
 				DispList *dlVerts= find_displist(&ob->disp, DL_VERTS);
-
+				// not needed anymore, recode it (ton)
 				dlm= subsurf_make_dispListMesh_from_mesh(me, dlVerts?dlVerts->verts:NULL, 
 													me->subdiv, me->flag);
 			}
@@ -1764,6 +1780,8 @@ void makeDispList(Object *ob)
 			free_displist_by_type(&me->disp, DL_MESH);
 			BLI_addtail(&me->disp, dl);
 		}
+		
+		if(ob!=G.obedit) mesh_modifier(ob, 'e');
 	}
 	else if(ob->type==OB_MBALL) {
 		
@@ -1783,8 +1801,11 @@ void makeDispList(Object *ob)
 		freedisplist(dispbase);
 		
 		if(ob==G.obedit) nu= editNurb.first;
-		else nu= cu->nurb.first;
-
+		else {
+			curve_modifier(ob, 's');
+			nu= cu->nurb.first;
+		}
+		
 		while(nu) {
 			if(nu->hide==0) {
 				if(nu->pntsv==1) {
@@ -1856,7 +1877,8 @@ void makeDispList(Object *ob)
 		}
 		
 		tex_space_curve(cu);
-		
+
+		if(ob!=G.obedit) curve_modifier(ob, 'e');
 		if(ob!=G.obedit) object_deform(ob);
 	}
 	else if ELEM(ob->type, OB_CURVE, OB_FONT) {
@@ -1872,6 +1894,8 @@ void makeDispList(Object *ob)
 		
 		BLI_freelistN(&(cu->bev));
 		
+		if(ob!=G.obedit) curve_modifier(ob, 's');
+		
 		if(ob==G.obedit) {
 			if(ob->type==OB_CURVE) curve_to_displist(&editNurb, dispbase);
 			else curve_to_displist(&cu->nurb, dispbase);
@@ -1986,12 +2010,14 @@ void makeDispList(Object *ob)
 			}
 		}
 
+		if(ob!=G.obedit) curve_modifier(ob, 'e');
 		if(ob!=G.obedit) object_deform(ob);
 
 		tex_space_curve(cu);
 
 	}
 	
+	boundbox_displist(ob);
 }
 
 
@@ -2294,12 +2320,13 @@ void imagestodisplist(void)
 }
 
 /* on frame change */
-
+/* new method: only frees displists, and relies on 
+   drawobject.c & convertscene.c to build it when needed
+*/
 void test_all_displists(void)
 {
 	Base *base;
 	Object *ob;
-	int done;	/* prevent displist to be made too often */
 	unsigned int lay;
 	
 	/* background */	
@@ -2310,8 +2337,6 @@ void test_all_displists(void)
 		if(base->lay & lay) {
 			ob= base->object;
 			
-			done= 0;
-			
 			if(ob->type==OB_MBALL && (ob->ipo || ob->parent)) {
 				// find metaball object holding the displist
 				// WARNING: if more metaballs have IPO's the displist
@@ -2321,44 +2346,62 @@ void test_all_displists(void)
 				if(ob->disp.first == NULL) {
 					ob= find_basis_mball(ob);
 				}
-				// makeDispList(ob);
 				freedisplist(&ob->disp);
 			}
 			else if(ob->parent) {
 				
-				done= 1;
 				if (ob->parent->type == OB_LATTICE)
-					makeDispList(ob);
+					freedisplist_object(ob);
 				else if ((ob->parent->type == OB_IKA) && (ob->partype == PARSKEL))
-					makeDispList(ob);
+					freedisplist_object(ob);
 				else if ((ob->parent->type==OB_ARMATURE) && (ob->partype == PARSKEL))
-					makeDispList(ob);
-				else done= 0;
+					freedisplist_object(ob);
+				else if ((ob->parent->type==OB_CURVE) && (ob->partype == PARSKEL))
+					freedisplist_object(ob);
 			}
 
-			/* warn, ob pointer changed in case of OB_MALL */
-			if(done==0) {
-				if ELEM(ob->type, OB_CURVE, OB_SURF) {
-					if(ob!=G.obedit) {
-						if( ((Curve *)(ob->data))->key ) makeDispList(ob);
-					}
+			if(ob->hooks.first) {
+				ObHook *hook;
+				for(hook= ob->hooks.first; hook; hook= hook->next) {
+					if(hook->parent) freedisplist_object(ob);
+					break;
 				}
-				else if(ob->type==OB_FONT) {
+			}
+
+			/* warn, ob pointer changed in case of OB_MALL */
+
+			if ELEM(ob->type, OB_CURVE, OB_SURF) {
+				if(ob!=G.obedit) {
 					Curve *cu= ob->data;
-					if(cu->textoncurve) {
-						if( ((Curve *)cu->textoncurve->data)->key ) {
-							text_to_curve(ob, 0);
-							makeDispList(ob);
-						}
+					
+					if(cu->key ) freedisplist_object(ob); //makeDispList(ob);
+					if(cu->bevobj) {
+						Curve *cu1= cu->bevobj->data;
+						if(cu1->key ) freedisplist_object(ob);
+					}
+					if(cu->taperobj) {
+						Curve *cu1= cu->taperobj->data;
+						if(cu1->key ) freedisplist_object(ob);
 					}
 				}
-				else if(ob->type==OB_MESH) {
-					if(ob->effect.first) object_wave(ob);
-					if(ob!=G.obedit) {
-						if(( ((Mesh *)(ob->data))->key )||(ob->effect.first)) makeDispList(ob);
+			}
+			else if(ob->type==OB_FONT) {
+				Curve *cu= ob->data;
+				if(cu->textoncurve) {
+					if( ((Curve *)cu->textoncurve->data)->key ) {
+						text_to_curve(ob, 0);
+						freedisplist_object(ob); //makeDispList(ob);
 					}
 				}
 			}
+			else if(ob->type==OB_MESH) {
+				if(ob->effect.first) object_wave(ob);
+				if(ob!=G.obedit) {
+					if(( ((Mesh *)(ob->data))->key )||(ob->effect.first)) 
+						freedisplist_object(ob); //makeDispList(ob);
+				}
+			}
+
 		}
 		if(base->next==0 && G.scene->set && base==G.scene->base.last) base= G.scene->set->base.first;
 		else base= base->next;
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index 3cb2f20925f941c0c8c70a84894ec253498d39b8..959cb7001fb3af3343963c00e1f4259579769ba9 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -53,23 +53,27 @@
 #include "DNA_key_types.h"
 #include "DNA_ika_types.h"
 
-#include "BKE_utildefines.h"
+#include "BKE_anim.h"
 #include "BKE_armature.h"
-#include "BKE_library.h"
-#include "BKE_global.h"
-#include "BKE_main.h"
-#include "BKE_screen.h"
+#include "BKE_curve.h"
+#include "BKE_deform.h"
 #include "BKE_displist.h"
-#include "BKE_lattice.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_ika.h"
-#include "BKE_curve.h"
+#include "BKE_screen.h"
+#include "BKE_utildefines.h"
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
 
+#include "blendef.h"
+
 Lattice *editLatt=0, *deformLatt=0;
 
 float *latticedata=0, latmat[4][4];
@@ -236,6 +240,7 @@ void init_latt_deform(Object *oblatt, Object *ob)
 	
 	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);
@@ -279,6 +284,9 @@ void init_latt_deform(Object *oblatt, Object *ob)
 		}
 		vec[2]+= dw;
 	}
+
+	lattice_modifier(oblatt, 'e');
+
 }
 
 void calc_latt_deform(float *co)
@@ -383,6 +391,119 @@ void end_latt_deform()
 	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 */
+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;
+
+	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[3], 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);
+
+	/* 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)
 {
@@ -391,32 +512,59 @@ static int _object_deform(Object *ob, int applyflag)
 	DispList *dl;
 	MVert *mvert;
 	float *fp;
-	int a, tot;
+	int a, tot, flag;
 
-	if(ob->parent==0) return 0;
+	if(ob->parent==NULL) return 0;
 	
 	/* always try to do the entire deform in this function: apply! */
-	
-	if(ob->parent->type==OB_LATTICE) {
+
+	if(ob->parent->type==OB_CURVE) {
+		CurveDeform cd;
 		
-		init_latt_deform(ob->parent, ob);
+		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;
 			
-			dl= find_displist_create(&ob->disp, DL_VERTS);
+			/* init deform */
+			init_curve_deform(ob->parent, ob, &cd);
 			
-			mvert= me->mvert;
-			if(dl->verts) MEM_freeN(dl->verts);
-			dl->nr= me->totvert;
-			dl->verts= fp= MEM_mallocN(3*sizeof(float)*me->totvert, "deform1");
+			/* transformation to curve space, and min max*/
+			INIT_MINMAX(cd.dmin, cd.dmax);
+			
+			for(a=0, mvert=me->mvert; a<me->totvert; a++, mvert++) {
+				Mat4MulVecfl(cd.curvespace, mvert->co);
+				DO_MINMAX(mvert->co, cd.dmin, cd.dmax);
+			}
 
-			for(a=0; a<me->totvert; a++, mvert++, fp+=3) {
-				if(applyflag) calc_latt_deform(mvert->co);
-				else {
-					VECCOPY(fp, mvert->co);
-					calc_latt_deform(fp);
-				}
+			mvert= me->mvert;
+			for(a=0; a<me->totvert; 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; a<me->totvert; a++, mvert++) {
+				calc_latt_deform(mvert->co);
 			}
 		}
 		else if(ob->type==OB_MBALL) {
@@ -479,9 +627,6 @@ static int _object_deform(Object *ob, int applyflag)
 			}
 		}
 		end_latt_deform();
-
-		boundbox_displist(ob);	
-
 		return 1;
 	}
 	else if(ob->parent->type==OB_ARMATURE) {
@@ -495,97 +640,16 @@ static int _object_deform(Object *ob, int applyflag)
 		case OB_MESH:
 			me= ob->data;
 			
-			dl= find_displist_create(&ob->disp, DL_VERTS);
-			
 			mvert= me->mvert;
-			if(dl->verts) MEM_freeN(dl->verts);
-			dl->nr= me->totvert;
-			dl->verts= fp= MEM_mallocN(3*sizeof(float)*me->totvert, "deform1");
-
-			for(a=0; a<me->totvert; a++, mvert++, fp+=3) {
-				if(applyflag){
-					calc_armature_deform(ob->parent, mvert->co, a);
-				}
-				else {
-					VECCOPY(fp, mvert->co);
-					calc_armature_deform(ob->parent, fp, a);
-				}
+			for(a=0; a<me->totvert; a++, mvert++) {
+				calc_armature_deform(ob->parent, mvert->co, a);
 			}
-
 			break;
-		default:
+		case OB_CURVE:
+		case OB_SURF:
 			break;
 		}
 		
-		boundbox_displist(ob);	
-		return 1;
-	}
-	else if(ob->parent->type==OB_IKA) {
-
-		Ika *ika;
-		
-		if(ob->partype!=PARSKEL) return 0;
-		
-		ika= ob->parent->data;
-		if(ika->def==0) return 0;
-		
-		init_skel_deform(ob->parent, ob);
-		
-		if(ob->type==OB_MESH) {
-			me= ob->data;
-			
-			dl= find_displist_create(&ob->disp, DL_VERTS);
-			
-			mvert= me->mvert;
-			if(dl->verts) MEM_freeN(dl->verts);
-			dl->nr= me->totvert;
-			dl->verts= fp= MEM_mallocN(3*sizeof(float)*me->totvert, "deform1");
-
-			for(a=0; a<me->totvert; a++, mvert++, fp+=3) {
-				if(applyflag) calc_skel_deform(ika, mvert->co);
-				else {
-					VECCOPY(fp, mvert->co);
-					calc_skel_deform(ika, fp);
-				}
-			}
-		}
-		else if ELEM(ob->type, OB_CURVE, OB_SURF) {
-		
-			cu= ob->data;
-			if(applyflag) {
-				Nurb *nu;
-				BPoint *bp;
-				
-				nu= cu->nurb.first;
-				while(nu) {
-					if(nu->bp) {
-						a= nu->pntsu*nu->pntsv;
-						bp= nu->bp;
-						while(a--) {
-							calc_skel_deform(ika, bp->vec);
-							bp++;
-						}
-					}
-					nu= nu->next;
-				}
-			}
-			
-			/* when apply, do this too, looks more interactive */
-			dl= cu->disp.first;
-			while(dl) {
-				
-				fp= dl->verts;
-				tot= dl->nr*dl->parts;
-				for(a=0; a<tot; a++, fp+=3) {
-					calc_skel_deform(ika, fp);
-				}
-				
-				dl= dl->next;
-			}
-		}
-		
-		boundbox_displist(ob);
-		
 		return 1;
 	}
 	
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index bd7cb626182b8ea237162f8504be4fd8bc72af06..b4b8203355bf2a35b6809f84c8c88ae2b04f1ba6 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -148,6 +148,16 @@ void update_base_layer(Object *ob)
 	}
 }
 
+static void free_hooks(ListBase *lb)
+{
+	while(lb->first) {
+		ObHook *hook= lb->first;
+		if(hook->indexar) MEM_freeN(hook->indexar);
+		BLI_remlink(lb, hook);
+		MEM_freeN(hook);
+	}
+}
+
 /* do not free object itself */
 void free_object(Object *ob)
 {
@@ -193,7 +203,9 @@ void free_object(Object *ob)
 	free_constraints(&ob->constraints);
 	free_constraint_channels(&ob->constraintChannels);
 	free_nlastrips(&ob->nlastrips);
-
+	
+	free_hooks(&ob->hooks);
+	
 	freedisplist(&ob->disp);
 	
 	BPY_free_scriptlink(&ob->scriptlink);
@@ -210,6 +222,7 @@ void unlink_object(Object *ob)
 	Scene *sce;
 	Curve *cu;
 	Tex *tex;
+	ObHook *hook;
 	Group *group;
 	int a;
 
@@ -225,6 +238,9 @@ void unlink_object(Object *ob)
 				if(ob->type==OB_LATTICE) freedisplist(&obt->disp);
 			}
 			if(obt->track==ob) obt->track= NULL;
+			for(hook=obt->hooks.first; hook; hook= hook->next) {
+				if(hook->parent==ob) hook->parent= NULL;
+			}
 			if ELEM(obt->type, OB_CURVE, OB_FONT) {
 				cu= obt->data;
 				if(cu->bevobj==ob) cu->bevobj= NULL;
@@ -752,7 +768,8 @@ Object *copy_object(Object *ob)
 	id_us_plus((ID *)obn->action);
 	for(a=0; a<obn->totcol; a++) id_us_plus((ID *)obn->mat[a]);
 	
-	obn->disp.first= obn->disp.last= 0;
+	obn->disp.first= obn->disp.last= NULL;
+	obn->hooks.first= obn->hooks.last= NULL;
 	
 	return obn;
 }
@@ -969,7 +986,8 @@ void ob_parcurve(Object *ob, Object *par, float mat[][4])
 
 		if(cu->flag & CU_FOLLOW) {
 			quat= vectoquat(dir, ob->trackflag, ob->upflag);
-
+			
+			/* the tilt */
 			Normalise(dir);
 			q[0]= (float)cos(0.5*vec[3]);
 			x1= (float)sin(0.5*vec[3]);
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 8da7ff687c83dc6ff318d90614f51a0eddc92410..a9a5b16b46237f464ea56d13a6fa6b874e88ee9e 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -2122,7 +2122,7 @@ static void lib_link_object(FileData *fd, Main *main)
 	bSensor *sens;
 	bController *cont;
 	bActuator *act;
-
+	ObHook *hook;
 	void *poin;
 	int warn=0, a;
 
@@ -2240,6 +2240,10 @@ static void lib_link_object(FileData *fd, Main *main)
 			}
 
 			lib_link_scriptlink(fd, &ob->id, &ob->scriptlink);
+			
+			for(hook= ob->hooks.first; hook; hook= hook->next) {
+				hook->parent= newlibadr(fd, ob->id.lib, hook->parent);
+			}
 		}
 		ob= ob->id.next;
 	}
@@ -2270,7 +2274,8 @@ static void direct_link_object(FileData *fd, Object *ob)
 	bSensor *sens;
 	bController *cont;
 	bActuator *act;
-
+	ObHook *hook;
+	
 	ob->disp.first=ob->disp.last= 0;
 
 	ob->pose= newdataadr(fd, ob->pose);
@@ -2335,7 +2340,18 @@ static void direct_link_object(FileData *fd, Object *ob)
 		act= act->next;
 	}
 
-	ob->bb= 0;
+	link_list(fd, &ob->hooks);
+	for(hook= ob->hooks.first; hook; hook= hook->next) {
+		hook->indexar= newdataadr(fd, hook->indexar);
+		if(fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
+			int a;
+			for(a=0; a<hook->totindex; a++) {
+				SWITCH_INT(hook->indexar[a]);
+			}
+		}
+	}
+	
+	ob->bb= NULL;
 }
 
 /* ************ READ SCENE ***************** */
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 94e2e8040738aa4183654ce7f91bbea69e7efcc3..0bb8d3789782d3789a35d8601b9cf092a1b4e42f 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -655,7 +655,8 @@ static void write_constraint_channels(WriteData *wd, ListBase *chanbase)
 static void write_objects(WriteData *wd, ListBase *idbase)
 {
 	Object *ob;
-
+	ObHook *hook;
+	
 	ob= idbase->first;
 	while(ob) {
 		if(ob->id.us>0) {
@@ -677,6 +678,11 @@ static void write_objects(WriteData *wd, ListBase *idbase)
 			write_nlastrips(wd, &ob->nlastrips);
 			
 			writestruct(wd, DATA, "PartDeflect", 1, ob->pd);
+			
+			for(hook= ob->hooks.first; hook; hook= hook->next) {
+				writestruct(wd, DATA, "ObHook", 1, hook);
+				writedata(wd, DATA, sizeof(int)*hook->totindex, hook->indexar);
+			}
 		}
 		ob= ob->id.next;
 	}
diff --git a/source/blender/include/BDR_editcurve.h b/source/blender/include/BDR_editcurve.h
index e99ce2c625f6405f600f6540842cec790268330c..839bf4c68025a51e3a159e42eb8e16b0e209f2d0 100644
--- a/source/blender/include/BDR_editcurve.h
+++ b/source/blender/include/BDR_editcurve.h
@@ -33,6 +33,7 @@
 #ifndef BDR_EDITCURVE_H
 #define BDR_EDITCURVE_H
 
+struct Object;
 struct Curve;
 struct Nurb;
 struct BezTriple;
@@ -89,6 +90,7 @@ void add_primitiveNurb(int type);
 void clear_tilt(void);
 void clever_numbuts_curve(void);         
 int bezt_compare (const void *e1, const void *e2);
+void curve_changes_other_objects(struct Object *ob);
 
 extern void undo_push_curve(char *name);
 extern void undo_clear_curve(void);
diff --git a/source/blender/include/BDR_editobject.h b/source/blender/include/BDR_editobject.h
index 5b1fe2552aa97d20f962c935d7f64e45cab07e7e..a00878448fa869742de2a7695a852615ab34e82d 100644
--- a/source/blender/include/BDR_editobject.h
+++ b/source/blender/include/BDR_editobject.h
@@ -119,6 +119,7 @@ void mirrormenu(void);
 void mirror_edit(short mode);
 void mirror_object(short mode);
 void flag_edge_crease(void);
+void add_hook(void);
 
 #endif /*  BDR_EDITOBJECT_H */
 
diff --git a/source/blender/include/butspace.h b/source/blender/include/butspace.h
index 54af18adfb337620d0474addb88cb5a4d3543180..2c83b50e6e3fc5e27f1b7c2b46adc43dc68dbcd2 100644
--- a/source/blender/include/butspace.h
+++ b/source/blender/include/butspace.h
@@ -209,11 +209,14 @@ void butspace_context_switch(SpaceButs *buts, struct Base *new);
 #define B_ANIMBUTS		1500
 
 #define B_RECALCPATH	1401
-
+#define B_TRACKBUTS		1402
+#define B_DEL_HOOK		1403
+#define B_CLR_HOOK		1404
 
 #define B_PRINTSPEED	1413
 #define B_PRINTLEN		1414
 #define B_RELKEY		1415
+#define B_CURVECHECK	1416
 
 	/* this has MAX_EFFECT settings! Next free define is 1450... */
 #define B_SELEFFECT	1430	
diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h
index 59e91fa861b152de6752cfc1bf5fcf049009930a..bdf91f35a2f01cd87ca3b26054f49c32739fe3b7 100644
--- a/source/blender/makesdna/DNA_curve_types.h
+++ b/source/blender/makesdna/DNA_curve_types.h
@@ -174,6 +174,7 @@ typedef struct IpoCurve {
 #define CU_FOLLOW		16
 #define CU_UV_ORCO		32
 #define CU_NOPUNOFLIP	64
+#define CU_STRETCH		128
 
 /* spacemode */
 #define CU_LEFT			0
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index ac6e75f03e5f7a02037e0cc471292de8cb57bedb..2905b2eeb0962206b23e184c1baa66feb119a565 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -89,7 +89,6 @@ typedef struct PartDeflect {
 	float f_power;       /* The power law - real gravitation is 2 (square)  */
 } PartDeflect;
 
-
 typedef struct Object {
 	ID id;
 
@@ -191,7 +190,8 @@ typedef struct Object {
 
 	ListBase constraints;
 	ListBase nlastrips;
-
+	ListBase hooks;
+	
 	PartDeflect *pd;	/* particle deflector/attractor/collision data */
 	struct Life *life;
 
@@ -201,6 +201,24 @@ typedef struct Object {
 	float toonedge, smoothresh;	/* smoothresh is phong interpolation ray_shadow correction in render */
 } Object;
 
+typedef struct ObHook {
+	struct ObHook *next, *prev;
+	
+	struct Object *parent;
+	float parentinv[4][4];	/* matrix making current transform unmodified */
+	float mat[4][4];		/* temp matrix while hooking */
+	float cent[3];			/* visualization of hook */
+	int pad;
+	
+	char name[32];
+
+	int *indexar;
+	int totindex, curindex; /* curindex is cache for fast lookup */
+	short type, active;		/* active is only first hook, for button menu */
+	float force;
+} ObHook;
+
+
 /* this work object is defined in object.c */
 extern Object workob;
 
diff --git a/source/blender/renderconverter/intern/convertBlenderScene.c b/source/blender/renderconverter/intern/convertBlenderScene.c
index 3f5765c3fb5f5df84c3d5460c8e495f80ce54f98..25698bfe5ca0f0579c56d5179a1b9e1054b6419d 100644
--- a/source/blender/renderconverter/intern/convertBlenderScene.c
+++ b/source/blender/renderconverter/intern/convertBlenderScene.c
@@ -68,27 +68,27 @@
 #include "DNA_meta_types.h"
 #include "DNA_space_types.h"
 
-#include "BKE_mesh.h"
-#include "BKE_key.h"
+#include "BKE_anim.h"
+#include "BKE_armature.h"
 #include "BKE_action.h"
 #include "BKE_curve.h"
-#include "BKE_armature.h"
-#include "BKE_object.h"
-#include "BKE_texture.h"
-#include "BKE_material.h"
-#include "BKE_main.h"
-#include "BKE_mball.h"
-#include "BKE_anim.h"
-#include "BKE_global.h"
+#include "BKE_constraint.h"
+#include "BKE_displist.h"
+#include "BKE_deform.h"
 #include "BKE_effect.h"
-#include "BKE_world.h"
+#include "BKE_global.h"
+#include "BKE_key.h"
 #include "BKE_ipo.h"
 #include "BKE_ika.h"
-#include "BKE_displist.h"
 #include "BKE_lattice.h"
-#include "BKE_constraint.h"
-#include "BKE_utildefines.h"
+#include "BKE_material.h"
+#include "BKE_main.h"
+#include "BKE_mball.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
 #include "BKE_subsurf.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
 #include "BKE_world.h"
 
 #include "render.h"
@@ -1247,8 +1247,8 @@ static void init_render_mesh(Object *ob)
 
 	me= ob->data;
 
-	/* object_deform changes imat */
-	do_puno= object_deform(ob);
+	/* object_deform changes imat! */
+	do_puno= mesh_modifier(ob, 's');
 
 	paf = give_parteff(ob);
 	if(paf) {
@@ -1299,8 +1299,6 @@ static void init_render_mesh(Object *ob)
 			if((me->subdivdone-1)!=me->subdivr) {
 				DispList *dlVerts;
 
-				object_deform(ob);
-
 				dlVerts= find_displist(&ob->disp, DL_VERTS);
 				dlm= subsurf_make_dispListMesh_from_mesh(me, dlVerts?dlVerts->verts:NULL, me->subdivr, me->flag);
 				dl= MEM_callocN(sizeof(*dl), "dl");
@@ -1317,16 +1315,19 @@ static void init_render_mesh(Object *ob)
 			}
 		}
 
-		if(dl==0 || dl->type!=DL_MESH) return;
-		dlm= dl->mesh;
-
-		mvert= dlm->mvert;
-		totvert= dlm->totvert;
-
-		if(need_orco) {
-			make_orco_displist_mesh(ob, me->subdivr);
+		if(dl==NULL || dl->type!=DL_MESH);  // here used to be a return, but why?
+		else {
+			dlm= dl->mesh;
+	
+			mvert= dlm->mvert;
+			totvert= dlm->totvert;
+	
+			if(need_orco) {
+				make_orco_displist_mesh(ob, me->subdivr);
+			}
+			ms= NULL; // no stick in displistmesh
 		}
-		ms= NULL; // no stick in displistmesh
+		
 	} else {
 		dlm= NULL;
 		mvert= me->mvert;
@@ -1527,7 +1528,8 @@ static void init_render_mesh(Object *ob)
 	}
 	
 	if(do_puno) normalenrender(totverto, totvlako);
-
+	
+	mesh_modifier(ob, 'e');  // end
 }
 
 /* ------------------------------------------------------------------------- */
@@ -1797,6 +1799,8 @@ static void init_render_surf(Object *ob)
 	if(cu->orco==0 && need_orco) make_orco_surf(cu);
 	orco= cu->orco;
 
+	curve_modifier(ob, 's');
+
 	/* make a complete new displist, the base-displist can be different */
 	displist.first= displist.last= 0;
 	nu= cu->nurb.first;
@@ -1840,6 +1844,9 @@ static void init_render_surf(Object *ob)
 		end_latt_deform();
 	}
 	
+	/* note; deform will be included in modifier() later */
+	curve_modifier(ob, 'e');
+
 	if(ob->partype==PARSKEL && ob->parent && ob->parent->type==OB_ARMATURE) {
 /*  		bArmature *arm= ob->parent->data; */
 		init_armature_deform(ob->parent, ob);
@@ -2162,6 +2169,8 @@ static void init_render_curve(Object *ob)
 	nu= cu->nurb.first;
 	if(nu==0) return;
 
+	curve_modifier(ob, 's');
+
 	/* test displist */
 	if(cu->disp.first==0) makeDispList(ob);
 	dl= cu->disp.first;
@@ -2234,6 +2243,9 @@ static void init_render_curve(Object *ob)
 		}
 	}
 
+	/* modifier() will get deform included later */
+	curve_modifier(ob, 'e');
+
 	if(ob->parent && ob->parent->type==OB_LATTICE) {
 		lt= ob->parent->data;
 		init_latt_deform(ob->parent, ob);
diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c
index fb1bb652be3891998a7825333a93131f0eb523f5..8d40bb2307f2ee2ea4e2b44f61cb1e9b9ec57c68 100644
--- a/source/blender/src/buttons_editing.c
+++ b/source/blender/src/buttons_editing.c
@@ -1248,17 +1248,20 @@ static void editing_panel_curve_type(Object *ob, Curve *cu)
 	}
 
 	if(ob->type!=OB_SURF) {
-
+	
 		if(ob->type==OB_CURVE) {
 			extern float prlen;		// buttons_object.c, should be moved....
 			char str[32];
 			uiBlockBeginAlign(block);
-			uiDefButS(block, NUM, B_RECALCPATH, "PathLen:",			600,50,150,19, &cu->pathlen, 1.0, 9000.0, 0, 0, "");
-			uiDefButS(block, TOG|BIT|3, B_RECALCPATH, "CurvePath",	600,30,75,19 , &cu->flag, 0, 0, 0, 0, "");
-			uiDefButS(block, TOG|BIT|4, REDRAWVIEW3D, "CurveFollow",675,30,75,19, &cu->flag, 0, 0, 0, 0, "");
+			uiDefButS(block, NUM, B_RECALCPATH, "PathLen:",			600,50,150,19, &cu->pathlen, 1.0, 9000.0, 0, 0, "If no speed Ipo was set, the amount of frames of the path");
+			uiDefButS(block, TOG|BIT|3, B_RECALCPATH, "CurvePath",	600,30,75,19 , &cu->flag, 0, 0, 0, 0, "Enables curve to become translation path");
+			uiDefButS(block, TOG|BIT|4, REDRAWVIEW3D, "CurveFollow",675,30,75,19, &cu->flag, 0, 0, 0, 0, "Makes curve path children to rotate along path");
+			uiDefButS(block, TOG|BIT|7, B_CURVECHECK, "CurveStretch", 600,10,150,19, &cu->flag, 0, 0, 0, 0, "Option for curve-deform: makes deformed child to stretch along entire path");
+
+			uiBlockEndAlign(block);
 			sprintf(str, "%.4f", prlen);
-			uiDefBut(block, BUT, B_PRINTLEN,		"PrintLen",	600,10,75,19, 0, 0, 0, 0, 0, "");
-			uiDefBut(block, LABEL, 0, str,						675,10,75,19, 0, 1.0, 0, 0, 0, "");
+			uiDefBut(block, BUT, B_PRINTLEN,		"PrintLen",	600,-10,75,19, 0, 0, 0, 0, 0, "");
+			uiDefBut(block, LABEL, 0, str,						675,-10,75,19, 0, 1.0, 0, 0, 0, "");
 		}
 
 		uiBlockBeginAlign(block);
diff --git a/source/blender/src/buttons_object.c b/source/blender/src/buttons_object.c
index 4314b3fa408d313ac4e7033cd842fa2b88a1fd2f..29fa70a1644571205c6e5e00a472f31ffdce5b80 100644
--- a/source/blender/src/buttons_object.c
+++ b/source/blender/src/buttons_object.c
@@ -72,6 +72,7 @@
 #include "BDR_editcurve.h"
 #include "BDR_editface.h"
 #include "BDR_drawobject.h"
+
 #include "BIF_butspace.h"
 
 #include "mydevice.h"
@@ -1033,18 +1034,102 @@ void object_panel_draw(Object *ob)
 	
 }
 
+void object_panel_hooks(Object *ob)
+{
+	uiBlock *block;
+	ObHook *hook;
+	int tothook=0, nr, active;
+	char *cp;
+	
+	block= uiNewBlock(&curarea->uiblocks, "object_panel_hooks", UI_EMBOSS, UI_HELV, curarea->win);
+	uiNewPanelTabbed("Draw", "Object");
+	if(uiNewPanel(curarea, block, "Hooks", "Object", 320, 0, 318, 204)==0) return;
+
+	if(ob->hooks.first==NULL) {
+		uiDefBut(block, LABEL, 0, "Add hooks in Editmode", 10,180,300,19, NULL, 0, 0, 0, 0, "");
+		return;
+	}
+	
+	/* build menu */
+	for(hook= ob->hooks.first; hook; hook= hook->next) tothook++;
+	
+	cp= MEM_callocN(32*tothook+32, "temp string");
+	strcpy(cp, "Active Hook %t|");
+
+	for(hook= ob->hooks.first; hook; hook= hook->next) {
+		strcat(cp, hook->name);
+		strcat(cp, " |");
+	}
+	/* active is stored in first hook */
+	hook= ob->hooks.first;
+	if(hook->active<1 || hook->active > tothook) hook->active= 1;
+	active= hook->active;
+	
+	uiDefButS(block, MENU, B_REDR, cp, 10,180,150,19, &hook->active, 0, 0, 0, 0, "Set active hook");
+	MEM_freeN(cp);
 
+	for(nr=1, hook= ob->hooks.first; hook; hook= hook->next, nr++) {
+		if(nr==active) break;
+	}
+	if(hook==NULL) printf("error in object_panel_hooks\n");
+	
+	uiBlockBeginAlign(block);
+	uiDefButC(block, TEX, B_REDR, "Name: ", 				160,180,150,19, hook->name, 0, 32, 0, 0, "Set name of hook");
+	uiDefIDPoinBut(block, test_obpoin_but, B_CLR_HOOK, "Parent:", 	160, 160, 150, 19, &hook->parent, "Parent Object for hook, also recalculates and clears offset"); 
+	uiDefButF(block, NUMSLI, B_MAKEDISP, "Force: ", 		160,140,150,19, &hook->force, 0.0, 1.0, 100, 0, "Set force of hook");
+
+	uiBlockBeginAlign(block);
+	uiDefBut(block, BUT, B_DEL_HOOK, "Delete", 				10,100,150,19, NULL, 0.0, 0.0, 0, 0, "Delete hook");
+	uiDefBut(block, BUT, B_CLR_HOOK, "Clear offset", 		160,100,150,19, NULL, 0.0, 0.0, 0, 0, "Recalculate and clear offset (transform) of hook");
+}
 
 
 void do_object_panels(unsigned short event)
 {
 	Object *ob;
+	ObHook *hook;
 	Effect *eff;
 	
 	ob= OBACT;
 
 	switch(event) {
-		
+	case B_TRACKBUTS:
+		ob= OBACT;
+		if(ob && ob->parent && ob->parent->type==OB_CURVE) freedisplist(&ob->disp);
+		allqueue(REDRAWVIEW3D, 0);
+		break;
+	case B_DEL_HOOK:
+		hook= ob->hooks.first;
+		if(hook) {
+			int active= hook->active, nr;
+			for(nr=1, hook=ob->hooks.first; hook; hook=hook->next, nr++) {
+				if(active==nr) break;
+			}
+			if(hook) {
+				BLI_remlink(&ob->hooks, hook);
+				if(hook->indexar) MEM_freeN(hook->indexar);
+				MEM_freeN(hook);
+			}
+			freedisplist(&ob->disp);
+			allqueue(REDRAWVIEW3D, 0);
+			allqueue(REDRAWBUTSOBJECT, 0);
+		}
+		break;
+	case B_CLR_HOOK:
+		hook= ob->hooks.first;
+		if(hook) {
+			int active= hook->active, nr;
+			for(nr=1, hook=ob->hooks.first; hook; hook=hook->next, nr++) {
+				if(active==nr) break;
+			}
+			if(hook && hook->parent) {
+				Mat4Invert(hook->parent->imat, hook->parent->obmat);
+				/* apparently this call goes from right to left... */
+				Mat4MulSerie(hook->parentinv, hook->parent->imat, ob->obmat, NULL, 
+							NULL, NULL, NULL, NULL, NULL);
+			}
+		}
+		break;
 	case B_RECALCPATH:
 		calc_curvepath(OBACT);
 		allqueue(REDRAWVIEW3D, 0);
@@ -1079,7 +1164,11 @@ void do_object_panels(unsigned short event)
 		allqueue(REDRAWBUTSOBJECT, 0);
 		allqueue(REDRAWIPO, 0);
 		break;
-		
+	case B_CURVECHECK:
+		curve_changes_other_objects(OBACT);
+		allqueue(REDRAWVIEW3D, 0);
+		break;
+	
 	default:
 		if(event>=B_SELEFFECT && event<B_SELEFFECT+MAX_EFFECT) {
 			ob= OBACT;
@@ -1101,7 +1190,6 @@ void do_object_panels(unsigned short event)
 
 }
 
-
 static void object_panel_anim(Object *ob)
 {
 	uiBlock *block;
@@ -1111,12 +1199,12 @@ static void object_panel_anim(Object *ob)
 	if(uiNewPanel(curarea, block, "Anim settings", "Object", 0, 0, 318, 204)==0) return;
 	
 	uiBlockBeginAlign(block);
-	uiDefButC(block, ROW,REDRAWVIEW3D,"TrackX",	24,190,59,19, &ob->trackflag, 12.0, 0.0, 0, 0, "Specify the axis that points to another object");
-	uiDefButC(block, ROW,REDRAWVIEW3D,"Y",		85,190,19,19, &ob->trackflag, 12.0, 1.0, 0, 0, "Specify the axis that points to another object");
-	uiDefButC(block, ROW,REDRAWVIEW3D,"Z",		104,190,19,19, &ob->trackflag, 12.0, 2.0, 0, 0, "Specify the axis that points to another object");
-	uiDefButC(block, ROW,REDRAWVIEW3D,"-X",		124,190,24,19, &ob->trackflag, 12.0, 3.0, 0, 0, "Specify the axis that points to another object");
-	uiDefButC(block, ROW,REDRAWVIEW3D,"-Y",		150,190,24,19, &ob->trackflag, 12.0, 4.0, 0, 0, "Specify the axis that points to another object");
-	uiDefButC(block, ROW,REDRAWVIEW3D,"-Z",		178,190,24,19, &ob->trackflag, 12.0, 5.0, 0, 0, "Specify the axis that points to another object");
+	uiDefButC(block, ROW,B_TRACKBUTS,"TrackX",	24,190,59,19, &ob->trackflag, 12.0, 0.0, 0, 0, "Specify the axis that points to another object");
+	uiDefButC(block, ROW,B_TRACKBUTS,"Y",		85,190,19,19, &ob->trackflag, 12.0, 1.0, 0, 0, "Specify the axis that points to another object");
+	uiDefButC(block, ROW,B_TRACKBUTS,"Z",		104,190,19,19, &ob->trackflag, 12.0, 2.0, 0, 0, "Specify the axis that points to another object");
+	uiDefButC(block, ROW,B_TRACKBUTS,"-X",		124,190,24,19, &ob->trackflag, 12.0, 3.0, 0, 0, "Specify the axis that points to another object");
+	uiDefButC(block, ROW,B_TRACKBUTS,"-Y",		150,190,24,19, &ob->trackflag, 12.0, 4.0, 0, 0, "Specify the axis that points to another object");
+	uiDefButC(block, ROW,B_TRACKBUTS,"-Z",		178,190,24,19, &ob->trackflag, 12.0, 5.0, 0, 0, "Specify the axis that points to another object");
 	uiBlockBeginAlign(block);
 	uiDefButC(block, ROW,REDRAWVIEW3D,"UpX",	226,190,45,19, &ob->upflag, 13.0, 0.0, 0, 0, "Specify the axis that points up");
 	uiDefButC(block, ROW,REDRAWVIEW3D,"Y",		274,190,20,19, &ob->upflag, 13.0, 1.0, 0, 0, "Specify the axis that points up");
@@ -1485,6 +1573,7 @@ void object_panels()
 
 		object_panel_anim(ob);
 		object_panel_draw(ob);
+		object_panel_hooks(ob);
 		object_panel_constraint();
 		if(ob->type==OB_MESH) {
 			object_panel_effects(ob);
diff --git a/source/blender/src/drawobject.c b/source/blender/src/drawobject.c
index 127ba5d5582cf8b44d2bcbeb73dc46bcdaae5b35..935901548d4f5c90a14a807c1aeca742d5861347 100644
--- a/source/blender/src/drawobject.c
+++ b/source/blender/src/drawobject.c
@@ -74,15 +74,16 @@
 #include "BKE_utildefines.h"
 #include "BKE_curve.h"
 #include "BKE_constraint.h" // for the get_constraint_target function
-#include "BKE_object.h"
-#include "BKE_global.h"
+#include "BKE_deform.h"		// lattice_modifier()
 #include "BKE_displist.h"
-#include "BKE_material.h"
-#include "BKE_mball.h"
-#include "BKE_ipo.h"
-#include "BKE_mesh.h"
 #include "BKE_effect.h"
+#include "BKE_global.h"
+#include "BKE_ipo.h"
 #include "BKE_lattice.h"
+#include "BKE_mesh.h"
+#include "BKE_material.h"
+#include "BKE_mball.h"
+#include "BKE_object.h"
 
 #include "BIF_gl.h"
 #include "BIF_mywindow.h"
@@ -861,6 +862,7 @@ static void drawlattice(Object *ob)
 		cpack(0x004000);
 	}
 	else {
+		lattice_modifier(ob, 's');
 		bp= lt->def;
 	}
 	
@@ -950,6 +952,8 @@ static void drawlattice(Object *ob)
 		
 		if(G.zbuf) glEnable(GL_DEPTH_TEST); 
 	}
+	else lattice_modifier(ob, 'e');
+
 }
 
 /* ***************** ******************** */
@@ -3701,6 +3705,33 @@ static void draw_extra_wire(Object *ob)
 	}
 }
 
+/* should be called in view space */
+static void draw_hooks(Object *ob)
+{
+	ObHook *hook;
+	float vec[3];
+	
+	for(hook= ob->hooks.first; hook; hook= hook->next) {
+		
+		VecMat4MulVecfl(vec, ob->obmat, hook->cent);
+		if(hook->parent) {
+			setlinestyle(3);
+			glBegin(GL_LINES);
+			glVertex3fv(hook->parent->obmat[3]);
+			glVertex3fv(vec);
+			glEnd();
+			setlinestyle(0);
+		}
+
+		glPointSize(3.0);
+		bglBegin(GL_POINTS);
+		bglVertex3fv(vec);
+		bglEnd();
+		glPointSize(1.0);
+
+	}
+}
+
 void draw_object(Base *base)
 {
 	PartEff *paf;
@@ -3873,6 +3904,17 @@ void draw_object(Base *base)
 		}
 	}
 
+	/* exception for mesh..., needs to be here for outline draw */
+	if(ob->type==OB_MESH) {
+		me= ob->data;
+		/* check for need for displist (it's zero when parent, key, or hook changed) */
+		if(ob->disp.first==NULL) {
+			if(ob->parent && ob->partype==PARSKEL) makeDispList(ob);
+			else if(ob->hooks.first) makeDispList(ob);
+			else if(mesh_uses_displist(me)) makeDispList(ob);
+		}
+	}
+	
 	/* draw outline for selected solid objects */
 	if(G.vd->flag & V3D_SELECT_OUTLINE) {
 		if(dt>OB_WIRE && ob!=G.obedit && (G.f & G_BACKBUFSEL)==0) {
@@ -3886,17 +3928,6 @@ void draw_object(Base *base)
 	case OB_MESH:
 		me= ob->data;
 
-#if 0
-		/* this is a source of great slowness */
-		/* Force a refresh of the display list if the parent is an armature */
-		if (ob->parent && ob->parent->type==OB_ARMATURE && ob->partype==PARSKEL){
-#if 0			/* Turn this on if there are problems with deformation lag */
-			where_is_armature (ob->parent);
-#endif
-			if (ob != G.obedit)
-				makeDispList (ob);
-		}
-#endif
 		if(base->flag & OB_RADIO);
 		else if(ob==G.obedit || (G.obedit && ob->data==G.obedit->data)) {
 			if(dt<=OB_WIRE) drawmeshwire(ob);
@@ -4013,7 +4044,7 @@ void draw_object(Base *base)
 		if(dtx & OB_DRAWIMAGE) drawDispListwire(&ob->disp);
 		if((dtx & OB_DRAWWIRE) && dt>=OB_SOLID) draw_extra_wire(ob);
 	}
-
+	
 	if(dt<OB_SHADED) {
 		if((ob->gameflag & OB_ACTOR) && (ob->gameflag & OB_DYNAMIC)) {
 			float tmat[4][4], imat[4][4], vec[3];
@@ -4040,6 +4071,9 @@ void draw_object(Base *base)
 	if((G.f & (G_BACKBUFSEL+G_PICKSEL))==0) {
 		ListBase *list;
 
+		/* draw hook center and offset line */
+		if(ob->hooks.first && ob!=G.obedit) draw_hooks(ob);
+
 		/* help lines and so */
 		if(ob->parent && (ob->parent->lay & G.vd->lay)) {
 			setlinestyle(3);
diff --git a/source/blender/src/editcurve.c b/source/blender/src/editcurve.c
index f6fc850064231f3c300129ca00f41071dd9f3944..1b2c202ae55dc298d5e72c059029c6837a3aa6fe 100644
--- a/source/blender/src/editcurve.c
+++ b/source/blender/src/editcurve.c
@@ -450,6 +450,8 @@ void separate_nurb()
 	
 	G.obedit= 0;	/* displists behave different in edit mode */
 	makeDispList(OBACT);	/* this is the separated one */
+
+	curve_changes_other_objects(oldob);
 	
 	G.obedit= oldob;
 	BASACT= oldbase;
@@ -1053,6 +1055,8 @@ void switchdirectionNurb2(void)
 	}
 	
 	makeDispList(G.obedit);
+	curve_changes_other_objects(G.obedit);
+
 	allqueue(REDRAWVIEW3D, 0);
 }
 
@@ -1714,6 +1718,8 @@ void subdivideNurb()
 
 
 	makeDispList(G.obedit);
+	curve_changes_other_objects(G.obedit);
+
 	countall();
 	allqueue(REDRAWVIEW3D, 0);
 	allqueue(REDRAWBUTSEDIT, 0);
@@ -2298,7 +2304,10 @@ void merge_nurb()
 	
 	countall();
 	lastnu= NULL;
+
 	makeDispList(G.obedit);
+	curve_changes_other_objects(G.obedit);
+
 	allqueue(REDRAWVIEW3D, 0);
 	allqueue(REDRAWBUTSEDIT, 0);
 }
@@ -2455,6 +2464,8 @@ void addsegment_nurb()
 		lastnu= NULL;	/* for selected */
 
 		makeDispList(G.obedit);
+		curve_changes_other_objects(G.obedit);
+
 		countall();
 		allqueue(REDRAWVIEW3D, 0);
 		allqueue(REDRAWBUTSEDIT, 0);
@@ -2653,6 +2664,24 @@ void spinNurb(float *dvec, short mode)
 	}
 }
 
+void curve_changes_other_objects(Object *ob)
+{
+	Base *base= FIRSTBASE;
+	while(base) {
+		if(base->lay & G.vd->lay) {
+			if(base->object->parent==ob && base->object->partype==PARSKEL)
+				freedisplist(&base->object->disp);
+			
+			if(base->object->type==OB_CURVE) {
+				Curve *cu= base->object->data;
+				if(ob==cu->bevobj || ob==cu->taperobj)
+					makeDispList(base->object);
+			}
+		}
+		base= base->next;
+	}
+}
+
 void addvert_Nurb(int mode)
 {
 	Nurb *nu;
@@ -2787,17 +2816,7 @@ void addvert_Nurb(int mode)
 
 	if(mode!='e') {
 		/* dependencies with other objects, should become event */
-		Base *base= FIRSTBASE;
-		while(base) {
-			if(base->lay & G.vd->lay) {
-				if(base->object->type==OB_CURVE) {
-					Curve *cu= base->object->data;
-					if(G.obedit==cu->bevobj || G.obedit==cu->taperobj)
-						makeDispList(base->object);
-				}
-			}
-			base= base->next;
-		}
+		curve_changes_other_objects(G.obedit);
 	}
 }
 
@@ -2941,6 +2960,8 @@ void makecyclicNurb()
 		nu= nu->next;
 	}
 	makeDispList(G.obedit);
+	curve_changes_other_objects(G.obedit);
+
 }
 
 void selectconnected_nurb()
@@ -3325,6 +3346,8 @@ void delNurb()
 
 	countall();
 	makeDispList(G.obedit);
+	curve_changes_other_objects(G.obedit);
+
 	allqueue(REDRAWVIEW3D, 0);
 	allqueue(REDRAWBUTSEDIT, 0);
 }
@@ -3880,7 +3903,8 @@ void add_primitiveCurve(int stype)
 	
 	BLI_addtail(&editNurb, nu);
 	makeDispList(G.obedit);
-	
+	curve_changes_other_objects(G.obedit);
+
 	countall();
 	allqueue(REDRAWALL, 0);
 }
@@ -4061,7 +4085,6 @@ void undo_push_curve(char *name)
 /* 1= an undo, -1 is a redo. we have to make sure 'curundo' remains at previous step */
 void undo_curve_step(int step)
 {
-	Base *base;
 	UndoElem *uel, *next;
 	
 	/* prevent undo to happen on wrong object */
@@ -4108,19 +4131,7 @@ void undo_curve_step(int step)
 	lastnu= NULL;	/* for selected */
 
 	makeDispList(G.obedit);
-
-	/* dependencies with other objects */
-	base= FIRSTBASE;
-	while(base) {
-		if(base->lay & G.vd->lay) {
-			if(base->object->type==OB_CURVE) {
-				Curve *cu= base->object->data;
-				if(G.obedit==cu->bevobj || G.obedit==cu->taperobj)
-					makeDispList(base->object);
-			}
-		}
-		base= base->next;
-	}
+	curve_changes_other_objects(G.obedit);
 
 	countall();
 	allqueue(REDRAWVIEW3D, 0);
diff --git a/source/blender/src/editobject.c b/source/blender/src/editobject.c
index b3fdef709ecc4c838858348282853737420b4bb3..a8399aa0bc73a689f1c81b5c2d3df6ca641b505c 100644
--- a/source/blender/src/editobject.c
+++ b/source/blender/src/editobject.c
@@ -224,14 +224,11 @@ void free_and_unlink_base(Base *base)
 void delete_obj(int ok)
 {
 	Base *base;
-extern int undo_push(char *);
 	
 	if(G.obpose) return;
 	if(G.obedit) return;
 	if(G.scene->id.lib) return;
 	
-//if (undo_push("Erase")) return;	
-	
 	base= FIRSTBASE;
 	while(base) {
 		Base *nbase= base->next;
@@ -260,6 +257,381 @@ extern int undo_push(char *);
 	allqueue(REDRAWNLA, 0);
 }
 
+int return_editmesh_indexar(int **indexar, float *cent)
+{
+	EditMesh *em = G.editMesh;
+	EditVert *eve;
+	int *index, nr, totvert=0;
+	
+	for(eve= em->verts.first; eve; eve= eve->next) {
+		if(eve->f & SELECT) totvert++;
+	}
+	if(totvert==0) return 0;
+	
+	*indexar= index= MEM_mallocN(4*totvert, "hook indexar");
+	nr= 0;
+	cent[0]= cent[1]= cent[2]= 0.0;
+	
+	for(eve= em->verts.first; eve; eve= eve->next) {
+		if(eve->f & SELECT) {
+			*index= nr; index++;
+			VecAddf(cent, cent, eve->co);
+		}
+		nr++;
+	}
+	
+	VecMulf(cent, 1.0/(float)totvert);
+	
+	return totvert;
+}
+
+static void select_editmesh_hook(ObHook *hook)
+{
+	EditMesh *em = G.editMesh;
+	EditVert *eve;
+	int index=0, nr=0;
+	
+	for(eve= em->verts.first; eve; eve= eve->next, nr++) {
+		if(nr==hook->indexar[index]) {
+			eve->f |= SELECT;
+			if(index < hook->totindex-1) index++;
+		}
+	}
+}
+
+int return_editlattice_indexar(int **indexar, float *cent)
+{
+	BPoint *bp;
+	int *index, nr, totvert=0, a;
+	
+	// count
+	a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
+	bp= editLatt->def;
+	while(a--) {
+		if(bp->f1 & SELECT) {
+			if(bp->hide==0) totvert++;
+		}
+		bp++;
+	}
+
+	if(totvert==0) return 0;
+	
+	*indexar= index= MEM_mallocN(4*totvert, "hook indexar");
+	nr= 0;
+	cent[0]= cent[1]= cent[2]= 0.0;
+	
+	a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
+	bp= editLatt->def;
+	while(a--) {
+		if(bp->f1 & SELECT) {
+			if(bp->hide==0) {
+				*index= nr; index++;
+				VecAddf(cent, cent, bp->vec);
+			}
+		}
+		bp++;
+		nr++;
+	}
+	
+	VecMulf(cent, 1.0/(float)totvert);
+	
+	return totvert;
+}
+
+static void select_editlattice_hook(ObHook *hook)
+{
+	BPoint *bp;
+	int index=0, nr=0, a;
+	
+	// count
+	a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
+	bp= editLatt->def;
+	while(a--) {
+		if(hook->indexar[index]==nr) {
+			bp->f1 |= SELECT;
+			if(index < hook->totindex-1) index++;
+		}
+		nr++;
+		bp++;
+	}
+}
+
+int return_editcurve_indexar(int **indexar, float *cent)
+{
+	extern ListBase editNurb;
+	Nurb *nu;
+	BPoint *bp;
+	BezTriple *bezt;
+	int *index, a, nr, totvert=0;
+	
+	for(nu= editNurb.first; nu; nu= nu->next) {
+		if((nu->type & 7)==CU_BEZIER) {
+			bezt= nu->bezt;
+			a= nu->pntsu;
+			while(a--) {
+				if(bezt->f1 & SELECT) totvert++;
+				if(bezt->f2 & SELECT) totvert++;
+				if(bezt->f3 & SELECT) totvert++;
+				bezt++;
+			}
+		}
+		else {
+			bp= nu->bp;
+			a= nu->pntsu*nu->pntsv;
+			while(a--) {
+				if(bp->f1 & SELECT) totvert++;
+				bp++;
+			}
+		}
+	}
+	if(totvert==0) return 0;
+	
+	*indexar= index= MEM_mallocN(4*totvert, "hook indexar");
+	nr= 0;
+	cent[0]= cent[1]= cent[2]= 0.0;
+	
+	for(nu= editNurb.first; nu; nu= nu->next) {
+		if((nu->type & 7)==CU_BEZIER) {
+			bezt= nu->bezt;
+			a= nu->pntsu;
+			while(a--) {
+				if(bezt->f1 & SELECT) {
+					*index= nr; index++;
+					VecAddf(cent, cent, bezt->vec[0]);
+				}
+				nr++;
+				if(bezt->f2 & SELECT) {
+					*index= nr; index++;
+					VecAddf(cent, cent, bezt->vec[1]);
+				}
+				nr++;
+				if(bezt->f3 & SELECT) {
+					*index= nr; index++;
+					VecAddf(cent, cent, bezt->vec[2]);
+				}
+				nr++;
+				bezt++;
+			}
+		}
+		else {
+			bp= nu->bp;
+			a= nu->pntsu*nu->pntsv;
+			while(a--) {
+				if(bp->f1 & SELECT) {
+					*index= nr; index++;
+					VecAddf(cent, cent, bp->vec);
+				}
+				nr++;
+				bp++;
+			}
+		}
+	}
+	
+	VecMulf(cent, 1.0/(float)totvert);
+	
+	return totvert;
+}
+
+static void select_editcurve_hook(ObHook *hook)
+{
+	extern ListBase editNurb;
+	Nurb *nu;
+	BPoint *bp;
+	BezTriple *bezt;
+	int index=0, a, nr=0;
+	
+	for(nu= editNurb.first; nu; nu= nu->next) {
+		if((nu->type & 7)==CU_BEZIER) {
+			bezt= nu->bezt;
+			a= nu->pntsu;
+			while(a--) {
+				if(nr == hook->indexar[index]) {
+					bezt->f1 |= SELECT;
+					if(index<hook->totindex-1) index++;
+				}
+				nr++;
+				if(nr == hook->indexar[index]) {
+					bezt->f2 |= SELECT;
+					if(index<hook->totindex-1) index++;
+				}
+				nr++;
+				if(nr == hook->indexar[index]) {
+					bezt->f3 |= SELECT;
+					if(index<hook->totindex-1) index++;
+				}
+				nr++;
+
+				bezt++;
+			}
+		}
+		else {
+			bp= nu->bp;
+			a= nu->pntsu*nu->pntsv;
+			while(a--) {
+				if(nr == hook->indexar[index]) {
+					bp->f1 |= SELECT;
+					if(index<hook->totindex-1) index++;
+				}
+				nr++;
+				bp++;
+			}
+		}
+	}
+}
+
+void add_hook(void)
+{
+	Object *ob=NULL;
+	ObHook *hook=NULL;
+	float cent[3];
+	int tot=0, *indexar, mode;
+
+	if(G.obedit==NULL) return;
+	
+	if(G.obedit->hooks.first)
+		mode= pupmenu("Hooks %t|Add Hook, To New Empty %x1|Add Hook, To Selected Object %x2|Remove... %x3|Reassign... %x4|Select... %x5|Clear Offset...%x6");
+	else
+		mode= pupmenu("Hooks %t|Add, New Empty %x1|Add, To Selected Object %x2");
+
+	if(mode<1) return;
+	
+	/* preconditions */
+
+	if(mode==2) { // selected object
+		Base *base= FIRSTBASE;
+		while(base) {
+			if TESTBASELIB(base) {
+				if(base!=BASACT) {
+					ob= base->object;
+					break;
+				}
+			}
+			base= base->next;
+		}
+		if(ob==NULL) {
+			error("Requires selected Object");
+			return;
+		}
+	}
+	else if(mode!=1) {
+		int maxlen=0, a, nr;
+		char *cp;
+		
+		// make pupmenu with hooks
+		for(hook= G.obedit->hooks.first; hook; hook= hook->next) maxlen+=32;
+		
+		if(maxlen==0) {
+			error("Object has no hooks yet");
+			return;
+		}
+		
+		cp= MEM_callocN(maxlen+32, "temp string");
+		if(mode==3) strcpy(cp, "Remove %t|");
+		else if(mode==4) strcpy(cp, "Reassign %t|");
+		else if(mode==5) strcpy(cp, "Select %t|");
+		else if(mode==6) strcpy(cp, "Clear Offset %t|");
+		
+		for(hook= G.obedit->hooks.first; hook; hook= hook->next) {
+			strcat(cp, hook->name);
+			strcat(cp, " |");
+		}
+	
+		nr= pupmenu(cp);
+		MEM_freeN(cp);
+		
+		if(nr<1) return;
+		
+		a= 1;
+		for(hook= G.obedit->hooks.first; hook; hook= hook->next, a++) {
+			if(a==nr) break;
+		}
+		ob= hook->parent;
+	}
+
+	/* do it, new hooks or reassign */
+	if(mode==1 || mode==2 || mode==4) {
+	
+		switch(G.obedit->type) {
+		case OB_MESH:
+			tot= return_editmesh_indexar(&indexar, cent);
+			break;
+		case OB_CURVE:
+		case OB_SURF:
+			tot= return_editcurve_indexar(&indexar, cent);
+			break;
+		case OB_LATTICE:
+			tot= return_editlattice_indexar(&indexar, cent);
+			break;
+		}
+		
+		if(tot==0) {
+			error("Requires selected vertices");
+		}
+		else {
+			
+			if(mode==1) {
+				Base *base= BASACT;
+
+				ob= add_object(OB_EMPTY);
+				/* transform cent to global coords for loc */
+				VecMat4MulVecfl(ob->loc, G.obedit->obmat, cent);
+				
+				/* restore, add_object sets active */
+				BASACT= base;
+			}
+			/* if mode is 2 or 4, ob has been set */
+									
+			/* new hook */
+			if(mode==1 || mode==2) {
+				hook= MEM_callocN(sizeof(ObHook), "new hook");
+				BLI_addtail(&G.obedit->hooks, hook);
+				strncpy(hook->name, ob->id.name+2, 30);
+				hook->force= 1.0;
+			}
+			else MEM_freeN(hook->indexar); // reassign, hook was set
+
+			hook->parent= ob;
+			hook->indexar= indexar;
+			VECCOPY(hook->cent, cent);
+			hook->totindex= tot;
+			
+			if(mode==1 || mode==2) {
+				/* matrix calculus */
+				/* vert x (obmat x hook->imat) x hook->obmat x ob->imat */
+				/*        (parentinv         )                          */
+				
+				where_is_object(ob);
+		
+				Mat4Invert(ob->imat, ob->obmat);
+				/* apparently this call goes from right to left... */
+				Mat4MulSerie(hook->parentinv, ob->imat, G.obedit->obmat, NULL, 
+							NULL, NULL, NULL, NULL, NULL);
+			}
+		}
+	}
+	else if(mode==3) { // remove
+		BLI_remlink(&G.obedit->hooks, hook);
+		MEM_freeN(hook->indexar);
+		MEM_freeN(hook);
+	}
+	else if(mode==5) { // select
+		if(G.obedit->type==OB_MESH) select_editmesh_hook(hook);
+		else if(G.obedit->type==OB_LATTICE) select_editlattice_hook(hook);
+		else if(G.obedit->type==OB_CURVE) select_editcurve_hook(hook);
+		else if(G.obedit->type==OB_SURF) select_editcurve_hook(hook);
+	}
+	else if(mode==6) { // clear offset
+		where_is_object(ob);	// ob is hook->parent
+
+		Mat4Invert(ob->imat, ob->obmat);
+		/* this call goes from right to left... */
+		Mat4MulSerie(hook->parentinv, ob->imat, G.obedit->obmat, NULL, 
+					NULL, NULL, NULL, NULL, NULL);
+	}
+
+	allqueue(REDRAWVIEW3D, 0);
+	allqueue(REDRAWBUTSOBJECT, 0);
+}
 
 void make_track(void)
 {
@@ -463,6 +835,7 @@ void clear_track(void)
 void clear_object(char mode)
 {
 	Base *base;
+	Object *ob;
 	float *v1, *v3, mat[3][3];
 	
 	if(G.obedit) return;
@@ -492,28 +865,30 @@ void clear_object(char mode)
 	base= FIRSTBASE;
 	while(base) {
 		if TESTBASELIB(base) {
+			ob= base->object;
+			
 			if(mode=='r') {
-				memset(base->object->rot, 0, 3*sizeof(float));
-				memset(base->object->drot, 0, 3*sizeof(float));
-				QuatOne(base->object->quat);
-				QuatOne(base->object->dquat);
+				memset(ob->rot, 0, 3*sizeof(float));
+				memset(ob->drot, 0, 3*sizeof(float));
+				QuatOne(ob->quat);
+				QuatOne(ob->dquat);
 			}
 			else if(mode=='g') {
-				memset(base->object->loc, 0, 3*sizeof(float));
-				memset(base->object->dloc, 0, 3*sizeof(float));
+				memset(ob->loc, 0, 3*sizeof(float));
+				memset(ob->dloc, 0, 3*sizeof(float));
 			}
 			else if(mode=='s') {
-				memset(base->object->dsize, 0, 3*sizeof(float));
-				base->object->size[0]= 1.0;
-				base->object->size[1]= 1.0;
-				base->object->size[2]= 1.0;
+				memset(ob->dsize, 0, 3*sizeof(float));
+				ob->size[0]= 1.0;
+				ob->size[1]= 1.0;
+				ob->size[2]= 1.0;
 			}
 			else if(mode=='o') {
-				if(base->object->parent) {
-					v1= base->object->loc;
-					v3= base->object->parentinv[3];
+				if(ob->parent) {
+					v1= ob->loc;
+					v3= ob->parentinv[3];
 					
-					Mat3CpyMat4(mat, base->object->parentinv);
+					Mat3CpyMat4(mat, ob->parentinv);
 					VECCOPY(v3, v1);
 					v3[0]= -v3[0];
 					v3[1]= -v3[1];
@@ -521,6 +896,11 @@ void clear_object(char mode)
 					Mat3MulVecfl(mat, v3);
 				}
 			}
+			
+			if(ob->parent && ob->partype==PARSKEL)
+				freedisplist(&ob->disp);
+			else if(ob->hooks.first)
+				freedisplist(&ob->disp);
 		}
 		base= base->next;
 	}
@@ -768,11 +1148,17 @@ void make_parent(void)
 		bConstraint *con;
 		bFollowPathConstraint *data;
 
-		mode= pupmenu("Make Parent %t|Normal Parent %x1|Follow Path %x2");
-		if (mode == 0){
+		mode= pupmenu("Make Parent %t|Normal Parent %x1|Follow Path %x2|Curve Deform %x3");
+		if(mode==0){
 			return;
 		}
-		else if (mode == 2){
+		else if(mode==1) {
+			mode= PAROBJECT;
+		}
+		else if(mode==3) {
+			mode= PARSKEL;
+		}
+		else if(mode==2) {
 
 			base= FIRSTBASE;
 			while(base) {
@@ -936,6 +1322,8 @@ void make_parent(void)
 					}
 					else {
 						
+						/* the ifs below are horrible code (ton) */
+						
 						if(par->type==OB_IKA){
 							base->object->partype= mode;
 							base->object->par1= limbnr;
@@ -947,14 +1335,17 @@ void make_parent(void)
 							else
 								base->object->parsubstr[0]=0;
 						}
-						
-						else if(qual & LR_ALTKEY) {
-							base->object->partype= PARVERT1;
-						}
 						else {
-							base->object->partype= PAROBJECT;
+							if(qual & LR_ALTKEY) {
+								base->object->partype= PARVERT1;
+							}
+							else if(par->type==OB_CURVE) {
+								base->object->partype= mode;
+							}
+							else {
+								base->object->partype= PAROBJECT;
+							}
 						}
-						
 						base->object->parent= par;
 						
 						/* calculate inverse parent matrix? */
@@ -983,7 +1374,7 @@ void make_parent(void)
 						}
 						
 						if(par->type==OB_LATTICE) makeDispList(base->object);
-						if(par->type==OB_IKA && mode==PARSKEL) makeDispList(base->object);
+						if(par->type==OB_CURVE && mode==PARSKEL) makeDispList(base->object);
 						if(par->type==OB_ARMATURE && mode == PARSKEL){
 							verify_defgroups(base->object);
 							makeDispList(base->object);
@@ -3100,8 +3491,18 @@ static void setbaseflags_for_editing(int mode)	/* 0,'g','r','s' */
 			base->flag= BA_PARSEL
 				
 	*/
-	GHash *object_to_base_hash= NULL; /* built on demand, see below - zr */
+	GHash *object_to_base_hash= NULL; 
 	Base *base;
+
+	/* moved to start of function, it is needed for hooks now too */
+	if (!object_to_base_hash) {
+		Base *b;
+		object_to_base_hash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+		
+		for (b= FIRSTBASE; b; b= b->next)
+			BLI_ghash_insert(object_to_base_hash, b->object, b);
+	}
+	
 	
 	copy_baseflags();
 
@@ -3133,14 +3534,36 @@ static void setbaseflags_for_editing(int mode)	/* 0,'g','r','s' */
 				if(ika->parent && parsel) base->flag |= BA_WHERE_UPDATE;
 			}
 			
+			if(ob->hooks.first) {
+				Base *b;
+				ObHook *hook= ob->hooks.first;
+				
+				while(hook) {
+					if(hook->parent) {
+						Object *parsel= is_a_parent_selected(hook->parent);
+						
+						b= BLI_ghash_lookup(object_to_base_hash, hook->parent);
+						if(parsel || ((base->flag | b->flag) & (SELECT | BA_PARSEL)) ) {
+							base->flag |= BA_DISP_UPDATE;
+						}
+					}
+					hook= hook->next;
+				}
+			}
+			
+			if(ob->parent && ob->parent->type==OB_LATTICE)
+				if(ob->parent->hooks.first) base->flag |= BA_DISP_UPDATE;
+			
 			if(base->flag & (SELECT | BA_PARSEL)) {
 				
 				base->flag |= BA_WHERE_UPDATE;
 				
 				if(ob->parent) {
 					if(ob->parent->type==OB_LATTICE) base->flag |= BA_DISP_UPDATE;
-					if(ob->parent->type==OB_IKA && ob->partype==PARSKEL) base->flag |= BA_DISP_UPDATE;
-					if(ob->parent->type==OB_ARMATURE && ob->partype==PARSKEL) base->flag |= BA_DISP_UPDATE;
+					else if(ob->partype==PARSKEL) {
+						if ELEM3(ob->parent->type, OB_IKA, OB_CURVE, OB_ARMATURE) 
+							base->flag |= BA_DISP_UPDATE;
+					}
 				}
 				if(ob->track) {
 					;
@@ -3151,16 +3574,6 @@ static void setbaseflags_for_editing(int mode)	/* 0,'g','r','s' */
 				if(ob->type==OB_MBALL) {
 					Base *b;
 					
-						/* Only bother building the object to base
-						 * hash if we are going to be needing it... - zr
-						 */
-					if (!object_to_base_hash) {
-						object_to_base_hash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
-						
-						for (b= FIRSTBASE; b; b= b->next)
-							BLI_ghash_insert(object_to_base_hash, b->object, b);
-					}
-
 					b= BLI_ghash_lookup(object_to_base_hash, find_basis_mball(ob));
 					b->flag |= BA_DISP_UPDATE;
 				}
@@ -3693,14 +4106,16 @@ void special_trans_update(int keyflags)
 	if(G.obedit) {
 		if(G.obedit->type==OB_CURVE) {
 			cu= G.obedit->data;
-			if(cu->flag & CU_3D) makeBevelList(G.obedit);
 			
+			makeBevelList(G.obedit); // might be needed for deform
 			calc_curvepath(G.obedit);
 			
 			base= FIRSTBASE;
 			while(base) {
 				if(base->lay & G.vd->lay) {
-					if(base->object->type==OB_CURVE) {
+					if(base->object->parent==G.obedit && base->object->partype==PARSKEL)
+						makeDispList(base->object);
+					else if(base->object->type==OB_CURVE) {
 						Curve *cu= base->object->data;
 						if(G.obedit==cu->bevobj || G.obedit==cu->taperobj)
 							makeDispList(base->object);
diff --git a/source/blender/src/space.c b/source/blender/src/space.c
index 6300139888c1651c47848e2dbc18669216f8f529..64a62af930f6b2191ab09b13ffc7f688231d9809 100644
--- a/source/blender/src/space.c
+++ b/source/blender/src/space.c
@@ -1127,7 +1127,9 @@ void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
 			case HKEY:
 				if(G.obedit) {
 					if(G.obedit->type==OB_MESH) {
-						if(G.qual==LR_ALTKEY)
+						if(G.qual==LR_CTRLKEY)
+							add_hook();
+						else if(G.qual==LR_ALTKEY)
 							reveal_mesh();
 						else if((G.qual==LR_SHIFTKEY))
 							hide_mesh(1);
@@ -1135,7 +1137,9 @@ void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
 							hide_mesh(0);
 					}
 					else if(G.obedit->type== OB_SURF) {
-						if(G.qual==LR_ALTKEY)
+						if(G.qual==LR_CTRLKEY)
+							add_hook();
+						else if(G.qual==LR_ALTKEY)
 							revealNurb();
 						else if((G.qual==LR_SHIFTKEY))
 							hideNurb(1);
@@ -1143,17 +1147,24 @@ void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
 							hideNurb(0);
 					}
 					else if(G.obedit->type==OB_CURVE) {
-						undo_push_curve("Handle change");
 						if(G.qual==LR_CTRLKEY)
-							autocalchandlesNurb_all(1);	/* flag=1, selected */
-						else if((G.qual==LR_SHIFTKEY))
-							sethandlesNurb(1);
-						else if((G.qual==0))
-							sethandlesNurb(3);
-						
-						makeDispList(G.obedit);
-						
-						allqueue(REDRAWVIEW3D, 0);
+							add_hook();
+						else {
+							undo_push_curve("Handle change");
+							if(G.qual==LR_CTRLKEY)
+								autocalchandlesNurb_all(1);	/* flag=1, selected */
+							else if((G.qual==LR_SHIFTKEY))
+								sethandlesNurb(1);
+							else if((G.qual==0))
+								sethandlesNurb(3);
+							
+							makeDispList(G.obedit);
+							
+							allqueue(REDRAWVIEW3D, 0);
+						}
+					}
+					else if(G.obedit->type==OB_LATTICE) {
+						if(G.qual==LR_CTRLKEY) add_hook();
 					}
 				}
 				else if(G.f & G_FACESELECT)