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