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