2.5
[blender-staging.git] / source / blender / editors / object / object_edit.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * Contributor(s): Blender Foundation, 2002-2008 full recode
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27 #include <stdlib.h>
28 #include <string.h>
29 #include <math.h>
30 #include <time.h>
31
32 #include "MEM_guardedalloc.h"
33
34 #include "IMB_imbuf_types.h"
35
36 #include "DNA_action_types.h"
37 #include "DNA_armature_types.h"
38 #include "DNA_camera_types.h"
39 #include "DNA_constraint_types.h"
40 #include "DNA_curve_types.h"
41 #include "DNA_effect_types.h"
42 #include "DNA_group_types.h"
43 #include "DNA_image_types.h"
44 #include "DNA_ipo_types.h"
45 #include "DNA_key_types.h"
46 #include "DNA_lamp_types.h"
47 #include "DNA_lattice_types.h"
48 #include "DNA_material_types.h"
49 #include "DNA_mesh_types.h"
50 #include "DNA_meshdata_types.h"
51 #include "DNA_meta_types.h"
52 #include "DNA_nla_types.h"
53 #include "DNA_object_types.h"
54 #include "DNA_object_fluidsim.h"
55 #include "DNA_object_force.h"
56 #include "DNA_scene_types.h"
57 #include "DNA_space_types.h"
58 #include "DNA_screen_types.h"
59 #include "DNA_texture_types.h"
60 #include "DNA_particle_types.h"
61 #include "DNA_property_types.h"
62 #include "DNA_userdef_types.h"
63 #include "DNA_view3d_types.h"
64 #include "DNA_vfont_types.h"
65 #include "DNA_world_types.h"
66 #include "DNA_modifier_types.h"
67
68 #include "BLI_blenlib.h"
69 #include "BLI_arithb.h"
70 #include "BLI_editVert.h"
71 #include "BLI_ghash.h"
72 #include "BLI_rand.h"
73
74 #include "BKE_action.h"
75 #include "BKE_anim.h"
76 #include "BKE_armature.h"
77 #include "BKE_booleanops.h"
78 #include "BKE_constraint.h"
79 #include "BKE_context.h"
80 #include "BKE_customdata.h"
81 #include "BKE_blender.h"
82 #include "BKE_booleanops.h"
83 #include "BKE_cloth.h"
84 #include "BKE_curve.h"
85 #include "BKE_displist.h"
86 #include "BKE_depsgraph.h"
87 #include "BKE_DerivedMesh.h"
88 #include "BKE_effect.h"
89 #include "BKE_font.h"
90 #include "BKE_global.h"
91 #include "BKE_group.h"
92 #include "BKE_ipo.h"
93 #include "BKE_image.h"
94 #include "BKE_key.h"
95 #include "BKE_lattice.h"
96 #include "BKE_library.h"
97 #include "BKE_main.h"
98 #include "BKE_material.h"
99 #include "BKE_mball.h"
100 #include "BKE_mesh.h"
101 #include "BKE_multires.h"
102 #include "BKE_nla.h"
103 #include "BKE_object.h"
104 #include "BKE_particle.h"
105 #include "BKE_property.h"
106 #include "BKE_sca.h"
107 #include "BKE_scene.h"
108 #include "BKE_softbody.h"
109 #include "BKE_subsurf.h"
110 #include "BKE_texture.h"
111 #include "BKE_utildefines.h"
112 #include "BKE_modifier.h"
113
114 #include "ED_anim_api.h"
115 #include "ED_mesh.h"
116 #include "ED_object.h"
117 #include "ED_screen.h"
118 #include "ED_types.h"
119 #include "ED_util.h"
120 #include "ED_view3d.h"
121
122 #include "BMF_Api.h"
123
124 #include "UI_interface.h"
125
126 #include "RNA_access.h"
127 #include "RNA_define.h"
128
129 /* for menu/popup icons etc etc*/
130 #include "UI_interface.h"
131 #include "UI_resources.h"
132
133 #include "WM_api.h"
134 #include "WM_types.h"
135
136 #include "object_intern.h"      // own include
137
138 /* ************* XXX **************** */
139 static void allqueue() {}
140 static void BIF_undo_push() {}
141 static void error() {}
142 static void waitcursor() {}
143 static int pupmenu() {return 0;}
144 static int pupmenu_col() {return 0;}
145 static int okee() {return 0;}
146 static void EM_select_flush() {}
147
148 /* port over here */
149 static bContext *C;
150 static void error_libdata() {}
151
152 /* ********************************** */
153
154 /* --------------------------------- */
155
156 /* simple API for object selection, rather than just using the flag
157  * this takes into account the 'restrict selection in 3d view' flag.
158  * deselect works always, the restriction just prevents selection */
159
160 /* Note: send a NC_SCENE|ND_OB_SELECT notifier yourself! */
161
162 void ED_base_object_select(Base *base, short mode)
163 {
164         if (base) {
165                 if (mode==BA_SELECT) {
166                         if (!(base->object->restrictflag & OB_RESTRICT_SELECT))
167                                 if (mode==BA_SELECT) base->flag |= SELECT;
168                 }
169                 else if (mode==BA_DESELECT) {
170                         base->flag &= ~SELECT;
171                 }
172                 base->object->flag= base->flag;
173         }
174 }
175
176 /* also to set active NULL */
177 void ED_base_object_activate(bContext *C, Base *base)
178 {
179         Scene *scene= CTX_data_scene(C);
180         Base *tbase;
181         
182         /* activating a non-mesh, should end a couple of modes... */
183         //      if(base && base->object->type!=OB_MESH)
184         // XXX          exit_paint_modes();
185         
186         /* sets scene->basact */
187         BASACT= base;
188         
189         if(base) {
190                 
191                 /* XXX old signals, remember to handle notifiers now! */
192                 //              allqueue(REDRAWIPO, base->object->ipowin);
193                 //              select_actionchannel_by_name(base->object->action, "Object", 1);
194                 
195                 /* disable temporal locks */
196                 for(tbase=FIRSTBASE; tbase; tbase= tbase->next) {
197                         if(base!=tbase && (tbase->object->shapeflag & OB_SHAPE_TEMPLOCK)) {
198                                 tbase->object->shapeflag &= ~OB_SHAPE_TEMPLOCK;
199                                 DAG_object_flush_update(scene, tbase->object, OB_RECALC_DATA);
200                         }
201                 }
202                 WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, scene);
203         }
204         else
205                 WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, NULL);
206 }
207
208
209
210
211 /*
212  * Returns true if the Object is a from an external blend file (libdata)
213  */
214 int object_is_libdata(Object *ob)
215 {
216         if (!ob) return 0;
217         if (ob->proxy) return 0;
218         if (ob->id.lib) return 1;
219         return 0;
220 }
221
222
223 /*
224  * Returns true if the Object data is a from an external blend file (libdata)
225  */
226 int object_data_is_libdata(Object *ob)
227 {
228         if (!ob) return 0;
229         if (ob->proxy) return 0;
230         if (ob->id.lib) return 1;
231         if (!ob->data) return 0;
232         if (((ID *)ob->data)->lib) return 1;
233         return 0;
234 }
235
236
237
238 void exit_paint_modes(void)
239 {
240 #if 0
241         if(G.f & G_VERTEXPAINT) set_vpaint();
242         if(G.f & G_TEXTUREPAINT) set_texturepaint();
243         if(G.f & G_WEIGHTPAINT) set_wpaint();
244         if(G.f & G_SCULPTMODE) set_sculptmode();
245         if(G.f & G_PARTICLEEDIT) PE_set_particle_edit();
246
247         G.f &= ~(G_VERTEXPAINT+G_TEXTUREPAINT+G_WEIGHTPAINT+G_SCULPTMODE+G_PARTICLEEDIT);
248 #endif
249 }
250
251 void add_object_draw(Scene *scene, View3D *v3d, int type)       /* for toolbox or menus, only non-editmode stuff */
252 {
253         Object *ob;
254         
255         exit_paint_modes();
256
257 // XXX  if (G.obedit) ED_object_exit_editmode(C, EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR); /* freedata, and undo */
258         ob= add_object(type);
259 //      ED_base_object_activate(C, BASACT);
260         base_init_from_view3d(BASACT, v3d);
261         
262         /* only undo pushes on objects without editmode... */
263         if(type==OB_EMPTY) BIF_undo_push("Add Empty");
264         else if(type==OB_LAMP) {
265                 BIF_undo_push("Add Lamp");
266                 reshadeall_displist();  /* only frees */
267         }
268         else if(type==OB_LATTICE) BIF_undo_push("Add Lattice");
269         else if(type==OB_CAMERA) BIF_undo_push("Add Camera");
270                 
271         allqueue(REDRAWVIEW3D, 0);
272
273 // XXX  redraw_test_buttons(OBACT);
274
275         allqueue(REDRAWALL, 0);
276
277 // XXX  deselect_all_area_oops();
278 // XXX  set_select_flag_oops();
279         
280         DAG_scene_sort(scene);
281         allqueue(REDRAWINFO, 1);        /* 1, because header->win==0! */
282 }
283
284 void add_objectLamp(Scene *scene, View3D *v3d, short type)
285 {
286         Lamp *la;
287
288         if(G.obedit==0) {
289                 add_object_draw(scene, v3d, OB_LAMP);
290                 base_init_from_view3d(BASACT, v3d);
291         }
292         
293         la = BASACT->object->data;
294         la->type = type;        
295
296         allqueue(REDRAWALL, 0);
297 }
298
299 /* remove base from a specific scene */
300 /* note: now unlinks constraints as well */
301 void ED_base_object_free_and_unlink(Scene *scene, Base *base)
302 {
303         BLI_remlink(&scene->base, base);
304         free_libblock_us(&G.main->object, base->object);
305         if(scene->basact==base) scene->basact= NULL;
306         MEM_freeN(base);
307 }
308
309 void delete_obj(Scene *scene, View3D *v3d, int ok)
310 {
311         Base *base, *nbase;
312         int islamp= 0;
313         
314         if(G.obedit) return;
315         if(scene->id.lib) return;
316
317         for(base= FIRSTBASE; base; base= nbase) {
318                 nbase= base->next;
319
320                 if(TESTBASE(v3d, base)) { 
321                         if(ok==0) {
322                                 int shift= 0; // XXX
323                                 /* Shift Del is global delete */
324                                 if (shift) {
325                                         if(!okee("Erase selected Object(s) Globally")) return;
326                                         ok= 2;
327                                 } else {
328                                         if(!okee("Erase selected Object(s)")) return;
329                                         ok= 1;
330                                 }
331                         }
332                         
333                         exit_paint_modes();
334
335                         if(base->object->type==OB_LAMP) islamp= 1;
336
337                         if (ok==2) {
338                                 Scene *scene; 
339                                 Base *base_other;
340                                 
341                                 for (scene= G.main->scene.first; scene; scene= scene->id.next) {
342                                         if (scene != scene && !(scene->id.lib)) {
343                                                 base_other= object_in_scene( base->object, scene );
344                                                 if (base_other) {
345                                                         ED_base_object_free_and_unlink( scene, base_other );
346                                                 }
347                                         }
348                                 }
349                         }
350                         
351                         /* remove from current scene only */
352                         ED_base_object_free_and_unlink(scene, base);
353                 }
354         }
355
356         if(islamp) reshadeall_displist();       /* only frees displist */
357
358 // XXX  redraw_test_buttons(OBACT);
359         allqueue(REDRAWVIEW3D, 0);
360         allqueue (REDRAWACTION, 0);
361         allqueue(REDRAWIPO, 0);
362         allqueue(REDRAWDATASELECT, 0);
363 //      allspace(OOPS_TEST, 0);
364         allqueue(REDRAWOOPS, 0);
365         allqueue(REDRAWACTION, 0);
366         allqueue(REDRAWNLA, 0);
367         
368         DAG_scene_sort(scene);
369         ED_anim_dag_flush_update(C);    
370
371         BIF_undo_push("Delete object(s)");
372 }
373
374 static int return_editmesh_indexar(EditMesh *em, int *tot, int **indexar, float *cent)
375 {
376         EditVert *eve;
377         int *index, nr, totvert=0;
378         
379         for(eve= em->verts.first; eve; eve= eve->next) {
380                 if(eve->f & SELECT) totvert++;
381         }
382         if(totvert==0) return 0;
383         
384         *indexar= index= MEM_mallocN(4*totvert, "hook indexar");
385         *tot= totvert;
386         nr= 0;
387         cent[0]= cent[1]= cent[2]= 0.0;
388         
389         for(eve= em->verts.first; eve; eve= eve->next) {
390                 if(eve->f & SELECT) {
391                         *index= nr; index++;
392                         VecAddf(cent, cent, eve->co);
393                 }
394                 nr++;
395         }
396         
397         VecMulf(cent, 1.0f/(float)totvert);
398         
399         return totvert;
400 }
401
402 static int return_editmesh_vgroup(EditMesh *em, char *name, float *cent)
403 {
404         MDeformVert *dvert;
405         EditVert *eve;
406         int i, totvert=0;
407         
408         cent[0]= cent[1]= cent[2]= 0.0;
409         
410         if(G.obedit->actdef) {
411                 
412                 /* find the vertices */
413                 for(eve= em->verts.first; eve; eve= eve->next) {
414                         dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
415
416                         if(dvert) {
417                                 for(i=0; i<dvert->totweight; i++){
418                                         if(dvert->dw[i].def_nr == (G.obedit->actdef-1)) {
419                                                 totvert++;
420                                                 VecAddf(cent, cent, eve->co);
421                                         }
422                                 }
423                         }
424                 }
425                 if(totvert) {
426                         bDeformGroup *defGroup = BLI_findlink(&G.obedit->defbase, G.obedit->actdef-1);
427                         strcpy(name, defGroup->name);
428                         VecMulf(cent, 1.0f/(float)totvert);
429                         return 1;
430                 }
431         }
432         
433         return 0;
434 }       
435
436 static void select_editmesh_hook(Object *ob, HookModifierData *hmd)
437 {
438         Mesh *me= ob->data;
439         EditMesh *em= me->edit_mesh;
440         EditVert *eve;
441         int index=0, nr=0;
442         
443         for(eve= em->verts.first; eve; eve= eve->next, nr++) {
444                 if(nr==hmd->indexar[index]) {
445                         eve->f |= SELECT;
446                         if(index < hmd->totindex-1) index++;
447                 }
448         }
449         EM_select_flush();
450 }
451
452 static int return_editlattice_indexar(int *tot, int **indexar, float *cent)
453 {
454         BPoint *bp;
455         int *index, nr, totvert=0, a;
456         
457         /* count */
458         a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
459         bp= editLatt->def;
460         while(a--) {
461                 if(bp->f1 & SELECT) {
462                         if(bp->hide==0) totvert++;
463                 }
464                 bp++;
465         }
466
467         if(totvert==0) return 0;
468         
469         *indexar= index= MEM_mallocN(4*totvert, "hook indexar");
470         *tot= totvert;
471         nr= 0;
472         cent[0]= cent[1]= cent[2]= 0.0;
473         
474         a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
475         bp= editLatt->def;
476         while(a--) {
477                 if(bp->f1 & SELECT) {
478                         if(bp->hide==0) {
479                                 *index= nr; index++;
480                                 VecAddf(cent, cent, bp->vec);
481                         }
482                 }
483                 bp++;
484                 nr++;
485         }
486         
487         VecMulf(cent, 1.0f/(float)totvert);
488         
489         return totvert;
490 }
491
492 static void select_editlattice_hook(HookModifierData *hmd)
493 {
494         BPoint *bp;
495         int index=0, nr=0, a;
496         
497         /* count */
498         a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
499         bp= editLatt->def;
500         while(a--) {
501                 if(hmd->indexar[index]==nr) {
502                         bp->f1 |= SELECT;
503                         if(index < hmd->totindex-1) index++;
504                 }
505                 nr++;
506                 bp++;
507         }
508 }
509
510 static int return_editcurve_indexar(int *tot, int **indexar, float *cent)
511 {
512         extern ListBase editNurb;
513         Nurb *nu;
514         BPoint *bp;
515         BezTriple *bezt;
516         int *index, a, nr, totvert=0;
517         
518         for(nu= editNurb.first; nu; nu= nu->next) {
519                 if((nu->type & 7)==CU_BEZIER) {
520                         bezt= nu->bezt;
521                         a= nu->pntsu;
522                         while(a--) {
523                                 if(bezt->f1 & SELECT) totvert++;
524                                 if(bezt->f2 & SELECT) totvert++;
525                                 if(bezt->f3 & SELECT) totvert++;
526                                 bezt++;
527                         }
528                 }
529                 else {
530                         bp= nu->bp;
531                         a= nu->pntsu*nu->pntsv;
532                         while(a--) {
533                                 if(bp->f1 & SELECT) totvert++;
534                                 bp++;
535                         }
536                 }
537         }
538         if(totvert==0) return 0;
539         
540         *indexar= index= MEM_mallocN(4*totvert, "hook indexar");
541         *tot= totvert;
542         nr= 0;
543         cent[0]= cent[1]= cent[2]= 0.0;
544         
545         for(nu= editNurb.first; nu; nu= nu->next) {
546                 if((nu->type & 7)==CU_BEZIER) {
547                         bezt= nu->bezt;
548                         a= nu->pntsu;
549                         while(a--) {
550                                 if(bezt->f1 & SELECT) {
551                                         *index= nr; index++;
552                                         VecAddf(cent, cent, bezt->vec[0]);
553                                 }
554                                 nr++;
555                                 if(bezt->f2 & SELECT) {
556                                         *index= nr; index++;
557                                         VecAddf(cent, cent, bezt->vec[1]);
558                                 }
559                                 nr++;
560                                 if(bezt->f3 & SELECT) {
561                                         *index= nr; index++;
562                                         VecAddf(cent, cent, bezt->vec[2]);
563                                 }
564                                 nr++;
565                                 bezt++;
566                         }
567                 }
568                 else {
569                         bp= nu->bp;
570                         a= nu->pntsu*nu->pntsv;
571                         while(a--) {
572                                 if(bp->f1 & SELECT) {
573                                         *index= nr; index++;
574                                         VecAddf(cent, cent, bp->vec);
575                                 }
576                                 nr++;
577                                 bp++;
578                         }
579                 }
580         }
581         
582         VecMulf(cent, 1.0f/(float)totvert);
583         
584         return totvert;
585 }
586
587 static void apply_obmat(Object *ob)
588 {
589         float mat[3][3], imat[3][3], tmat[3][3];
590         
591         /* from obmat to loc rot size */
592         
593         if(ob==NULL) return;
594         Mat3CpyMat4(mat, ob->obmat);
595         
596         VECCOPY(ob->loc, ob->obmat[3]);
597
598         Mat3ToEul(mat, ob->rot);
599         EulToMat3(ob->rot, tmat);
600
601         Mat3Inv(imat, tmat);
602         
603         Mat3MulMat3(tmat, imat, mat);
604         
605         ob->size[0]= tmat[0][0];
606         ob->size[1]= tmat[1][1];
607         ob->size[2]= tmat[2][2];
608         
609 }
610
611 int hook_getIndexArray(int *tot, int **indexar, char *name, float *cent_r)
612 {
613         *indexar= NULL;
614         *tot= 0;
615         name[0]= 0;
616         
617         switch(G.obedit->type) {
618                 case OB_MESH:
619                 {
620                         Mesh *me= G.obedit->data;
621                         /* check selected vertices first */
622                         if( return_editmesh_indexar(me->edit_mesh, tot, indexar, cent_r)) return 1;
623                         else return return_editmesh_vgroup(me->edit_mesh, name, cent_r);
624                 }
625                 case OB_CURVE:
626                 case OB_SURF:
627                         return return_editcurve_indexar(tot, indexar, cent_r);
628                 case OB_LATTICE:
629                         return return_editlattice_indexar(tot, indexar, cent_r);
630                 default:
631                         return 0;
632         }
633 }
634
635 static void select_editcurve_hook(HookModifierData *hmd)
636 {
637         extern ListBase editNurb;
638         Nurb *nu;
639         BPoint *bp;
640         BezTriple *bezt;
641         int index=0, a, nr=0;
642         
643         for(nu= editNurb.first; nu; nu= nu->next) {
644                 if((nu->type & 7)==CU_BEZIER) {
645                         bezt= nu->bezt;
646                         a= nu->pntsu;
647                         while(a--) {
648                                 if(nr == hmd->indexar[index]) {
649                                         bezt->f1 |= SELECT;
650                                         if(index<hmd->totindex-1) index++;
651                                 }
652                                 nr++;
653                                 if(nr == hmd->indexar[index]) {
654                                         bezt->f2 |= SELECT;
655                                         if(index<hmd->totindex-1) index++;
656                                 }
657                                 nr++;
658                                 if(nr == hmd->indexar[index]) {
659                                         bezt->f3 |= SELECT;
660                                         if(index<hmd->totindex-1) index++;
661                                 }
662                                 nr++;
663                                 
664                                 bezt++;
665                         }
666                 }
667                 else {
668                         bp= nu->bp;
669                         a= nu->pntsu*nu->pntsv;
670                         while(a--) {
671                                 if(nr == hmd->indexar[index]) {
672                                         bp->f1 |= SELECT;
673                                         if(index<hmd->totindex-1) index++;
674                                 }
675                                 nr++;
676                                 bp++;
677                         }
678                 }
679         }
680 }
681
682 void obedit_hook_select(Object *ob, HookModifierData *hmd) 
683 {
684         
685         if(ob->type==OB_MESH) select_editmesh_hook(ob, hmd);
686         else if(ob->type==OB_LATTICE) select_editlattice_hook(hmd);
687         else if(ob->type==OB_CURVE) select_editcurve_hook(hmd);
688         else if(ob->type==OB_SURF) select_editcurve_hook(hmd);
689 }
690
691
692 void add_hook(Scene *scene, View3D *v3d, int mode)
693 {
694         ModifierData *md = NULL;
695         HookModifierData *hmd = NULL;
696         Object *ob=NULL;
697         
698         if(G.obedit==NULL) return;
699         
700         /* preconditions */
701         if(mode==2) { /* selected object */
702                 Base *base;
703                 for(base= FIRSTBASE; base; base= base->next) {
704                         if(TESTBASELIB(v3d, base)) {
705                                 if(base!=BASACT) {
706                                         ob= base->object;
707                                         break;
708                                 }
709                         }
710                 }
711                 if(ob==NULL) {
712                         error("Requires selected Object");
713                         return;
714                 }
715         }
716         else if(mode!=1) {
717                 int maxlen=0, a, nr;
718                 char *cp;
719                 
720                 /* make pupmenu with hooks */
721                 for(md=G.obedit->modifiers.first; md; md= md->next) {
722                         if (md->type==eModifierType_Hook) 
723                                 maxlen+=32;
724                 }
725                 
726                 if(maxlen==0) {
727                         error("Object has no hooks yet");
728                         return;
729                 }
730                 
731                 cp= MEM_callocN(maxlen+32, "temp string");
732                 if(mode==3) strcpy(cp, "Remove %t|");
733                 else if(mode==4) strcpy(cp, "Reassign %t|");
734                 else if(mode==5) strcpy(cp, "Select %t|");
735                 else if(mode==6) strcpy(cp, "Clear Offset %t|");
736                 
737                 for(md=G.obedit->modifiers.first; md; md= md->next) {
738                         if (md->type==eModifierType_Hook) {
739                                 strcat(cp, md->name);
740                                 strcat(cp, " |");
741                         }
742                 }
743                 
744                 nr= pupmenu(cp);
745                 MEM_freeN(cp);
746                 
747                 if(nr<1) return;
748                 
749                 a= 1;
750                 for(md=G.obedit->modifiers.first; md; md=md->next) {
751                         if (md->type==eModifierType_Hook) {
752                                 if(a==nr) break;
753                                 a++;
754                         }
755                 }
756                 
757                 hmd = (HookModifierData*) md;
758                 ob= hmd->object;
759         }
760
761         /* do it, new hooks or reassign */
762         if(mode==1 || mode==2 || mode==4) {
763                 float cent[3];
764                 int tot, ok, *indexar;
765                 char name[32];
766                 
767                 ok = hook_getIndexArray(&tot, &indexar, name, cent);
768                 
769                 if(ok==0) {
770                         error("Requires selected vertices or active Vertex Group");
771                 }
772                 else {
773                         
774                         if(mode==1) {
775                                 Base *base= BASACT, *newbase;
776                                 
777                                 ob= add_object(OB_EMPTY);
778                                 /* set layers OK */
779                                 newbase= BASACT;
780                                 newbase->lay= base->lay;
781                                 ob->lay= newbase->lay;
782                                 
783                                 /* transform cent to global coords for loc */
784                                 VecMat4MulVecfl(ob->loc, G.obedit->obmat, cent);
785                                 
786                                 /* restore, add_object sets active */
787                                 BASACT= base;
788                         }
789                         /* if mode is 2 or 4, ob has been set */
790                         
791                         /* new hook */
792                         if(mode==1 || mode==2) {
793                                 ModifierData *md = G.obedit->modifiers.first;
794                                 
795                                 while (md && modifierType_getInfo(md->type)->type==eModifierTypeType_OnlyDeform) {
796                                         md = md->next;
797                                 }
798                                 
799                                 hmd = (HookModifierData*) modifier_new(eModifierType_Hook);
800                                 BLI_insertlinkbefore(&G.obedit->modifiers, md, hmd);
801                                 sprintf(hmd->modifier.name, "Hook-%s", ob->id.name+2);
802                         }
803                         else if (hmd->indexar) MEM_freeN(hmd->indexar); /* reassign, hook was set */
804                 
805                         hmd->object= ob;
806                         hmd->indexar= indexar;
807                         VECCOPY(hmd->cent, cent);
808                         hmd->totindex= tot;
809                         BLI_strncpy(hmd->name, name, 32);
810                         
811                         if(mode==1 || mode==2) {
812                                 /* matrix calculus */
813                                 /* vert x (obmat x hook->imat) x hook->obmat x ob->imat */
814                                 /*        (parentinv         )                          */
815                                 
816                                 where_is_object(ob);
817                                 
818                                 Mat4Invert(ob->imat, ob->obmat);
819                                 /* apparently this call goes from right to left... */
820                                 Mat4MulSerie(hmd->parentinv, ob->imat, G.obedit->obmat, NULL, 
821                                                          NULL, NULL, NULL, NULL, NULL);
822                         }
823                 }
824         }
825         else if(mode==3) { /* remove */
826                 BLI_remlink(&G.obedit->modifiers, md);
827                 modifier_free(md);
828         }
829         else if(mode==5) { /* select */
830                 obedit_hook_select(G.obedit, hmd);
831         }
832         else if(mode==6) { /* clear offset */
833                 where_is_object(ob);    /* ob is hook->parent */
834
835                 Mat4Invert(ob->imat, ob->obmat);
836                 /* this call goes from right to left... */
837                 Mat4MulSerie(hmd->parentinv, ob->imat, G.obedit->obmat, NULL, 
838                                          NULL, NULL, NULL, NULL, NULL);
839         }
840
841         DAG_scene_sort(scene);
842 }
843
844
845 /* use this when the loc/size/rot of the parent has changed but the children should stay in the same place
846  * apply-size-rot or object center for eg */
847 static void ignore_parent_tx( Object *ob ) 
848 {
849         Object workob;
850         Object *ob_child;
851         
852         /* a change was made, adjust the children to compensate */
853         for (ob_child=G.main->object.first; ob_child; ob_child=ob_child->id.next) {
854                 if (ob_child->parent == ob) {
855                         apply_obmat(ob_child);
856                         what_does_parent(ob_child, &workob);
857                         Mat4Invert(ob_child->parentinv, workob.obmat);
858                 }
859         }
860 }
861
862
863 void add_hook_menu(Scene *scene, View3D *v3d)
864 {
865         int mode;
866         
867         if(G.obedit==NULL) return;
868         
869         if(modifiers_findByType(G.obedit, eModifierType_Hook))
870                 mode= pupmenu("Hooks %t|Add, To New Empty %x1|Add, To Selected Object %x2|Remove... %x3|Reassign... %x4|Select... %x5|Clear Offset...%x6");
871         else
872                 mode= pupmenu("Hooks %t|Add, New Empty %x1|Add, To Selected Object %x2");
873
874         if(mode<1) return;
875                 
876         /* do operations */
877         add_hook(scene, v3d, mode);
878         
879         allqueue(REDRAWVIEW3D, 0);
880         allqueue(REDRAWBUTSOBJECT, 0);
881         
882         BIF_undo_push("Add hook");
883 }
884
885 void make_track(Scene *scene, View3D *v3d, short mode)
886 {
887         Base *base;
888         /*short mode=0;*/
889         
890         if(scene->id.lib) return;
891         if(G.obedit) {
892                 return;
893         }
894         if(BASACT==0) return;
895
896         mode= pupmenu("Make Track %t|TrackTo Constraint %x1|LockTrack Constraint %x2|Old Track %x3");
897         if (mode == 0){
898                 return;
899         }
900         else if (mode == 1){
901                 bConstraint *con;
902                 bTrackToConstraint *data;
903
904                 for(base= FIRSTBASE; base; base= base->next) {
905                         if(TESTBASELIB(v3d, base)) {
906                                 if(base!=BASACT) {
907 // XXX                                  con = add_new_constraint(CONSTRAINT_TYPE_TRACKTO);
908                                         strcpy (con->name, "AutoTrack");
909
910                                         data = con->data;
911                                         data->tar = BASACT->object;
912                                         base->object->recalc |= OB_RECALC;
913                                         
914                                         /* Lamp and Camera track differently by default */
915                                         if (base->object->type == OB_LAMP || base->object->type == OB_CAMERA) {
916                                                 data->reserved1 = TRACK_nZ;
917                                                 data->reserved2 = UP_Y;
918                                         }
919
920 // XXX                                  add_constraint_to_object(con, base->object);
921                                 }
922                         }
923                 }
924
925         }
926         else if (mode == 2){
927                 bConstraint *con;
928                 bLockTrackConstraint *data;
929
930                 for(base= FIRSTBASE; base; base= base->next) {
931                         if(TESTBASELIB(v3d, base)) {
932                                 if(base!=BASACT) {
933 // XXX                                  con = add_new_constraint(CONSTRAINT_TYPE_LOCKTRACK);
934                                         strcpy (con->name, "AutoTrack");
935
936                                         data = con->data;
937                                         data->tar = BASACT->object;
938                                         base->object->recalc |= OB_RECALC;
939                                         
940                                         /* Lamp and Camera track differently by default */
941                                         if (base->object->type == OB_LAMP || base->object->type == OB_CAMERA) {
942                                                 data->trackflag = TRACK_nZ;
943                                                 data->lockflag = LOCK_Y;
944                                         }
945
946 // XXX                                  add_constraint_to_object(con, base->object);
947                                 }
948                         }
949                 }
950
951         }
952         else if (mode == 3){
953                 for(base= FIRSTBASE; base; base= base->next) {
954                         if(TESTBASELIB(v3d, base)) {
955                                 if(base!=BASACT) {
956                                         base->object->track= BASACT->object;
957                                         base->object->recalc |= OB_RECALC;
958                                 }
959                         }
960                 }
961         }
962
963         allqueue(REDRAWOOPS, 0);
964         allqueue(REDRAWVIEW3D, 0);
965         DAG_scene_sort(scene);
966         
967         BIF_undo_push("Make Track");
968 }
969
970 /* ******************** clear parent operator ******************* */
971
972
973 static EnumPropertyItem prop_clear_parent_types[] = {
974         {0, "CLEAR", "Clear Parent", ""},
975         {1, "CLEAR_KEEP_TRANSFORM", "Clear and Keep Transformation (Clear Track)", ""},
976         {2, "CLEAR_INVERSE", "Clear Parent Inverse", ""},
977         {0, NULL, NULL, NULL}
978 };
979
980 /* note, poll should check for editable scene */
981 static int clear_parent_exec(bContext *C, wmOperator *op)
982 {
983         
984         CTX_DATA_BEGIN(C, Object*, ob, selected_objects) {
985
986                 if(RNA_enum_is_equal(op->ptr, "type", "CLEAR")) {
987                         ob->parent= NULL;
988                 }                       
989                 if(RNA_enum_is_equal(op->ptr, "type", "CLEAR_KEEP_TRANSFORM")) {
990                         ob->parent= NULL;
991                         ob->track= NULL;
992                         apply_obmat(ob);
993                 }
994                 if(RNA_enum_is_equal(op->ptr, "type", "CLEAR_INVERSE")) {
995                         Mat4One(ob->parentinv);
996                 }
997                 ob->recalc |= OB_RECALC;
998         }
999         CTX_DATA_END;
1000         
1001         DAG_scene_sort(CTX_data_scene(C));
1002         ED_anim_dag_flush_update(C);
1003         
1004         BIF_undo_push("Clear Parent");  
1005         
1006         return OPERATOR_FINISHED;
1007 }
1008
1009 void OBJECT_OT_clear_parent(wmOperatorType *ot)
1010 {
1011         PropertyRNA *prop;
1012         
1013         /* identifiers */
1014         ot->name= "Clear parent";
1015         ot->idname= "OBJECT_OT_clear_parent";
1016         
1017         /* api callbacks */
1018         ot->invoke= WM_menu_invoke;
1019         ot->exec= clear_parent_exec;
1020         
1021         ot->poll= ED_operator_object_active;
1022         ot->flag= OPTYPE_REGISTER;
1023         
1024         prop = RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
1025         RNA_def_property_enum_items(prop, prop_clear_parent_types);
1026 }
1027
1028 /* ******************** clear track operator ******************* */
1029
1030
1031 static EnumPropertyItem prop_clear_track_types[] = {
1032         {0, "CLEAR", "Clear Track", ""},
1033         {1, "CLEAR_KEEP_TRANSFORM", "Clear and Keep Transformation (Clear Track)", ""},
1034         {0, NULL, NULL, NULL}
1035 };
1036
1037 /* note, poll should check for editable scene */
1038 static int object_clear_track_exec(bContext *C, wmOperator *op)
1039 {
1040         if(G.obedit) return OPERATOR_CANCELLED;
1041
1042         CTX_DATA_BEGIN(C, Object*, ob, selected_objects) {
1043                 /*if(TESTBASELIB(v3d, base)) {*/
1044                         ob->track= NULL;
1045                         ob->recalc |= OB_RECALC;
1046                         
1047                         if(RNA_enum_is_equal(op->ptr, "type", "CLEAR_KEEP_TRANSFORM")) {
1048                                 apply_obmat(ob);
1049                         }                       
1050                 /*}*/
1051         }
1052         CTX_DATA_END;
1053
1054         DAG_scene_sort(CTX_data_scene(C));
1055         ED_anim_dag_flush_update(C);
1056
1057         BIF_undo_push("Clear Track");   
1058         
1059         return OPERATOR_FINISHED;
1060 }
1061
1062 void OBJECT_OT_clear_track(wmOperatorType *ot)
1063 {
1064         PropertyRNA *prop;
1065         
1066         /* identifiers */
1067         ot->name= "Clear track";
1068         ot->idname= "OBJECT_OT_clear_track";
1069         
1070         /* api callbacks */
1071         ot->invoke= WM_menu_invoke;
1072         ot->exec= object_clear_track_exec;
1073         
1074         ot->poll= ED_operator_scene_editable;
1075         ot->flag= OPTYPE_REGISTER;
1076         
1077         prop = RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
1078         RNA_def_property_enum_items(prop, prop_clear_track_types);
1079 }
1080
1081
1082 /* ***************************** */
1083 /* ****** Select by Type ****** */
1084 static EnumPropertyItem prop_select_object_types[] = {
1085         {OB_EMPTY, "EMPTY", "Empty", ""},
1086         {OB_MESH, "MESH", "Mesh", ""},
1087         {OB_CURVE, "CURVE", "Curve", ""},
1088         {OB_SURF, "SURFACE", "Surface", ""},
1089         {OB_FONT, "TEXT", "Text", ""},
1090         {OB_MBALL, "META", "Meta", ""},
1091         {OB_LAMP, "LAMP", "Lamp", ""},
1092         {OB_CAMERA, "CAMERA", "Camera", ""},
1093         {OB_LATTICE, "LATTICE", "Lattice", ""},
1094         {0, NULL, NULL, NULL}
1095 };
1096
1097 static int object_select_by_type_exec(bContext *C, wmOperator *op)
1098 {
1099         short obtype;
1100         
1101         obtype = RNA_enum_get(op->ptr, "type");
1102                 
1103         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1104                 if(base->object->type==obtype) {
1105                         ED_base_object_select(base, BA_SELECT);
1106                 }
1107         }
1108         CTX_DATA_END;
1109         
1110         /* undo? */
1111         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1112         
1113         return OPERATOR_FINISHED;
1114 }
1115
1116 void OBJECT_OT_select_by_type(wmOperatorType *ot)
1117 {
1118         PropertyRNA *prop;
1119         
1120         /* identifiers */
1121         ot->name= "Select By Type";
1122         ot->idname= "OBJECT_OT_select_by_type";
1123         
1124         /* api callbacks */
1125         ot->invoke= WM_menu_invoke;
1126         ot->exec= object_select_by_type_exec;
1127         ot->poll= ED_operator_scene_editable;
1128         
1129         prop = RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
1130         RNA_def_property_enum_items(prop, prop_select_object_types);
1131
1132 }
1133
1134 /* ****** selection by layer *******/
1135
1136 static int object_select_by_layer_exec(bContext *C, wmOperator *op)
1137 {
1138         unsigned int layernum;
1139         
1140         layernum = RNA_int_get(op->ptr, "layer");
1141                 
1142         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1143                 if(base->lay == (1<< (layernum -1)))
1144                         ED_base_object_select(base, BA_SELECT);
1145         }
1146         CTX_DATA_END;
1147         
1148         /* undo? */
1149         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1150         
1151         return OPERATOR_FINISHED;
1152 }
1153
1154 void OBJECT_OT_select_by_layer(wmOperatorType *ot)
1155 {
1156         PropertyRNA *prop;
1157         
1158         /* identifiers */
1159         ot->name= "Selection by layer";
1160         ot->idname= "OBJECT_OT_select_by_layer";
1161         
1162         /* api callbacks */
1163         /*ot->invoke = XXX - need a int grid popup*/
1164         ot->exec= object_select_by_layer_exec;
1165         ot->poll= ED_operator_scene_editable;
1166         
1167         prop = RNA_def_property(ot->srna, "layer", PROP_INT, PROP_UNSIGNED);
1168         RNA_def_property_ui_range(prop, 1, 20,1, 1);
1169         RNA_def_property_ui_text(prop, "layer", "The layer to select objects in");
1170         RNA_def_property_int_default(prop, 2);
1171
1172 }
1173
1174 /* ****** invert selection *******/
1175 static int object_select_invert_exec(bContext *C, wmOperator *op)
1176 {
1177         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1178                 if (base->flag & SELECT)
1179                         ED_base_object_select(base, BA_DESELECT);
1180                 else
1181                         ED_base_object_select(base, BA_SELECT);
1182         }
1183         CTX_DATA_END;
1184         
1185         /* undo? */
1186         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1187         
1188         return OPERATOR_FINISHED;
1189 }
1190
1191 void OBJECT_OT_select_invert(wmOperatorType *ot)
1192 {
1193         
1194         /* identifiers */
1195         ot->name= "Invert selection";
1196         ot->idname= "OBJECT_OT_select_invert";
1197         
1198         /* api callbacks */
1199         ot->exec= object_select_invert_exec;
1200         ot->poll= ED_operator_scene_editable;
1201
1202 }
1203 /* ****** (de)select All *******/
1204
1205 static int object_de_select_all_exec(bContext *C, wmOperator *op)
1206 {
1207         
1208         int a=0, ok=0; 
1209         
1210         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1211                 if (base->flag & SELECT) {
1212                         ok= a= 1;
1213                         break;
1214                 }
1215                 else ok=1;
1216         }
1217         CTX_DATA_END;
1218         
1219         if (!ok) return OPERATOR_PASS_THROUGH;
1220         
1221         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1222                 if (a) ED_base_object_select(base, BA_DESELECT);
1223                 else ED_base_object_select(base, BA_SELECT);
1224         }
1225         CTX_DATA_END;
1226         
1227         /* undo? */
1228         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1229         
1230         return OPERATOR_FINISHED;
1231 }
1232
1233 void OBJECT_OT_de_select_all(wmOperatorType *ot)
1234 {
1235         
1236         /* identifiers */
1237         ot->name= "deselect all";
1238         ot->idname= "OBJECT_OT_de_select_all";
1239         
1240         /* api callbacks */
1241         ot->exec= object_de_select_all_exec;
1242         ot->poll= ED_operator_scene_editable;
1243
1244 }
1245 /* ****** random selection *******/
1246
1247 static int object_select_random_exec(bContext *C, wmOperator *op)
1248 {       
1249         int percent;
1250         
1251         percent = RNA_int_get(op->ptr, "percent");
1252                 
1253         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1254                 if ((!base->flag & SELECT && (BLI_frand() * 100) < percent)) {
1255                                 ED_base_object_select(base, BA_SELECT);
1256                 }
1257         }
1258         CTX_DATA_END;
1259         
1260         /* undo? */
1261         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1262         
1263         return OPERATOR_FINISHED;
1264 }
1265
1266 void OBJECT_OT_select_random(wmOperatorType *ot)
1267 {
1268         PropertyRNA *prop;
1269         
1270         /* identifiers */
1271         ot->name= "Random selection";
1272         ot->idname= "OBJECT_OT_select_random";
1273         
1274         /* api callbacks */
1275         /*ot->invoke= object_select_random_invoke XXX - need a number popup ;*/
1276         ot->exec = object_select_random_exec;
1277         ot->poll= ED_operator_scene_editable;
1278         
1279         prop = RNA_def_property(ot->srna, "percent", PROP_INT, PROP_NONE);
1280         RNA_def_property_ui_range(prop, 1, 100,1, 1);
1281         RNA_def_property_ui_text(prop, "Percent", "Max persentage that will be selected");
1282         RNA_def_property_int_default(prop, 50);
1283 }
1284
1285 /* ******** Clear object Translation *********** */
1286
1287 static int object_clear_location_exec(bContext *C, wmOperator *op)
1288 {
1289         Scene *scene= CTX_data_scene(C);
1290         int armature_clear= 0;
1291
1292         CTX_DATA_BEGIN(C, Object*, ob, selected_objects) {
1293                 if ((ob->flag & OB_POSEMODE)) {
1294                         /* only clear pose transforms if:
1295                          *      - with a mesh in weightpaint mode, it's related armature needs to be cleared
1296                          *      - with clearing transform of object being edited at the time
1297                          */
1298                         if ((G.f & G_WEIGHTPAINT) || (ob==OBACT)) {
1299 // XXX                          clear_armature(ob, mode);
1300                                 armature_clear= 1;      /* silly system to prevent another dag update, so no action applied */
1301                         }
1302                 }
1303                 else if((G.f & G_WEIGHTPAINT)==0) {
1304                         if ((ob->protectflag & OB_LOCK_LOCX)==0)
1305                                 ob->loc[0]= ob->dloc[0]= 0.0f;
1306                         if ((ob->protectflag & OB_LOCK_LOCY)==0)
1307                                 ob->loc[1]= ob->dloc[1]= 0.0f;
1308                         if ((ob->protectflag & OB_LOCK_LOCZ)==0)
1309                                 ob->loc[2]= ob->dloc[2]= 0.0f;
1310                 }
1311         }
1312         CTX_DATA_END;
1313         
1314         DAG_scene_sort(scene);
1315         if(armature_clear==0) /* in this case flush was done */
1316                 ED_anim_dag_flush_update(C);    
1317         BIF_undo_push("Clear Location");
1318         
1319         ED_region_tag_redraw(CTX_wm_region(C));
1320         
1321         return OPERATOR_FINISHED;
1322 }
1323
1324
1325 void OBJECT_OT_clear_location(wmOperatorType *ot)
1326 {
1327         PropertyRNA *prop;
1328         
1329         /* identifiers */
1330         ot->name= "Clear Object Location";
1331         ot->idname= "OBJECT_OT_clear_location";
1332         
1333         /* api callbacks */
1334         ot->invoke= WM_operator_confirm;
1335         ot->exec= object_clear_location_exec;
1336         ot->poll= ED_operator_object_active;
1337 }
1338
1339 static int object_clear_rotation_exec(bContext *C, wmOperator *op)
1340 {
1341         Scene *scene= CTX_data_scene(C);
1342         int armature_clear= 0;
1343
1344         CTX_DATA_BEGIN(C, Object*, ob, selected_objects) {
1345                 if ((ob->flag & OB_POSEMODE)) {
1346                         /* only clear pose transforms if:
1347                          *      - with a mesh in weightpaint mode, it's related armature needs to be cleared
1348                          *      - with clearing transform of object being edited at the time
1349                          */
1350                         if ((G.f & G_WEIGHTPAINT) || (ob==OBACT)) {
1351 // XXX                          clear_armature(ob, mode);
1352                                 armature_clear= 1;      /* silly system to prevent another dag update, so no action applied */
1353                         }
1354                 }
1355                 else if((G.f & G_WEIGHTPAINT)==0) {
1356                                 /* eulers can only get cleared if they are not protected */
1357                                 if ((ob->protectflag & OB_LOCK_ROTX)==0)
1358                                         ob->rot[0]= ob->drot[0]= 0.0f;
1359                                 if ((ob->protectflag & OB_LOCK_ROTY)==0)
1360                                         ob->rot[1]= ob->drot[1]= 0.0f;
1361                                 if ((ob->protectflag & OB_LOCK_ROTZ)==0)
1362                                         ob->rot[2]= ob->drot[2]= 0.0f;
1363                 }
1364         }
1365         CTX_DATA_END;
1366         
1367         DAG_scene_sort(scene);
1368         if(armature_clear==0) /* in this case flush was done */
1369                 ED_anim_dag_flush_update(C);    
1370         BIF_undo_push("Clear Rotation");
1371         
1372         ED_region_tag_redraw(CTX_wm_region(C));
1373         
1374         return OPERATOR_FINISHED;
1375 }
1376
1377
1378 void OBJECT_OT_clear_rotation(wmOperatorType *ot)
1379 {
1380         PropertyRNA *prop;
1381         
1382         /* identifiers */
1383         ot->name= "Clear Object Rotation";
1384         ot->idname= "OBJECT_OT_clear_rotation";
1385         
1386         /* api callbacks */
1387         ot->invoke= WM_operator_confirm;
1388         ot->exec= object_clear_rotation_exec;
1389         ot->poll= ED_operator_object_active;
1390 }
1391
1392 static int object_clear_scale_exec(bContext *C, wmOperator *op)
1393 {
1394         Scene *scene= CTX_data_scene(C);
1395         int armature_clear= 0;
1396
1397         CTX_DATA_BEGIN(C, Object*, ob, selected_objects) {
1398                 if ((ob->flag & OB_POSEMODE)) {
1399                         /* only clear pose transforms if:
1400                          *      - with a mesh in weightpaint mode, it's related armature needs to be cleared
1401                          *      - with clearing transform of object being edited at the time
1402                          */
1403                         if ((G.f & G_WEIGHTPAINT) || (ob==OBACT)) {
1404 // XXX                          clear_armature(ob, mode);
1405                                 armature_clear= 1;      /* silly system to prevent another dag update, so no action applied */
1406                         }
1407                 }
1408                 else if((G.f & G_WEIGHTPAINT)==0) {
1409                                 if ((ob->protectflag & OB_LOCK_SCALEX)==0) {
1410                                         ob->dsize[0]= 0.0f;
1411                                         ob->size[0]= 1.0f;
1412                                 }
1413                                 if ((ob->protectflag & OB_LOCK_SCALEY)==0) {
1414                                         ob->dsize[1]= 0.0f;
1415                                         ob->size[1]= 1.0f;
1416                                 }
1417                                 if ((ob->protectflag & OB_LOCK_SCALEZ)==0) {
1418                                         ob->dsize[2]= 0.0f;
1419                                         ob->size[2]= 1.0f;
1420                                 }
1421                 }
1422         }
1423         CTX_DATA_END;
1424         
1425         DAG_scene_sort(scene);
1426         if(armature_clear==0) /* in this case flush was done */
1427                 ED_anim_dag_flush_update(C);    
1428         BIF_undo_push("Clear Scale");
1429         
1430         ED_region_tag_redraw(CTX_wm_region(C));
1431         
1432         return OPERATOR_FINISHED;
1433 }
1434
1435 void OBJECT_OT_clear_scale(wmOperatorType *ot)
1436 {
1437         PropertyRNA *prop;
1438         
1439         /* identifiers */
1440         ot->name= "Clear Object Scale";
1441         ot->idname= "OBJECT_OT_clear_scale";
1442         
1443         /* api callbacks */
1444         ot->invoke= WM_operator_confirm;
1445         ot->exec= object_clear_scale_exec;
1446         ot->poll= ED_operator_object_active;
1447 }
1448
1449 static int object_clear_origin_exec(bContext *C, wmOperator *op)
1450 {
1451         Scene *scene= CTX_data_scene(C);
1452         float *v1, *v3, mat[3][3];
1453         int armature_clear= 0;
1454
1455         CTX_DATA_BEGIN(C, Object*, ob, selected_objects) {
1456                 if ((ob->flag & OB_POSEMODE)) {
1457                         /* only clear pose transforms if:
1458                          *      - with a mesh in weightpaint mode, it's related armature needs to be cleared
1459                          *      - with clearing transform of object being edited at the time
1460                          */
1461                         if ((G.f & G_WEIGHTPAINT) || (ob==OBACT)) {
1462 // XXX                          clear_armature(ob, mode);
1463                                 armature_clear= 1;      /* silly system to prevent another dag update, so no action applied */
1464                         }
1465                 }
1466                 else if((G.f & G_WEIGHTPAINT)==0) {
1467                         if(ob->parent) {
1468                                 v1= ob->loc;
1469                                 v3= ob->parentinv[3];
1470                                 
1471                                 Mat3CpyMat4(mat, ob->parentinv);
1472                                 VECCOPY(v3, v1);
1473                                 v3[0]= -v3[0];
1474                                 v3[1]= -v3[1];
1475                                 v3[2]= -v3[2];
1476                                 Mat3MulVecfl(mat, v3);
1477                         }
1478                 }
1479         }
1480         CTX_DATA_END;
1481         
1482         
1483         DAG_scene_sort(scene);
1484         if(armature_clear==0) /* in this case flush was done */
1485                 ED_anim_dag_flush_update(C);    
1486         BIF_undo_push("Clear origin");
1487         
1488         ED_region_tag_redraw(CTX_wm_region(C));
1489         
1490         return OPERATOR_FINISHED;
1491 }
1492
1493 void OBJECT_OT_clear_origin(wmOperatorType *ot)
1494 {
1495
1496         /* identifiers */
1497         ot->name= "Clear Object Origin";
1498         ot->idname= "OBJECT_OT_clear_origin";
1499         
1500         /* api callbacks */
1501         ot->invoke= WM_operator_confirm;
1502         ot->exec= object_clear_origin_exec;
1503         ot->poll= ED_operator_object_active;
1504 }
1505 /* ******************** **************** */
1506
1507 void reset_slowparents(Scene *scene, View3D *v3d)
1508 {
1509         /* back to original locations */
1510         Base *base;
1511
1512         for(base= FIRSTBASE; base; base= base->next) {
1513                 if(base->object->parent) {
1514                         if(base->object->partype & PARSLOW) {
1515                                 base->object->partype -= PARSLOW;
1516                                 where_is_object(base->object);
1517                                 base->object->partype |= PARSLOW;
1518                         }
1519                 }
1520         }
1521 }
1522 void set_slowparent(Scene *scene, View3D *v3d)
1523 {
1524         Base *base;
1525
1526         if( okee("Set slow parent")==0 ) return;
1527
1528         for(base= FIRSTBASE; base; base= base->next) {
1529                 if(TESTBASELIB(v3d, base)) {
1530                         if(base->object->parent) base->object->partype |= PARSLOW;
1531                 }
1532         }
1533         BIF_undo_push("Slow parent");
1534 }
1535
1536 // XXX
1537 #define BEZSELECTED_HIDDENHANDLES(bezt)   ((G.f & G_HIDDENHANDLES) ? (bezt)->f2 & SELECT : BEZSELECTED(bezt))
1538 /* only in edit mode */
1539 void make_vertex_parent(Scene *scene, View3D *v3d)
1540 {
1541         EditVert *eve;
1542         Base *base;
1543         Nurb *nu;
1544         BezTriple *bezt;
1545         BPoint *bp;
1546         Object *par, *ob;
1547         int a, v1=0, v2=0, v3=0, v4=0, nr=1;
1548         
1549         /* we need 1 to 3 selected vertices */
1550         
1551         if(G.obedit->type==OB_MESH) {
1552                 Mesh *me= G.obedit->data;
1553                 
1554                 eve= me->edit_mesh->verts.first;
1555                 while(eve) {
1556                         if(eve->f & 1) {
1557                                 if(v1==0) v1= nr;
1558                                 else if(v2==0) v2= nr;
1559                                 else if(v3==0) v3= nr;
1560                                 else if(v4==0) v4= nr;
1561                                 else break;
1562                         }
1563                         nr++;
1564                         eve= eve->next;
1565                 }
1566         }
1567         else if(ELEM(G.obedit->type, OB_SURF, OB_CURVE)) {
1568                 extern ListBase editNurb;
1569                 nu= editNurb.first;
1570                 while(nu) {
1571                         if((nu->type & 7)==CU_BEZIER) {
1572                                 bezt= nu->bezt;
1573                                 a= nu->pntsu;
1574                                 while(a--) {
1575                                         if(BEZSELECTED_HIDDENHANDLES(bezt)) {
1576                                                 if(v1==0) v1= nr;
1577                                                 else if(v2==0) v2= nr;
1578                                                 else if(v3==0) v3= nr;
1579                                                 else if(v4==0) v4= nr;
1580                                                 else break;
1581                                         }
1582                                         nr++;
1583                                         bezt++;
1584                                 }
1585                         }
1586                         else {
1587                                 bp= nu->bp;
1588                                 a= nu->pntsu*nu->pntsv;
1589                                 while(a--) {
1590                                         if(bp->f1 & SELECT) {
1591                                                 if(v1==0) v1= nr;
1592                                                 else if(v2==0) v2= nr;
1593                                                 else if(v3==0) v3= nr;
1594                                                 else if(v4==0) v4= nr;
1595                                                 else break;
1596                                         }
1597                                         nr++;
1598                                         bp++;
1599                                 }
1600                         }
1601                         nu= nu->next;
1602                 }
1603         }
1604         else if(G.obedit->type==OB_LATTICE) {
1605                 
1606                 a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
1607                 bp= editLatt->def;
1608                 while(a--) {
1609                         if(bp->f1 & SELECT) {
1610                                 if(v1==0) v1= nr;
1611                                 else if(v2==0) v2= nr;
1612                                 else if(v3==0) v3= nr;
1613                                 else if(v4==0) v4= nr;
1614                                 else break;
1615                         }
1616                         nr++;
1617                         bp++;
1618                 }
1619         }
1620         
1621         if(v4 || !((v1 && v2==0 && v3==0) || (v1 && v2 && v3)) ) {
1622                 error("Select either 1 or 3 vertices to parent to");
1623                 return;
1624         }
1625         
1626         if(okee("Make vertex parent")==0) return;
1627         
1628         for(base= FIRSTBASE; base; base= base->next) {
1629                 if(TESTBASELIB(v3d, base)) {
1630                         if(base!=BASACT) {
1631                                 
1632                                 ob= base->object;
1633                                 ob->recalc |= OB_RECALC;
1634                                 par= BASACT->object->parent;
1635                                 
1636                                 while(par) {
1637                                         if(par==ob) break;
1638                                         par= par->parent;
1639                                 }
1640                                 if(par) {
1641                                         error("Loop in parents");
1642                                 }
1643                                 else {
1644                                         Object workob;
1645                                         
1646                                         ob->parent= BASACT->object;
1647                                         if(v3) {
1648                                                 ob->partype= PARVERT3;
1649                                                 ob->par1= v1-1;
1650                                                 ob->par2= v2-1;
1651                                                 ob->par3= v3-1;
1652
1653                                                 /* inverse parent matrix */
1654                                                 what_does_parent(ob, &workob);
1655                                                 Mat4Invert(ob->parentinv, workob.obmat);
1656                                         }
1657                                         else {
1658                                                 ob->partype= PARVERT1;
1659                                                 ob->par1= v1-1;
1660
1661                                                 /* inverse parent matrix */
1662                                                 what_does_parent(ob, &workob);
1663                                                 Mat4Invert(ob->parentinv, workob.obmat);
1664                                         }
1665                                 }
1666                         }
1667                 }
1668         }
1669         allqueue(REDRAWVIEW3D, 0);
1670         
1671         DAG_scene_sort(scene);
1672         /* BIF_undo_push(str); not, conflicts with editmode undo... */
1673 }
1674
1675 static Object *group_objects_menu(Group *group)
1676 {
1677         GroupObject *go;
1678         int len= 0;
1679         short a, nr;
1680         char *str;
1681                 
1682         for(go= group->gobject.first; go; go= go->next) {
1683                 if(go->ob)
1684                         len++;
1685         }
1686         if(len==0) return NULL;
1687         
1688         str= MEM_callocN(40+32*len, "menu");
1689         
1690         strcpy(str, "Make Proxy for: %t");
1691         a= strlen(str);
1692         for(nr=1, go= group->gobject.first; go; go= go->next, nr++) {
1693                 a+= sprintf(str+a, "|%s %%x%d", go->ob->id.name+2, nr);
1694         }
1695         
1696         a= pupmenu_col(str, 20);
1697         MEM_freeN(str);
1698         if(a>0) {
1699                 go= BLI_findlink(&group->gobject, a-1);
1700                 return go->ob;
1701         }
1702         return NULL;
1703 }
1704
1705
1706 /* adds empty object to become local replacement data of a library-linked object */
1707 void make_proxy(Scene *scene)
1708 {
1709         Object *ob= OBACT;
1710         Object *gob= NULL;
1711         
1712         if(scene->id.lib) return;
1713         if(ob==NULL) return;
1714         
1715         
1716         if(ob->dup_group && ob->dup_group->id.lib) {
1717                 gob= ob;
1718                 /* gives menu with list of objects in group */
1719                 ob= group_objects_menu(ob->dup_group);
1720         }
1721         else if(ob->id.lib) {
1722                 if(okee("Make Proxy Object")==0)
1723                 return;
1724         }
1725         else {
1726                 error("Can only make proxy for a referenced object or group");
1727                 return;
1728         }
1729         
1730         if(ob) {
1731                 Object *newob;
1732                 Base *newbase, *oldbase= BASACT;
1733                 char name[32];
1734                 
1735                 newob= add_object(OB_EMPTY);
1736                 if(gob)
1737                         strcpy(name, gob->id.name+2);
1738                 else
1739                         strcpy(name, ob->id.name+2);
1740                 strcat(name, "_proxy");
1741                 rename_id(&newob->id, name);
1742                 
1743                 /* set layers OK */
1744                 newbase= BASACT;        /* add_object sets active... */
1745                 newbase->lay= oldbase->lay;
1746                 newob->lay= newbase->lay;
1747                 
1748                 /* remove base, leave user count of object, it gets linked in object_make_proxy */
1749                 if(gob==NULL) {
1750                         BLI_remlink(&scene->base, oldbase);
1751                         MEM_freeN(oldbase);
1752                 }               
1753                 object_make_proxy(newob, ob, gob);
1754                 
1755                 DAG_scene_sort(scene);
1756                 DAG_object_flush_update(scene, newob, OB_RECALC);
1757                 allqueue(REDRAWALL, 0);
1758                 BIF_undo_push("Make Proxy Object");
1759         }
1760 }
1761
1762 /* ******************** make parent operator *********************** */
1763
1764 #if 0
1765 oldcode()
1766 {
1767         else if(mode==4) {
1768                 bConstraint *con;
1769                 bFollowPathConstraint *data;
1770                         
1771                 for(base= FIRSTBASE; base; base= base->next) {
1772                         if(TESTBASELIB(v3d, base)) {
1773                                 if(base!=BASACT) {
1774                                         float cmat[4][4], vec[3];
1775                                         
1776 // XXX                                          con = add_new_constraint(CONSTRAINT_TYPE_FOLLOWPATH);
1777                                         strcpy (con->name, "AutoPath");
1778                                         
1779                                         data = con->data;
1780                                         data->tar = BASACT->object;
1781                                         
1782 // XXX                                          add_constraint_to_object(con, base->object);
1783                                         
1784                                         get_constraint_target_matrix(con, 0, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, scene->r.cfra - give_timeoffset(base->object));
1785                                         VecSubf(vec, base->object->obmat[3], cmat[3]);
1786                                         
1787                                         base->object->loc[0] = vec[0];
1788                                         base->object->loc[1] = vec[1];
1789                                         base->object->loc[2] = vec[2];
1790                                 }
1791                         }
1792                 }
1793
1794                 if(mode==PARSKEL && base->object->type==OB_MESH && par->type == OB_ARMATURE) {
1795                         /* Prompt the user as to whether he wants to
1796                                 * add some vertex groups based on the bones
1797                                 * in the parent armature.
1798                                 */
1799 // XXX                                                  create_vgroups_from_armature(base->object, par);
1800
1801                         base->object->partype= PAROBJECT;
1802                         what_does_parent(base->object);
1803                         Mat4One (base->object->parentinv);
1804                         base->object->partype= mode;
1805                 }
1806                 else
1807                         what_does_parent(base->object, &workob);
1808                 Mat4Invert(base->object->parentinv, workob.obmat);
1809         }
1810 }
1811 #endif
1812
1813 #define PAR_OBJECT              0
1814 #define PAR_ARMATURE    1
1815 #define PAR_BONE                2
1816 #define PAR_CURVE               3
1817 #define PAR_FOLLOW              4
1818 #define PAR_PATH_CONST  5
1819 #define PAR_LATTICE             6
1820 #define PAR_VERTEX              7
1821 #define PAR_TRIA                8
1822
1823 static EnumPropertyItem prop_make_parent_types[] = {
1824         {PAR_OBJECT, "OBJECT", "Object", ""},
1825         {PAR_ARMATURE, "ARMATURE", "Armature Deform", ""},
1826         {PAR_BONE, "BONE", "Bone", ""},
1827         {PAR_CURVE, "CURVE", "Curve Deform", ""},
1828         {PAR_FOLLOW, "FOLLOW", "Follow Path", ""},
1829         {PAR_PATH_CONST, "PATH_CONST", "Path Constraint", ""},
1830         {PAR_LATTICE, "LATTICE", "Lattice Deform", ""},
1831         {PAR_VERTEX, "VERTEX", "Vertex", ""},
1832         {PAR_TRIA, "TRIA", "Triangle", ""},
1833         {0, NULL, NULL, NULL}
1834 };
1835
1836 static int test_parent_loop(Object *par, Object *ob)
1837 {
1838         /* test if 'ob' is a parent somewhere in par's parents */
1839         
1840         if(par == NULL) return 0;
1841         if(ob == par) return 1;
1842         
1843         return test_parent_loop(par->parent, ob);
1844 }
1845
1846
1847 static int make_parent_exec(bContext *C, wmOperator *op)
1848 {
1849         Object *par= CTX_data_active_object(C);
1850         bPoseChannel *pchan= NULL;
1851         int partype= RNA_enum_get(op->ptr, "type");
1852         
1853         par->recalc |= OB_RECALC_OB;
1854         
1855         /* preconditions */
1856         if(partype==PAR_FOLLOW || partype==PAR_PATH_CONST) {
1857                 if(par->type!=OB_CURVE)
1858                         return OPERATOR_CANCELLED;
1859                 else {
1860                         Curve *cu= par->data;
1861                         
1862                         if((cu->flag & CU_PATH)==0) {
1863                                 cu->flag |= CU_PATH|CU_FOLLOW;
1864                                 makeDispListCurveTypes(par, 0);  /* force creation of path data */
1865                         }
1866                         else cu->flag |= CU_FOLLOW;
1867                         
1868                         /* fall back on regular parenting now */
1869                         partype= PAR_OBJECT;
1870                 }               
1871         }
1872         else if(partype==PAR_BONE) {
1873                 pchan= get_active_posechannel(par);
1874                 
1875                 if(pchan==NULL) {
1876                         error("No active Bone");
1877                         return OPERATOR_CANCELLED;
1878                 }
1879         }
1880         
1881         /* context itterator */
1882         CTX_DATA_BEGIN(C, Object*, ob, selected_objects) {
1883                 
1884                 if(ob!=par) {
1885                         
1886                         if( test_parent_loop(par, ob) ) {
1887                                 error("Loop in parents");
1888                         }
1889                         else {
1890                                 Object workob;
1891                                 
1892                                 /* apply transformation of previous parenting */
1893                                 apply_obmat(ob);
1894                                 
1895                                 ob->parent= par;
1896                                 
1897                                 /* handle types */
1898                                 if (pchan)
1899                                         strcpy (ob->parsubstr, pchan->name);
1900                                 else
1901                                         ob->parsubstr[0]= 0;
1902                                 
1903                                 /* constraint XXX */
1904                                 if(partype==PAR_PATH_CONST) {
1905                                 }
1906                                 
1907                                 /* calculate inverse parent matrix */
1908                                 what_does_parent(ob, &workob);
1909                                 Mat4Invert(ob->parentinv, workob.obmat);
1910                                 
1911                                 ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA;
1912                                 
1913                                 if( ELEM3(partype, PAR_CURVE, PAR_ARMATURE, PAR_LATTICE) )
1914                                         ob->partype= PARSKEL; /* note, dna define, not operator property */
1915                                 else
1916                                         ob->partype= PAROBJECT; /* note, dna define, not operator property */
1917                         }
1918                 }
1919         }
1920         CTX_DATA_END;
1921         
1922         DAG_scene_sort(CTX_data_scene(C));
1923         ED_anim_dag_flush_update(C);    
1924         
1925         BIF_undo_push("make Parent");
1926         
1927         return OPERATOR_FINISHED;
1928 }
1929
1930 static int make_parent_invoke(bContext *C, wmOperator *op, wmEvent *event)
1931 {
1932         Object *ob= CTX_data_active_object(C);
1933         char *str, string[256];
1934         char formatstr[] = "|%s %%x%d";
1935         
1936         str= string + sprintf(string, "Make Parent To %%t");
1937         
1938         /* ob becomes parent, make the associated menus */
1939         if(ob->type==OB_ARMATURE) {
1940                 str += sprintf(str, formatstr, "Object", PAR_OBJECT);
1941                 str += sprintf(str, formatstr, "Armature Deform", PAR_ARMATURE);
1942                 str += sprintf(str, formatstr, "Bone", PAR_BONE);
1943         }
1944         else if(ob->type==OB_CURVE) {
1945                 str += sprintf(str, formatstr, "Object", PAR_OBJECT);
1946                 str += sprintf(str, formatstr, "Curve Deform", PAR_CURVE);
1947                 str += sprintf(str, formatstr, "Follow Path", PAR_FOLLOW);
1948                 str += sprintf(str, formatstr, "Path Constraint", PAR_PATH_CONST);
1949         }
1950         else if(ob->type == OB_LATTICE) {
1951                 str += sprintf(str, formatstr, "Object", PAR_OBJECT);
1952                 str += sprintf(str, formatstr, "Lattice Deform", PAR_LATTICE);
1953         }
1954         else
1955                 str += sprintf(str, formatstr, "Object", PAR_OBJECT);
1956         
1957         uiPupmenuOperator(C, 0, op, "type", string);
1958         
1959         return OPERATOR_RUNNING_MODAL;
1960 }
1961
1962
1963 void OBJECT_OT_make_parent(wmOperatorType *ot)
1964 {
1965         PropertyRNA *prop;
1966         
1967         /* identifiers */
1968         ot->name= "Make parent";
1969         ot->idname= "OBJECT_OT_make_parent";
1970         
1971         /* api callbacks */
1972         ot->invoke= make_parent_invoke;
1973         ot->exec= make_parent_exec;
1974         
1975         ot->poll= ED_operator_object_active;
1976         ot->flag= OPTYPE_REGISTER;
1977         
1978         prop = RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
1979         RNA_def_property_enum_items(prop, prop_make_parent_types);
1980 }
1981
1982 /* *** make track ***** */
1983 static EnumPropertyItem prop_make_track_types[] = {
1984         {1, "TRACKTO", "TrackTo Constraint", ""},
1985         {2, "LOCKTRACK", "LockTrack Constraint", ""},
1986         {3, "OLDTRACK", "Old Track", ""},
1987         {0, NULL, NULL, NULL}
1988 };
1989
1990 static int make_track_exec(bContext *C, wmOperator *op)
1991 {
1992         Scene *scene= CTX_data_scene(C);
1993         ScrArea *sa= CTX_wm_area(C);
1994         View3D *v3d= sa->spacedata.first;
1995         Base *base;
1996         
1997         if(scene->id.lib) return OPERATOR_CANCELLED;
1998
1999         if(RNA_enum_is_equal(op->ptr, "type", "TRACKTO")){
2000                 bConstraint *con;
2001                 bTrackToConstraint *data;
2002
2003                 for(base= FIRSTBASE; base; base= base->next) {
2004                         if(TESTBASELIB(v3d, base)) {
2005                                 if(base!=BASACT) {
2006 // XXX                                  con = add_new_constraint(CONSTRAINT_TYPE_TRACKTO);
2007                                         strcpy (con->name, "AutoTrack");
2008
2009                                         data = con->data;
2010                                         data->tar = BASACT->object;
2011                                         base->object->recalc |= OB_RECALC;
2012                                         
2013                                         /* Lamp and Camera track differently by default */
2014                                         if (base->object->type == OB_LAMP || base->object->type == OB_CAMERA) {
2015                                                 data->reserved1 = TRACK_nZ;
2016                                                 data->reserved2 = UP_Y;
2017                                         }
2018
2019 // XXX                                  add_constraint_to_object(con, base->object);
2020                                 }
2021                         }
2022                 }
2023
2024         }
2025         else if(RNA_enum_is_equal(op->ptr, "type", "LOCKTRACK")){
2026                 bConstraint *con;
2027                 bLockTrackConstraint *data;
2028
2029                 for(base= FIRSTBASE; base; base= base->next) {
2030                         if(TESTBASELIB(v3d, base)) {
2031                                 if(base!=BASACT) {
2032 // XXX                                  con = add_new_constraint(CONSTRAINT_TYPE_LOCKTRACK);
2033                                         strcpy (con->name, "AutoTrack");
2034
2035                                         data = con->data;
2036                                         data->tar = BASACT->object;
2037                                         base->object->recalc |= OB_RECALC;
2038                                         
2039                                         /* Lamp and Camera track differently by default */
2040                                         if (base->object->type == OB_LAMP || base->object->type == OB_CAMERA) {
2041                                                 data->trackflag = TRACK_nZ;
2042                                                 data->lockflag = LOCK_Y;
2043                                         }
2044
2045 // XXX                                  add_constraint_to_object(con, base->object);
2046                                 }
2047                         }
2048                 }
2049
2050         }
2051         else if(RNA_enum_is_equal(op->ptr, "type", "OLDTRACK")){
2052                 for(base= FIRSTBASE; base; base= base->next) {
2053                         if(TESTBASELIB(v3d, base)) {
2054                                 if(base!=BASACT) {
2055                                         base->object->track= BASACT->object;
2056                                         base->object->recalc |= OB_RECALC;
2057                                 }
2058                         }
2059                 }
2060         }
2061         DAG_scene_sort(CTX_data_scene(C));
2062         ED_anim_dag_flush_update(C);    
2063         
2064         BIF_undo_push("make track");
2065         
2066         return OPERATOR_FINISHED;
2067 }
2068
2069 void OBJECT_OT_make_track(wmOperatorType *ot)
2070 {
2071         PropertyRNA *prop;
2072         
2073         /* identifiers */
2074         ot->name= "Make Track";
2075         ot->idname= "OBJECT_OT_make_track";
2076         
2077         /* api callbacks */
2078         ot->invoke= WM_menu_invoke;
2079         ot->exec= make_track_exec;
2080         
2081         ot->poll= ED_operator_scene_editable;
2082         ot->flag= OPTYPE_REGISTER;
2083         
2084         prop = RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
2085         RNA_def_property_enum_items(prop, prop_make_track_types);
2086 }
2087
2088
2089 /* ******************* toggle editmode operator  ***************** */
2090
2091 void ED_object_exit_editmode(bContext *C, int flag)
2092 {
2093         Scene *scene= CTX_data_scene(C);
2094         Object *ob;
2095 //      Object *obedit= CTX_data_edit_object(C);
2096         int freedata = flag & EM_FREEDATA;
2097         
2098         if(G.obedit==NULL) return;
2099         
2100         if(flag & EM_WAITCURSOR) waitcursor(1);
2101         if(G.obedit->type==OB_MESH) {
2102                 Mesh *me= G.obedit->data;
2103                 
2104 //              if(EM_texFaceCheck())
2105                 
2106 //              if(retopo_mesh_paint_check())
2107 //                      retopo_end_okee();
2108                 
2109                 if(G.totvert>MESH_MAX_VERTS) {
2110                         error("Too many vertices");
2111                         return;
2112                 }
2113                 load_editMesh(scene, G.obedit);
2114                 
2115                 if(freedata) free_editMesh(me->edit_mesh);
2116                 
2117                 if(G.f & G_WEIGHTPAINT)
2118                         mesh_octree_table(G.obedit, NULL, NULL, 'e');
2119         }
2120         else if (G.obedit->type==OB_ARMATURE){  
2121 //              load_editArmature();
2122 //              if (freedata) free_editArmature();
2123         }
2124         else if(ELEM(G.obedit->type, OB_CURVE, OB_SURF)) {
2125 //              extern ListBase editNurb;
2126 //              load_editNurb();
2127 //              if(freedata) freeNurblist(&editNurb);
2128         }
2129         else if(G.obedit->type==OB_FONT && freedata) {
2130 //              load_editText();
2131         }
2132         else if(G.obedit->type==OB_LATTICE) {
2133 //              load_editLatt();
2134 //              if(freedata) free_editLatt();
2135         }
2136         else if(G.obedit->type==OB_MBALL) {
2137 //              extern ListBase editelems;
2138 //              load_editMball();
2139 //              if(freedata) BLI_freelistN(&editelems);
2140         }
2141         
2142         ob= G.obedit;
2143         
2144         /* for example; displist make is different in editmode */
2145         if(freedata) G.obedit= NULL;
2146         scene->obedit= G.obedit; // XXX
2147         
2148         if(ob->type==OB_MESH && get_mesh(ob)->mr)
2149                 multires_edge_level_update(ob, get_mesh(ob));
2150         
2151         /* also flush ob recalc, doesn't take much overhead, but used for particles */
2152         DAG_object_flush_update(scene, ob, OB_RECALC_OB|OB_RECALC_DATA);
2153         
2154         if(G.obedit==NULL) // XXX && (flag & EM_FREEUNDO)) 
2155                 ED_undo_push(C, "Editmode");
2156         
2157         if(flag & EM_WAITCURSOR) waitcursor(0);
2158         
2159         WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_OBJECT, ob);
2160
2161 }
2162
2163
2164 void ED_object_enter_editmode(bContext *C, int flag)
2165 {
2166         Scene *scene= CTX_data_scene(C);
2167         Base *base= CTX_data_active_base(C);
2168         Object *ob= base->object;
2169         View3D *v3d= (View3D *)CTX_wm_space_data(C);
2170         int ok= 0;
2171         
2172         if(scene->id.lib) return;
2173         if(base==NULL) return;
2174         if((v3d==NULL || (base->lay & v3d->lay))==0) return;
2175         
2176         if(ob->data==NULL) return;
2177         
2178         if (object_data_is_libdata(ob)) {
2179                 error_libdata();
2180                 return;
2181         }
2182         
2183         if(flag & EM_WAITCURSOR) waitcursor(1);
2184         
2185         if(ob->type==OB_MESH) {
2186                 Mesh *me= ob->data;
2187                 
2188                 if(me->pv) mesh_pmv_off(ob, me);
2189                 ok= 1;
2190                 G.obedit= ob; // XXX
2191                 scene->obedit= ob;      // context sees this
2192                 
2193                 make_editMesh(scene, ob);
2194
2195                 WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_EDITMODE_MESH, ob);
2196         }
2197         if (ob->type==OB_ARMATURE){
2198                 bArmature *arm= base->object->data;
2199                 if (!arm) return;
2200                 /*
2201                  * The function object_data_is_libdata make a problem here, the
2202                  * check for ob->proxy return 0 and let blender enter to edit mode
2203                  * this causa a crash when you try leave the edit mode.
2204                  * The problem is that i can't remove the ob->proxy check from
2205                  * object_data_is_libdata that prevent the bugfix #6614, so
2206                  * i add this little hack here.
2207                  */
2208                 if(arm->id.lib) {
2209                         error_libdata();
2210                         return;
2211                 }
2212                 ok=1;
2213                 G.obedit=ob;
2214 // XXX          make_editArmature();
2215                 /* to ensure all goes in restposition and without striding */
2216                 DAG_object_flush_update(scene, G.obedit, OB_RECALC);
2217
2218                 WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_EDITMODE_ARMATURE, ob);
2219         }
2220         else if(ob->type==OB_FONT) {
2221                 G.obedit= ob;
2222                 ok= 1;
2223 // XXX          make_editText();
2224         }
2225         else if(ob->type==OB_MBALL) {
2226                 G.obedit= ob;
2227                 ok= 1;
2228 // XXX          make_editMball();
2229         }
2230         else if(ob->type==OB_LATTICE) {
2231                 G.obedit= ob;
2232                 ok= 1;
2233 // XXX          make_editLatt();
2234         }
2235         else if(ob->type==OB_SURF || ob->type==OB_CURVE) {
2236                 ok= 1;
2237                 G.obedit= ob;
2238 // XXX          make_editNurb();
2239         }
2240         
2241         if(ok) {
2242                 DAG_object_flush_update(scene, G.obedit, OB_RECALC_DATA);
2243         }
2244         else {
2245                 G.obedit= NULL;
2246                 WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_OBJECT, ob);
2247         }
2248         
2249         if(flag & EM_WAITCURSOR) waitcursor(0);
2250 }
2251
2252 static int toggle_editmode_exec(bContext *C, wmOperator *op)
2253 {
2254         
2255         if(!CTX_data_edit_object(C))
2256                 ED_object_enter_editmode(C, EM_WAITCURSOR);
2257         else
2258                 ED_object_exit_editmode(C, EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR);
2259         
2260         return OPERATOR_FINISHED;
2261 }
2262
2263 void OBJECT_OT_toggle_editmode(wmOperatorType *ot)
2264 {
2265         
2266         /* identifiers */
2267         ot->name= "Toggle Editmode";
2268         ot->idname= "OBJECT_OT_toggle_editmode";
2269         
2270         /* api callbacks */
2271         ot->exec= toggle_editmode_exec;
2272         
2273         ot->poll= ED_operator_object_active;
2274         ot->flag= OPTYPE_REGISTER;
2275 }
2276
2277 /* *************************** */
2278
2279
2280 void check_editmode(int type)
2281 {
2282         
2283         if (G.obedit==0 || G.obedit->type==type) return;
2284
2285 // XXX  ED_object_exit_editmode(C, EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR); /* freedata, and undo */
2286 }
2287
2288 /* 0 == do center, 1 == center new, 2 == center cursor */
2289
2290 void docenter(Scene *scene, View3D *v3d, int centermode)
2291 {
2292         Base *base;
2293         Object *ob;
2294         Mesh *me, *tme;
2295         Curve *cu;
2296 /*      BezTriple *bezt;
2297         BPoint *bp; */
2298         Nurb *nu, *nu1;
2299         EditVert *eve;
2300         float cent[3], centn[3], min[3], max[3], omat[3][3];
2301         int a, total= 0;
2302         
2303         /* keep track of what is changed */
2304         int tot_change=0, tot_lib_error=0, tot_multiuser_arm_error=0;
2305         MVert *mvert;
2306
2307         if(scene->id.lib || v3d==NULL) return;
2308         
2309         cent[0]= cent[1]= cent[2]= 0.0;
2310         
2311         if(G.obedit) {
2312
2313                 INIT_MINMAX(min, max);
2314         
2315                 if(G.obedit->type==OB_MESH) {
2316                         Mesh *me= G.obedit->data;
2317                         
2318                         for(eve= me->edit_mesh->verts.first; eve; eve= eve->next) {
2319                                 if(v3d->around==V3D_CENTROID) {
2320                                         total++;
2321                                         VECADD(cent, cent, eve->co);
2322                                 }
2323                                 else {
2324                                         DO_MINMAX(eve->co, min, max);
2325                                 }
2326                         }
2327                         
2328                         if(v3d->around==V3D_CENTROID) {
2329                                 VecMulf(cent, 1.0f/(float)total);
2330                         }
2331                         else {
2332                                 cent[0]= (min[0]+max[0])/2.0f;
2333                                 cent[1]= (min[1]+max[1])/2.0f;
2334                                 cent[2]= (min[2]+max[2])/2.0f;
2335                         }
2336                         
2337                         for(eve= me->edit_mesh->verts.first; eve; eve= eve->next) {
2338                                 VecSubf(eve->co, eve->co, cent);                        
2339                         }
2340                         
2341 // XXX                  recalc_editnormals();
2342                         tot_change++;
2343                         DAG_object_flush_update(scene, G.obedit, OB_RECALC_DATA);
2344                 }
2345         }
2346         
2347         /* reset flags */
2348         for (base=FIRSTBASE; base; base= base->next) {
2349                 if(TESTBASELIB(v3d, base))
2350                         base->object->flag &= ~OB_DONE;
2351         }
2352         
2353         for (me= G.main->mesh.first; me; me= me->id.next) {
2354                 me->flag &= ~ME_ISDONE;
2355         }
2356         
2357         for(base= FIRSTBASE; base; base= base->next) {
2358                 if(TESTBASELIB(v3d, base)) {
2359                         if((base->object->flag & OB_DONE)==0) {
2360                                 base->object->flag |= OB_DONE;
2361                                 
2362                                 if(base->object->id.lib) {
2363                                         tot_lib_error++;
2364                                 }
2365                                 else if(G.obedit==0 && (me=get_mesh(base->object)) ) {
2366                                         if (me->id.lib) {
2367                                                 tot_lib_error++;
2368                                         } else {
2369                                                 if(centermode==2) {
2370                                                         VECCOPY(cent, give_cursor(scene, v3d));
2371                                                         Mat4Invert(base->object->imat, base->object->obmat);
2372                                                         Mat4MulVecfl(base->object->imat, cent);
2373                                                 } else {
2374                                                         INIT_MINMAX(min, max);
2375                                                         mvert= me->mvert;
2376                                                         for(a=0; a<me->totvert; a++, mvert++) {
2377                                                                 DO_MINMAX(mvert->co, min, max);
2378                                                         }
2379                                         
2380                                                         cent[0]= (min[0]+max[0])/2.0f;
2381                                                         cent[1]= (min[1]+max[1])/2.0f;
2382                                                         cent[2]= (min[2]+max[2])/2.0f;
2383                                                 }
2384
2385                                                 mvert= me->mvert;
2386                                                 for(a=0; a<me->totvert; a++, mvert++) {
2387                                                         VecSubf(mvert->co, mvert->co, cent);
2388                                                 }
2389                                                 
2390                                                 if (me->key) {
2391                                                         KeyBlock *kb;
2392                                                         for (kb=me->key->block.first; kb; kb=kb->next) {
2393                                                                 float *fp= kb->data;
2394                                                                 
2395                                                                 for (a=0; a<kb->totelem; a++, fp+=3) {
2396                                                                         VecSubf(fp, fp, cent);
2397                                                                 }
2398                                                         }
2399                                                 }
2400                                                 
2401                                                 me->flag |= ME_ISDONE;
2402                                                 
2403                                                 if(centermode) {
2404                                                         Mat3CpyMat4(omat, base->object->obmat);
2405                                                         
2406                                                         VECCOPY(centn, cent);
2407                                                         Mat3MulVecfl(omat, centn);
2408                                                         base->object->loc[0]+= centn[0];
2409                                                         base->object->loc[1]+= centn[1];
2410                                                         base->object->loc[2]+= centn[2];
2411                                                         
2412                                                         where_is_object(base->object);
2413                                                         ignore_parent_tx(base->object);
2414                                                         
2415                                                         /* other users? */
2416                                                         ob= G.main->object.first;
2417                                                         while(ob) {
2418                                                                 if((ob->flag & OB_DONE)==0) {
2419                                                                         tme= get_mesh(ob);
2420                                                                         
2421                                                                         if(tme==me) {
2422                                                                                 
2423                                                                                 ob->flag |= OB_DONE;
2424                                                                                 ob->recalc= OB_RECALC_OB|OB_RECALC_DATA;
2425
2426                                                                                 Mat3CpyMat4(omat, ob->obmat);
2427                                                                                 VECCOPY(centn, cent);
2428                                                                                 Mat3MulVecfl(omat, centn);
2429                                                                                 ob->loc[0]+= centn[0];
2430                                                                                 ob->loc[1]+= centn[1];
2431                                                                                 ob->loc[2]+= centn[2];
2432                                                                                 
2433                                                                                 where_is_object(ob);
2434                                                                                 ignore_parent_tx(ob);
2435                                                                                 
2436                                                                                 if(tme && (tme->flag & ME_ISDONE)==0) {
2437                                                                                         mvert= tme->mvert;
2438                                                                                         for(a=0; a<tme->totvert; a++, mvert++) {
2439                                                                                                 VecSubf(mvert->co, mvert->co, cent);
2440                                                                                         }
2441                                                                                         
2442                                                                                         if (tme->key) {
2443                                                                                                 KeyBlock *kb;
2444                                                                                                 for (kb=tme->key->block.first; kb; kb=kb->next) {
2445                                                                                                         float *fp= kb->data;
2446                                                                                                         
2447                                                                                                         for (a=0; a<kb->totelem; a++, fp+=3) {
2448                                                                                                                 VecSubf(fp, fp, cent);
2449                                                                                                         }
2450                                                                                                 }
2451                                                                                         }
2452                                                                                         
2453                                                                                         tme->flag |= ME_ISDONE;
2454                                                                                 }
2455                                                                         }
2456                                                                 }
2457                                                                 
2458                                                                 ob= ob->id.next;
2459                                                         }
2460                                                 }
2461                                                 tot_change++;
2462                                         }
2463                                 }
2464                                 else if (ELEM(base->object->type, OB_CURVE, OB_SURF)) {
2465                                         
2466                                         /* totally weak code here... (ton) */
2467                                         if(G.obedit==base->object) {
2468                                                 extern ListBase editNurb;
2469                                                 nu1= editNurb.first;
2470                                                 cu= G.obedit->data;
2471                                         }
2472                                         else {
2473                                                 cu= base->object->data;
2474                                                 nu1= cu->nurb.first;
2475                                         }
2476                                         
2477                                         if (cu->id.lib) {
2478                                                 tot_lib_error++;
2479                                         } else {
2480                                                 if(centermode==2) {
2481                                                         VECCOPY(cent, give_cursor(scene, v3d));
2482                                                         Mat4Invert(base->object->imat, base->object->obmat);
2483                                                         Mat4MulVecfl(base->object->imat, cent);
2484
2485                                                         /* don't allow Z change if curve is 2D */
2486                                                         if( !( cu->flag & CU_3D ) )
2487                                                                 cent[2] = 0.0;
2488                                                 } 
2489                                                 else {
2490                                                         INIT_MINMAX(min, max);
2491                                                         
2492                                                         nu= nu1;
2493                                                         while(nu) {
2494                                                                 minmaxNurb(nu, min, max);
2495                                                                 nu= nu->next;
2496                                                         }
2497                                                         
2498                                                         cent[0]= (min[0]+max[0])/2.0f;
2499                                                         cent[1]= (min[1]+max[1])/2.0f;
2500                                                         cent[2]= (min[2]+max[2])/2.0f;
2501                                                 }
2502                                                 
2503                                                 nu= nu1;
2504                                                 while(nu) {
2505                                                         if( (nu->type & 7)==1) {
2506                                                                 a= nu->pntsu;
2507                                                                 while (a--) {
2508                                                                         VecSubf(nu->bezt[a].vec[0], nu->bezt[a].vec[0], cent);
2509                                                                         VecSubf(nu->bezt[a].vec[1], nu->bezt[a].vec[1], cent);
2510                                                                         VecSubf(nu->bezt[a].vec[2], nu->bezt[a].vec[2], cent);
2511                                                                 }
2512                                                         }
2513                                                         else {
2514                                                                 a= nu->pntsu*nu->pntsv;
2515                                                                 while (a--)
2516                                                                         VecSubf(nu->bp[a].vec, nu->bp[a].vec, cent);
2517                                                         }
2518                                                         nu= nu->next;
2519                                                 }
2520                                 
2521                                                 if(centermode && G.obedit==0) {
2522                                                         Mat3CpyMat4(omat, base->object->obmat);
2523                                                         
2524                                                         Mat3MulVecfl(omat, cent);
2525                                                         base->object->loc[0]+= cent[0];
2526                                                         base->object->loc[1]+= cent[1];
2527                                                         base->object->loc[2]+= cent[2];
2528                                                         
2529                                                         where_is_object(base->object);
2530                                                         ignore_parent_tx(base->object);
2531                                                 }
2532                                                 
2533                                                 tot_change++;
2534                                                 if(G.obedit) {
2535                                                         if (centermode==0) {
2536                                                                 DAG_object_flush_update(scene, G.obedit, OB_RECALC_DATA);
2537                                                         }
2538                                                         break;
2539                                                 }
2540                                         }
2541                                 }
2542                                 else if(base->object->type==OB_FONT) {
2543                                         /* get from bb */
2544                                         
2545                                         cu= base->object->data;
2546                                         
2547                                         if(cu->bb==0) {
2548                                                 /* do nothing*/
2549                                         } else if (cu->id.lib) {
2550                                                 tot_lib_error++;
2551                                         } else {
2552                                                 cu->xof= -0.5f*( cu->bb->vec[4][0] - cu->bb->vec[0][0]);
2553                                                 cu->yof= -0.5f -0.5f*( cu->bb->vec[0][1] - cu->bb->vec[2][1]);  /* extra 0.5 is the height of above line */
2554                                                 
2555                                                 /* not really ok, do this better once! */
2556                                                 cu->xof /= cu->fsize;
2557                                                 cu->yof /= cu->fsize;
2558
2559                                                 allqueue(REDRAWBUTSEDIT, 0);
2560                                                 tot_change++;
2561                                         }
2562                                 }
2563                                 else if(base->object->type==OB_ARMATURE) {
2564                                         bArmature *arm = base->object->data;
2565                                         
2566                                         if (arm->id.lib) {
2567                                                 tot_lib_error++;
2568                                         } else if(arm->id.us>1) {
2569                                                 /*error("Can't apply to a multi user armature");
2570                                                 return;*/
2571                                                 tot_multiuser_arm_error++;
2572                                         } else {
2573                                                 /* Function to recenter armatures in editarmature.c 
2574                                                  * Bone + object locations are handled there.
2575                                                  */
2576 // XXX                                          docenter_armature(base->object, centermode);
2577                                                 tot_change++;
2578                                                 
2579                                                 where_is_object(base->object);
2580                                                 ignore_parent_tx(base->object);
2581                                                 
2582                                                 if(G.obedit) 
2583                                                         break;
2584                                         }
2585                                 }
2586                                 base->object->recalc= OB_RECALC_OB|OB_RECALC_DATA;
2587                         }
2588                 }
2589         }
2590         if (tot_change) {
2591                 ED_anim_dag_flush_update(C);
2592                 allqueue(REDRAWVIEW3D, 0);
2593                 BIF_undo_push("Do Center");     
2594         }
2595         
2596         /* Warn if any errors occured */
2597         if (tot_lib_error+tot_multiuser_arm_error) {
2598                 char err[512];
2599                 sprintf(err, "Warning %i Object(s) Not Centered, %i Changed:", tot_lib_error+tot_multiuser_arm_error, tot_change);
2600                 
2601                 if (tot_lib_error)
2602                         sprintf(err+strlen(err), "|%i linked library objects", tot_lib_error);
2603                 if (tot_multiuser_arm_error)
2604                         sprintf(err+strlen(err), "|%i multiuser armature object(s)", tot_multiuser_arm_error);
2605                 
2606                 error(err);
2607         }
2608 }
2609
2610 void docenter_new(Scene *scene, View3D *v3d)
2611 {
2612         if(scene->id.lib) return;
2613
2614         if(G.obedit) {
2615                 error("Unable to center new in Edit Mode");
2616         }
2617         else {
2618                 docenter(scene, v3d, 1);
2619         }
2620 }
2621
2622 void docenter_cursor(Scene *scene, View3D *v3d)
2623 {
2624         if(scene->id.lib) return;
2625
2626         if(G.obedit) {
2627                 error("Unable to center cursor in Edit Mode");
2628         }
2629         else {
2630                 docenter(scene, v3d, 2);
2631         }
2632 }
2633
2634 void movetolayer(Scene *scene, View3D *v3d)
2635 {
2636         Base *base;
2637         unsigned int lay= 0, local;
2638         int islamp= 0;
2639         
2640         if(scene->id.lib) return;
2641
2642         for(base= FIRSTBASE; base; base= base->next) {
2643                 if (TESTBASE(v3d, base)) lay |= base->lay;
2644         }
2645         if(lay==0) return;
2646         lay &= 0xFFFFFF;
2647         
2648         if(lay==0) return;
2649         
2650         if(v3d->localview) {
2651                 /* now we can move out of localview. */
2652                 if (!okee("Move from localview")) return;
2653                 for(base= FIRSTBASE; base; base= base->next) {
2654                         if (TESTBASE(v3d, base)) {
2655                                 lay= base->lay & ~v3d->lay;
2656                                 base->lay= lay;
2657                                 base->object->lay= lay;
2658                                 base->object->flag &= ~SELECT;
2659                                 base->flag &= ~SELECT;
2660                                 if(base->object->type==OB_LAMP) islamp= 1;
2661                         }
2662                 }
2663         } else {
2664 // XXX          if( movetolayer_buts(&lay, NULL)==0 ) return;
2665                 
2666                 /* normal non localview operation */
2667                 for(base= FIRSTBASE; base; base= base->next) {
2668                         if (TESTBASE(v3d, base)) {
2669                                 /* upper byte is used for local view */
2670                                 local= base->lay & 0xFF000000;  
2671                                 base->lay= lay + local;
2672                                 base->object->lay= lay;
2673                                 if(base->object->type==OB_LAMP) islamp= 1;
2674                         }
2675                 }
2676         }
2677         if(islamp) reshadeall_displist();       /* only frees */
2678         
2679         /* warning, active object may be hidden now */
2680         
2681         DAG_scene_sort(scene);
2682         
2683         allqueue(REDRAWBUTSEDIT, 0);
2684         allqueue(REDRAWVIEW3D, 0);
2685         allqueue(REDRAWOOPS, 0);
2686         allqueue(REDRAWINFO, 0);
2687         
2688         BIF_undo_push("Move to layer");
2689 }
2690
2691
2692 #if 0
2693 // XXX should be in view3d?
2694
2695 /* context: ob = lamp */
2696 /* code should be replaced with proper (custom) transform handles for lamp properties */
2697 static void spot_interactive(Object *ob, int mode)
2698 {
2699         Lamp *la= ob->data;
2700         float transfac, dx, dy, ratio, origval;
2701         int keep_running= 1, center2d[2];
2702         short mval[2], mvalo[2];
2703         
2704 //      getmouseco_areawin(mval);
2705 //      getmouseco_areawin(mvalo);
2706         
2707         project_int(ob->obmat[3], center2d);
2708         if( center2d[0] > 100000 ) {            /* behind camera */
2709 //              center2d[0]= curarea->winx/2;
2710 //              center2d[1]= curarea->winy/2;
2711         }
2712
2713 //      helpline(mval, center2d);
2714         
2715         /* ratio is like scaling */
2716         dx = (float)(center2d[0] - mval[0]);
2717         dy = (float)(center2d[1] - mval[1]);
2718         transfac = (float)sqrt( dx*dx + dy*dy);
2719         if(transfac==0.0f) transfac= 1.0f;
2720         
2721         if(mode==1)     
2722                 origval= la->spotsize;
2723         else if(mode==2)        
2724                 origval= la->dist;
2725         else if(mode==3)        
2726                 origval= la->clipsta;
2727         else    
2728                 origval= la->clipend;
2729         
2730         while (keep_running>0) {
2731                 
2732 //              getmouseco_areawin(mval);
2733                 
2734                 /* essential for idling subloop */
2735                 if(mval[0]==mvalo[0] && mval[1]==mvalo[1]) {
2736                         PIL_sleep_ms(2);
2737                 }
2738                 else {
2739                         char str[32];
2740                         
2741                         dx = (float)(center2d[0] - mval[0]);
2742                         dy = (float)(center2d[1] - mval[1]);
2743                         ratio = (float)(sqrt( dx*dx + dy*dy))/transfac;
2744                         
2745                         /* do the trick */
2746                         
2747                         if(mode==1) {   /* spot */
2748                                 la->spotsize = ratio*origval;
2749                                 CLAMP(la->spotsize, 1.0f, 180.0f);
2750                                 sprintf(str, "Spot size %.2f\n", la->spotsize);
2751                         }
2752                         else if(mode==2) {      /* dist */
2753                                 la->dist = ratio*origval;
2754                                 CLAMP(la->dist, 0.01f, 5000.0f);
2755                                 sprintf(str, "Distance %.2f\n", la->dist);
2756                         }
2757                         else if(mode==3) {      /* sta */
2758                                 la->clipsta = ratio*origval;
2759                                 CLAMP(la->clipsta, 0.001f, 5000.0f);
2760                                 sprintf(str, "Distance %.2f\n", la->clipsta);
2761                         }
2762                         else if(mode==4) {      /* end */
2763                                 la->clipend = ratio*origval;
2764                                 CLAMP(la->clipend, 0.1f, 5000.0f);
2765                                 sprintf(str, "Clip End %.2f\n", la->clipend);
2766                         }
2767
2768                         /* cleanup */
2769                         mvalo[0]= mval[0];
2770                         mvalo[1]= mval[1];
2771                         
2772                         /* handle shaded mode */
2773 // XXX                  shade_buttons_change_3d();
2774
2775                         /* DRAW */      
2776                         headerprint(str);
2777                         force_draw_plus(SPACE_BUTS, 0);
2778
2779 //                      helpline(mval, center2d);
2780                 }
2781                 
2782                 while( qtest() ) {
2783                         short val;
2784                         unsigned short event= extern_qread(&val);
2785                         
2786                         switch (event){
2787                                 case ESCKEY:
2788                                 case RIGHTMOUSE:
2789                                         keep_running= 0;
2790                                         break;
2791                                 case LEFTMOUSE:
2792                                 case SPACEKEY:
2793                                 case PADENTER:
2794                                 case RETKEY:
2795                                         if(val)
2796                                                 keep_running= -1;
2797                                         break;
2798                         }
2799                 }
2800         }
2801
2802         if(keep_running==0) {
2803                 if(mode==1)     
2804                         la->spotsize= origval;
2805                 else if(mode==2)        
2806                         la->dist= origval;
2807                 else if(mode==3)        
2808                         la->clipsta= origval;
2809                 else    
2810                         la->clipend= origval;
2811         }
2812
2813         allqueue(REDRAWVIEW3D, 0);
2814         allqueue(REDRAWBUTSSHADING, 0);
2815         BIF_preview_changed(ID_LA);
2816 }
2817 #endif
2818
2819 void special_editmenu(Scene *scene, View3D *v3d)
2820 {
2821 // XXX  static short numcuts= 2;
2822         Object *ob= OBACT;
2823         float fac;
2824         int nr,ret;
2825         short randfac;
2826         
2827         if(ob==NULL) return;
2828         
2829         if(G.obedit==NULL) {
2830                 
2831                 if(ob->flag & OB_POSEMODE) {
2832 // XXX                  pose_special_editmenu();
2833                 }
2834                 else if(FACESEL_PAINT_TEST) {
2835                         Mesh *me= get_mesh(ob);
2836                         MTFace *tface;
2837                         MFace *mface;
2838                         int a;
2839                         
2840                         if(me==0 || me->mtface==0) return;
2841                         
2842                         nr= pupmenu("Specials%t|Set     Tex%x1|         Shared%x2|         Light%x3|         Invisible%x4|         Collision%x5|         TwoSide%x6|Clr     Tex%x7|         Shared%x8|         Light%x9|         Invisible%x10|         Collision%x11|         TwoSide%x12");
2843                         
2844                         tface= me->mtface;
2845                         mface= me->mface;
2846                         for(a=me->totface; a>0; a--, tface++, mface++) {
2847                                 if(mface->flag & ME_FACE_SEL) {
2848                                         switch(nr) {
2849                                         case 1:
2850                                                 tface->mode |= TF_TEX; break;
2851                                         case 2:
2852                                                 tface->mode |= TF_SHAREDCOL; break;
2853                                         case 3:
2854                                                 tface->mode |= TF_LIGHT; break; 
2855                                         case 4:
2856                                                 tface->mode |= TF_INVISIBLE; break;
2857                                         case 5:
2858                                                 tface->mode |= TF_DYNAMIC; break;
2859                                         case 6:
2860                                                 tface->mode |= TF_TWOSIDE; break;
2861                                         case 7:
2862                                                 tface->mode &= ~TF_TEX;
2863                                                 tface->tpage= 0;
2864                                                 break;
2865                                         case 8:
2866                                                 tface->mode &= ~TF_SHAREDCOL; break;
2867                                         case 9:
2868                                                 tface->mode &= ~TF_LIGHT; break;
2869                                         case 10:
2870                                                 tface->mode &= ~TF_INVISIBLE; break;
2871                                         case 11:
2872                                                 tface->mode &= ~TF_DYNAMIC; break;
2873                                         case 12:
2874                                                 tface->mode &= ~TF_TWOSIDE; break;
2875                                         }
2876                                 }
2877                         }
2878                         DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
2879                         allqueue(REDRAWVIEW3D, 0);
2880                         allqueue(REDRAWBUTSEDIT, 0);
2881                         BIF_undo_push("Change texture face");
2882                 }
2883                 else if(G.f & G_VERTEXPAINT) {
2884                         Mesh *me= get_mesh(ob);
2885                         
2886                         if(me==0 || (me->mcol==NULL && me->mtface==NULL) ) return;
2887                         
2888                         nr= pupmenu("Specials%t|Shared VertexCol%x1");
2889                         if(nr==1) {
2890                                 
2891 // XXX                          do_shared_vertexcol(me);