2.5
[blender-staging.git] / source / blender / editors / object / object_edit.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * Contributor(s): Blender Foundation, 2002-2008 full recode
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27 #include <stdlib.h>
28 #include <string.h>
29 #include <math.h>
30 #include <time.h>
31
32 #include "MEM_guardedalloc.h"
33
34 #include "IMB_imbuf_types.h"
35
36 #include "DNA_action_types.h"
37 #include "DNA_armature_types.h"
38 #include "DNA_camera_types.h"
39 #include "DNA_constraint_types.h"
40 #include "DNA_curve_types.h"
41 #include "DNA_effect_types.h"
42 #include "DNA_group_types.h"
43 #include "DNA_image_types.h"
44 #include "DNA_ipo_types.h"
45 #include "DNA_key_types.h"
46 #include "DNA_lamp_types.h"
47 #include "DNA_lattice_types.h"
48 #include "DNA_material_types.h"
49 #include "DNA_mesh_types.h"
50 #include "DNA_meshdata_types.h"
51 #include "DNA_meta_types.h"
52 #include "DNA_nla_types.h"
53 #include "DNA_object_types.h"
54 #include "DNA_object_fluidsim.h"
55 #include "DNA_object_force.h"
56 #include "DNA_scene_types.h"
57 #include "DNA_space_types.h"
58 #include "DNA_screen_types.h"
59 #include "DNA_texture_types.h"
60 #include "DNA_particle_types.h"
61 #include "DNA_property_types.h"
62 #include "DNA_userdef_types.h"
63 #include "DNA_view3d_types.h"
64 #include "DNA_vfont_types.h"
65 #include "DNA_world_types.h"
66 #include "DNA_modifier_types.h"
67
68 #include "BLI_blenlib.h"
69 #include "BLI_arithb.h"
70 #include "BLI_editVert.h"
71 #include "BLI_ghash.h"
72 #include "BLI_rand.h"
73
74 #include "BKE_action.h"
75 #include "BKE_anim.h"
76 #include "BKE_armature.h"
77 #include "BKE_booleanops.h"
78 #include "BKE_constraint.h"
79 #include "BKE_context.h"
80 #include "BKE_customdata.h"
81 #include "BKE_blender.h"
82 #include "BKE_booleanops.h"
83 #include "BKE_cloth.h"
84 #include "BKE_curve.h"
85 #include "BKE_displist.h"
86 #include "BKE_depsgraph.h"
87 #include "BKE_DerivedMesh.h"
88 #include "BKE_effect.h"
89 #include "BKE_font.h"
90 #include "BKE_global.h"
91 #include "BKE_group.h"
92 #include "BKE_ipo.h"
93 #include "BKE_image.h"
94 #include "BKE_key.h"
95 #include "BKE_lattice.h"
96 #include "BKE_library.h"
97 #include "BKE_main.h"
98 #include "BKE_material.h"
99 #include "BKE_mball.h"
100 #include "BKE_mesh.h"
101 #include "BKE_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 /* ************* Slow Parent ******************* */
1643 static int object_set_slowparent_exec(bContext *C, wmOperator *op)
1644 {
1645         Scene *scene= CTX_data_scene(C);
1646
1647         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1648                                 
1649                 if(base->object->parent) base->object->partype |= PARSLOW;
1650                 base->object->recalc |= OB_RECALC_OB;
1651                 
1652         }
1653         CTX_DATA_END;
1654
1655         ED_anim_dag_flush_update(C);    
1656         ED_undo_push(C,"Set Slow Parent");
1657         
1658         WM_event_add_notifier(C, NC_SCENE, CTX_data_scene(C));
1659         
1660         return OPERATOR_FINISHED;
1661 }
1662
1663 void OBJECT_OT_set_slowparent(wmOperatorType *ot)
1664 {
1665         
1666         /* identifiers */
1667         ot->name= "Set Slow Parent";
1668         ot->idname= "OBJECT_OT_set_slow_parent";
1669         
1670         /* api callbacks */
1671         ot->invoke= WM_operator_confirm;
1672         ot->exec= object_set_slowparent_exec;
1673         ot->poll= ED_operator_view3d_active;
1674 }
1675
1676 static int object_clear_slowparent_exec(bContext *C, wmOperator *op)
1677 {
1678         Scene *scene= CTX_data_scene(C);
1679
1680         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1681                 if(base->object->parent) {
1682                         if(base->object->partype & PARSLOW) {
1683                                 base->object->partype -= PARSLOW;
1684                                 where_is_object(scene, base->object);
1685                                 base->object->partype |= PARSLOW;
1686                                 base->object->recalc |= OB_RECALC_OB;
1687                         }
1688                 }
1689                 
1690         }
1691         CTX_DATA_END;
1692
1693         ED_anim_dag_flush_update(C);    
1694         ED_undo_push(C,"Clear Slow Parent");
1695         
1696         WM_event_add_notifier(C, NC_SCENE, CTX_data_scene(C));
1697         
1698         return OPERATOR_FINISHED;
1699 }
1700
1701 void OBJECT_OT_clear_slowparent(wmOperatorType *ot)
1702 {
1703         
1704         /* identifiers */
1705         ot->name= "Clear Slow Parent";
1706         ot->idname= "OBJECT_OT_clear_slow_parent";
1707         
1708         /* api callbacks */
1709         ot->invoke= WM_operator_confirm;
1710         ot->exec= object_clear_slowparent_exec;
1711         ot->poll= ED_operator_view3d_active;
1712 }
1713 /* ******************** **************** */
1714
1715 // XXX
1716 #define BEZSELECTED_HIDDENHANDLES(bezt)   ((G.f & G_HIDDENHANDLES) ? (bezt)->f2 & SELECT : BEZSELECTED(bezt))
1717 /* only in edit mode */
1718 void make_vertex_parent(Scene *scene, Object *obedit, View3D *v3d)
1719 {
1720         EditVert *eve;
1721         Base *base;
1722         Nurb *nu;
1723         BezTriple *bezt;
1724         BPoint *bp;
1725         Object *par, *ob;
1726         int a, v1=0, v2=0, v3=0, v4=0, nr=1;
1727         
1728         /* we need 1 to 3 selected vertices */
1729         
1730         if(obedit->type==OB_MESH) {
1731                 Mesh *me= obedit->data;
1732                 
1733                 eve= me->edit_mesh->verts.first;
1734                 while(eve) {
1735                         if(eve->f & 1) {
1736                                 if(v1==0) v1= nr;
1737                                 else if(v2==0) v2= nr;
1738                                 else if(v3==0) v3= nr;
1739                                 else if(v4==0) v4= nr;
1740                                 else break;
1741                         }
1742                         nr++;
1743                         eve= eve->next;
1744                 }
1745         }
1746         else if(ELEM(obedit->type, OB_SURF, OB_CURVE)) {
1747                 extern ListBase editNurb;
1748                 nu= editNurb.first;
1749                 while(nu) {
1750                         if((nu->type & 7)==CU_BEZIER) {
1751                                 bezt= nu->bezt;
1752                                 a= nu->pntsu;
1753                                 while(a--) {
1754                                         if(BEZSELECTED_HIDDENHANDLES(bezt)) {
1755                                                 if(v1==0) v1= nr;
1756                                                 else if(v2==0) v2= nr;
1757                                                 else if(v3==0) v3= nr;
1758                                                 else if(v4==0) v4= nr;
1759                                                 else break;
1760                                         }
1761                                         nr++;
1762                                         bezt++;
1763                                 }
1764                         }
1765                         else {
1766                                 bp= nu->bp;
1767                                 a= nu->pntsu*nu->pntsv;
1768                                 while(a--) {
1769                                         if(bp->f1 & SELECT) {
1770                                                 if(v1==0) v1= nr;
1771                                                 else if(v2==0) v2= nr;
1772                                                 else if(v3==0) v3= nr;
1773                                                 else if(v4==0) v4= nr;
1774                                                 else break;
1775                                         }
1776                                         nr++;
1777                                         bp++;
1778                                 }
1779                         }
1780                         nu= nu->next;
1781                 }
1782         }
1783         else if(obedit->type==OB_LATTICE) {
1784                 
1785                 a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
1786                 bp= editLatt->def;
1787                 while(a--) {
1788                         if(bp->f1 & SELECT) {
1789                                 if(v1==0) v1= nr;
1790                                 else if(v2==0) v2= nr;
1791                                 else if(v3==0) v3= nr;
1792                                 else if(v4==0) v4= nr;
1793                                 else break;
1794                         }
1795                         nr++;
1796                         bp++;
1797                 }
1798         }
1799         
1800         if(v4 || !((v1 && v2==0 && v3==0) || (v1 && v2 && v3)) ) {
1801                 error("Select either 1 or 3 vertices to parent to");
1802                 return;
1803         }
1804         
1805         if(okee("Make vertex parent")==0) return;
1806         
1807         for(base= FIRSTBASE; base; base= base->next) {
1808                 if(TESTBASELIB(v3d, base)) {
1809                         if(base!=BASACT) {
1810                                 
1811                                 ob= base->object;
1812                                 ob->recalc |= OB_RECALC;
1813                                 par= BASACT->object->parent;
1814                                 
1815                                 while(par) {
1816                                         if(par==ob) break;
1817                                         par= par->parent;
1818                                 }
1819                                 if(par) {
1820                                         error("Loop in parents");
1821                                 }
1822                                 else {
1823                                         Object workob;
1824                                         
1825                                         ob->parent= BASACT->object;
1826                                         if(v3) {
1827                                                 ob->partype= PARVERT3;
1828                                                 ob->par1= v1-1;
1829                                                 ob->par2= v2-1;
1830                                                 ob->par3= v3-1;
1831
1832                                                 /* inverse parent matrix */
1833                                                 what_does_parent(scene, ob, &workob);
1834                                                 Mat4Invert(ob->parentinv, workob.obmat);
1835                                         }
1836                                         else {
1837                                                 ob->partype= PARVERT1;
1838                                                 ob->par1= v1-1;
1839
1840                                                 /* inverse parent matrix */
1841                                                 what_does_parent(scene, ob, &workob);
1842                                                 Mat4Invert(ob->parentinv, workob.obmat);
1843                                         }
1844                                 }
1845                         }
1846                 }
1847         }
1848         allqueue(REDRAWVIEW3D, 0);
1849         
1850         DAG_scene_sort(scene);
1851         /* BIF_undo_push(str); not, conflicts with editmode undo... */
1852 }
1853
1854 static Object *group_objects_menu(Group *group)
1855 {
1856         GroupObject *go;
1857         int len= 0;
1858         short a, nr;
1859         char *str;
1860                 
1861         for(go= group->gobject.first; go; go= go->next) {
1862                 if(go->ob)
1863                         len++;
1864         }
1865         if(len==0) return NULL;
1866         
1867         str= MEM_callocN(40+32*len, "menu");
1868         
1869         strcpy(str, "Make Proxy for: %t");
1870         a= strlen(str);
1871         for(nr=1, go= group->gobject.first; go; go= go->next, nr++) {
1872                 a+= sprintf(str+a, "|%s %%x%d", go->ob->id.name+2, nr);
1873         }
1874         
1875         a= pupmenu_col(str, 20);
1876         MEM_freeN(str);
1877         if(a>0) {
1878                 go= BLI_findlink(&group->gobject, a-1);
1879                 return go->ob;
1880         }
1881         return NULL;
1882 }
1883
1884
1885 /* adds empty object to become local replacement data of a library-linked object */
1886 void make_proxy(Scene *scene)
1887 {
1888         Object *ob= OBACT;
1889         Object *gob= NULL;
1890         
1891         if(scene->id.lib) return;
1892         if(ob==NULL) return;
1893         
1894         
1895         if(ob->dup_group && ob->dup_group->id.lib) {
1896                 gob= ob;
1897                 /* gives menu with list of objects in group */
1898                 ob= group_objects_menu(ob->dup_group);
1899         }
1900         else if(ob->id.lib) {
1901                 if(okee("Make Proxy Object")==0)
1902                 return;
1903         }
1904         else {
1905                 error("Can only make proxy for a referenced object or group");
1906                 return;
1907         }
1908         
1909         if(ob) {
1910                 Object *newob;
1911                 Base *newbase, *oldbase= BASACT;
1912                 char name[32];
1913                 
1914                 newob= add_object(scene, OB_EMPTY);
1915                 if(gob)
1916                         strcpy(name, gob->id.name+2);
1917                 else
1918                         strcpy(name, ob->id.name+2);
1919                 strcat(name, "_proxy");
1920                 rename_id(&newob->id, name);
1921                 
1922                 /* set layers OK */
1923                 newbase= BASACT;        /* add_object sets active... */
1924                 newbase->lay= oldbase->lay;
1925                 newob->lay= newbase->lay;
1926                 
1927                 /* remove base, leave user count of object, it gets linked in object_make_proxy */
1928                 if(gob==NULL) {
1929                         BLI_remlink(&scene->base, oldbase);
1930                         MEM_freeN(oldbase);
1931                 }               
1932                 object_make_proxy(newob, ob, gob);
1933                 
1934                 DAG_scene_sort(scene);
1935                 DAG_object_flush_update(scene, newob, OB_RECALC);
1936                 allqueue(REDRAWALL, 0);
1937                 BIF_undo_push("Make Proxy Object");
1938         }
1939 }
1940
1941 /* ******************** make parent operator *********************** */
1942
1943 #if 0
1944 oldcode()
1945 {
1946         else if(mode==4) {
1947                 bConstraint *con;
1948                 bFollowPathConstraint *data;
1949                         
1950                 for(base= FIRSTBASE; base; base= base->next) {
1951                         if(TESTBASELIB(v3d, base)) {
1952                                 if(base!=BASACT) {
1953                                         float cmat[4][4], vec[3];
1954                                         
1955 // XXX                                          con = add_new_constraint(CONSTRAINT_TYPE_FOLLOWPATH);
1956                                         strcpy (con->name, "AutoPath");
1957                                         
1958                                         data = con->data;
1959                                         data->tar = BASACT->object;
1960                                         
1961 // XXX                                          add_constraint_to_object(con, base->object);
1962                                         
1963                                         get_constraint_target_matrix(con, 0, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, scene->r.cfra - give_timeoffset(base->object));
1964                                         VecSubf(vec, base->object->obmat[3], cmat[3]);
1965                                         
1966                                         base->object->loc[0] = vec[0];
1967                                         base->object->loc[1] = vec[1];
1968                                         base->object->loc[2] = vec[2];
1969                                 }
1970                         }
1971                 }
1972
1973                 if(mode==PARSKEL && base->object->type==OB_MESH && par->type == OB_ARMATURE) {
1974                         /* Prompt the user as to whether he wants to
1975                                 * add some vertex groups based on the bones
1976                                 * in the parent armature.
1977                                 */
1978 // XXX                                                  create_vgroups_from_armature(base->object, par);
1979
1980                         base->object->partype= PAROBJECT;
1981                         what_does_parent(scene, base->object);
1982                         Mat4One (base->object->parentinv);
1983                         base->object->partype= mode;
1984                 }
1985                 else
1986                         what_does_parent(scene, base->object, &workob);
1987                 Mat4Invert(base->object->parentinv, workob.obmat);
1988         }
1989 }
1990 #endif
1991
1992 #define PAR_OBJECT              0
1993 #define PAR_ARMATURE    1
1994 #define PAR_BONE                2
1995 #define PAR_CURVE               3
1996 #define PAR_FOLLOW              4
1997 #define PAR_PATH_CONST  5
1998 #define PAR_LATTICE             6
1999 #define PAR_VERTEX              7
2000 #define PAR_TRIA                8
2001
2002 static EnumPropertyItem prop_make_parent_types[] = {
2003         {PAR_OBJECT, "OBJECT", "Object", ""},
2004         {PAR_ARMATURE, "ARMATURE", "Armature Deform", ""},
2005         {PAR_BONE, "BONE", "Bone", ""},
2006         {PAR_CURVE, "CURVE", "Curve Deform", ""},
2007         {PAR_FOLLOW, "FOLLOW", "Follow Path", ""},
2008         {PAR_PATH_CONST, "PATH_CONST", "Path Constraint", ""},
2009         {PAR_LATTICE, "LATTICE", "Lattice Deform", ""},
2010         {PAR_VERTEX, "VERTEX", "Vertex", ""},
2011         {PAR_TRIA, "TRIA", "Triangle", ""},
2012         {0, NULL, NULL, NULL}
2013 };
2014
2015 static int test_parent_loop(Object *par, Object *ob)
2016 {
2017         /* test if 'ob' is a parent somewhere in par's parents */
2018         
2019         if(par == NULL) return 0;
2020         if(ob == par) return 1;
2021         
2022         return test_parent_loop(par->parent, ob);
2023 }
2024
2025
2026 static int make_parent_exec(bContext *C, wmOperator *op)
2027 {
2028         Scene *scene= CTX_data_scene(C);
2029         Object *par= CTX_data_active_object(C);
2030         bPoseChannel *pchan= NULL;
2031         int partype= RNA_enum_get(op->ptr, "type");
2032         
2033         par->recalc |= OB_RECALC_OB;
2034         
2035         /* preconditions */
2036         if(partype==PAR_FOLLOW || partype==PAR_PATH_CONST) {
2037                 if(par->type!=OB_CURVE)
2038                         return OPERATOR_CANCELLED;
2039                 else {
2040                         Curve *cu= par->data;
2041                         
2042                         if((cu->flag & CU_PATH)==0) {
2043                                 cu->flag |= CU_PATH|CU_FOLLOW;
2044                                 makeDispListCurveTypes(scene, par, 0);  /* force creation of path data */
2045                         }
2046                         else cu->flag |= CU_FOLLOW;
2047                         
2048                         /* fall back on regular parenting now */
2049                         partype= PAR_OBJECT;
2050                 }               
2051         }
2052         else if(partype==PAR_BONE) {
2053                 pchan= get_active_posechannel(par);
2054                 
2055                 if(pchan==NULL) {
2056                         error("No active Bone");
2057                         return OPERATOR_CANCELLED;
2058                 }
2059         }
2060         
2061         /* context itterator */
2062         CTX_DATA_BEGIN(C, Object*, ob, selected_objects) {
2063                 
2064                 if(ob!=par) {
2065                         
2066                         if( test_parent_loop(par, ob) ) {
2067                                 error("Loop in parents");
2068                         }
2069                         else {
2070                                 Object workob;
2071                                 
2072                                 /* apply transformation of previous parenting */
2073                                 ED_object_apply_obmat(ob);
2074                                 
2075                                 ob->parent= par;
2076                                 
2077                                 /* handle types */
2078                                 if (pchan)
2079                                         strcpy (ob->parsubstr, pchan->name);
2080                                 else
2081                                         ob->parsubstr[0]= 0;
2082                                 
2083                                 /* constraint XXX */
2084                                 if(partype==PAR_PATH_CONST) {
2085                                 }
2086                                 
2087                                 /* calculate inverse parent matrix */
2088                                 what_does_parent(scene, ob, &workob);
2089                                 Mat4Invert(ob->parentinv, workob.obmat);
2090                                 
2091                                 ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA;
2092                                 
2093                                 if( ELEM3(partype, PAR_CURVE, PAR_ARMATURE, PAR_LATTICE) )
2094                                         ob->partype= PARSKEL; /* note, dna define, not operator property */
2095                                 else
2096                                         ob->partype= PAROBJECT; /* note, dna define, not operator property */
2097                         }
2098                 }
2099         }
2100         CTX_DATA_END;
2101         
2102         DAG_scene_sort(CTX_data_scene(C));
2103         ED_anim_dag_flush_update(C);    
2104         
2105         BIF_undo_push("make Parent");
2106         
2107         return OPERATOR_FINISHED;
2108 }
2109
2110 static int make_parent_invoke(bContext *C, wmOperator *op, wmEvent *event)
2111 {
2112         Object *ob= CTX_data_active_object(C);
2113         char *str, string[256];
2114         char formatstr[] = "|%s %%x%d";
2115         
2116         str= string + sprintf(string, "Make Parent To %%t");
2117         
2118         /* ob becomes parent, make the associated menus */
2119         if(ob->type==OB_ARMATURE) {
2120                 str += sprintf(str, formatstr, "Object", PAR_OBJECT);
2121                 str += sprintf(str, formatstr, "Armature Deform", PAR_ARMATURE);
2122                 str += sprintf(str, formatstr, "Bone", PAR_BONE);
2123         }
2124         else if(ob->type==OB_CURVE) {
2125                 str += sprintf(str, formatstr, "Object", PAR_OBJECT);
2126                 str += sprintf(str, formatstr, "Curve Deform", PAR_CURVE);
2127                 str += sprintf(str, formatstr, "Follow Path", PAR_FOLLOW);
2128                 str += sprintf(str, formatstr, "Path Constraint", PAR_PATH_CONST);
2129         }
2130         else if(ob->type == OB_LATTICE) {
2131                 str += sprintf(str, formatstr, "Object", PAR_OBJECT);
2132                 str += sprintf(str, formatstr, "Lattice Deform", PAR_LATTICE);
2133         }
2134         else
2135                 str += sprintf(str, formatstr, "Object", PAR_OBJECT);
2136         
2137         uiPupmenuOperator(C, 0, op, "type", string);
2138         
2139         return OPERATOR_RUNNING_MODAL;
2140 }
2141
2142
2143 void OBJECT_OT_make_parent(wmOperatorType *ot)
2144 {
2145         PropertyRNA *prop;
2146         
2147         /* identifiers */
2148         ot->name= "Make parent";
2149         ot->idname= "OBJECT_OT_make_parent";
2150         
2151         /* api callbacks */
2152         ot->invoke= make_parent_invoke;
2153         ot->exec= make_parent_exec;
2154         
2155         ot->poll= ED_operator_object_active;
2156         ot->flag= OPTYPE_REGISTER;
2157         
2158         prop = RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
2159         RNA_def_property_enum_items(prop, prop_make_parent_types);
2160 }
2161
2162 /* *** make track ***** */
2163 static EnumPropertyItem prop_make_track_types[] = {
2164         {1, "TRACKTO", "TrackTo Constraint", ""},
2165         {2, "LOCKTRACK", "LockTrack Constraint", ""},
2166         {3, "OLDTRACK", "Old Track", ""},
2167         {0, NULL, NULL, NULL}
2168 };
2169
2170 static int make_track_exec(bContext *C, wmOperator *op)
2171 {
2172         Scene *scene= CTX_data_scene(C);
2173         ScrArea *sa= CTX_wm_area(C);
2174         View3D *v3d= sa->spacedata.first;
2175         Base *base;
2176         
2177         if(scene->id.lib) return OPERATOR_CANCELLED;
2178
2179         if(RNA_enum_is_equal(op->ptr, "type", "TRACKTO")){
2180                 bConstraint *con;
2181                 bTrackToConstraint *data;
2182
2183                 for(base= FIRSTBASE; base; base= base->next) {
2184                         if(TESTBASELIB(v3d, base)) {
2185                                 if(base!=BASACT) {
2186 // XXX                                  con = add_new_constraint(CONSTRAINT_TYPE_TRACKTO);
2187                                         strcpy (con->name, "AutoTrack");
2188
2189                                         data = con->data;
2190                                         data->tar = BASACT->object;
2191                                         base->object->recalc |= OB_RECALC;
2192                                         
2193                                         /* Lamp and Camera track differently by default */
2194                                         if (base->object->type == OB_LAMP || base->object->type == OB_CAMERA) {
2195                                                 data->reserved1 = TRACK_nZ;
2196                                                 data->reserved2 = UP_Y;
2197                                         }
2198
2199 // XXX                                  add_constraint_to_object(con, base->object);
2200                                 }
2201                         }
2202                 }
2203
2204         }
2205         else if(RNA_enum_is_equal(op->ptr, "type", "LOCKTRACK")){
2206                 bConstraint *con;
2207                 bLockTrackConstraint *data;
2208
2209                 for(base= FIRSTBASE; base; base= base->next) {
2210                         if(TESTBASELIB(v3d, base)) {
2211                                 if(base!=BASACT) {
2212 // XXX                                  con = add_new_constraint(CONSTRAINT_TYPE_LOCKTRACK);
2213                                         strcpy (con->name, "AutoTrack");
2214
2215                                         data = con->data;
2216                                         data->tar = BASACT->object;
2217                                         base->object->recalc |= OB_RECALC;
2218                                         
2219                                         /* Lamp and Camera track differently by default */
2220                                         if (base->object->type == OB_LAMP || base->object->type == OB_CAMERA) {
2221                                                 data->trackflag = TRACK_nZ;
2222                                                 data->lockflag = LOCK_Y;
2223                                         }
2224
2225 // XXX                                  add_constraint_to_object(con, base->object);
2226                                 }
2227                         }
2228                 }
2229
2230         }
2231         else if(RNA_enum_is_equal(op->ptr, "type", "OLDTRACK")){
2232                 for(base= FIRSTBASE; base; base= base->next) {
2233                         if(TESTBASELIB(v3d, base)) {
2234                                 if(base!=BASACT) {
2235                                         base->object->track= BASACT->object;
2236                                         base->object->recalc |= OB_RECALC;
2237                                 }
2238                         }
2239                 }
2240         }
2241         DAG_scene_sort(CTX_data_scene(C));
2242         ED_anim_dag_flush_update(C);    
2243         
2244         BIF_undo_push("make track");
2245         
2246         return OPERATOR_FINISHED;
2247 }
2248
2249 void OBJECT_OT_make_track(wmOperatorType *ot)
2250 {
2251         PropertyRNA *prop;
2252         
2253         /* identifiers */
2254         ot->name= "Make Track";
2255         ot->idname= "OBJECT_OT_make_track";
2256         
2257         /* api callbacks */
2258         ot->invoke= WM_menu_invoke;
2259         ot->exec= make_track_exec;
2260         
2261         ot->poll= ED_operator_scene_editable;
2262         ot->flag= OPTYPE_REGISTER;
2263         
2264         prop = RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
2265         RNA_def_property_enum_items(prop, prop_make_track_types);
2266 }
2267
2268
2269 /* ******************* toggle editmode operator  ***************** */
2270
2271 void ED_object_exit_editmode(bContext *C, int flag)
2272 {
2273         Scene *scene= CTX_data_scene(C);
2274         Object *ob;
2275         Object *obedit= CTX_data_edit_object(C);
2276         int freedata = flag & EM_FREEDATA;
2277         
2278         if(obedit==NULL) return;
2279         
2280         if(flag & EM_WAITCURSOR) waitcursor(1);
2281         if(obedit->type==OB_MESH) {
2282                 Mesh *me= obedit->data;
2283                 
2284 //              if(EM_texFaceCheck())
2285                 
2286 //              if(retopo_mesh_paint_check())
2287 //                      retopo_end_okee();
2288                 
2289                 if(G.totvert>MESH_MAX_VERTS) {
2290                         error("Too many vertices");
2291                         return;
2292                 }
2293                 load_editMesh(scene, obedit);
2294                 
2295                 if(freedata) free_editMesh(me->edit_mesh);
2296                 
2297                 if(G.f & G_WEIGHTPAINT)
2298                         mesh_octree_table(obedit, NULL, NULL, 'e');
2299         }
2300         else if (obedit->type==OB_ARMATURE) {   
2301                 ED_armature_from_edit(scene, obedit);
2302                 if(freedata)
2303                         ED_armature_edit_free(obedit);
2304         }
2305         else if(ELEM(obedit->type, OB_CURVE, OB_SURF)) {
2306 //              extern ListBase editNurb;
2307 //              load_editNurb();
2308 //              if(freedata) freeNurblist(&editNurb);
2309         }
2310         else if(obedit->type==OB_FONT && freedata) {
2311 //              load_editText();
2312         }
2313         else if(obedit->type==OB_LATTICE) {
2314 //              load_editLatt();
2315 //              if(freedata) free_editLatt();
2316         }
2317         else if(obedit->type==OB_MBALL) {
2318 //              extern ListBase editelems;
2319 //              load_editMball();
2320 //              if(freedata) BLI_freelistN(&editelems);
2321         }
2322         
2323         ob= obedit;
2324         
2325         /* for example; displist make is different in editmode */
2326         if(freedata) obedit= NULL;
2327         scene->obedit= obedit; // XXX for context
2328         
2329         /* also flush ob recalc, doesn't take much overhead, but used for particles */
2330         DAG_object_flush_update(scene, ob, OB_RECALC_OB|OB_RECALC_DATA);
2331         
2332         if(obedit==NULL) // XXX && (flag & EM_FREEUNDO)) 
2333                 ED_undo_push(C, "Editmode");
2334         
2335         if(flag & EM_WAITCURSOR) waitcursor(0);
2336         
2337         WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_OBJECT, ob);
2338
2339 }
2340
2341
2342 void ED_object_enter_editmode(bContext *C, int flag)
2343 {
2344         Scene *scene= CTX_data_scene(C);
2345         Base *base= CTX_data_active_base(C);
2346         Object *ob= base->object;
2347         ScrArea *sa= CTX_wm_area(C);
2348         View3D *v3d= NULL;
2349         int ok= 0;
2350         
2351         if(scene->id.lib) return;
2352         if(base==NULL) return;
2353         
2354         if(sa->spacetype==SPACE_VIEW3D)
2355                 v3d= sa->spacedata.first;
2356         
2357         if((v3d==NULL || (base->lay & v3d->lay))==0) return;
2358         
2359         if(ob->data==NULL) return;
2360         
2361         if (object_data_is_libdata(ob)) {
2362                 error_libdata();
2363                 return;
2364         }
2365         
2366         if(flag & EM_WAITCURSOR) waitcursor(1);
2367         
2368         if(ob->type==OB_MESH) {
2369                 Mesh *me= ob->data;
2370                 
2371                 if(me->pv) mesh_pmv_off(ob, me);
2372                 ok= 1;
2373                 scene->obedit= ob;      // context sees this
2374                 
2375                 make_editMesh(scene, ob);
2376
2377                 WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_EDITMODE_MESH, ob);
2378         }
2379         else if (ob->type==OB_ARMATURE){
2380                 bArmature *arm= base->object->data;
2381                 if (!arm) return;
2382                 /*
2383                  * The function object_data_is_libdata make a problem here, the
2384                  * check for ob->proxy return 0 and let blender enter to edit mode
2385                  * this causa a crash when you try leave the edit mode.
2386                  * The problem is that i can't remove the ob->proxy check from
2387                  * object_data_is_libdata that prevent the bugfix #6614, so
2388                  * i add this little hack here.
2389                  */
2390                 if(arm->id.lib) {
2391                         error_libdata();
2392                         return;
2393                 }
2394                 ok=1;
2395                 scene->obedit= ob;
2396                 ED_armature_to_edit(ob);
2397                 /* to ensure all goes in restposition and without striding */
2398                 DAG_object_flush_update(scene, ob, OB_RECALC);
2399
2400                 WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_EDITMODE_ARMATURE, ob);
2401         }
2402         else if(ob->type==OB_FONT) {
2403                 scene->obedit= ob; // XXX for context
2404 //              ok= 1;
2405 // XXX          make_editText();
2406         }
2407         else if(ob->type==OB_MBALL) {
2408                 scene->obedit= ob; // XXX for context
2409 //              ok= 1;
2410 // XXX          make_editMball();
2411         }
2412         else if(ob->type==OB_LATTICE) {
2413                 scene->obedit= ob; // XXX for context
2414 //              ok= 1;
2415 // XXX          make_editLatt();
2416         }
2417         else if(ob->type==OB_SURF || ob->type==OB_CURVE) {
2418 //              ok= 1;
2419                 scene->obedit= ob; // XXX for context
2420 // XXX          make_editNurb();
2421         }
2422         
2423         if(ok) {
2424                 DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
2425         }
2426         else {
2427                 scene->obedit= NULL; // XXX for context
2428                 WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_OBJECT, ob);
2429         }
2430         
2431         if(flag & EM_WAITCURSOR) waitcursor(0);
2432 }
2433
2434 static int toggle_editmode_exec(bContext *C, wmOperator *op)
2435 {
2436         
2437         if(!CTX_data_edit_object(C))
2438                 ED_object_enter_editmode(C, EM_WAITCURSOR);
2439         else
2440                 ED_object_exit_editmode(C, EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR);
2441         
2442         return OPERATOR_FINISHED;
2443 }
2444
2445 void OBJECT_OT_toggle_editmode(wmOperatorType *ot)
2446 {
2447         
2448         /* identifiers */
2449         ot->name= "Toggle Editmode";
2450         ot->idname= "OBJECT_OT_toggle_editmode";
2451         
2452         /* api callbacks */
2453         ot->exec= toggle_editmode_exec;
2454         
2455         ot->poll= ED_operator_object_active;
2456         ot->flag= OPTYPE_REGISTER;
2457 }
2458
2459 /* *************************** */
2460
2461
2462 void check_editmode(int type)
2463 {
2464         Object *obedit= NULL; // XXX
2465         
2466         if (obedit==NULL || obedit->type==type) return;
2467
2468 // XXX  ED_object_exit_editmode(C, EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR); /* freedata, and undo */
2469 }
2470
2471 /* 0 == do center, 1 == center new, 2 == center cursor */
2472
2473 void docenter(Scene *scene, View3D *v3d, int centermode)
2474 {
2475         Base *base;
2476         Object *ob;
2477         Mesh *me, *tme;
2478         Curve *cu;
2479 /*      BezTriple *bezt;
2480         BPoint *bp; */
2481         Object *obedit= NULL; // XXX
2482         Nurb *nu, *nu1;
2483         EditVert *eve;
2484         float cent[3], centn[3], min[3], max[3], omat[3][3];
2485         int a, total= 0;
2486         
2487         /* keep track of what is changed */
2488         int tot_change=0, tot_lib_error=0, tot_multiuser_arm_error=0;
2489         MVert *mvert;
2490
2491         if(scene->id.lib || v3d==NULL) return;
2492         
2493         cent[0]= cent[1]= cent[2]= 0.0;
2494         
2495         if(obedit) {
2496
2497                 INIT_MINMAX(min, max);
2498         
2499                 if(obedit->type==OB_MESH) {
2500                         Mesh *me= obedit->data;
2501                         
2502                         for(eve= me->edit_mesh->verts.first; eve; eve= eve->next) {
2503                                 if(v3d->around==V3D_CENTROID) {
2504                                         total++;
2505                                         VECADD(cent, cent, eve->co);
2506                                 }
2507                                 else {
2508                                         DO_MINMAX(eve->co, min, max);
2509                                 }
2510                         }
2511                         
2512                         if(v3d->around==V3D_CENTROID) {
2513                                 VecMulf(cent, 1.0f/(float)total);
2514                         }
2515                         else {
2516                                 cent[0]= (min[0]+max[0])/2.0f;
2517                                 cent[1]= (min[1]+max[1])/2.0f;
2518                                 cent[2]= (min[2]+max[2])/2.0f;
2519                         }
2520                         
2521                         for(eve= me->edit_mesh->verts.first; eve; eve= eve->next) {
2522                                 VecSubf(eve->co, eve->co, cent);                        
2523                         }
2524                         
2525 // XXX                  recalc_editnormals();
2526                         tot_change++;
2527                         DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
2528                 }
2529         }
2530         
2531         /* reset flags */
2532         for (base=FIRSTBASE; base; base= base->next) {
2533                 if(TESTBASELIB(v3d, base))
2534                         base->object->flag &= ~OB_DONE;
2535         }
2536         
2537         for (me= G.main->mesh.first; me; me= me->id.next) {
2538                 me->flag &= ~ME_ISDONE;
2539         }
2540         
2541         for(base= FIRSTBASE; base; base= base->next) {
2542                 if(TESTBASELIB(v3d, base)) {
2543                         if((base->object->flag & OB_DONE)==0) {
2544                                 base->object->flag |= OB_DONE;
2545                                 
2546                                 if(base->object->id.lib) {
2547                                         tot_lib_error++;
2548                                 }
2549                                 else if(obedit==0 && (me=get_mesh(base->object)) ) {
2550                                         if (me->id.lib) {
2551                                                 tot_lib_error++;
2552                                         } else {
2553                                                 if(centermode==2) {
2554                                                         VECCOPY(cent, give_cursor(scene, v3d));
2555                                                         Mat4Invert(base->object->imat, base->object->obmat);
2556                                                         Mat4MulVecfl(base->object->imat, cent);
2557                                                 } else {
2558                                                         INIT_MINMAX(min, max);
2559                                                         mvert= me->mvert;
2560                                                         for(a=0; a<me->totvert; a++, mvert++) {
2561                                                                 DO_MINMAX(mvert->co, min, max);
2562                                                         }
2563                                         
2564                                                         cent[0]= (min[0]+max[0])/2.0f;
2565                                                         cent[1]= (min[1]+max[1])/2.0f;
2566                                                         cent[2]= (min[2]+max[2])/2.0f;
2567                                                 }
2568
2569                                                 mvert= me->mvert;
2570                                                 for(a=0; a<me->totvert; a++, mvert++) {
2571                                                         VecSubf(mvert->co, mvert->co, cent);
2572                                                 }
2573                                                 
2574                                                 if (me->key) {
2575                                                         KeyBlock *kb;
2576                                                         for (kb=me->key->block.first; kb; kb=kb->next) {
2577                                                                 float *fp= kb->data;
2578                                                                 
2579                                                                 for (a=0; a<kb->totelem; a++, fp+=3) {
2580                                                                         VecSubf(fp, fp, cent);
2581                                                                 }
2582                                                         }
2583                                                 }
2584                                                 
2585                                                 me->flag |= ME_ISDONE;
2586                                                 
2587                                                 if(centermode) {
2588                                                         Mat3CpyMat4(omat, base->object->obmat);
2589                                                         
2590                                                         VECCOPY(centn, cent);
2591                                                         Mat3MulVecfl(omat, centn);
2592                                                         base->object->loc[0]+= centn[0];
2593                                                         base->object->loc[1]+= centn[1];
2594                                                         base->object->loc[2]+= centn[2];
2595                                                         
2596                                                         where_is_object(scene, base->object);
2597                                                         ignore_parent_tx(scene, base->object);
2598                                                         
2599                                                         /* other users? */
2600                                                         ob= G.main->object.first;
2601                                                         while(ob) {
2602                                                                 if((ob->flag & OB_DONE)==0) {
2603                                                                         tme= get_mesh(ob);
2604                                                                         
2605                                                                         if(tme==me) {
2606                                                                                 
2607                                                                                 ob->flag |= OB_DONE;
2608                                                                                 ob->recalc= OB_RECALC_OB|OB_RECALC_DATA;
2609
2610                                                                                 Mat3CpyMat4(omat, ob->obmat);
2611                                                                                 VECCOPY(centn, cent);
2612                                                                                 Mat3MulVecfl(omat, centn);
2613                                                                                 ob->loc[0]+= centn[0];
2614                                                                                 ob->loc[1]+= centn[1];
2615                                                                                 ob->loc[2]+= centn[2];
2616                                                                                 
2617                                                                                 where_is_object(scene, ob);
2618                                                                                 ignore_parent_tx(scene, ob);
2619                                                                                 
2620                                                                                 if(tme && (tme->flag & ME_ISDONE)==0) {
2621                                                                                         mvert= tme->mvert;
2622                                                                                         for(a=0; a<tme->totvert; a++, mvert++) {
2623                                                                                                 VecSubf(mvert->co, mvert->co, cent);
2624                                                                                         }
2625                                                                                         
2626                                                                                         if (tme->key) {
2627                                                                                                 KeyBlock *kb;
2628                                                                                                 for (kb=tme->key->block.first; kb; kb=kb->next) {
2629                                                                                                         float *fp= kb->data;
2630                                                                                                         
2631                                                                                                         for (a=0; a<kb->totelem; a++, fp+=3) {
2632                                                                                                                 VecSubf(fp, fp, cent);
2633                                                                                                         }
2634                                                                                                 }
2635                                                                                         }
2636                                                                                         
2637                                                                                         tme->flag |= ME_ISDONE;
2638                                                                                 }
2639                                                                         }
2640                                                                 }
2641                                                                 
2642                                                                 ob= ob->id.next;
2643                                                         }
2644                                                 }
2645                                                 tot_change++;
2646                                         }
2647                                 }
2648                                 else if (ELEM(base->object->type, OB_CURVE, OB_SURF)) {
2649                                         
2650                                         /* totally weak code here... (ton) */
2651                                         if(obedit==base->object) {
2652                                                 extern ListBase editNurb;
2653                                                 nu1= editNurb.first;
2654                                                 cu= obedit->data;
2655                                         }
2656                                         else {
2657                                                 cu= base->object->data;
2658                                                 nu1= cu->nurb.first;
2659                                         }
2660                                         
2661                                         if (cu->id.lib) {
2662                                                 tot_lib_error++;
2663                                         } else {
2664                                                 if(centermode==2) {
2665                                                         VECCOPY(cent, give_cursor(scene, v3d));
2666                                                         Mat4Invert(base->object->imat, base->object->obmat);
2667                                                         Mat4MulVecfl(base->object->imat, cent);
2668
2669                                                         /* don't allow Z change if curve is 2D */
2670                                                         if( !( cu->flag & CU_3D ) )
2671                                                                 cent[2] = 0.0;
2672                                                 } 
2673                                                 else {
2674                                                         INIT_MINMAX(min, max);
2675                                                         
2676                                                         nu= nu1;
2677                                                         while(nu) {
2678                                                                 minmaxNurb(nu, min, max);
2679                                                                 nu= nu->next;
2680                                                         }
2681                                                         
2682                                                         cent[0]= (min[0]+max[0])/2.0f;
2683                                                         cent[1]= (min[1]+max[1])/2.0f;
2684                                                         cent[2]= (min[2]+max[2])/2.0f;
2685                                                 }
2686                                                 
2687                                                 nu= nu1;
2688                                                 while(nu) {
2689                                                         if( (nu->type & 7)==1) {
2690                                                                 a= nu->pntsu;
2691                                                                 while (a--) {
2692                                                                         VecSubf(nu->bezt[a].vec[0], nu->bezt[a].vec[0], cent);
2693                                                                         VecSubf(nu->bezt[a].vec[1], nu->bezt[a].vec[1], cent);
2694                                                                         VecSubf(nu->bezt[a].vec[2], nu->bezt[a].vec[2], cent);
2695                                                                 }
2696                                                         }
2697                                                         else {
2698                                                                 a= nu->pntsu*nu->pntsv;
2699                                                                 while (a--)
2700                                                                         VecSubf(nu->bp[a].vec, nu->bp[a].vec, cent);
2701                                                         }
2702                                                         nu= nu->next;
2703                                                 }
2704                                 
2705                                                 if(centermode && obedit==0) {
2706                                                         Mat3CpyMat4(omat, base->object->obmat);
2707                                                         
2708                                                         Mat3MulVecfl(omat, cent);
2709                                                         base->object->loc[0]+= cent[0];
2710                                                         base->object->loc[1]+= cent[1];
2711                                                         base->object->loc[2]+= cent[2];
2712                                                         
2713                                                         where_is_object(scene, base->object);
2714                                                         ignore_parent_tx(scene, base->object);
2715                                                 }
2716                                                 
2717                                                 tot_change++;
2718                                                 if(obedit) {
2719                                                         if (centermode==0) {
2720                                                                 DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
2721                                                         }
2722                                                         break;
2723                                                 }
2724                                         }
2725                                 }
2726                                 else if(base->object->type==OB_FONT) {
2727                                         /* get from bb */
2728                                         
2729                                         cu= base->object->data;
2730                                         
2731                                         if(cu->bb==0) {
2732                                                 /* do nothing*/
2733                                         } else if (cu->id.lib) {
2734                                                 tot_lib_error++;
2735                                         } else {
2736                                                 cu->xof= -0.5f*( cu->bb->vec[4][0] - cu->bb->vec[0][0]);
2737                                                 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 */
2738                                                 
2739                                                 /* not really ok, do this better once! */
2740                                                 cu->xof /= cu->fsize;
2741                                                 cu->yof /= cu->fsize;
2742
2743                                                 allqueue(REDRAWBUTSEDIT, 0);
2744                                                 tot_change++;
2745                                         }
2746                                 }
2747                                 else if(base->object->type==OB_ARMATURE) {
2748                                         bArmature *arm = base->object->data;
2749                                         
2750                                         if (arm->id.lib) {
2751                                                 tot_lib_error++;
2752                                         } else if(arm->id.us>1) {
2753                                                 /*error("Can't apply to a multi user armature");
2754                                                 return;*/
2755                                                 tot_multiuser_arm_error++;
2756                                         } else {
2757                                                 /* Function to recenter armatures in editarmature.c 
2758                                                  * Bone + object locations are handled there.
2759                                                  */
2760 // XXX                                          docenter_armature(base->object, centermode);
2761                                                 tot_change++;
2762                                                 
2763                                                 where_is_object(scene, base->object);
2764                                                 ignore_parent_tx(scene, base->object);
2765                                                 
2766                                                 if(obedit) 
2767                                                         break;
2768                                         }
2769                                 }
2770                                 base->object->recalc= OB_RECALC_OB|OB_RECALC_DATA;
2771                         }
2772                 }
2773         }
2774         if (tot_change) {
2775                 ED_anim_dag_flush_update(C);
2776                 allqueue(REDRAWVIEW3D, 0);
2777                 BIF_undo_push("Do Center");     
2778         }
2779         
2780         /* Warn if any errors occured */
2781         if (tot_lib_error+tot_multiuser_arm_error) {
2782                 char err[512];
2783                 sprintf(err, "Warning %i Object(s) Not Centered, %i Changed:", tot_lib_error+tot_multiuser_arm_error, tot_change);
2784                 
2785                 if (tot_lib_error)
2786                         sprintf(err+strlen(err), "|%i linked library objects", tot_lib_error);
2787                 if (tot_multiuser_arm_error)
2788                         sprintf(err+strlen(err), "|%i multiuser armature object(s)", tot_multiuser_arm_error);
2789                 
2790                 error(err);
2791         }
2792 }
2793
2794 void docenter_new(Scene *scene, View3D *v3d)
2795 {
2796         if(scene->id.lib) return;
2797
2798         if(scene->obedit) { // XXX get from context
2799                 error("Unable to center new in Edit Mode");
2800         }
2801         else {
2802                 docenter(scene, v3d, 1);
2803         }
2804 }
2805
2806 void docenter_cursor(Scene *scene, View3D *v3d)
2807 {
2808         if(scene->id.lib) return;
2809
2810         if(scene->obedit) { // XXX get from context
2811                 error("Unable to center cursor in Edit Mode");
2812         }
2813         else {
2814                 docenter(scene, v3d, 2);
2815         }
2816 }
2817
2818 void movetolayer(Scene *scene, View3D *v3d)
2819 {
2820         Base *base;
2821         unsigned int lay= 0, local;
2822         int islamp= 0;
2823         
2824         if(scene->id.lib) return;
2825
2826         for(base= FIRSTBASE; base; base= base->next) {
2827                 if (TESTBASE(v3d, base)) lay |= base->lay;
2828         }
2829         if(lay==0) return;
2830         lay &= 0xFFFFFF;
2831         
2832         if(lay==0) return;
2833         
2834         if(v3d->localview) {
2835                 /* now we can move out of localview. */
2836                 if (!okee("Move from localview")) return;
2837                 for(base= FIRSTBASE; base; base= base->next) {
2838                         if (TESTBASE(v3d, base)) {
2839                                 lay= base->lay & ~v3d->lay;
2840                                 base->lay= lay;
2841                                 base->object->lay= lay;
2842                                 base->object->flag &= ~SELECT;
2843                                 base->flag &= ~SELECT;
2844                                 if(base->object->type==OB_LAMP) islamp= 1;
2845                         }
2846                 }
2847         } else {
2848 // XXX          if( movetolayer_buts(&lay, NULL)==0 ) return;
2849                 
2850                 /* normal non localview operation */
2851                 for(base= FIRSTBASE; base; base= base->next) {
2852                         if (TESTBASE(v3d, base)) {
2853                                 /* upper byte is used for local view */
2854                                 local= base->lay & 0xFF000000;  
2855                                 base->lay= lay + local;
2856                                 base->object->lay= lay;
2857                                 if(base->object->type==OB_LAMP) islamp= 1;
2858                         }
2859                 }
2860         }
2861         if(islamp) reshadeall_displist(scene);  /* only frees */
2862         
2863         /* warning, active object may be hidden now */
2864         
2865         DAG_scene_sort(scene);
2866         
2867         allqueue(REDRAWBUTSEDIT, 0);
2868         allqueue(REDRAWVIEW3D, 0);
2869         allqueue(REDRAWOOPS, 0);
2870         allqueue(REDRAWINFO, 0);
2871         
2872         BIF_undo_push("Move to layer");
2873 }
2874
2875
2876 #if 0
2877 // XXX should be in view3d?
2878
2879 /* context: ob = lamp */
2880 /* code should be replaced with proper (custom) transform handles for lamp properties */
2881 static void spot_interactive(Object *ob, int mode)
2882 {
2883         Lamp *la= ob->data;
2884         float transfac, dx, dy, ratio, origval;
2885         int keep_running= 1, center2d[2];
2886         short mval[2], mvalo[2];
2887         
2888 //      getmouseco_areawin(mval);
2889 //      getmouseco_areawin(mvalo);
2890         
2891         project_int(ob->obmat[3], center2d);
2892         if( center2d[0] > 100000 ) {            /* behind camera */
2893 //              center2d[0]= curarea->winx/2;
2894 //              center2d[1]= curarea->winy/2;
2895         }
2896
2897 //      helpline(mval, center2d);
2898         
2899         /* ratio is like scaling */
2900         dx = (float)(center2d[0] - mval[0]);
2901         dy = (float)(center2d[1] - mval[1]);
2902         transfac = (float)sqrt( dx*dx + dy*dy);
2903         if(transfac==0.0f) transfac= 1.0f;
2904         
2905         if(mode==1)     
2906                 origval= la->spotsize;
2907         else if(mode==2)        
2908                 origval= la->dist;
2909         else if(mode==3)        
2910                 origval= la->clipsta;
2911         else    
2912                 origval= la->clipend;
2913         
2914         while (keep_running>0) {
2915                 
2916 //              getmouseco_areawin(mval);
2917                 
2918                 /* essential for idling subloop */
2919                 if(mval[0]==mvalo[0] && mval[1]==mvalo[1]) {
2920                         PIL_sleep_ms(2);
2921                 }
2922                 else {
2923                         char str[32];
2924                         
2925                         dx = (float)(center2d[0] - mval[0]);
2926                         dy = (float)(center2d[1] - mval[1]);
2927                         ratio = (float)(sqrt( dx*dx + dy*dy))/transfac;
2928                         
2929                         /* do the trick */
2930