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