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