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 (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(scene->obedit==NULL) { // XXX get from context
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(scene->obedit) return; // XXX get from context
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(Object *obedit, 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(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 == (obedit->actdef-1)) {
419                                                 totvert++;
420                                                 VecAddf(cent, cent, eve->co);
421                                         }
422                                 }
423                         }
424                 }
425                 if(totvert) {
426                         bDeformGroup *defGroup = BLI_findlink(&obedit->defbase, 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(Object *obedit, int *tot, int **indexar, char *name, float *cent_r)
612 {
613         *indexar= NULL;
614         *tot= 0;
615         name[0]= 0;
616         
617         switch(obedit->type) {
618                 case OB_MESH:
619                 {
620                         Mesh *me= 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(obedit, 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         Object *obedit= scene->obedit;  // XXX get from context
698         
699         if(obedit==NULL) return;
700         
701         /* preconditions */
702         if(mode==2) { /* selected object */
703                 Base *base;
704                 for(base= FIRSTBASE; base; base= base->next) {
705                         if(TESTBASELIB(v3d, base)) {
706                                 if(base!=BASACT) {
707                                         ob= base->object;
708                                         break;
709                                 }
710                         }
711                 }
712                 if(ob==NULL) {
713                         error("Requires selected Object");
714                         return;
715                 }
716         }
717         else if(mode!=1) {
718                 int maxlen=0, a, nr;
719                 char *cp;
720                 
721                 /* make pupmenu with hooks */
722                 for(md=obedit->modifiers.first; md; md= md->next) {
723                         if (md->type==eModifierType_Hook) 
724                                 maxlen+=32;
725                 }
726                 
727                 if(maxlen==0) {
728                         error("Object has no hooks yet");
729                         return;
730                 }
731                 
732                 cp= MEM_callocN(maxlen+32, "temp string");
733                 if(mode==3) strcpy(cp, "Remove %t|");
734                 else if(mode==4) strcpy(cp, "Reassign %t|");
735                 else if(mode==5) strcpy(cp, "Select %t|");
736                 else if(mode==6) strcpy(cp, "Clear Offset %t|");
737                 
738                 for(md=obedit->modifiers.first; md; md= md->next) {
739                         if (md->type==eModifierType_Hook) {
740                                 strcat(cp, md->name);
741                                 strcat(cp, " |");
742                         }
743                 }
744                 
745                 nr= pupmenu(cp);
746                 MEM_freeN(cp);
747                 
748                 if(nr<1) return;
749                 
750                 a= 1;
751                 for(md=obedit->modifiers.first; md; md=md->next) {
752                         if (md->type==eModifierType_Hook) {
753                                 if(a==nr) break;
754                                 a++;
755                         }
756                 }
757                 
758                 hmd = (HookModifierData*) md;
759                 ob= hmd->object;
760         }
761
762         /* do it, new hooks or reassign */
763         if(mode==1 || mode==2 || mode==4) {
764                 float cent[3];
765                 int tot, ok, *indexar;
766                 char name[32];
767                 
768                 ok = hook_getIndexArray(obedit, &tot, &indexar, name, cent);
769                 
770                 if(ok==0) {
771                         error("Requires selected vertices or active Vertex Group");
772                 }
773                 else {
774                         
775                         if(mode==1) {
776                                 Base *base= BASACT, *newbase;
777                                 
778                                 ob= add_object(OB_EMPTY);
779                                 /* set layers OK */
780                                 newbase= BASACT;
781                                 newbase->lay= base->lay;
782                                 ob->lay= newbase->lay;
783                                 
784                                 /* transform cent to global coords for loc */
785                                 VecMat4MulVecfl(ob->loc, obedit->obmat, cent);
786                                 
787                                 /* restore, add_object sets active */
788                                 BASACT= base;
789                         }
790                         /* if mode is 2 or 4, ob has been set */
791                         
792                         /* new hook */
793                         if(mode==1 || mode==2) {
794                                 ModifierData *md = obedit->modifiers.first;
795                                 
796                                 while (md && modifierType_getInfo(md->type)->type==eModifierTypeType_OnlyDeform) {
797                                         md = md->next;
798                                 }
799                                 
800                                 hmd = (HookModifierData*) modifier_new(eModifierType_Hook);
801                                 BLI_insertlinkbefore(&obedit->modifiers, md, hmd);
802                                 sprintf(hmd->modifier.name, "Hook-%s", ob->id.name+2);
803                         }
804                         else if (hmd->indexar) MEM_freeN(hmd->indexar); /* reassign, hook was set */
805                 
806                         hmd->object= ob;
807                         hmd->indexar= indexar;
808                         VECCOPY(hmd->cent, cent);
809                         hmd->totindex= tot;
810                         BLI_strncpy(hmd->name, name, 32);
811                         
812                         if(mode==1 || mode==2) {
813                                 /* matrix calculus */
814                                 /* vert x (obmat x hook->imat) x hook->obmat x ob->imat */
815                                 /*        (parentinv         )                          */
816                                 
817                                 where_is_object(ob);
818                                 
819                                 Mat4Invert(ob->imat, ob->obmat);
820                                 /* apparently this call goes from right to left... */
821                                 Mat4MulSerie(hmd->parentinv, ob->imat, obedit->obmat, NULL, 
822                                                          NULL, NULL, NULL, NULL, NULL);
823                         }
824                 }
825         }
826         else if(mode==3) { /* remove */
827                 BLI_remlink(&obedit->modifiers, md);
828                 modifier_free(md);
829         }
830         else if(mode==5) { /* select */
831                 obedit_hook_select(obedit, hmd);
832         }
833         else if(mode==6) { /* clear offset */
834                 where_is_object(ob);    /* ob is hook->parent */
835
836                 Mat4Invert(ob->imat, ob->obmat);
837                 /* this call goes from right to left... */
838                 Mat4MulSerie(hmd->parentinv, ob->imat, obedit->obmat, NULL, 
839                                          NULL, NULL, NULL, NULL, NULL);
840         }
841
842         DAG_scene_sort(scene);
843 }
844
845
846 /* use this when the loc/size/rot of the parent has changed but the children should stay in the same place
847  * apply-size-rot or object center for eg */
848 static void ignore_parent_tx( Object *ob ) 
849 {
850         Object workob;
851         Object *ob_child;
852         
853         /* a change was made, adjust the children to compensate */
854         for (ob_child=G.main->object.first; ob_child; ob_child=ob_child->id.next) {
855                 if (ob_child->parent == ob) {
856                         apply_obmat(ob_child);
857                         what_does_parent(ob_child, &workob);
858                         Mat4Invert(ob_child->parentinv, workob.obmat);
859                 }
860         }
861 }
862
863
864 void add_hook_menu(Scene *scene, View3D *v3d)
865 {
866         Object *obedit= scene->obedit;  // XXX get from context
867         int mode;
868         
869         if(obedit==NULL) return;
870         
871         if(modifiers_findByType(obedit, eModifierType_Hook))
872                 mode= pupmenu("Hooks %t|Add, To New Empty %x1|Add, To Selected Object %x2|Remove... %x3|Reassign... %x4|Select... %x5|Clear Offset...%x6");
873         else
874                 mode= pupmenu("Hooks %t|Add, New Empty %x1|Add, To Selected Object %x2");
875
876         if(mode<1) return;
877                 
878         /* do operations */
879         add_hook(scene, v3d, mode);
880         
881         allqueue(REDRAWVIEW3D, 0);
882         allqueue(REDRAWBUTSOBJECT, 0);
883         
884         BIF_undo_push("Add hook");
885 }
886
887 void make_track(Scene *scene, View3D *v3d, short mode)
888 {
889         Base *base;
890         /*short mode=0;*/
891         
892         if(scene->id.lib) return;
893 // XXX  if(obedit) {
894 //              return; 
895 //      }
896         if(BASACT==0) return;
897
898         mode= pupmenu("Make Track %t|TrackTo Constraint %x1|LockTrack Constraint %x2|Old Track %x3");
899         if (mode == 0){
900                 return;
901         }
902         else if (mode == 1){
903                 bConstraint *con;
904                 bTrackToConstraint *data;
905
906                 for(base= FIRSTBASE; base; base= base->next) {
907                         if(TESTBASELIB(v3d, base)) {
908                                 if(base!=BASACT) {
909 // XXX                                  con = add_new_constraint(CONSTRAINT_TYPE_TRACKTO);
910                                         strcpy (con->name, "AutoTrack");
911
912                                         data = con->data;
913                                         data->tar = BASACT->object;
914                                         base->object->recalc |= OB_RECALC;
915                                         
916                                         /* Lamp and Camera track differently by default */
917                                         if (base->object->type == OB_LAMP || base->object->type == OB_CAMERA) {
918                                                 data->reserved1 = TRACK_nZ;
919                                                 data->reserved2 = UP_Y;
920                                         }
921
922 // XXX                                  add_constraint_to_object(con, base->object);
923                                 }
924                         }
925                 }
926
927         }
928         else if (mode == 2){
929                 bConstraint *con;
930                 bLockTrackConstraint *data;
931
932                 for(base= FIRSTBASE; base; base= base->next) {
933                         if(TESTBASELIB(v3d, base)) {
934                                 if(base!=BASACT) {
935 // XXX                                  con = add_new_constraint(CONSTRAINT_TYPE_LOCKTRACK);
936                                         strcpy (con->name, "AutoTrack");
937
938                                         data = con->data;
939                                         data->tar = BASACT->object;
940                                         base->object->recalc |= OB_RECALC;
941                                         
942                                         /* Lamp and Camera track differently by default */
943                                         if (base->object->type == OB_LAMP || base->object->type == OB_CAMERA) {
944                                                 data->trackflag = TRACK_nZ;
945                                                 data->lockflag = LOCK_Y;
946                                         }
947
948 // XXX                                  add_constraint_to_object(con, base->object);
949                                 }
950                         }
951                 }
952
953         }
954         else if (mode == 3){
955                 for(base= FIRSTBASE; base; base= base->next) {
956                         if(TESTBASELIB(v3d, base)) {
957                                 if(base!=BASACT) {
958                                         base->object->track= BASACT->object;
959                                         base->object->recalc |= OB_RECALC;
960                                 }
961                         }
962                 }
963         }
964
965         allqueue(REDRAWOOPS, 0);
966         allqueue(REDRAWVIEW3D, 0);
967         DAG_scene_sort(scene);
968         
969         BIF_undo_push("Make Track");
970 }
971
972 /* ******************** clear parent operator ******************* */
973
974
975 static EnumPropertyItem prop_clear_parent_types[] = {
976         {0, "CLEAR", "Clear Parent", ""},
977         {1, "CLEAR_KEEP_TRANSFORM", "Clear and Keep Transformation (Clear Track)", ""},
978         {2, "CLEAR_INVERSE", "Clear Parent Inverse", ""},
979         {0, NULL, NULL, NULL}
980 };
981
982 /* note, poll should check for editable scene */
983 static int clear_parent_exec(bContext *C, wmOperator *op)
984 {
985         
986         CTX_DATA_BEGIN(C, Object*, ob, selected_objects) {
987
988                 if(RNA_enum_is_equal(op->ptr, "type", "CLEAR")) {
989                         ob->parent= NULL;
990                 }                       
991                 if(RNA_enum_is_equal(op->ptr, "type", "CLEAR_KEEP_TRANSFORM")) {
992                         ob->parent= NULL;
993                         ob->track= NULL;
994                         apply_obmat(ob);
995                 }
996                 if(RNA_enum_is_equal(op->ptr, "type", "CLEAR_INVERSE")) {
997                         Mat4One(ob->parentinv);
998                 }
999                 ob->recalc |= OB_RECALC;
1000         }
1001         CTX_DATA_END;
1002         
1003         DAG_scene_sort(CTX_data_scene(C));
1004         ED_anim_dag_flush_update(C);
1005         
1006         BIF_undo_push("Clear Parent");  
1007         
1008         return OPERATOR_FINISHED;
1009 }
1010
1011 void OBJECT_OT_clear_parent(wmOperatorType *ot)
1012 {
1013         PropertyRNA *prop;
1014         
1015         /* identifiers */
1016         ot->name= "Clear parent";
1017         ot->idname= "OBJECT_OT_clear_parent";
1018         
1019         /* api callbacks */
1020         ot->invoke= WM_menu_invoke;
1021         ot->exec= clear_parent_exec;
1022         
1023         ot->poll= ED_operator_object_active;
1024         ot->flag= OPTYPE_REGISTER;
1025         
1026         prop = RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
1027         RNA_def_property_enum_items(prop, prop_clear_parent_types);
1028 }
1029
1030 /* ******************** clear track operator ******************* */
1031
1032
1033 static EnumPropertyItem prop_clear_track_types[] = {
1034         {0, "CLEAR", "Clear Track", ""},
1035         {1, "CLEAR_KEEP_TRANSFORM", "Clear and Keep Transformation (Clear Track)", ""},
1036         {0, NULL, NULL, NULL}
1037 };
1038
1039 /* note, poll should check for editable scene */
1040 static int object_clear_track_exec(bContext *C, wmOperator *op)
1041 {
1042         if(CTX_data_edit_object(C)) return OPERATOR_CANCELLED;
1043
1044         CTX_DATA_BEGIN(C, Object*, ob, selected_objects) {
1045                 /*if(TESTBASELIB(v3d, base)) {*/
1046                         ob->track= NULL;
1047                         ob->recalc |= OB_RECALC;
1048                         
1049                         if(RNA_enum_is_equal(op->ptr, "type", "CLEAR_KEEP_TRANSFORM")) {
1050                                 apply_obmat(ob);
1051                         }                       
1052                 /*}*/
1053         }
1054         CTX_DATA_END;
1055
1056         DAG_scene_sort(CTX_data_scene(C));
1057         ED_anim_dag_flush_update(C);
1058
1059         BIF_undo_push("Clear Track");   
1060         
1061         return OPERATOR_FINISHED;
1062 }
1063
1064 void OBJECT_OT_clear_track(wmOperatorType *ot)
1065 {
1066         PropertyRNA *prop;
1067         
1068         /* identifiers */
1069         ot->name= "Clear track";
1070         ot->idname= "OBJECT_OT_clear_track";
1071         
1072         /* api callbacks */
1073         ot->invoke= WM_menu_invoke;
1074         ot->exec= object_clear_track_exec;
1075         
1076         ot->poll= ED_operator_scene_editable;
1077         ot->flag= OPTYPE_REGISTER;
1078         
1079         prop = RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
1080         RNA_def_property_enum_items(prop, prop_clear_track_types);
1081 }
1082
1083
1084 /* ***************************** */
1085 /* ****** Select by Type ****** */
1086 static EnumPropertyItem prop_select_object_types[] = {
1087         {OB_EMPTY, "EMPTY", "Empty", ""},
1088         {OB_MESH, "MESH", "Mesh", ""},
1089         {OB_CURVE, "CURVE", "Curve", ""},
1090         {OB_SURF, "SURFACE", "Surface", ""},
1091         {OB_FONT, "TEXT", "Text", ""},
1092         {OB_MBALL, "META", "Meta", ""},
1093         {OB_LAMP, "LAMP", "Lamp", ""},
1094         {OB_CAMERA, "CAMERA", "Camera", ""},
1095         {OB_LATTICE, "LATTICE", "Lattice", ""},
1096         {0, NULL, NULL, NULL}
1097 };
1098
1099 static int object_select_by_type_exec(bContext *C, wmOperator *op)
1100 {
1101         short obtype;
1102         
1103         obtype = RNA_enum_get(op->ptr, "type");
1104                 
1105         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1106                 if(base->object->type==obtype) {
1107                         ED_base_object_select(base, BA_SELECT);
1108                 }
1109         }
1110         CTX_DATA_END;
1111         
1112         /* undo? */
1113         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1114         
1115         return OPERATOR_FINISHED;
1116 }
1117
1118 void OBJECT_OT_select_by_type(wmOperatorType *ot)
1119 {
1120         PropertyRNA *prop;
1121         
1122         /* identifiers */
1123         ot->name= "Select By Type";
1124         ot->idname= "OBJECT_OT_select_by_type";
1125         
1126         /* api callbacks */
1127         ot->invoke= WM_menu_invoke;
1128         ot->exec= object_select_by_type_exec;
1129         ot->poll= ED_operator_scene_editable;
1130         
1131         prop = RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
1132         RNA_def_property_enum_items(prop, prop_select_object_types);
1133
1134 }
1135
1136 /* ****** selection by layer *******/
1137
1138 static int object_select_by_layer_exec(bContext *C, wmOperator *op)
1139 {
1140         unsigned int layernum;
1141         
1142         layernum = RNA_int_get(op->ptr, "layer");
1143                 
1144         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1145                 if(base->lay == (1<< (layernum -1)))
1146                         ED_base_object_select(base, BA_SELECT);
1147         }
1148         CTX_DATA_END;
1149         
1150         /* undo? */
1151         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1152         
1153         return OPERATOR_FINISHED;
1154 }
1155
1156 void OBJECT_OT_select_by_layer(wmOperatorType *ot)
1157 {
1158         PropertyRNA *prop;
1159         
1160         /* identifiers */
1161         ot->name= "Selection by layer";
1162         ot->idname= "OBJECT_OT_select_by_layer";
1163         
1164         /* api callbacks */
1165         /*ot->invoke = XXX - need a int grid popup*/
1166         ot->exec= object_select_by_layer_exec;
1167         ot->poll= ED_operator_scene_editable;
1168         
1169         prop = RNA_def_property(ot->srna, "layer", PROP_INT, PROP_UNSIGNED);
1170         RNA_def_property_ui_range(prop, 1, 20,1, 1);
1171         RNA_def_property_ui_text(prop, "layer", "The layer to select objects in");
1172         RNA_def_property_int_default(prop, 2);
1173
1174 }
1175
1176 /* ****** invert selection *******/
1177 static int object_select_invert_exec(bContext *C, wmOperator *op)
1178 {
1179         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1180                 if (base->flag & SELECT)
1181                         ED_base_object_select(base, BA_DESELECT);
1182                 else
1183                         ED_base_object_select(base, BA_SELECT);
1184         }
1185         CTX_DATA_END;
1186         
1187         /* undo? */
1188         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1189         
1190         return OPERATOR_FINISHED;
1191 }
1192
1193 void OBJECT_OT_select_invert(wmOperatorType *ot)
1194 {
1195         
1196         /* identifiers */
1197         ot->name= "Invert selection";
1198         ot->idname= "OBJECT_OT_select_invert";
1199         
1200         /* api callbacks */
1201         ot->exec= object_select_invert_exec;
1202         ot->poll= ED_operator_scene_editable;
1203
1204 }
1205 /* ****** (de)select All *******/
1206
1207 static int object_de_select_all_exec(bContext *C, wmOperator *op)
1208 {
1209         
1210         int a=0, ok=0; 
1211         
1212         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1213                 if (base->flag & SELECT) {
1214                         ok= a= 1;
1215                         break;
1216                 }
1217                 else ok=1;
1218         }
1219         CTX_DATA_END;
1220         
1221         if (!ok) return OPERATOR_PASS_THROUGH;
1222         
1223         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1224                 if (a) ED_base_object_select(base, BA_DESELECT);
1225                 else ED_base_object_select(base, BA_SELECT);
1226         }
1227         CTX_DATA_END;
1228         
1229         /* undo? */
1230         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1231         
1232         return OPERATOR_FINISHED;
1233 }
1234
1235 void OBJECT_OT_de_select_all(wmOperatorType *ot)
1236 {
1237         
1238         /* identifiers */
1239         ot->name= "deselect all";
1240         ot->idname= "OBJECT_OT_de_select_all";
1241         
1242         /* api callbacks */
1243         ot->exec= object_de_select_all_exec;
1244         ot->poll= ED_operator_scene_editable;
1245
1246 }
1247 /* ****** random selection *******/
1248
1249 static int object_select_random_exec(bContext *C, wmOperator *op)
1250 {       
1251         int percent;
1252         
1253         percent = RNA_int_get(op->ptr, "percent");
1254                 
1255         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1256                 if ((!base->flag & SELECT && (BLI_frand() * 100) < percent)) {
1257                                 ED_base_object_select(base, BA_SELECT);
1258                 }
1259         }
1260         CTX_DATA_END;
1261         
1262         /* undo? */
1263         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1264         
1265         return OPERATOR_FINISHED;
1266 }
1267
1268 void OBJECT_OT_select_random(wmOperatorType *ot)
1269 {
1270         PropertyRNA *prop;
1271         
1272         /* identifiers */
1273         ot->name= "Random selection";
1274         ot->idname= "OBJECT_OT_select_random";
1275         
1276         /* api callbacks */
1277         /*ot->invoke= object_select_random_invoke XXX - need a number popup ;*/
1278         ot->exec = object_select_random_exec;
1279         ot->poll= ED_operator_scene_editable;
1280         
1281         prop = RNA_def_property(ot->srna, "percent", PROP_INT, PROP_NONE);
1282         RNA_def_property_ui_range(prop, 1, 100,1, 1);
1283         RNA_def_property_ui_text(prop, "Percent", "Max persentage that will be selected");
1284         RNA_def_property_int_default(prop, 50);
1285 }
1286
1287 /* ******** Clear object Translation *********** */
1288
1289 static int object_clear_location_exec(bContext *C, wmOperator *op)
1290 {
1291         Scene *scene= CTX_data_scene(C);
1292         int armature_clear= 0;
1293
1294         CTX_DATA_BEGIN(C, Object*, ob, selected_objects) {
1295                 if ((ob->flag & OB_POSEMODE)) {
1296                         /* only clear pose transforms if:
1297                          *      - with a mesh in weightpaint mode, it's related armature needs to be cleared
1298                          *      - with clearing transform of object being edited at the time
1299                          */
1300                         if ((G.f & G_WEIGHTPAINT) || (ob==OBACT)) {
1301 // XXX                          clear_armature(ob, mode);
1302                                 armature_clear= 1;      /* silly system to prevent another dag update, so no action applied */
1303                         }
1304                 }
1305                 else if((G.f & G_WEIGHTPAINT)==0) {
1306                         if ((ob->protectflag & OB_LOCK_LOCX)==0)
1307                                 ob->loc[0]= ob->dloc[0]= 0.0f;
1308                         if ((ob->protectflag & OB_LOCK_LOCY)==0)
1309                                 ob->loc[1]= ob->dloc[1]= 0.0f;
1310                         if ((ob->protectflag & OB_LOCK_LOCZ)==0)
1311                                 ob->loc[2]= ob->dloc[2]= 0.0f;
1312                 }
1313                 ob->recalc |= OB_RECALC_OB;
1314         }
1315         CTX_DATA_END;
1316
1317         if(armature_clear==0) /* in this case flush was done */
1318                 ED_anim_dag_flush_update(C);    
1319         BIF_undo_push("Clear Location");
1320         
1321         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
1322         
1323         return OPERATOR_FINISHED;
1324 }
1325
1326
1327 void OBJECT_OT_clear_location(wmOperatorType *ot)
1328 {
1329         
1330         /* identifiers */
1331         ot->name= "Clear Object Location";
1332         ot->idname= "OBJECT_OT_clear_location";
1333         
1334         /* api callbacks */
1335         ot->invoke= WM_operator_confirm;
1336         ot->exec= object_clear_location_exec;
1337         ot->poll= ED_operator_object_active;
1338 }
1339
1340 static int object_clear_rotation_exec(bContext *C, wmOperator *op)
1341 {
1342         Scene *scene= CTX_data_scene(C);
1343         int armature_clear= 0;
1344
1345         CTX_DATA_BEGIN(C, Object*, ob, selected_objects) {
1346                 if ((ob->flag & OB_POSEMODE)) {
1347                         /* only clear pose transforms if:
1348                          *      - with a mesh in weightpaint mode, it's related armature needs to be cleared
1349                          *      - with clearing transform of object being edited at the time
1350                          */
1351                         if ((G.f & G_WEIGHTPAINT) || (ob==OBACT)) {
1352 // XXX                          clear_armature(ob, mode);
1353                                 armature_clear= 1;      /* silly system to prevent another dag update, so no action applied */
1354                         }
1355                 }
1356                 else if((G.f & G_WEIGHTPAINT)==0) {
1357                         /* eulers can only get cleared if they are not protected */
1358                         if ((ob->protectflag & OB_LOCK_ROTX)==0)
1359                                 ob->rot[0]= ob->drot[0]= 0.0f;
1360                         if ((ob->protectflag & OB_LOCK_ROTY)==0)
1361                                 ob->rot[1]= ob->drot[1]= 0.0f;
1362                         if ((ob->protectflag & OB_LOCK_ROTZ)==0)
1363                                 ob->rot[2]= ob->drot[2]= 0.0f;
1364                 }
1365                 ob->recalc |= OB_RECALC_OB;
1366         }
1367         CTX_DATA_END;
1368
1369         if(armature_clear==0) /* in this case flush was done */
1370                 ED_anim_dag_flush_update(C);    
1371         BIF_undo_push("Clear Rotation");
1372         
1373         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
1374         
1375         return OPERATOR_FINISHED;
1376 }
1377
1378
1379 void OBJECT_OT_clear_rotation(wmOperatorType *ot)
1380 {
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                 ob->recalc |= OB_RECALC_OB;
1423         }
1424         CTX_DATA_END;
1425         
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         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, CTX_data_scene(C));
1431         
1432         return OPERATOR_FINISHED;
1433 }
1434
1435 void OBJECT_OT_clear_scale(wmOperatorType *ot)
1436 {
1437         
1438         /* identifiers */
1439         ot->name= "Clear Object Scale";
1440         ot->idname= "OBJECT_OT_clear_scale";
1441         
1442         /* api callbacks */
1443         ot->invoke= WM_operator_confirm;
1444         ot->exec= object_clear_scale_exec;
1445         ot->poll= ED_operator_object_active;
1446 }
1447
1448 static int object_clear_origin_exec(bContext *C, wmOperator *op)
1449 {
1450         Scene *scene= CTX_data_scene(C);
1451         float *v1, *v3, mat[3][3];
1452         int armature_clear= 0;
1453
1454         CTX_DATA_BEGIN(C, Object*, ob, selected_objects) {
1455                 if ((ob->flag & OB_POSEMODE)) {
1456                         /* only clear pose transforms if:
1457                          *      - with a mesh in weightpaint mode, it's related armature needs to be cleared
1458                          *      - with clearing transform of object being edited at the time
1459                          */
1460                         if ((G.f & G_WEIGHTPAINT) || (ob==OBACT)) {
1461 // XXX                          clear_armature(ob, mode);
1462                                 armature_clear= 1;      /* silly system to prevent another dag update, so no action applied */
1463                         }
1464                 }
1465                 else if((G.f & G_WEIGHTPAINT)==0) {
1466                         if(ob->parent) {
1467                                 v1= ob->loc;
1468                                 v3= ob->parentinv[3];
1469                                 
1470                                 Mat3CpyMat4(mat, ob->parentinv);
1471                                 VECCOPY(v3, v1);
1472                                 v3[0]= -v3[0];
1473                                 v3[1]= -v3[1];
1474                                 v3[2]= -v3[2];
1475                                 Mat3MulVecfl(mat, v3);
1476                         }
1477                 }
1478                 ob->recalc |= OB_RECALC_OB;
1479         }
1480         CTX_DATA_END;
1481
1482         if(armature_clear==0) /* in this case flush was done */
1483                 ED_anim_dag_flush_update(C);    
1484         BIF_undo_push("Clear origin");
1485         
1486         WM_event_add_notifier(C, NC_SCENE|ND_TRANSFORM, CTX_data_scene(C));
1487         
1488         return OPERATOR_FINISHED;
1489 }
1490
1491 void OBJECT_OT_clear_origin(wmOperatorType *ot)
1492 {
1493
1494         /* identifiers */
1495         ot->name= "Clear Object Origin";
1496         ot->idname= "OBJECT_OT_clear_origin";
1497         
1498         /* api callbacks */
1499         ot->invoke= WM_operator_confirm;
1500         ot->exec= object_clear_origin_exec;
1501         ot->poll= ED_operator_object_active;
1502 }
1503 /* ******************** **************** */
1504
1505 void reset_slowparents(Scene *scene, View3D *v3d)
1506 {
1507         /* back to original locations */
1508         Base *base;
1509
1510         for(base= FIRSTBASE; base; base= base->next) {
1511                 if(base->object->parent) {
1512                         if(base->object->partype & PARSLOW) {
1513                                 base->object->partype -= PARSLOW;
1514                                 where_is_object(base->object);
1515                                 base->object->partype |= PARSLOW;
1516                         }
1517                 }
1518         }
1519 }
1520 void set_slowparent(Scene *scene, View3D *v3d)
1521 {
1522         Base *base;
1523
1524         if( okee("Set slow parent")==0 ) return;
1525
1526         for(base= FIRSTBASE; base; base= base->next) {
1527                 if(TESTBASELIB(v3d, base)) {
1528                         if(base->object->parent) base->object->partype |= PARSLOW;
1529                 }
1530         }
1531         BIF_undo_push("Slow parent");
1532 }
1533
1534 // XXX
1535 #define BEZSELECTED_HIDDENHANDLES(bezt)   ((G.f & G_HIDDENHANDLES) ? (bezt)->f2 & SELECT : BEZSELECTED(bezt))
1536 /* only in edit mode */
1537 void make_vertex_parent(Scene *scene, Object *obedit, View3D *v3d)
1538 {
1539         EditVert *eve;
1540         Base *base;
1541         Nurb *nu;
1542         BezTriple *bezt;
1543         BPoint *bp;
1544         Object *par, *ob;
1545         int a, v1=0, v2=0, v3=0, v4=0, nr=1;
1546         
1547         /* we need 1 to 3 selected vertices */
1548         
1549         if(obedit->type==OB_MESH) {
1550                 Mesh *me= obedit->data;
1551                 
1552                 eve= me->edit_mesh->verts.first;
1553                 while(eve) {
1554                         if(eve->f & 1) {
1555                                 if(v1==0) v1= nr;
1556                                 else if(v2==0) v2= nr;
1557                                 else if(v3==0) v3= nr;
1558                                 else if(v4==0) v4= nr;
1559                                 else break;
1560                         }
1561                         nr++;
1562                         eve= eve->next;
1563                 }
1564         }
1565         else if(ELEM(obedit->type, OB_SURF, OB_CURVE)) {
1566                 extern ListBase editNurb;
1567                 nu= editNurb.first;
1568                 while(nu) {
1569                         if((nu->type & 7)==CU_BEZIER) {
1570                                 bezt= nu->bezt;
1571                                 a= nu->pntsu;
1572                                 while(a--) {
1573                                         if(BEZSELECTED_HIDDENHANDLES(bezt)) {
1574                                                 if(v1==0) v1= nr;
1575                                                 else if(v2==0) v2= nr;
1576                                                 else if(v3==0) v3= nr;
1577                                                 else if(v4==0) v4= nr;
1578                                                 else break;
1579                                         }
1580                                         nr++;
1581                                         bezt++;
1582                                 }
1583                         }
1584                         else {
1585                                 bp= nu->bp;
1586                                 a= nu->pntsu*nu->pntsv;
1587                                 while(a--) {
1588                                         if(bp->f1 & SELECT) {
1589                                                 if(v1==0) v1= nr;
1590                                                 else if(v2==0) v2= nr;
1591                                                 else if(v3==0) v3= nr;
1592                                                 else if(v4==0) v4= nr;
1593                                                 else break;
1594                                         }
1595                                         nr++;
1596                                         bp++;
1597                                 }
1598                         }
1599                         nu= nu->next;
1600                 }
1601         }
1602         else if(obedit->type==OB_LATTICE) {
1603                 
1604                 a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
1605                 bp= editLatt->def;
1606                 while(a--) {
1607                         if(bp->f1 & SELECT) {
1608                                 if(v1==0) v1= nr;
1609                                 else if(v2==0) v2= nr;
1610                                 else if(v3==0) v3= nr;
1611                                 else if(v4==0) v4= nr;
1612                                 else break;
1613                         }
1614                         nr++;
1615                         bp++;
1616                 }
1617         }
1618         
1619         if(v4 || !((v1 && v2==0 && v3==0) || (v1 && v2 && v3)) ) {
1620                 error("Select either 1 or 3 vertices to parent to");
1621                 return;
1622         }
1623         
1624         if(okee("Make vertex parent")==0) return;
1625         
1626         for(base= FIRSTBASE; base; base= base->next) {
1627                 if(TESTBASELIB(v3d, base)) {
1628                         if(base!=BASACT) {
1629                                 
1630                                 ob= base->object;
1631                                 ob->recalc |= OB_RECALC;
1632                                 par= BASACT->object->parent;
1633                                 
1634                                 while(par) {
1635                                         if(par==ob) break;
1636                                         par= par->parent;
1637                                 }
1638                                 if(par) {
1639                                         error("Loop in parents");
1640                                 }
1641                                 else {
1642                                         Object workob;
1643                                         
1644                                         ob->parent= BASACT->object;
1645                                         if(v3) {
1646                                                 ob->partype= PARVERT3;
1647                                                 ob->par1= v1-1;
1648                                                 ob->par2= v2-1;
1649                                                 ob->par3= v3-1;
1650
1651                                                 /* inverse parent matrix */
1652                                                 what_does_parent(ob, &workob);
1653                                                 Mat4Invert(ob->parentinv, workob.obmat);
1654                                         }
1655                                         else {
1656                                                 ob->partype= PARVERT1;
1657                                                 ob->par1= v1-1;
1658
1659                                                 /* inverse parent matrix */
1660                                                 what_does_parent(ob, &workob);
1661                                                 Mat4Invert(ob->parentinv, workob.obmat);
1662                                         }
1663                                 }
1664                         }
1665                 }
1666         }
1667         allqueue(REDRAWVIEW3D, 0);
1668         
1669         DAG_scene_sort(scene);
1670         /* BIF_undo_push(str); not, conflicts with editmode undo... */
1671 }
1672
1673 static Object *group_objects_menu(Group *group)
1674 {
1675         GroupObject *go;
1676         int len= 0;
1677         short a, nr;
1678         char *str;
1679                 
1680         for(go= group->gobject.first; go; go= go->next) {
1681                 if(go->ob)
1682                         len++;
1683         }
1684         if(len==0) return NULL;
1685         
1686         str= MEM_callocN(40+32*len, "menu");
1687         
1688         strcpy(str, "Make Proxy for: %t");
1689         a= strlen(str);
1690         for(nr=1, go= group->gobject.first; go; go= go->next, nr++) {
1691                 a+= sprintf(str+a, "|%s %%x%d", go->ob->id.name+2, nr);
1692         }
1693         
1694         a= pupmenu_col(str, 20);
1695         MEM_freeN(str);
1696         if(a>0) {
1697                 go= BLI_findlink(&group->gobject, a-1);
1698                 return go->ob;
1699         }
1700         return NULL;
1701 }
1702
1703
1704 /* adds empty object to become local replacement data of a library-linked object */
1705 void make_proxy(Scene *scene)
1706 {
1707         Object *ob= OBACT;
1708         Object *gob= NULL;
1709         
1710         if(scene->id.lib) return;
1711         if(ob==NULL) return;
1712         
1713         
1714         if(ob->dup_group && ob->dup_group->id.lib) {
1715                 gob= ob;
1716                 /* gives menu with list of objects in group */
1717                 ob= group_objects_menu(ob->dup_group);
1718         }
1719         else if(ob->id.lib) {
1720                 if(okee("Make Proxy Object")==0)
1721                 return;
1722         }
1723         else {
1724                 error("Can only make proxy for a referenced object or group");
1725                 return;
1726         }
1727         
1728         if(ob) {
1729                 Object *newob;
1730                 Base *newbase, *oldbase= BASACT;
1731                 char name[32];
1732                 
1733                 newob= add_object(OB_EMPTY);
1734                 if(gob)
1735                         strcpy(name, gob->id.name+2);
1736                 else
1737                         strcpy(name, ob->id.name+2);
1738                 strcat(name, "_proxy");
1739                 rename_id(&newob->id, name);
1740                 
1741                 /* set layers OK */
1742                 newbase= BASACT;        /* add_object sets active... */
1743                 newbase->lay= oldbase->lay;
1744                 newob->lay= newbase->lay;
1745                 
1746                 /* remove base, leave user count of object, it gets linked in object_make_proxy */
1747                 if(gob==NULL) {
1748                         BLI_remlink(&scene->base, oldbase);
1749                         MEM_freeN(oldbase);
1750                 }               
1751                 object_make_proxy(newob, ob, gob);
1752                 
1753                 DAG_scene_sort(scene);
1754                 DAG_object_flush_update(scene, newob, OB_RECALC);
1755                 allqueue(REDRAWALL, 0);
1756                 BIF_undo_push("Make Proxy Object");
1757         }
1758 }
1759
1760 /* ******************** make parent operator *********************** */
1761
1762 #if 0
1763 oldcode()
1764 {
1765         else if(mode==4) {
1766                 bConstraint *con;
1767                 bFollowPathConstraint *data;
1768                         
1769                 for(base= FIRSTBASE; base; base= base->next) {
1770                         if(TESTBASELIB(v3d, base)) {
1771                                 if(base!=BASACT) {
1772                                         float cmat[4][4], vec[3];
1773                                         
1774 // XXX                                          con = add_new_constraint(CONSTRAINT_TYPE_FOLLOWPATH);
1775                                         strcpy (con->name, "AutoPath");
1776                                         
1777                                         data = con->data;
1778                                         data->tar = BASACT->object;
1779                                         
1780 // XXX                                          add_constraint_to_object(con, base->object);
1781                                         
1782                                         get_constraint_target_matrix(con, 0, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, scene->r.cfra - give_timeoffset(base->object));
1783                                         VecSubf(vec, base->object->obmat[3], cmat[3]);
1784                                         
1785                                         base->object->loc[0] = vec[0];
1786                                         base->object->loc[1] = vec[1];
1787                                         base->object->loc[2] = vec[2];
1788                                 }
1789                         }
1790                 }
1791
1792                 if(mode==PARSKEL && base->object->type==OB_MESH && par->type == OB_ARMATURE) {
1793                         /* Prompt the user as to whether he wants to
1794                                 * add some vertex groups based on the bones
1795                                 * in the parent armature.
1796                                 */
1797 // XXX                                                  create_vgroups_from_armature(base->object, par);
1798
1799                         base->object->partype= PAROBJECT;
1800                         what_does_parent(base->object);
1801                         Mat4One (base->object->parentinv);
1802                         base->object->partype= mode;
1803                 }
1804                 else
1805                         what_does_parent(base->object, &workob);
1806                 Mat4Invert(base->object->parentinv, workob.obmat);
1807         }
1808 }
1809 #endif
1810
1811 #define PAR_OBJECT              0
1812 #define PAR_ARMATURE    1
1813 #define PAR_BONE                2
1814 #define PAR_CURVE               3
1815 #define PAR_FOLLOW              4
1816 #define PAR_PATH_CONST  5
1817 #define PAR_LATTICE             6
1818 #define PAR_VERTEX              7
1819 #define PAR_TRIA                8
1820
1821 static EnumPropertyItem prop_make_parent_types[] = {
1822         {PAR_OBJECT, "OBJECT", "Object", ""},
1823         {PAR_ARMATURE, "ARMATURE", "Armature Deform", ""},
1824         {PAR_BONE, "BONE", "Bone", ""},
1825         {PAR_CURVE, "CURVE", "Curve Deform", ""},
1826         {PAR_FOLLOW, "FOLLOW", "Follow Path", ""},
1827         {PAR_PATH_CONST, "PATH_CONST", "Path Constraint", ""},
1828         {PAR_LATTICE, "LATTICE", "Lattice Deform", ""},
1829         {PAR_VERTEX, "VERTEX", "Vertex", ""},
1830         {PAR_TRIA, "TRIA", "Triangle", ""},
1831         {0, NULL, NULL, NULL}
1832 };
1833
1834 static int test_parent_loop(Object *par, Object *ob)
1835 {
1836         /* test if 'ob' is a parent somewhere in par's parents */
1837         
1838         if(par == NULL) return 0;
1839         if(ob == par) return 1;
1840         
1841         return test_parent_loop(par->parent, ob);
1842 }
1843
1844
1845 static int make_parent_exec(bContext *C, wmOperator *op)
1846 {
1847         Object *par= CTX_data_active_object(C);
1848         bPoseChannel *pchan= NULL;
1849         int partype= RNA_enum_get(op->ptr, "type");
1850         
1851         par->recalc |= OB_RECALC_OB;
1852         
1853         /* preconditions */
1854         if(partype==PAR_FOLLOW || partype==PAR_PATH_CONST) {
1855                 if(par->type!=OB_CURVE)
1856                         return OPERATOR_CANCELLED;
1857                 else {
1858                         Curve *cu= par->data;
1859                         
1860                         if((cu->flag & CU_PATH)==0) {
1861                                 cu->flag |= CU_PATH|CU_FOLLOW;
1862                                 makeDispListCurveTypes(par, 0);  /* force creation of path data */
1863                         }
1864                         else cu->flag |= CU_FOLLOW;
1865                         
1866                         /* fall back on regular parenting now */
1867                         partype= PAR_OBJECT;
1868                 }               
1869         }
1870         else if(partype==PAR_BONE) {
1871                 pchan= get_active_posechannel(par);
1872                 
1873                 if(pchan==NULL) {
1874                         error("No active Bone");
1875                         return OPERATOR_CANCELLED;
1876                 }
1877         }
1878         
1879         /* context itterator */
1880         CTX_DATA_BEGIN(C, Object*, ob, selected_objects) {
1881                 
1882                 if(ob!=par) {
1883                         
1884                         if( test_parent_loop(par, ob) ) {
1885                                 error("Loop in parents");
1886                         }
1887                         else {
1888                                 Object workob;
1889                                 
1890                                 /* apply transformation of previous parenting */
1891                                 apply_obmat(ob);
1892                                 
1893                                 ob->parent= par;
1894                                 
1895                                 /* handle types */
1896                                 if (pchan)
1897                                         strcpy (ob->parsubstr, pchan->name);
1898                                 else
1899                                         ob->parsubstr[0]= 0;
1900                                 
1901                                 /* constraint XXX */
1902                                 if(partype==PAR_PATH_CONST) {
1903                                 }
1904                                 
1905                                 /* calculate inverse parent matrix */
1906                                 what_does_parent(ob, &workob);
1907                                 Mat4Invert(ob->parentinv, workob.obmat);
1908                                 
1909                                 ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA;
1910                                 
1911                                 if( ELEM3(partype, PAR_CURVE, PAR_ARMATURE, PAR_LATTICE) )
1912                                         ob->partype= PARSKEL; /* note, dna define, not operator property */
1913                                 else
1914                                         ob->partype= PAROBJECT; /* note, dna define, not operator property */
1915                         }
1916                 }
1917         }
1918         CTX_DATA_END;
1919         
1920         DAG_scene_sort(CTX_data_scene(C));
1921         ED_anim_dag_flush_update(C);    
1922         
1923         BIF_undo_push("make Parent");
1924         
1925         return OPERATOR_FINISHED;
1926 }
1927
1928 static int make_parent_invoke(bContext *C, wmOperator *op, wmEvent *event)
1929 {
1930         Object *ob= CTX_data_active_object(C);
1931         char *str, string[256];
1932         char formatstr[] = "|%s %%x%d";
1933         
1934         str= string + sprintf(string, "Make Parent To %%t");
1935         
1936         /* ob becomes parent, make the associated menus */
1937         if(ob->type==OB_ARMATURE) {
1938                 str += sprintf(str, formatstr, "Object", PAR_OBJECT);
1939                 str += sprintf(str, formatstr, "Armature Deform", PAR_ARMATURE);
1940                 str += sprintf(str, formatstr, "Bone", PAR_BONE);
1941         }
1942         else if(ob->type==OB_CURVE) {
1943                 str += sprintf(str, formatstr, "Object", PAR_OBJECT);
1944                 str += sprintf(str, formatstr, "Curve Deform", PAR_CURVE);
1945                 str += sprintf(str, formatstr, "Follow Path", PAR_FOLLOW);
1946                 str += sprintf(str, formatstr, "Path Constraint", PAR_PATH_CONST);
1947         }
1948         else if(ob->type == OB_LATTICE) {
1949                 str += sprintf(str, formatstr, "Object", PAR_OBJECT);
1950                 str += sprintf(str, formatstr, "Lattice Deform", PAR_LATTICE);
1951         }
1952         else
1953                 str += sprintf(str, formatstr, "Object", PAR_OBJECT);
1954         
1955         uiPupmenuOperator(C, 0, op, "type", string);
1956         
1957         return OPERATOR_RUNNING_MODAL;
1958 }
1959
1960
1961 void OBJECT_OT_make_parent(wmOperatorType *ot)
1962 {
1963         PropertyRNA *prop;
1964         
1965         /* identifiers */
1966         ot->name= "Make parent";
1967         ot->idname= "OBJECT_OT_make_parent";
1968         
1969         /* api callbacks */
1970         ot->invoke= make_parent_invoke;
1971         ot->exec= make_parent_exec;
1972         
1973         ot->poll= ED_operator_object_active;
1974         ot->flag= OPTYPE_REGISTER;
1975         
1976         prop = RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
1977         RNA_def_property_enum_items(prop, prop_make_parent_types);
1978 }
1979
1980 /* *** make track ***** */
1981 static EnumPropertyItem prop_make_track_types[] = {
1982         {1, "TRACKTO", "TrackTo Constraint", ""},
1983         {2, "LOCKTRACK", "LockTrack Constraint", ""},
1984         {3, "OLDTRACK", "Old Track", ""},
1985         {0, NULL, NULL, NULL}
1986 };
1987
1988 static int make_track_exec(bContext *C, wmOperator *op)
1989 {
1990         Scene *scene= CTX_data_scene(C);
1991         ScrArea *sa= CTX_wm_area(C);
1992         View3D *v3d= sa->spacedata.first;
1993         Base *base;
1994         
1995         if(scene->id.lib) return OPERATOR_CANCELLED;
1996
1997         if(RNA_enum_is_equal(op->ptr, "type", "TRACKTO")){
1998                 bConstraint *con;
1999                 bTrackToConstraint *data;
2000
2001                 for(base= FIRSTBASE; base; base= base->next) {
2002                         if(TESTBASELIB(v3d, base)) {
2003                                 if(base!=BASACT) {
2004 // XXX                                  con = add_new_constraint(CONSTRAINT_TYPE_TRACKTO);
2005                                         strcpy (con->name, "AutoTrack");
2006
2007                                         data = con->data;
2008                                         data->tar = BASACT->object;
2009                                         base->object->recalc |= OB_RECALC;
2010                                         
2011                                         /* Lamp and Camera track differently by default */
2012                                         if (base->object->type == OB_LAMP || base->object->type == OB_CAMERA) {
2013                                                 data->reserved1 = TRACK_nZ;
2014                                                 data->reserved2 = UP_Y;
2015                                         }
2016
2017 // XXX                                  add_constraint_to_object(con, base->object);
2018                                 }
2019                         }
2020                 }
2021
2022         }
2023         else if(RNA_enum_is_equal(op->ptr, "type", "LOCKTRACK")){
2024                 bConstraint *con;
2025                 bLockTrackConstraint *data;
2026
2027                 for(base= FIRSTBASE; base; base= base->next) {
2028                         if(TESTBASELIB(v3d, base)) {
2029                                 if(base!=BASACT) {
2030 // XXX                                  con = add_new_constraint(CONSTRAINT_TYPE_LOCKTRACK);
2031                                         strcpy (con->name, "AutoTrack");
2032
2033                                         data = con->data;
2034                                         data->tar = BASACT->object;
2035                                         base->object->recalc |= OB_RECALC;
2036                                         
2037                                         /* Lamp and Camera track differently by default */
2038                                         if (base->object->type == OB_LAMP || base->object->type == OB_CAMERA) {
2039                                                 data->trackflag = TRACK_nZ;
2040                                                 data->lockflag = LOCK_Y;
2041                                         }
2042
2043 // XXX                                  add_constraint_to_object(con, base->object);
2044                                 }
2045                         }
2046                 }
2047
2048         }
2049         else if(RNA_enum_is_equal(op->ptr, "type", "OLDTRACK")){
2050                 for(base= FIRSTBASE; base; base= base->next) {
2051                         if(TESTBASELIB(v3d, base)) {
2052                                 if(base!=BASACT) {
2053                                         base->object->track= BASACT->object;
2054                                         base->object->recalc |= OB_RECALC;
2055                                 }
2056                         }
2057                 }
2058         }
2059         DAG_scene_sort(CTX_data_scene(C));
2060         ED_anim_dag_flush_update(C);    
2061         
2062         BIF_undo_push("make track");
2063         
2064         return OPERATOR_FINISHED;
2065 }
2066
2067 void OBJECT_OT_make_track(wmOperatorType *ot)
2068 {
2069         PropertyRNA *prop;
2070         
2071         /* identifiers */
2072         ot->name= "Make Track";
2073         ot->idname= "OBJECT_OT_make_track";
2074         
2075         /* api callbacks */
2076         ot->invoke= WM_menu_invoke;
2077         ot->exec= make_track_exec;
2078         
2079         ot->poll= ED_operator_scene_editable;
2080         ot->flag= OPTYPE_REGISTER;
2081         
2082         prop = RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
2083         RNA_def_property_enum_items(prop, prop_make_track_types);
2084 }
2085
2086
2087 /* ******************* toggle editmode operator  ***************** */
2088
2089 void ED_object_exit_editmode(bContext *C, int flag)
2090 {
2091         Scene *scene= CTX_data_scene(C);
2092         Object *ob;
2093         Object *obedit= CTX_data_edit_object(C);
2094         int freedata = flag & EM_FREEDATA;
2095         
2096         if(obedit==NULL) return;
2097         
2098         if(flag & EM_WAITCURSOR) waitcursor(1);
2099         if(obedit->type==OB_MESH) {
2100                 Mesh *me= obedit->data;
2101                 
2102 //              if(EM_texFaceCheck())
2103                 
2104 //              if(retopo_mesh_paint_check())
2105 //                      retopo_end_okee();
2106                 
2107                 if(G.totvert>MESH_MAX_VERTS) {
2108                         error("Too many vertices");
2109                         return;
2110                 }
2111                 load_editMesh(scene, obedit);
2112                 
2113                 if(freedata) free_editMesh(me->edit_mesh);
2114                 
2115                 if(G.f & G_WEIGHTPAINT)
2116                         mesh_octree_table(obedit, NULL, NULL, 'e');
2117         }
2118         else if (obedit->type==OB_ARMATURE){    
2119 //              load_editArmature();
2120 //              if (freedata) free_editArmature();
2121         }
2122         else if(ELEM(obedit->type, OB_CURVE, OB_SURF)) {
2123 //              extern ListBase editNurb;
2124 //              load_editNurb();
2125 //              if(freedata) freeNurblist(&editNurb);
2126         }
2127         else if(obedit->type==OB_FONT && freedata) {
2128 //              load_editText();
2129         }
2130         else if(obedit->type==OB_LATTICE) {
2131 //              load_editLatt();
2132 //              if(freedata) free_editLatt();
2133         }
2134         else if(obedit->type==OB_MBALL) {
2135 //              extern ListBase editelems;
2136 //              load_editMball();
2137 //              if(freedata) BLI_freelistN(&editelems);
2138         }
2139         
2140         ob= obedit;
2141         
2142         /* for example; displist make is different in editmode */
2143         if(freedata) obedit= NULL;
2144         scene->obedit= obedit; // XXX for context
2145         
2146         if(ob->type==OB_MESH && get_mesh(ob)->mr)
2147                 multires_edge_level_update(ob, get_mesh(ob));
2148         
2149         /* also flush ob recalc, doesn't take much overhead, but used for particles */
2150         DAG_object_flush_update(scene, ob, OB_RECALC_OB|OB_RECALC_DATA);
2151         
2152         if(obedit==NULL) // XXX && (flag & EM_FREEUNDO)) 
2153                 ED_undo_push(C, "Editmode");
2154         
2155         if(flag & EM_WAITCURSOR) waitcursor(0);
2156         
2157         WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_OBJECT, ob);
2158
2159 }
2160
2161
2162 void ED_object_enter_editmode(bContext *C, int flag)
2163 {
2164         Scene *scene= CTX_data_scene(C);
2165         Base *base= CTX_data_active_base(C);
2166         Object *ob= base->object;
2167         View3D *v3d= (View3D *)CTX_wm_space_data(C);
2168         int ok= 0;
2169         
2170         if(scene->id.lib) return;
2171         if(base==NULL) return;
2172         if((v3d==NULL || (base->lay & v3d->lay))==0) return;
2173         
2174         if(ob->data==NULL) return;
2175         
2176         if (object_data_is_libdata(ob)) {
2177                 error_libdata();
2178                 return;
2179         }
2180         
2181         if(flag & EM_WAITCURSOR) waitcursor(1);
2182         
2183         if(ob->type==OB_MESH) {
2184                 Mesh *me= ob->data;
2185                 
2186                 if(me->pv) mesh_pmv_off(ob, me);
2187                 ok= 1;
2188                 scene->obedit= ob;      // context sees this
2189                 
2190                 make_editMesh(scene, ob);
2191
2192                 WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_EDITMODE_MESH, ob);
2193         }
2194         if (ob->type==OB_ARMATURE){
2195                 bArmature *arm= base->object->data;
2196                 if (!arm) return;
2197                 /*
2198                  * The function object_data_is_libdata make a problem here, the
2199                  * check for ob->proxy return 0 and let blender enter to edit mode
2200                  * this causa a crash when you try leave the edit mode.
2201                  * The problem is that i can't remove the ob->proxy check from
2202                  * object_data_is_libdata that prevent the bugfix #6614, so
2203                  * i add this little hack here.
2204                  */
2205                 if(arm->id.lib) {
2206                         error_libdata();
2207                         return;
2208                 }
2209 //              ok=1;
2210                 scene->obedit= ob;
2211 // XXX          make_editArmature();
2212                 /* to ensure all goes in restposition and without striding */
2213                 DAG_object_flush_update(scene, ob, OB_RECALC);
2214
2215                 WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_EDITMODE_ARMATURE, ob);
2216         }
2217         else if(ob->type==OB_FONT) {
2218                 scene->obedit= ob; // XXX for context
2219 //              ok= 1;
2220 // XXX          make_editText();
2221         }
2222         else if(ob->type==OB_MBALL) {
2223                 scene->obedit= ob; // XXX for context
2224 //              ok= 1;
2225 // XXX          make_editMball();
2226         }
2227         else if(ob->type==OB_LATTICE) {
2228                 scene->obedit= ob; // XXX for context
2229 //              ok= 1;
2230 // XXX          make_editLatt();
2231         }
2232         else if(ob->type==OB_SURF || ob->type==OB_CURVE) {
2233 //              ok= 1;
2234                 scene->obedit= ob; // XXX for context
2235 // XXX          make_editNurb();
2236         }
2237         
2238         if(ok) {
2239                 DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
2240         }
2241         else {
2242                 scene->obedit= NULL; // XXX for context
2243                 WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_OBJECT, ob);
2244         }
2245         
2246         if(flag & EM_WAITCURSOR) waitcursor(0);
2247 }
2248
2249 static int toggle_editmode_exec(bContext *C, wmOperator *op)
2250 {
2251         
2252         if(!CTX_data_edit_object(C))
2253                 ED_object_enter_editmode(C, EM_WAITCURSOR);
2254         else
2255                 ED_object_exit_editmode(C, EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR);
2256         
2257         return OPERATOR_FINISHED;
2258 }
2259
2260 void OBJECT_OT_toggle_editmode(wmOperatorType *ot)
2261 {
2262         
2263         /* identifiers */
2264         ot->name= "Toggle Editmode";
2265         ot->idname= "OBJECT_OT_toggle_editmode";
2266         
2267         /* api callbacks */
2268         ot->exec= toggle_editmode_exec;
2269         
2270         ot->poll= ED_operator_object_active;
2271         ot->flag= OPTYPE_REGISTER;
2272 }
2273
2274 /* *************************** */
2275
2276
2277 void check_editmode(int type)
2278 {
2279         Object *obedit= NULL; // XXX
2280         
2281         if (obedit==NULL || obedit->type==type) return;
2282
2283 // XXX  ED_object_exit_editmode(C, EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR); /* freedata, and undo */
2284 }
2285
2286 /* 0 == do center, 1 == center new, 2 == center cursor */
2287
2288 void docenter(Scene *scene, View3D *v3d, int centermode)
2289 {
2290         Base *base;
2291         Object *ob;
2292         Mesh *me, *tme;
2293         Curve *cu;
2294 /*      BezTriple *bezt;
2295         BPoint *bp; */
2296         Object *obedit= NULL; // XXX
2297         Nurb *nu, *nu1;
2298         EditVert *eve;
2299         float cent[3], centn[3], min[3], max[3], omat[3][3];
2300         int a, total= 0;
2301         
2302         /* keep track of what is changed */
2303         int tot_change=0, tot_lib_error=0, tot_multiuser_arm_error=0;
2304         MVert *mvert;
2305
2306         if(scene->id.lib || v3d==NULL) return;
2307         
2308         cent[0]= cent[1]= cent[2]= 0.0;
2309         
2310         if(obedit) {
2311
2312                 INIT_MINMAX(min, max);
2313         
2314                 if(obedit->type==OB_MESH) {
2315                         Mesh *me= obedit->data;
2316                         
2317                         for(eve= me->edit_mesh->verts.first; eve; eve= eve->next) {
2318                                 if(v3d->around==V3D_CENTROID) {
2319                                         total++;
2320                                         VECADD(cent, cent, eve->co);
2321                                 }
2322                                 else {
2323                                         DO_MINMAX(eve->co, min, max);
2324                                 }
2325                         }
2326                         
2327                         if(v3d->around==V3D_CENTROID) {
2328                                 VecMulf(cent, 1.0f/(float)total);
2329                         }
2330                         else {
2331                                 cent[0]= (min[0]+max[0])/2.0f;
2332                                 cent[1]= (min[1]+max[1])/2.0f;
2333                                 cent[2]= (min[2]+max[2])/2.0f;
2334                         }
2335                         
2336                         for(eve= me->edit_mesh->verts.first; eve; eve= eve->next) {
2337                                 VecSubf(eve->co, eve->co, cent);                        
2338                         }
2339                         
2340 // XXX                  recalc_editnormals();
2341                         tot_change++;
2342                         DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
2343                 }
2344         }
2345         
2346         /* reset flags */
2347         for (base=FIRSTBASE; base; base= base->next) {
2348                 if(TESTBASELIB(v3d, base))
2349                         base->object->flag &= ~OB_DONE;
2350         }
2351         
2352         for (me= G.main->mesh.first; me; me= me->id.next) {
2353                 me->flag &= ~ME_ISDONE;
2354         }
2355         
2356         for(base= FIRSTBASE; base; base= base->next) {
2357                 if(TESTBASELIB(v3d, base)) {
2358                         if((base->object->flag & OB_DONE)==0) {
2359                                 base->object->flag |= OB_DONE;
2360                                 
2361                                 if(base->object->id.lib) {
2362                                         tot_lib_error++;
2363                                 }
2364                                 else if(obedit==0 && (me=get_mesh(base->object)) ) {
2365                                         if (me->id.lib) {
2366                                                 tot_lib_error++;
2367                                         } else {
2368                                                 if(centermode==2) {
2369                                                         VECCOPY(cent, give_cursor(scene, v3d));
2370                                                         Mat4Invert(base->object->imat, base->object->obmat);
2371                                                         Mat4MulVecfl(base->object->imat, cent);
2372                                                 } else {
2373                                                         INIT_MINMAX(min, max);
2374                                                         mvert= me->mvert;
2375                                                         for(a=0; a<me->totvert; a++, mvert++) {
2376                                                                 DO_MINMAX(mvert->co, min, max);
2377                                                         }
2378                                         
2379                                                         cent[0]= (min[0]+max[0])/2.0f;
2380                                                         cent[1]= (min[1]+max[1])/2.0f;
2381                                                         cent[2]= (min[2]+max[2])/2.0f;
2382                                                 }
2383
2384                                                 mvert= me->mvert;
2385                                                 for(a=0; a<me->totvert; a++, mvert++) {
2386                                                         VecSubf(mvert->co, mvert->co, cent);
2387                                                 }
2388                                                 
2389                                                 if (me->key) {
2390                                                         KeyBlock *kb;
2391                                                         for (kb=me->key->block.first; kb; kb=kb->next) {
2392                                                                 float *fp= kb->data;
2393                                                                 
2394                                                                 for (a=0; a<kb->totelem; a++, fp+=3) {
2395                                                                         VecSubf(fp, fp, cent);
2396                                                                 }
2397                                                         }
2398                                                 }
2399                                                 
2400                                                 me->flag |= ME_ISDONE;
2401                                                 
2402                                                 if(centermode) {
2403                                                         Mat3CpyMat4(omat, base->object->obmat);
2404                                                         
2405                                                         VECCOPY(centn, cent);
2406                                                         Mat3MulVecfl(omat, centn);
2407                                                         base->object->loc[0]+= centn[0];
2408                                                         base->object->loc[1]+= centn[1];
2409                                                         base->object->loc[2]+= centn[2];
2410                                                         
2411                                                         where_is_object(base->object);
2412                                                         ignore_parent_tx(base->object);
2413                                                         
2414                                                         /* other users? */
2415                                                         ob= G.main->object.first;
2416                                                         while(ob) {
2417                                                                 if((ob->flag & OB_DONE)==0) {
2418                                                                         tme= get_mesh(ob);
2419                                                                         
2420                                                                         if(tme==me) {
2421                                                                                 
2422                                                                                 ob->flag |= OB_DONE;
2423                                                                                 ob->recalc= OB_RECALC_OB|OB_RECALC_DATA;
2424
2425                                                                                 Mat3CpyMat4(omat, ob->obmat);
2426                                                                                 VECCOPY(centn, cent);
2427                                                                                 Mat3MulVecfl(omat, centn);
2428                                                                                 ob->loc[0]+= centn[0];
2429                                                                                 ob->loc[1]+= centn[1];
2430                                                                                 ob->loc[2]+= centn[2];
2431                                                                                 
2432                                                                                 where_is_object(ob);
2433                                                                                 ignore_parent_tx(ob);
2434                                                                                 
2435                                                                                 if(tme && (tme->flag & ME_ISDONE)==0) {
2436                                                                                         mvert= tme->mvert;
2437                                                                                         for(a=0; a<tme->totvert; a++, mvert++) {
2438                                                                                                 VecSubf(mvert->co, mvert->co, cent);
2439                                                                                         }
2440                                                                                         
2441                                                                                         if (tme->key) {
2442                                                                                                 KeyBlock *kb;
2443                                                                                                 for (kb=tme->key->block.first; kb; kb=kb->next) {
2444                                                                                                         float *fp= kb->data;
2445                                                                                                         
2446                                                                                                         for (a=0; a<kb->totelem; a++, fp+=3) {
2447                                                                                                                 VecSubf(fp, fp, cent);
2448                                                                                                         }
2449                                                                                                 }
2450                                                                                         }
2451                                                                                         
2452                                                                                         tme->flag |= ME_ISDONE;
2453                                                                                 }
2454                                                                         }
2455                                                                 }
2456                                                                 
2457                                                                 ob= ob->id.next;
2458                                                         }
2459                                                 }
2460                                                 tot_change++;
2461                                         }
2462                                 }
2463                                 else if (ELEM(base->object->type, OB_CURVE, OB_SURF)) {
2464                                         
2465                                         /* totally weak code here... (ton) */
2466                                         if(obedit==base->object) {
2467                                                 extern ListBase editNurb;
2468                                                 nu1= editNurb.first;
2469                                                 cu= obedit->data;
2470                                         }
2471                                         else {
2472                                                 cu= base->object->data;
2473                                                 nu1= cu->nurb.first;
2474                                         }
2475                                         
2476                                         if (cu->id.lib) {
2477                                                 tot_lib_error++;
2478                                         } else {
2479                                                 if(centermode==2) {
2480                                                         VECCOPY(cent, give_cursor(scene, v3d));
2481                                                         Mat4Invert(base->object->imat, base->object->obmat);
2482                                                         Mat4MulVecfl(base->object->imat, cent);
2483
2484                                                         /* don't allow Z change if curve is 2D */
2485                                                         if( !( cu->flag & CU_3D ) )
2486                                                                 cent[2] = 0.0;
2487                                                 } 
2488                                                 else {
2489                                                         INIT_MINMAX(min, max);
2490                                                         
2491                                                         nu= nu1;
2492                                                         while(nu) {
2493                                                                 minmaxNurb(nu, min, max);
2494                                                                 nu= nu->next;
2495                                                         }
2496                                                         
2497                                                         cent[0]= (min[0]+max[0])/2.0f;
2498                                                         cent[1]= (min[1]+max[1])/2.0f;
2499                                                         cent[2]= (min[2]+max[2])/2.0f;
2500                                                 }
2501                                                 
2502                                                 nu= nu1;
2503                                                 while(nu) {
2504                                                         if( (nu->type & 7)==1) {
2505                                                                 a= nu->pntsu;
2506                                                                 while (a--) {
2507                                                                         VecSubf(nu->bezt[a].vec[0], nu->bezt[a].vec[0], cent);
2508                                                                         VecSubf(nu->bezt[a].vec[1], nu->bezt[a].vec[1], cent);
2509                                                                         VecSubf(nu->bezt[a].vec[2], nu->bezt[a].vec[2], cent);
2510                                                                 }
2511                                                         }
2512                                                         else {
2513                                                                 a= nu->pntsu*nu->pntsv;
2514                                                                 while (a--)
2515                                                                         VecSubf(nu->bp[a].vec, nu->bp[a].vec, cent);
2516                                                         }
2517                                                         nu= nu->next;
2518                                                 }
2519                                 
2520                                                 if(centermode && obedit==0) {
2521                                                         Mat3CpyMat4(omat, base->object->obmat);
2522                                                         
2523                                                         Mat3MulVecfl(omat, cent);
2524                                                         base->object->loc[0]+= cent[0];
2525                                                         base->object->loc[1]+= cent[1];
2526                                                         base->object->loc[2]+= cent[2];
2527                                                         
2528                                                         where_is_object(base->object);
2529                                                         ignore_parent_tx(base->object);
2530                                                 }
2531                                                 
2532                                                 tot_change++;
2533                                                 if(obedit) {
2534                                                         if (centermode==0) {
2535                                                                 DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
2536                                                         }
2537                                                         break;
2538                                                 }
2539                                         }
2540                                 }
2541                                 else if(base->object->type==OB_FONT) {
2542                                         /* get from bb */
2543                                         
2544                                         cu= base->object->data;
2545                                         
2546                                         if(cu->bb==0) {
2547                                                 /* do nothing*/
2548                                         } else if (cu->id.lib) {
2549                                                 tot_lib_error++;
2550                                         } else {
2551                                                 cu->xof= -0.5f*( cu->bb->vec[4][0] - cu->bb->vec[0][0]);
2552                                                 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 */
2553                                                 
2554                                                 /* not really ok, do this better once! */
2555                                                 cu->xof /= cu->fsize;
2556                                                 cu->yof /= cu->fsize;
2557
2558                                                 allqueue(REDRAWBUTSEDIT, 0);
2559                                                 tot_change++;
2560                                         }
2561                                 }
2562                                 else if(base->object->type==OB_ARMATURE) {
2563                                         bArmature *arm = base->object->data;
2564                                         
2565                                         if (arm->id.lib) {
2566                                                 tot_lib_error++;
2567                                         } else if(arm->id.us>1) {
2568                                                 /*error("Can't apply to a multi user armature");
2569                                                 return;*/
2570                                                 tot_multiuser_arm_error++;
2571                                         } else {
2572                                                 /* Function to recenter armatures in editarmature.c 
2573                                                  * Bone + object locations are handled there.
2574                                                  */
2575 // XXX                                          docenter_armature(base->object, centermode);
2576                                                 tot_change++;
2577                                                 
2578                                                 where_is_object(base->object);
2579                                                 ignore_parent_tx(base->object);
2580                                                 
2581                                                 if(obedit) 
2582                                                         break;
2583                                         }
2584                                 }
2585                                 base->object->recalc= OB_RECALC_OB|OB_RECALC_DATA;
2586                         }
2587                 }
2588         }
2589         if (tot_change) {
2590                 ED_anim_dag_flush_update(C);
2591                 allqueue(REDRAWVIEW3D, 0);
2592                 BIF_undo_push("Do Center");     
2593         }
2594         
2595         /* Warn if any errors occured */
2596         if (tot_lib_error+tot_multiuser_arm_error) {
2597                 char err[512];
2598                 sprintf(err, "Warning %i Object(s) Not Centered, %i Changed:", tot_lib_error+tot_multiuser_arm_error, tot_change);
2599                 
2600                 if (tot_lib_error)
2601                         sprintf(err+strlen(err), "|%i linked library objects", tot_lib_error);
2602                 if (tot_multiuser_arm_error)
2603                         sprintf(err+strlen(err), "|%i multiuser armature object(s)", tot_multiuser_arm_error);
2604                 
2605                 error(err);
2606         }
2607 }
2608
2609 void docenter_new(Scene *scene, View3D *v3d)
2610 {
2611         if(scene->id.lib) return;
2612
2613         if(scene->obedit) { // XXX get from context
2614                 error("Unable to center new in Edit Mode");
2615         }
2616         else {
2617                 docenter(scene, v3d, 1);
2618         }
2619 }
2620
2621 void docenter_cursor(Scene *scene, View3D *v3d)
2622 {
2623         if(scene->id.lib) return;
2624
2625         if(scene->obedit) { // XXX get from context
2626                 error("Unable to center cursor in Edit Mode");
2627         }
2628         else {
2629                 docenter(scene, v3d, 2);
2630         }
2631 }
2632
2633 void movetolayer(Scene *scene, View3D *v3d)
2634 {
2635         Base *base;
2636         unsigned int lay= 0, local;
2637         int islamp= 0;
2638         
2639         if(scene->id.lib) return;
2640
2641         for(base= FIRSTBASE; base; base= base->next) {
2642                 if (TESTBASE(v3d, base)) lay |= base->lay;
2643         }
2644         if(lay==0) return;
2645         lay &= 0xFFFFFF;
2646         
2647         if(lay==0) return;
2648         
2649         if(v3d->localview) {
2650                 /* now we can move out of localview. */
2651                 if (!okee("Move from localview")) return;
2652                 for(base= FIRSTBASE; base; base= base->next) {
2653                         if (TESTBASE(v3d, base)) {
2654                                 lay= base->lay & ~v3d->lay;
2655                                 base->lay= lay;
2656                                 base->object->lay= lay;
2657                                 base->object->flag &= ~SELECT;
2658                                 base->flag &= ~SELECT;
2659                                 if(base->object->type==OB_LAMP) islamp= 1;
2660                         }
2661                 }
2662         } else {
2663 // XXX          if( movetolayer_buts(&lay, NULL)==0 ) return;
2664                 
2665                 /* normal non localview operation */
2666                 for(base= FIRSTBASE; base; base= base->next) {
2667                         if (TESTBASE(v3d, base)) {
2668                                 /* upper byte is used for local view */
2669                                 local= base->lay & 0xFF000000;  
2670                                 base->lay= lay + local;
2671                                 base->object->lay= lay;
2672                                 if(base->object->type==OB_LAMP) islamp= 1;
2673                         }
2674                 }
2675         }
2676         if(islamp) reshadeall_displist();       /* only frees */
2677         
2678         /* warning, active object may be hidden now */
2679         
2680         DAG_scene_sort(scene);
2681         
2682         allqueue(REDRAWBUTSEDIT, 0);
2683         allqueue(REDRAWVIEW3D, 0);
2684         allqueue(REDRAWOOPS, 0);
2685         allqueue(REDRAWINFO, 0);
2686         
2687         BIF_undo_push("Move to layer");
2688 }
2689
2690
2691 #if 0
2692 // XXX should be in view3d?
2693
2694 /* context: ob = lamp */
2695 /* code should be replaced with proper (custom) transform handles for lamp properties */
2696 static void spot_interactive(Object *ob, int mode)
2697 {
2698         Lamp *la= ob->data;
2699         float transfac, dx, dy, ratio, origval;
2700         int keep_running= 1, center2d[2];
2701         short mval[2], mvalo[2];
2702         
2703 //      getmouseco_areawin(mval);
2704 //      getmouseco_areawin(mvalo);
2705         
2706         project_int(ob->obmat[3], center2d);
2707         if( center2d[0] > 100000 ) {            /* behind camera */
2708 //              center2d[0]= curarea->winx/2;
2709 //              center2d[1]= curarea->winy/2;
2710         }
2711
2712 //      helpline(mval, center2d);
2713         
2714         /* ratio is like scaling */
2715         dx = (float)(center2d[0] - mval[0]);
2716         dy = (float)(center2d[1] - mval[1]);
2717         transfac = (float)sqrt( dx*dx + dy*dy);
2718         if(transfac==0.0f) transfac= 1.0f;
2719         
2720         if(mode==1)     
2721                 origval= la->spotsize;
2722         else if(mode==2)        
2723                 origval= la->dist;
2724         else if(mode==3)        
2725                 origval= la->clipsta;
2726         else    
2727                 origval= la->clipend;
2728         
2729         while (keep_running>0) {
2730                 
2731 //              getmouseco_areawin(mval);
2732                 
2733                 /* essential for idling subloop */
2734                 if(mval[0]==mvalo[0] && mval[1]==mvalo[1]) {
2735                         PIL_sleep_ms(2);
2736                 }
2737                 else {
2738                         char str[32];
2739                         
2740                         dx = (float)(center2d[0] - mval[0]);
2741                         dy = (float)(center2d[1] - mval[1]);
2742                         ratio = (float)(sqrt( dx*dx + dy*dy))/transfac;
2743                         
2744                         /* do the trick */
2745                         
2746                         if(mode==1) {   /* spot */
2747                                 la->spotsize = ratio*origval;
2748                                 CLAMP(la->spotsize, 1.0f, 180.0f);
2749                                 sprintf(str, "Spot size %.2f\n", la->spotsize);
2750                         }
2751                         else if(mode==2) {      /* dist */
2752                                 la->dist = ratio*origval;
2753                                 CLAMP(la->dist, 0.01f, 5000.0f);
2754                                 sprintf(str, "Distance %.2f\n", la->dist);
2755                         }
2756                         else if(mode==3) {      /* sta */
2757                                 la->clipsta = ratio*origval;
2758                                 CLAMP(la->clipsta, 0.001f, 5000.0f);
2759                                 sprintf(str, "Distance %.2f\n", la->clipsta);
2760                         }
2761                         else if(mode==4) {      /* end */
2762                                 la->clipend = ratio*origval;
2763                                 CLAMP(la->clipend, 0.1f, 5000.0f);
2764                                 sprintf(str, "Clip End %.2f\n", la->clipend);
2765                         }
2766
2767                         /* cleanup */
2768                         mvalo[0]= mval[0];
2769                         mvalo[1]= mval[1];
2770                         
2771                         /* handle shaded mode */
2772 // XXX                  shade_buttons_change_3d();
2773
2774                         /* DRAW */      
2775                         headerprint(str);
2776                         force_draw_plus(SPACE_BUTS, 0);
2777
2778 //                      helpline(mval, center2d);
2779                 }
2780                 
2781                 while( qtest() ) {
2782                         short val;
2783                         unsigned short event= extern_qread(&val);
2784                         
2785                         switch (event){
2786                                 case ESCKEY:
2787                                 case RIGHTMOUSE:
2788                                         keep_running= 0;
2789                                         break;
2790                                 case LEFTMOUSE:
2791                                 case SPACEKEY:
2792                                 case PADENTER:
2793                                 case RETKEY:
2794                                         if(val)
2795                                                 keep_running= -1;
2796                                         break;
2797                         }
2798                 }
2799         }
2800
2801         if(keep_running==0) {
2802                 if(mode==1)     
2803                         la->spotsize= origval;
2804                 else if(mode==2)        
2805                         la->dist= origval;
2806                 else if(mode==3)        
2807                         la->clipsta= origval;
2808                 else    
2809                         la->clipend= origval;
2810         }
2811
2812         allqueue(REDRAWVIEW3D, 0);
2813         allqueue(REDRAWBUTSSHADING, 0);
2814         BIF_preview_changed(ID_LA);
2815 }
2816 #endif
2817
2818 void special_editmenu(Scene *scene, View3D *v3d)
2819 {
2820 // XXX  static short numcuts= 2;
2821         Object *ob= OBACT;
2822         Object *obedit= NULL; // XXX
2823         float fac;
2824         int nr,ret;
2825         short randfac;
2826         
2827         if(ob==NULL) return;
2828         
2829         if(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);