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