Bug fix #1952
[blender.git] / source / blender / src / editobject.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL 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. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32
33 /** 
34  * Theorie: (matrices) A x B x C == A x ( B x C x Binv) x B
35  * ofwel: OB x PAR x EDIT = OB x (PAR x EDIT x PARinv) x PAR
36  */
37
38 #include <stdlib.h>
39 #include <string.h>
40 #include <math.h>
41
42 #ifdef HAVE_CONFIG_H
43 #include <config.h>
44 #endif
45
46 #ifndef WIN32
47 #include <unistd.h>
48 #else
49 #include <io.h>
50 #include "BLI_winstuff.h"
51 #endif
52 #include "MEM_guardedalloc.h"
53 #include "PIL_time.h"
54
55 #include "BMF_Api.h"
56
57
58 #include "IMB_imbuf_types.h"
59
60 #include "DNA_action_types.h"
61 #include "DNA_armature_types.h"
62 #include "DNA_camera_types.h"
63 #include "DNA_curve_types.h"
64 #include "DNA_effect_types.h"
65 #include "DNA_ika_types.h"
66 #include "DNA_image_types.h"
67 #include "DNA_ipo_types.h"
68 #include "DNA_key_types.h"
69 #include "DNA_lamp_types.h"
70 #include "DNA_lattice_types.h"
71 #include "DNA_mesh_types.h"
72 #include "DNA_meshdata_types.h"
73 #include "DNA_meta_types.h"
74 #include "DNA_object_types.h"
75 #include "DNA_scene_types.h"
76 #include "DNA_screen_types.h"
77 #include "DNA_texture_types.h"
78 #include "DNA_view3d_types.h"
79 #include "DNA_world_types.h"
80 #include "DNA_userdef_types.h"
81 #include "DNA_property_types.h"
82 #include "DNA_vfont_types.h"
83 #include "DNA_constraint_types.h"
84
85 #include "BLI_blenlib.h"
86 #include "BLI_arithb.h"
87 #include "BLI_editVert.h"
88 #include "BLI_ghash.h"
89
90 #include "BKE_constraint.h"
91 #include "BKE_action.h"
92 #include "BKE_armature.h"
93 #include "BKE_utildefines.h"
94 #include "BKE_anim.h"
95 #include "BKE_blender.h"
96 #include "BKE_booleanops.h"
97 #include "BKE_curve.h"
98 #include "BKE_displist.h"
99 #include "BKE_effect.h"
100 #include "BKE_font.h"
101 #include "BKE_global.h"
102 #include "BKE_ika.h"
103 #include "BKE_ipo.h"
104 #include "BKE_key.h"
105 #include "BKE_lattice.h"
106 #include "BKE_library.h"
107 #include "BKE_main.h"
108 #include "BKE_material.h"
109 #include "BKE_mball.h"
110 #include "BKE_mesh.h"
111 #include "BKE_nla.h"
112 #include "BKE_object.h"
113 #include "BKE_property.h"
114 #include "BKE_sca.h"
115 #include "BKE_scene.h"
116 #include "BKE_softbody.h"
117 #include "BKE_subsurf.h"
118 #include "BKE_texture.h"
119 #include "BKE_utildefines.h"
120
121 #include "BIF_gl.h"
122 #include "BIF_graphics.h"
123 #include "BIF_interface.h"
124 #include "BIF_mywindow.h"
125 #include "BIF_toolbox.h"
126 #include "BIF_screen.h"
127 #include "BIF_space.h"
128 #include "BIF_toets.h"
129 #include "BIF_butspace.h"
130 #include "BIF_editconstraint.h"
131 #include "BIF_editdeform.h"
132 #include "BIF_editfont.h"
133 #include "BIF_editika.h"
134 #include "BIF_editlattice.h"
135 #include "BIF_editmesh.h"
136 #include "BIF_editoops.h"
137 #include "BIF_editview.h"
138 #include "BIF_editarmature.h"
139 #include "BIF_resources.h"
140
141 #include "BSE_edit.h"
142 #include "BSE_editaction.h"
143 #include "BSE_editipo.h"
144 #include "BSE_filesel.h"        /* For activate_databrowse() */
145 #include "BSE_view.h"
146 #include "BSE_trans_types.h"
147 #include "BSE_editipo_types.h"
148
149 #include "BDR_vpaint.h"
150 #include "BDR_editmball.h"
151 #include "BDR_editobject.h"
152 #include "BDR_drawobject.h"
153 #include "BDR_editcurve.h"
154 #include "BDR_unwrapper.h"
155
156 #include "render.h"
157 #include <time.h>
158 #include "mydevice.h"
159 #include "nla.h"
160
161 #include "blendef.h"
162
163 #include "BIF_poseobject.h"
164
165 /*  extern Lattice *copy_lattice(Lattice *lt); */
166 extern ListBase editNurb;
167 extern ListBase editelems;
168
169 TransOb *transmain= 0;
170 TransVert *transvmain= 0;
171 int tottrans=0, transmode=0;    /* 1: texspace */
172
173 float prop_size= 1.0;
174 int prop_mode= 0;
175 float prop_cent[3];
176
177 /* used in editipo, editcurve and here */
178 #define BEZSELECTED(bezt)   (((bezt)->f1 & 1) || ((bezt)->f2 & 1) || ((bezt)->f3 & 1))
179
180 #define TRANS_TEX       1
181
182 #define KEYFLAG_ROT             0x00000001
183 #define KEYFLAG_LOC             0x00000002
184 #define KEYFLAG_SIZE    0x00000004
185
186 float centre[3], centroid[3];
187
188 void mirrormenu(void);
189
190 void add_object_draw(int type)  /* for toolbox or menus, only non-editmode stuff */
191 {
192         Object *ob;
193         
194         G.f &= ~(G_VERTEXPAINT+G_FACESELECT+G_TEXTUREPAINT+G_WEIGHTPAINT);
195         setcursor_space(SPACE_VIEW3D, CURSOR_STD);
196
197         if ELEM3(curarea->spacetype, SPACE_VIEW3D, SPACE_BUTS, SPACE_INFO) {
198                 if (G.obedit) exit_editmode(2); // freedata, and undo
199                 ob= add_object(type);
200                 base_init_from_view3d(BASACT, G.vd);
201                 
202                 if(type==OB_EMPTY) BIF_undo_push("Add Empty");
203                 else if(type==OB_LAMP) {
204                         BIF_undo_push("Add Lamp");
205                         if(G.vd->drawtype == OB_SHADED) reshadeall_displist();
206                 }
207                 else if(type==OB_LATTICE) BIF_undo_push("Add Lattice");
208                 else BIF_undo_push("Add Camera");
209                 
210                 allqueue(REDRAWVIEW3D, 0);
211         }
212
213         redraw_test_buttons(OBACT);
214
215         allqueue(REDRAWALL, 0);
216
217         deselect_all_area_oops();
218         set_select_flag_oops();
219         allqueue(REDRAWINFO, 1);        /* 1, because header->win==0! */
220 }
221
222 void add_objectLamp(short type)
223 {
224         Lamp *la;
225
226         /* this function also comes from an info window */
227         if ELEM(curarea->spacetype, SPACE_VIEW3D, SPACE_INFO); else return;
228         
229         if(G.obedit==0) {
230                 add_object_draw(OB_LAMP);
231                 base_init_from_view3d(BASACT, G.vd);
232         }
233         
234         la = BASACT->object->data;
235         la->type = type;        
236
237         allqueue(REDRAWALL, 0);
238 }
239
240 void free_and_unlink_base(Base *base)
241 {
242         if (base==BASACT)
243                 BASACT= NULL;
244         
245         BLI_remlink(&G.scene->base, base);
246         free_libblock_us(&G.main->object, base->object);
247         MEM_freeN(base);
248 }
249
250 void delete_obj(int ok)
251 {
252         Base *base;
253         int islamp= 0;
254         
255         if(G.obpose) return;
256         if(G.obedit) return;
257         if(G.scene->id.lib) return;
258         
259         base= FIRSTBASE;
260         while(base) {
261                 Base *nbase= base->next;
262
263                 if TESTBASE(base) {
264                         if(ok==0 &&  (ok=okee("Erase selected"))==0) return;
265                         if(base->object->type==OB_LAMP) islamp= 1;
266                         
267                         free_and_unlink_base(base);
268                 }
269                 
270                 base= nbase;
271         }
272         countall();
273
274         G.f &= ~(G_VERTEXPAINT+G_FACESELECT+G_TEXTUREPAINT+G_WEIGHTPAINT);
275         setcursor_space(SPACE_VIEW3D, CURSOR_STD);
276         
277         if(islamp && G.vd->drawtype==OB_SHADED) reshadeall_displist();
278
279         test_scene_constraints();
280         allqueue(REDRAWVIEW3D, 0);
281         redraw_test_buttons(OBACT);
282         allqueue (REDRAWACTION, 0);
283         allqueue(REDRAWIPO, 0);
284         allqueue(REDRAWDATASELECT, 0);
285         allqueue(REDRAWOOPS, 0);
286         allqueue(REDRAWACTION, 0);
287         allqueue(REDRAWNLA, 0);
288         
289         BIF_undo_push("Delete object(s)");
290 }
291
292 int return_editmesh_indexar(int **indexar, float *cent)
293 {
294         EditMesh *em = G.editMesh;
295         EditVert *eve;
296         int *index, nr, totvert=0;
297         
298         for(eve= em->verts.first; eve; eve= eve->next) {
299                 if(eve->f & SELECT) totvert++;
300         }
301         if(totvert==0) return 0;
302         
303         *indexar= index= MEM_mallocN(4*totvert, "hook indexar");
304         nr= 0;
305         cent[0]= cent[1]= cent[2]= 0.0;
306         
307         for(eve= em->verts.first; eve; eve= eve->next) {
308                 if(eve->f & SELECT) {
309                         *index= nr; index++;
310                         VecAddf(cent, cent, eve->co);
311                 }
312                 nr++;
313         }
314         
315         VecMulf(cent, 1.0/(float)totvert);
316         
317         return totvert;
318 }
319
320 static void select_editmesh_hook(ObHook *hook)
321 {
322         EditMesh *em = G.editMesh;
323         EditVert *eve;
324         int index=0, nr=0;
325         
326         for(eve= em->verts.first; eve; eve= eve->next, nr++) {
327                 if(nr==hook->indexar[index]) {
328                         eve->f |= SELECT;
329                         if(index < hook->totindex-1) index++;
330                 }
331         }
332 }
333
334 int return_editlattice_indexar(int **indexar, float *cent)
335 {
336         BPoint *bp;
337         int *index, nr, totvert=0, a;
338         
339         // count
340         a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
341         bp= editLatt->def;
342         while(a--) {
343                 if(bp->f1 & SELECT) {
344                         if(bp->hide==0) totvert++;
345                 }
346                 bp++;
347         }
348
349         if(totvert==0) return 0;
350         
351         *indexar= index= MEM_mallocN(4*totvert, "hook indexar");
352         nr= 0;
353         cent[0]= cent[1]= cent[2]= 0.0;
354         
355         a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
356         bp= editLatt->def;
357         while(a--) {
358                 if(bp->f1 & SELECT) {
359                         if(bp->hide==0) {
360                                 *index= nr; index++;
361                                 VecAddf(cent, cent, bp->vec);
362                         }
363                 }
364                 bp++;
365                 nr++;
366         }
367         
368         VecMulf(cent, 1.0/(float)totvert);
369         
370         return totvert;
371 }
372
373 static void select_editlattice_hook(ObHook *hook)
374 {
375         BPoint *bp;
376         int index=0, nr=0, a;
377         
378         // count
379         a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
380         bp= editLatt->def;
381         while(a--) {
382                 if(hook->indexar[index]==nr) {
383                         bp->f1 |= SELECT;
384                         if(index < hook->totindex-1) index++;
385                 }
386                 nr++;
387                 bp++;
388         }
389 }
390
391 int return_editcurve_indexar(int **indexar, float *cent)
392 {
393         extern ListBase editNurb;
394         Nurb *nu;
395         BPoint *bp;
396         BezTriple *bezt;
397         int *index, a, nr, totvert=0;
398         
399         for(nu= editNurb.first; nu; nu= nu->next) {
400                 if((nu->type & 7)==CU_BEZIER) {
401                         bezt= nu->bezt;
402                         a= nu->pntsu;
403                         while(a--) {
404                                 if(bezt->f1 & SELECT) totvert++;
405                                 if(bezt->f2 & SELECT) totvert++;
406                                 if(bezt->f3 & SELECT) totvert++;
407                                 bezt++;
408                         }
409                 }
410                 else {
411                         bp= nu->bp;
412                         a= nu->pntsu*nu->pntsv;
413                         while(a--) {
414                                 if(bp->f1 & SELECT) totvert++;
415                                 bp++;
416                         }
417                 }
418         }
419         if(totvert==0) return 0;
420         
421         *indexar= index= MEM_mallocN(4*totvert, "hook indexar");
422         nr= 0;
423         cent[0]= cent[1]= cent[2]= 0.0;
424         
425         for(nu= editNurb.first; nu; nu= nu->next) {
426                 if((nu->type & 7)==CU_BEZIER) {
427                         bezt= nu->bezt;
428                         a= nu->pntsu;
429                         while(a--) {
430                                 if(bezt->f1 & SELECT) {
431                                         *index= nr; index++;
432                                         VecAddf(cent, cent, bezt->vec[0]);
433                                 }
434                                 nr++;
435                                 if(bezt->f2 & SELECT) {
436                                         *index= nr; index++;
437                                         VecAddf(cent, cent, bezt->vec[1]);
438                                 }
439                                 nr++;
440                                 if(bezt->f3 & SELECT) {
441                                         *index= nr; index++;
442                                         VecAddf(cent, cent, bezt->vec[2]);
443                                 }
444                                 nr++;
445                                 bezt++;
446                         }
447                 }
448                 else {
449                         bp= nu->bp;
450                         a= nu->pntsu*nu->pntsv;
451                         while(a--) {
452                                 if(bp->f1 & SELECT) {
453                                         *index= nr; index++;
454                                         VecAddf(cent, cent, bp->vec);
455                                 }
456                                 nr++;
457                                 bp++;
458                         }
459                 }
460         }
461         
462         VecMulf(cent, 1.0/(float)totvert);
463         
464         return totvert;
465 }
466
467 static void select_editcurve_hook(ObHook *hook)
468 {
469         extern ListBase editNurb;
470         Nurb *nu;
471         BPoint *bp;
472         BezTriple *bezt;
473         int index=0, a, nr=0;
474         
475         for(nu= editNurb.first; nu; nu= nu->next) {
476                 if((nu->type & 7)==CU_BEZIER) {
477                         bezt= nu->bezt;
478                         a= nu->pntsu;
479                         while(a--) {
480                                 if(nr == hook->indexar[index]) {
481                                         bezt->f1 |= SELECT;
482                                         if(index<hook->totindex-1) index++;
483                                 }
484                                 nr++;
485                                 if(nr == hook->indexar[index]) {
486                                         bezt->f2 |= SELECT;
487                                         if(index<hook->totindex-1) index++;
488                                 }
489                                 nr++;
490                                 if(nr == hook->indexar[index]) {
491                                         bezt->f3 |= SELECT;
492                                         if(index<hook->totindex-1) index++;
493                                 }
494                                 nr++;
495
496                                 bezt++;
497                         }
498                 }
499                 else {
500                         bp= nu->bp;
501                         a= nu->pntsu*nu->pntsv;
502                         while(a--) {
503                                 if(nr == hook->indexar[index]) {
504                                         bp->f1 |= SELECT;
505                                         if(index<hook->totindex-1) index++;
506                                 }
507                                 nr++;
508                                 bp++;
509                         }
510                 }
511         }
512 }
513
514 void add_hook(void)
515 {
516         Object *ob=NULL;
517         ObHook *hook=NULL;
518         float cent[3];
519         int tot=0, *indexar, mode;
520
521         if(G.obedit==NULL) return;
522         
523         if(G.obedit->hooks.first)
524                 mode= pupmenu("Hooks %t|Add Hook, To New Empty %x1|Add Hook, To Selected Object %x2|Remove... %x3|Reassign... %x4|Select... %x5|Clear Offset...%x6");
525         else
526                 mode= pupmenu("Hooks %t|Add, New Empty %x1|Add, To Selected Object %x2");
527
528         if(mode<1) return;
529         
530         /* preconditions */
531
532         if(mode==2) { // selected object
533                 Base *base= FIRSTBASE;
534                 while(base) {
535                         if TESTBASELIB(base) {
536                                 if(base!=BASACT) {
537                                         ob= base->object;
538                                         break;
539                                 }
540                         }
541                         base= base->next;
542                 }
543                 if(ob==NULL) {
544                         error("Requires selected Object");
545                         return;
546                 }
547         }
548         else if(mode!=1) {
549                 int maxlen=0, a, nr;
550                 char *cp;
551                 
552                 // make pupmenu with hooks
553                 for(hook= G.obedit->hooks.first; hook; hook= hook->next) maxlen+=32;
554                 
555                 if(maxlen==0) {
556                         error("Object has no hooks yet");
557                         return;
558                 }
559                 
560                 cp= MEM_callocN(maxlen+32, "temp string");
561                 if(mode==3) strcpy(cp, "Remove %t|");
562                 else if(mode==4) strcpy(cp, "Reassign %t|");
563                 else if(mode==5) strcpy(cp, "Select %t|");
564                 else if(mode==6) strcpy(cp, "Clear Offset %t|");
565                 
566                 for(hook= G.obedit->hooks.first; hook; hook= hook->next) {
567                         strcat(cp, hook->name);
568                         strcat(cp, " |");
569                 }
570         
571                 nr= pupmenu(cp);
572                 MEM_freeN(cp);
573                 
574                 if(nr<1) return;
575                 
576                 a= 1;
577                 for(hook= G.obedit->hooks.first; hook; hook= hook->next, a++) {
578                         if(a==nr) break;
579                 }
580                 ob= hook->parent;
581         }
582
583         /* do it, new hooks or reassign */
584         if(mode==1 || mode==2 || mode==4) {
585         
586                 switch(G.obedit->type) {
587                 case OB_MESH:
588                         tot= return_editmesh_indexar(&indexar, cent);
589                         break;
590                 case OB_CURVE:
591                 case OB_SURF:
592                         tot= return_editcurve_indexar(&indexar, cent);
593                         break;
594                 case OB_LATTICE:
595                         tot= return_editlattice_indexar(&indexar, cent);
596                         break;
597                 }
598                 
599                 if(tot==0) {
600                         error("Requires selected vertices");
601                 }
602                 else {
603                         
604                         if(mode==1) {
605                                 Base *base= BASACT;
606
607                                 ob= add_object(OB_EMPTY);
608                                 /* transform cent to global coords for loc */
609                                 VecMat4MulVecfl(ob->loc, G.obedit->obmat, cent);
610                                 
611                                 /* restore, add_object sets active */
612                                 BASACT= base;
613                         }
614                         /* if mode is 2 or 4, ob has been set */
615                                                                         
616                         /* new hook */
617                         if(mode==1 || mode==2) {
618                                 hook= MEM_callocN(sizeof(ObHook), "new hook");
619                                 BLI_addtail(&G.obedit->hooks, hook);
620                                 strncpy(hook->name, ob->id.name+2, 30);
621                                 hook->force= 1.0;
622                         }
623                         else MEM_freeN(hook->indexar); // reassign, hook was set
624
625                         hook->parent= ob;
626                         hook->indexar= indexar;
627                         VECCOPY(hook->cent, cent);
628                         hook->totindex= tot;
629                         
630                         if(mode==1 || mode==2) {
631                                 /* matrix calculus */
632                                 /* vert x (obmat x hook->imat) x hook->obmat x ob->imat */
633                                 /*        (parentinv         )                          */
634                                 
635                                 where_is_object(ob);
636                 
637                                 Mat4Invert(ob->imat, ob->obmat);
638                                 /* apparently this call goes from right to left... */
639                                 Mat4MulSerie(hook->parentinv, ob->imat, G.obedit->obmat, NULL, 
640                                                         NULL, NULL, NULL, NULL, NULL);
641                         }
642                 }
643         }
644         else if(mode==3) { // remove
645                 BLI_remlink(&G.obedit->hooks, hook);
646                 MEM_freeN(hook->indexar);
647                 MEM_freeN(hook);
648         }
649         else if(mode==5) { // select
650                 if(G.obedit->type==OB_MESH) select_editmesh_hook(hook);
651                 else if(G.obedit->type==OB_LATTICE) select_editlattice_hook(hook);
652                 else if(G.obedit->type==OB_CURVE) select_editcurve_hook(hook);
653                 else if(G.obedit->type==OB_SURF) select_editcurve_hook(hook);
654         }
655         else if(mode==6) { // clear offset
656                 where_is_object(ob);    // ob is hook->parent
657
658                 Mat4Invert(ob->imat, ob->obmat);
659                 /* this call goes from right to left... */
660                 Mat4MulSerie(hook->parentinv, ob->imat, G.obedit->obmat, NULL, 
661                                         NULL, NULL, NULL, NULL, NULL);
662         }
663
664         allqueue(REDRAWVIEW3D, 0);
665         allqueue(REDRAWBUTSOBJECT, 0);
666         BIF_undo_push("Add hook");
667 }
668
669 void make_track(void)
670 {
671         Base *base;
672         short mode=0;
673         
674         if(G.scene->id.lib) return;
675         if(G.obedit) {
676                 return;
677         }
678         if(BASACT==0) return;
679
680         mode= pupmenu("Make Track %t|TrackTo Constraint %x1|LockTrack Constraint %x2|Old Track %x3");
681         if (mode == 0){
682                 return;
683         }
684         else if (mode == 1){
685                 bConstraint *con;
686                 bTrackToConstraint *data;
687
688                 base= FIRSTBASE;
689                 while(base) {
690                         if TESTBASELIB(base) {
691                                 if(base!=BASACT) {
692                                         con = add_new_constraint(CONSTRAINT_TYPE_TRACKTO);
693                                         strcpy (con->name, "AutoTrack");
694
695                                         data = con->data;
696                                         data->tar = BASACT->object;
697
698                                         /* Lamp and Camera track differently by default */
699                                         if (base->object->type == OB_LAMP || base->object->type == OB_CAMERA) {
700                                                 data->reserved1 = TRACK_nZ;
701                                                 data->reserved2 = UP_Y;
702                                         }
703
704                                         add_constraint_to_object(con, base->object);
705                                 }
706                         }
707                         base= base->next;
708                 }
709
710                 test_scene_constraints();
711                 allqueue(REDRAWVIEW3D, 0);
712                 sort_baselist(G.scene);
713         }
714         else if (mode == 2){
715                 bConstraint *con;
716                 bLockTrackConstraint *data;
717
718                 base= FIRSTBASE;
719                 while(base) {
720                         if TESTBASELIB(base) {
721                                 if(base!=BASACT) {
722                                         con = add_new_constraint(CONSTRAINT_TYPE_LOCKTRACK);
723                                         strcpy (con->name, "AutoTrack");
724
725                                         data = con->data;
726                                         data->tar = BASACT->object;
727
728                                         /* Lamp and Camera track differently by default */
729                                         if (base->object->type == OB_LAMP || base->object->type == OB_CAMERA) {
730                                                 data->trackflag = TRACK_nZ;
731                                                 data->lockflag = LOCK_Y;
732                                         }
733
734                                         add_constraint_to_object(con, base->object);
735                                 }
736                         }
737                         base= base->next;
738                 }
739
740                 test_scene_constraints();
741                 allqueue(REDRAWVIEW3D, 0);
742                 sort_baselist(G.scene);
743         }
744         else if (mode == 3){
745                 base= FIRSTBASE;
746                 while(base) {
747                         if TESTBASELIB(base) {
748                                 if(base!=BASACT) {
749
750                                         base->object->track= BASACT->object;
751                                 }
752                         }
753                         base= base->next;
754                 }
755
756                 test_scene_constraints();
757                 allqueue(REDRAWVIEW3D, 0);
758                 allqueue(REDRAWOOPS, 0);
759                 sort_baselist(G.scene);
760         }
761         BIF_undo_push("make Track");
762 }
763
764 void apply_obmat(Object *ob)
765 {
766         float mat[3][3], imat[3][3], tmat[3][3];
767         
768         /* from obmat to loc rot size */
769         
770         if(ob==0) return;
771         Mat3CpyMat4(mat, ob->obmat);
772         
773         VECCOPY(ob->loc, ob->obmat[3]);
774         
775         if(ob->transflag & OB_QUAT) {
776                 Mat3ToQuat(mat, ob->quat);
777                 QuatToMat3(ob->quat, tmat);
778         }
779         else {
780                 Mat3ToEul(mat, ob->rot);
781                 EulToMat3(ob->rot, tmat);
782         }
783         Mat3Inv(imat, tmat);
784         
785         Mat3MulMat3(tmat, imat, mat);
786         
787         ob->size[0]= tmat[0][0];
788         ob->size[1]= tmat[1][1];
789         ob->size[2]= tmat[2][2];
790
791 }
792
793 void clear_parent(void)
794 {
795         Object *par;
796         Base *base;
797         int mode;
798         
799         if(G.obedit) return;
800         if(G.scene->id.lib) return;
801
802         mode= pupmenu("OK? %t|Clear Parent %x1|Clear and Keep Transformation (Clear Track) %x2|Clear Parent Inverse %x3");
803         
804         if(mode<1) return;
805
806         base= FIRSTBASE;
807         while(base) {
808                 if TESTBASELIB(base) {
809                         par= 0;
810                         if(mode==1 || mode==2) {
811                                 if(base->object->type==OB_IKA) {
812                                         Ika *ika= base->object->data;
813                                         ika->parent= 0;
814                                 }
815                                 par= base->object->parent;
816                                 base->object->parent= 0;
817                         
818                                 if(mode==2) {
819                                         base->object->track= 0;
820                                         apply_obmat(base->object);
821                                 }
822                         }
823                         else if(mode==3) {
824                                 Mat4One(base->object->parentinv);
825                         }
826                         
827                         if(par) {
828                                 makeDispList(base->object);     // just always..., checks are not available well (ton)
829                         }
830                 }
831                 base= base->next;
832         }
833
834         test_scene_constraints();
835         allqueue(REDRAWVIEW3D, 0);
836         allqueue(REDRAWOOPS, 0);
837         
838         BIF_undo_push("Clear Parent");  
839 }
840
841 void clear_track(void)
842 {
843         Base *base;
844         int mode;
845         
846         if(G.obedit) return;
847         if(G.scene->id.lib) return;
848
849         mode= pupmenu("OK? %t|Clear Track %x1| Clear Track and Keep Transform %x2");
850
851         if(mode<1) return;
852
853         base= FIRSTBASE;
854         while(base) {
855                 if TESTBASELIB(base) {
856                         base->object->track= 0;
857
858                         if(mode==2) {
859                                 apply_obmat(base->object);
860                         }                       
861                 }
862                 base= base->next;
863         }
864         test_scene_constraints();
865         allqueue(REDRAWVIEW3D, 0);
866         allqueue(REDRAWOOPS, 0);
867         
868         BIF_undo_push("Clear Track");   
869 }
870
871 void clear_object(char mode)
872 {
873         Base *base;
874         Object *ob;
875         float *v1, *v3, mat[3][3];
876         char *str=NULL;
877         
878         if(G.obedit) return;
879         if(G.scene->id.lib) return;
880         
881         if(mode=='r') str= "Clear rotation";
882         else if(mode=='g') str= "Clear location";
883         else if(mode=='s') str= "Clear size";
884         else if(mode=='o') str= "Clear origin";
885         else return;
886         
887         if(okee(str)==0) return;
888         
889         if (G.obpose){
890
891                 switch (G.obpose->type){
892                 case OB_ARMATURE:
893                         clear_armature (G.obpose, mode);
894 #if 1
895                         clear_pose_constraint_status(G.obpose);
896                         make_displists_by_armature (G.obpose);
897 #endif
898                         break;
899                 }
900
901                 allqueue(REDRAWVIEW3D, 0);
902                 BIF_undo_push(str);
903                 return;
904         }
905
906         base= FIRSTBASE;
907         while(base) {
908                 if TESTBASELIB(base) {
909                         ob= base->object;
910                         
911                         if(mode=='r') {
912                                 memset(ob->rot, 0, 3*sizeof(float));
913                                 memset(ob->drot, 0, 3*sizeof(float));
914                                 QuatOne(ob->quat);
915                                 QuatOne(ob->dquat);
916                         }
917                         else if(mode=='g') {
918                                 memset(ob->loc, 0, 3*sizeof(float));
919                                 memset(ob->dloc, 0, 3*sizeof(float));
920                         }
921                         else if(mode=='s') {
922                                 memset(ob->dsize, 0, 3*sizeof(float));
923                                 ob->size[0]= 1.0;
924                                 ob->size[1]= 1.0;
925                                 ob->size[2]= 1.0;
926                         }
927                         else if(mode=='o') {
928                                 if(ob->parent) {
929                                         v1= ob->loc;
930                                         v3= ob->parentinv[3];
931                                         
932                                         Mat3CpyMat4(mat, ob->parentinv);
933                                         VECCOPY(v3, v1);
934                                         v3[0]= -v3[0];
935                                         v3[1]= -v3[1];
936                                         v3[2]= -v3[2];
937                                         Mat3MulVecfl(mat, v3);
938                                 }
939                         }
940                         
941                         if(ob->parent && ob->partype==PARSKEL)
942                                 freedisplist(&ob->disp);
943                         else if(ob->hooks.first)
944                                 freedisplist(&ob->disp);
945                 }
946                 base= base->next;
947         }
948         
949         allqueue(REDRAWVIEW3D, 0);
950         BIF_undo_push(str);
951 }
952
953 void reset_slowparents(void)
954 {
955         /* back to original locations */
956         Base *base;
957         
958         base= FIRSTBASE;
959         while(base) {
960                 if(base->object->parent) {
961                         if(base->object->partype & PARSLOW) {
962                                 base->object->partype -= PARSLOW;
963                                 where_is_object(base->object);
964                                 base->object->partype |= PARSLOW;
965                         }
966                 }
967                 base= base->next;
968         }
969 }
970
971 void set_slowparent(void)
972 {
973         Base *base;
974
975         if( okee("Set slow parent")==0 ) return;
976
977         base= FIRSTBASE;
978         while(base) {
979                 if TESTBASELIB(base) {
980                         if(base->object->parent) base->object->partype |= PARSLOW;
981                 }
982                 base= base->next;
983         }
984         BIF_undo_push("Slow parent");
985 }
986
987 void make_vertex_parent(void)
988 {
989         EditMesh *em = G.editMesh;
990         EditVert *eve;
991         Base *base;
992         Nurb *nu;
993         BezTriple *bezt;
994         BPoint *bp;
995         Object *par, *ob;
996         int a, v1=0, v2=0, v3=0, nr=1;
997         
998         /* we need 1 to 3 selected vertices */
999         
1000         if(G.obedit->type==OB_MESH) {
1001                 eve= em->verts.first;
1002                 while(eve) {
1003                         if(eve->f & 1) {
1004                                 if(v1==0) v1= nr;
1005                                 else if(v2==0) v2= nr;
1006                                 else if(v3==0) v3= nr;
1007                                 else break;
1008                         }
1009                         nr++;
1010                         eve= eve->next;
1011                 }
1012         }
1013         else if ELEM(G.obedit->type, OB_SURF, OB_CURVE) {
1014                 nu= editNurb.first;
1015                 while(nu) {
1016                         if((nu->type & 7)==CU_BEZIER) {
1017                                 bezt= nu->bezt;
1018                                 a= nu->pntsu;
1019                                 while(a--) {
1020                                         if(BEZSELECTED(bezt)) {
1021                                                 if(v1==0) v1= nr;
1022                                                 else if(v2==0) v2= nr;
1023                                                 else if(v3==0) v3= nr;
1024                                                 else break;
1025                                         }
1026                                         nr++;
1027                                         bezt++;
1028                                 }
1029                         }
1030                         else {
1031                                 bp= nu->bp;
1032                                 a= nu->pntsu*nu->pntsv;
1033                                 while(a--) {
1034                                         if(bp->f1 & SELECT) {
1035                                                 if(v1==0) v1= nr;
1036                                                 else if(v2==0) v2= nr;
1037                                                 else if(v3==0) v3= nr;
1038                                                 else break;
1039                                         }
1040                                         nr++;
1041                                         bp++;
1042                                 }
1043                         }
1044                         nu= nu->next;
1045                 }
1046                 
1047         }
1048         
1049         if( !(v1 && v2==0 && v3==0) && !(v1 && v2 && v3) ) {
1050                 error("Select either 1 or 3 vertices to parent to");
1051                 return;
1052         }
1053         
1054         if(okee("Make vertex parent")==0) return;
1055         
1056         base= FIRSTBASE;
1057         while(base) {
1058                 if TESTBASELIB(base) {
1059                         if(base!=BASACT) {
1060                                 ob= base->object;
1061                                 par= BASACT->object->parent;
1062                                 
1063                                 while(par) {
1064                                         if(par==ob) break;
1065                                         par= par->parent;
1066                                 }
1067                                 if(par) {
1068                                         error("Loop in parents");
1069                                 }
1070                                 else {
1071                                         ob->parent= BASACT->object;
1072                                         if(v3) {
1073                                                 ob->partype= PARVERT3;
1074                                                 ob->par1= v1-1;
1075                                                 ob->par2= v2-1;
1076                                                 ob->par3= v3-1;
1077
1078                                                 /* inverse parent matrix */
1079                                                 what_does_parent(ob);
1080                                                 Mat4Invert(ob->parentinv, workob.obmat);
1081                                                 clear_workob();
1082                                         }
1083                                         else {
1084                                                 ob->partype= PARVERT1;
1085                                                 ob->par1= v1-1;
1086
1087                                                 /* inverse parent matrix */
1088                                                 what_does_parent(ob);
1089                                                 Mat4Invert(ob->parentinv, workob.obmat);
1090                                                 clear_workob();
1091                                         }
1092                                 }
1093                         }
1094                 }
1095                 base= base->next;
1096         }
1097         allqueue(REDRAWVIEW3D, 0);
1098         
1099         // BIF_undo_push(str); not, conflicts with editmode undo...
1100 }
1101
1102 int test_parent_loop(Object *par, Object *ob)
1103 {
1104         /* test if 'ob' is a parent somewhere in par's parents */
1105         
1106         if(par==0) return 0;
1107         if(ob == par) return 1;
1108         
1109         if(par->type==OB_IKA) {
1110                 Ika *ika= par->data;
1111                 
1112                 if( ob == ika->parent ) return 1;
1113                 if( test_parent_loop(ika->parent, ob) ) return 1;
1114         }
1115
1116         return test_parent_loop(par->parent, ob);
1117
1118 }
1119
1120 void make_parent(void)
1121 {
1122         Base *base;
1123         Object *par;
1124         short qual, mode=0, limbnr=0, effchild=0;
1125         char *bonestr=NULL;
1126         Bone    *bone=NULL;
1127         int     bonenr;
1128
1129         if(G.scene->id.lib) return;
1130         if(G.obedit) {
1131                 if ELEM3(G.obedit->type, OB_MESH, OB_CURVE, OB_SURF) make_vertex_parent();
1132                 else if (G.obedit->type==OB_ARMATURE) make_bone_parent();
1133                 return;
1134         }
1135         if(BASACT==0) return;
1136         
1137         qual= G.qual;
1138         par= BASACT->object;
1139
1140         if(par->type == OB_CURVE){
1141                 bConstraint *con;
1142                 bFollowPathConstraint *data;
1143
1144                 mode= pupmenu("Make Parent %t|Normal Parent %x1|Follow Path %x2|Curve Deform %x3");
1145                 if(mode<=0){
1146                         return;
1147                 }
1148                 else if(mode==1) {
1149                         mode= PAROBJECT;
1150                 }
1151                 else if(mode==3) {
1152                         mode= PARSKEL;
1153                 }
1154                 else if(mode==2) {
1155
1156                         base= FIRSTBASE;
1157                         while(base) {
1158                                 if TESTBASELIB(base) {
1159                                         if(base!=BASACT) {
1160                                                 float cmat[4][4], vec[3], size[3];
1161
1162                                                 con = add_new_constraint(CONSTRAINT_TYPE_FOLLOWPATH);
1163                                                 strcpy (con->name, "AutoPath");
1164
1165                                                 data = con->data;
1166                                                 data->tar = BASACT->object;
1167
1168                                                 add_constraint_to_object(con, base->object);
1169
1170                                                 get_constraint_target_matrix(con, TARGET_OBJECT, NULL, cmat, size, G.scene->r.cfra - base->object->sf);
1171                                                 VecSubf(vec, base->object->obmat[3], cmat[3]);
1172
1173                                                 base->object->loc[0] = vec[0];
1174                                                 base->object->loc[1] = vec[1];
1175                                                 base->object->loc[2] = vec[2];
1176                                         }
1177                                 }
1178                                 base= base->next;
1179                         }
1180
1181                         test_scene_constraints();
1182                         allqueue(REDRAWVIEW3D, 0);
1183                         sort_baselist(G.scene);
1184                         BIF_undo_push("make Parent");
1185                         return;
1186                 }
1187         }
1188         else if(par->type == OB_ARMATURE){
1189
1190                         base= FIRSTBASE;
1191                         while(base) {
1192                                 if TESTBASELIB(base) {
1193                                         if(base!=BASACT) {
1194                                                 if(base->object->type==OB_MESH) {
1195                                                         mode= pupmenu("Make Parent To%t|Bone %x1|Armature %x2|Object %x3");
1196                                                         break;
1197                                                 }
1198                                                 else {
1199                                                         mode= pupmenu("Make Parent To %t|Bone %x1|Object %x3");
1200                                                         break;
1201                                                 }
1202                                         }
1203                                 }
1204                                 base= base->next;
1205                         }
1206                 
1207                         switch (mode){
1208                         case 1:
1209                                 mode=PARBONE;
1210                                 /* Make bone popup menu */
1211
1212                                 bonestr = make_bone_menu(get_armature(par));
1213                 //              if(mbutton(&bone, bonestr, 1, 24, "Bone: ")==0) {
1214
1215                                 bonenr= pupmenu_col(bonestr, 20);
1216                                 if (bonestr)
1217                                         MEM_freeN (bonestr);
1218                                 
1219                                 if (bonenr==-1){
1220                                         allqueue(REDRAWVIEW3D, 0);
1221                                         return;
1222                                 }
1223
1224                                 apply_pose_armature(get_armature(par), par->pose, 0);
1225                                 bone=get_indexed_bone(get_armature(par), bonenr); 
1226                                 if (!bone){
1227                 //                      error ("Invalid bone!");
1228                                         allqueue(REDRAWVIEW3D, 0);
1229                                         return;
1230                                 }
1231
1232                                 break;
1233                         case 2:
1234                                 mode=PARSKEL;
1235                                 break;
1236                         case 3:
1237                                 mode=PAROBJECT;
1238                                 break;
1239                         default:
1240                                 return;
1241                         }
1242         }
1243         else {
1244                 if(qual & LR_SHIFTKEY) {
1245                         if(okee("Make parent without inverse")==0) return;
1246                 }
1247                 else {
1248                         if(qual & LR_ALTKEY) {
1249                                 if(okee("Make vertex parent")==0) return;
1250                         }
1251                         else if(okee("Make parent")==0) return;
1252
1253                         /* test effchild */
1254                         base= FIRSTBASE;
1255                         while(base) {
1256                                 if TESTBASELIB(base) {
1257                                         if(base->object->type==OB_IKA && base->object != par) {
1258                                                 if(effchild==0) {
1259                                                         if(okee("Effector as Child")) effchild= 1;
1260                                                         else effchild= 2;
1261                                                 }
1262                                         }
1263                                 }
1264                                 if(effchild) break;
1265                                 base= base->next;
1266                         }
1267                         
1268                         /* now we'll clearparentandkeeptransform all objects */
1269                         base= FIRSTBASE;
1270                         while(base) {
1271                                 if TESTBASELIB(base) {
1272                                         if(base!=BASACT && base->object->parent) {
1273                                                 if(base->object->type==OB_IKA && effchild==1);
1274                                                 else {
1275                                                         base->object->parent= 0;
1276                                                         apply_obmat(base->object);
1277                                                 }
1278                                         }
1279                                 }
1280                                 base= base->next;
1281                         }
1282                 }
1283         }
1284         
1285         
1286         base= FIRSTBASE;
1287         while(base) {
1288                 if TESTBASELIB(base) {
1289                         if(base!=BASACT) {
1290                                 
1291                                 if( test_parent_loop(par, base->object) ) {
1292                                         error("Loop in parents");
1293                                 }
1294                                 else {
1295                                         
1296                                         /* the ifs below are horrible code (ton) */
1297                                         
1298                                         if(par->type==OB_IKA){
1299                                                 base->object->partype= mode;
1300                                                 base->object->par1= limbnr;
1301                                         }
1302                                         else if (par->type==OB_ARMATURE){
1303                                                 base->object->partype= mode;
1304                                                 if (bone)
1305                                                         strcpy (base->object->parsubstr, bone->name);
1306                                                 else
1307                                                         base->object->parsubstr[0]=0;
1308                                         }
1309                                         else {
1310                                                 if(qual & LR_ALTKEY) {
1311                                                         base->object->partype= PARVERT1;
1312                                                 }
1313                                                 else if(par->type==OB_CURVE) {
1314                                                         base->object->partype= mode;
1315                                                 }
1316                                                 else {
1317                                                         base->object->partype= PAROBJECT;
1318                                                 }
1319                                         }
1320                                         base->object->parent= par;
1321                                         
1322                                         /* calculate inverse parent matrix? */
1323                                         if( (qual & LR_SHIFTKEY) ) {
1324                                                 /* not... */
1325                                                 Mat4One(base->object->parentinv);
1326                                                 memset(base->object->loc, 0, 3*sizeof(float));
1327                                         }
1328                                         else {
1329                                                 if(mode==PARSKEL && par->type == OB_ARMATURE) {
1330                                                         /* Prompt the user as to whether he wants to
1331                                                                 * add some vertex groups based on the bones
1332                                                                 * in the parent armature.
1333                                                                 */
1334                                                         create_vgroups_from_armature(base->object, 
1335                                                                                                                         par);
1336
1337                                                         base->object->partype= PAROBJECT;
1338                                                         what_does_parent(base->object);
1339                                                         Mat4One (base->object->parentinv);
1340                                                         base->object->partype= mode;
1341                                                 }
1342                                                 else
1343                                                         what_does_parent(base->object);
1344                                                 Mat4Invert(base->object->parentinv, workob.obmat);
1345                                         }
1346                                         
1347                                         if(par->type==OB_LATTICE) makeDispList(base->object);
1348                                         if(par->type==OB_CURVE && mode==PARSKEL) makeDispList(base->object);
1349                                         if(par->type==OB_ARMATURE && mode == PARSKEL){
1350                                                 verify_defgroups(base->object);
1351                                                 makeDispList(base->object);
1352                                         }
1353                                 }
1354                         }
1355                 }
1356                 base= base->next;
1357         }
1358         allqueue(REDRAWVIEW3D, 0);
1359         allqueue(REDRAWOOPS, 0);
1360         
1361         test_scene_constraints();
1362         sort_baselist(G.scene);
1363
1364         BIF_undo_push("make Parent");
1365 }
1366
1367
1368 void enter_editmode(void)
1369 {
1370         Base *base;
1371         Object *ob;
1372         Ika *ika;
1373         ID *id;
1374         Mesh *me;
1375         int ok= 0;
1376         bArmature *arm;
1377         
1378         if(G.scene->id.lib) return;
1379         base= BASACT;
1380         if(base==0) return;
1381         if((base->lay & G.vd->lay)==0) return;
1382         
1383         ob= base->object;
1384         if(ob->data==0) return;
1385         
1386         id= ob->data;
1387         if(id->lib) {
1388                 error("Can't edit library data");
1389                 return;
1390         }
1391         
1392         if(ob->type==OB_MESH) {
1393                 me= get_mesh(ob);
1394                 if( me==0 ) return;
1395                 if(me->id.lib) {
1396                         error("Can't edit library data");
1397                         return;
1398                 }
1399                 ok= 1;
1400                 G.obedit= ob;
1401                 make_editMesh();
1402                 allqueue(REDRAWBUTSLOGIC, 0);
1403                 if(G.f & G_FACESELECT) allqueue(REDRAWIMAGE, 0);
1404         }
1405         if (ob->type==OB_ARMATURE){
1406                 arm=base->object->data;
1407                 if (!arm) return;
1408                 if (arm->id.lib){
1409                         error("Can't edit library data");
1410                         return;
1411                 }
1412                 ok=1;
1413                 G.obedit=ob;
1414                 make_editArmature();
1415                 allqueue (REDRAWVIEW3D,0);
1416         }
1417         else if(ob->type==OB_IKA) {     /* grab type */
1418                 base= FIRSTBASE;
1419                 while(base) {
1420                         if TESTBASE(base) {
1421                                 if(base->object->type==OB_IKA) {
1422                                         ika= base->object->data;
1423                                         if(ika->flag & IK_GRABEFF) ika->flag &= ~IK_GRABEFF;
1424                                         else ika->flag |= IK_GRABEFF;
1425                                 }
1426                         }
1427                         base= base->next;
1428                 }
1429                 allqueue(REDRAWVIEW3D, 0);
1430         }
1431         else if(ob->type==OB_FONT) {
1432                 G.obedit= ob;
1433                 ok= 1;
1434                 make_editText();
1435         }
1436         else if(ob->type==OB_MBALL) {
1437                 G.obedit= ob;
1438                 ok= 1;
1439                 make_editMball();
1440         }
1441         else if(ob->type==OB_LATTICE) {
1442                 G.obedit= ob;
1443                 ok= 1;
1444                 make_editLatt();
1445         }
1446         else if(ob->type==OB_SURF || ob->type==OB_CURVE) {
1447                 ok= 1;
1448                 G.obedit= ob;
1449                 make_editNurb();
1450         }
1451         allqueue(REDRAWBUTSEDIT, 0);
1452         allqueue(REDRAWOOPS, 0);
1453         countall();
1454         
1455         if(ok) {
1456                 setcursor_space(SPACE_VIEW3D, CURSOR_EDIT);
1457         
1458                 allqueue(REDRAWVIEW3D, 1);
1459         }
1460         else G.obedit= 0;
1461
1462         if (G.obpose)
1463                 exit_posemode (1);
1464         scrarea_queue_headredraw(curarea);
1465 }
1466
1467 void make_displists_by_parent(Object *ob) {
1468         Base *base;
1469         
1470         for (base= FIRSTBASE; base; base= base->next)
1471                 if (ob==base->object->parent)
1472                         makeDispList(base->object);
1473 }
1474
1475 void exit_editmode(int freedata)        /* freedata==0 at render, 1= freedata, 2= do undo buffer too */
1476 {
1477         Base *base;
1478         Object *ob;
1479         Curve *cu;
1480
1481         if(G.obedit==NULL) return;
1482
1483         if(G.obedit->type==OB_MESH) {
1484
1485                 /* temporal */
1486                 countall();
1487
1488                 if(G.totvert>MESH_MAX_VERTS) {
1489                         error("Too many vertices");
1490                         return;
1491                 }
1492                 load_editMesh();        /* makes new displist */
1493
1494                 if(freedata) free_editMesh(G.editMesh);
1495
1496                 if(G.f & G_FACESELECT) {
1497                         set_seamtface();
1498                         allqueue(REDRAWIMAGE, 0);
1499                 }
1500
1501                 build_particle_system(G.obedit);
1502         }
1503         else if (G.obedit->type==OB_ARMATURE){  
1504                 load_editArmature();
1505                 if (freedata) free_editArmature();
1506         }
1507         else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
1508                 load_editNurb();
1509                 if(freedata) freeNurblist(&editNurb);
1510         }
1511         else if(G.obedit->type==OB_FONT && freedata) {
1512                 load_editText();
1513         }
1514         else if(G.obedit->type==OB_LATTICE) {
1515                 load_editLatt();
1516                 if(freedata) free_editLatt();
1517         }
1518         else if(G.obedit->type==OB_MBALL) {
1519                 load_editMball();
1520                 if(freedata) BLI_freelistN(&editelems);
1521         }
1522
1523         ob= G.obedit;
1524         
1525         /* displist make is different in editmode */
1526         if(freedata) G.obedit= NULL;
1527         makeDispList(ob);
1528
1529         /* has this influence at other objects? */
1530         if(ob->type==OB_CURVE) {
1531
1532                 /* test if ob is use as bevelcurve r textoncurve */
1533                 base= FIRSTBASE;
1534                 while(base) {
1535                         if ELEM(base->object->type, OB_CURVE, OB_FONT) {
1536                                 cu= base->object->data;
1537                                 
1538                                 if(cu->textoncurve==ob) {
1539                                         text_to_curve(base->object, 0);
1540                                         makeDispList(base->object);
1541                                 }
1542                                 if(cu->bevobj==ob || cu->taperobj==ob) {
1543                                         makeDispList(base->object);
1544                                 }
1545                         }
1546                         base= base->next;
1547                 }
1548                 
1549         }
1550         else if(ob->type==OB_LATTICE) {
1551                 make_displists_by_parent(ob);
1552         }
1553
1554         if(freedata) {
1555                 setcursor_space(SPACE_VIEW3D, CURSOR_STD);
1556         
1557                 countall();
1558                 allqueue(REDRAWVIEW3D, 1);
1559                 allqueue(REDRAWBUTSEDIT, 0);
1560                 allqueue(REDRAWBUTSLOGIC, 0);
1561                 allqueue(REDRAWOOPS, 0);
1562         }
1563         scrarea_queue_headredraw(curarea);
1564
1565         if(ob->softflag) object_to_softbody(ob);
1566         
1567         if(G.obedit==NULL && freedata==2) 
1568                 BIF_undo_push("Editmode");
1569 }
1570
1571 void check_editmode(int type)
1572 {
1573         
1574         if (G.obedit==0 || G.obedit->type==type) return;
1575
1576         exit_editmode(2); // freedata, and undo
1577 }
1578
1579 /* 0 == do centre, 1 == centre new, 2 == centre cursor */
1580
1581 void docentre(int centremode)
1582 {
1583         EditMesh *em = G.editMesh;
1584         Base *base;
1585         Object *ob;
1586         Mesh *me, *tme;
1587         Curve *cu;
1588 //      BezTriple *bezt;
1589 //      BPoint *bp;
1590         Nurb *nu, *nu1;
1591         EditVert *eve;
1592         float cent[3], centn[3], min[3], max[3], omat[3][3];
1593         int a;
1594         MVert *mvert;
1595
1596         if(G.scene->id.lib) return;
1597
1598         if(G.obedit) {
1599
1600                 INIT_MINMAX(min, max);
1601         
1602                 if(G.obedit->type==OB_MESH) {
1603                         eve= em->verts.first;
1604                         while(eve) {
1605                                 DO_MINMAX(eve->co, min, max);
1606                                 eve= eve->next;
1607                         }
1608                         cent[0]= (min[0]+max[0])/2.0f;
1609                         cent[1]= (min[1]+max[1])/2.0f;
1610                         cent[2]= (min[2]+max[2])/2.0f;
1611                         
1612                         eve= em->verts.first;
1613                         while(eve) {
1614                                 VecSubf(eve->co, eve->co, cent);                        
1615                                 eve= eve->next;
1616                         }
1617                 }
1618         }
1619         
1620         /* reset flags */
1621         base= FIRSTBASE;
1622         while(base) {
1623                 if TESTBASELIB(base) {
1624                         base->object->flag &= ~OB_DONE;
1625                 }
1626                 base= base->next;
1627         }
1628         me= G.main->mesh.first;
1629         while(me) {
1630                 me->flag &= ~ME_ISDONE;
1631                 me= me->id.next;
1632         }
1633         
1634         base= FIRSTBASE;
1635         while(base) {
1636                 
1637                 if TESTBASELIB(base) {
1638                         if((base->object->flag & OB_DONE)==0) {
1639                                 
1640                                 base->object->flag |= OB_DONE;
1641                                 
1642                                 if(G.obedit==0 && (me=get_mesh(base->object)) ) {
1643                                         
1644                                         if(me->key) {
1645                                                 error("Can't change the center of a mesh with vertex keys");
1646                                                 return;
1647                                         }
1648                                         
1649                                         if(centremode==2) {
1650                                                 VECCOPY(cent, give_cursor());
1651                                                 Mat4Invert(base->object->imat, base->object->obmat);
1652                                                 Mat4MulVecfl(base->object->imat, cent);
1653                                         } else {
1654                                                 INIT_MINMAX(min, max);
1655                 
1656                                                 mvert= me->mvert;
1657                                                 for(a=0; a<me->totvert; a++, mvert++) {
1658                                                         DO_MINMAX(mvert->co, min, max);
1659                                                 }
1660                                 
1661                                                 cent[0]= (min[0]+max[0])/2.0f;
1662                                                 cent[1]= (min[1]+max[1])/2.0f;
1663                                                 cent[2]= (min[2]+max[2])/2.0f;
1664                                         }
1665                                                 
1666                                         mvert= me->mvert;
1667                                         for(a=0; a<me->totvert; a++, mvert++) {
1668                                                 VecSubf(mvert->co, mvert->co, cent);
1669                                         }
1670                                         me->flag |= ME_ISDONE;
1671                                         
1672                                         if(centremode) {
1673                                                 Mat3CpyMat4(omat, base->object->obmat);
1674                                                 
1675                                                 VECCOPY(centn, cent);
1676                                                 Mat3MulVecfl(omat, centn);
1677                                                 base->object->loc[0]+= centn[0];
1678                                                 base->object->loc[1]+= centn[1];
1679                                                 base->object->loc[2]+= centn[2];
1680                                                 
1681                                                 /* other users? */
1682                                                 ob= G.main->object.first;
1683                                                 while(ob) {
1684                                                         if((ob->flag & OB_DONE)==0) {
1685                                                                 tme= get_mesh(ob);
1686                                                                 
1687                                                                 if(tme==me) {
1688                                                                         
1689                                                                         ob->flag |= OB_DONE;
1690
1691                                                                         Mat3CpyMat4(omat, ob->obmat);
1692                                                                         VECCOPY(centn, cent);
1693                                                                         Mat3MulVecfl(omat, centn);
1694                                                                         ob->loc[0]+= centn[0];
1695                                                                         ob->loc[1]+= centn[1];
1696                                                                         ob->loc[2]+= centn[2];
1697                                                                         
1698                                                                         if(tme && (tme->flag & ME_ISDONE)==0) {
1699                                                                                 mvert= tme->mvert;
1700                                                                                 for(a=0; a<tme->totvert; a++, mvert++) {
1701                                                                                         VecSubf(mvert->co, mvert->co, cent);
1702                                                                                 }
1703                                                                                 tme->flag |= ME_ISDONE;
1704                                                                         }
1705                                                                 }
1706                                                         }
1707                                                         
1708                                                         ob= ob->id.next;
1709                                                 }
1710                                         }
1711                                 
1712                                         /* displist of all users, also this one */
1713                                         makeDispList(base->object);
1714                                         
1715                                         /* DO: check all users... */
1716                                         tex_space_mesh(me);
1717                 
1718                                 }
1719                                 else if ELEM(base->object->type, OB_CURVE, OB_SURF) {
1720                                                                         
1721                                         if(G.obedit) {
1722                                                 nu1= editNurb.first;
1723                                         }
1724                                         else {
1725                                                 cu= base->object->data;
1726                                                 nu1= cu->nurb.first;
1727                                         }
1728                                         
1729                                         if(centremode==2) {
1730                                                 VECCOPY(cent, give_cursor());
1731                                                 Mat4Invert(base->object->imat, base->object->obmat);
1732                                                 Mat4MulVecfl(base->object->imat, cent);
1733                                                         
1734                                                         /* Curves need to be 2d, never offset in
1735                                                          * Z. Is a somewhat arbitrary restriction, 
1736                                                          * would probably be nice to remove.
1737                                                          */
1738                                                 cent[2]= 0.0;
1739                                         } else {
1740                                                 INIT_MINMAX(min, max);
1741         
1742                                                 nu= nu1;
1743                                                 while(nu) {
1744                                                         minmaxNurb(nu, min, max);
1745                                                         nu= nu->next;
1746                                                 }
1747                                                 
1748                                                 cent[0]= (min[0]+max[0])/2.0f;
1749                                                 cent[1]= (min[1]+max[1])/2.0f;
1750                                                 cent[2]= (min[2]+max[2])/2.0f;
1751                                         }
1752                                         
1753                                         nu= nu1;
1754                                         while(nu) {
1755                                                 if( (nu->type & 7)==1) {
1756                                                         a= nu->pntsu;
1757                                                         while (a--) {
1758                                                                 VecSubf(nu->bezt[a].vec[0], nu->bezt[a].vec[0], cent);
1759                                                                 VecSubf(nu->bezt[a].vec[1], nu->bezt[a].vec[1], cent);
1760                                                                 VecSubf(nu->bezt[a].vec[2], nu->bezt[a].vec[2], cent);
1761                                                         }
1762                                                 }
1763                                                 else {
1764                                                         a= nu->pntsu*nu->pntsv;
1765                                                         while (a--)
1766                                                                 VecSubf(nu->bp[a].vec, nu->bp[a].vec, cent);
1767                                                 }
1768                                                 nu= nu->next;
1769                                         }
1770                         
1771                                         if(centremode && G.obedit==0) {
1772                                                 Mat3CpyMat4(omat, base->object->obmat);
1773                                                 
1774                                                 Mat3MulVecfl(omat, cent);
1775                                                 base->object->loc[0]+= cent[0];
1776                                                 base->object->loc[1]+= cent[1];
1777                                                 base->object->loc[2]+= cent[2];
1778                                         }
1779                         
1780                                         if(G.obedit) {
1781                                                 makeDispList(G.obedit);
1782                                                 break;
1783                                         }
1784                                         else makeDispList(base->object);
1785         
1786                                 }
1787                                 else if(base->object->type==OB_FONT) {
1788                                         /* get from bb */
1789                                         
1790                                         cu= base->object->data;
1791                                         if(cu->bb==0) return;
1792                                         
1793                                         cu->xof= -0.5f*( cu->bb->vec[4][0] - cu->bb->vec[0][0]);
1794                                         cu->yof= -0.5f -0.5f*( cu->bb->vec[0][1] - cu->bb->vec[2][1]);  /* extra 0.5 is the height of above line */
1795                                         
1796                                         /* not really ok, do this better once! */
1797                                         cu->xof /= cu->fsize;
1798                                         cu->yof /= cu->fsize;
1799                                         
1800                                         text_to_curve(base->object, 0);
1801                                         makeDispList(base->object);
1802                                         
1803                                         allqueue(REDRAWBUTSEDIT, 0);
1804                                 }
1805                         }
1806                 }
1807                 base= base->next;
1808         }
1809
1810         allqueue(REDRAWVIEW3D, 0);
1811         BIF_undo_push("Do Centre");     
1812 }
1813
1814 void docentre_new(void)
1815 {
1816         if(G.scene->id.lib) return;
1817
1818         if(G.obedit) {
1819                 error("Unable to center new in Edit Mode");
1820         }
1821         else {
1822                 docentre(1);
1823         }
1824 }
1825
1826 void docentre_cursor(void)
1827 {
1828         if(G.scene->id.lib) return;
1829
1830         if(G.obedit) {
1831                 error("Unable to center cursor in Edit Mode");
1832         }
1833         else {
1834                 docentre(2);
1835         }
1836 }
1837
1838 void movetolayer(void)
1839 {
1840         Base *base;
1841         unsigned int lay= 0, local;
1842         int islamp= 0;
1843         
1844         if(G.scene->id.lib) return;
1845
1846         base= FIRSTBASE;
1847         while(base) {
1848                 if TESTBASE(base) lay |= base->lay;
1849                 base= base->next;
1850         }
1851         if(lay==0) return;
1852         lay &= 0xFFFFFF;
1853         
1854         if( movetolayer_buts(&lay)==0 ) return;
1855         if(lay==0) return;
1856
1857         base= FIRSTBASE;
1858         while(base) {
1859                 if TESTBASE(base) {
1860                         /* upper byte is used for local view */
1861                         local= base->lay & 0xFF000000;  
1862                         base->lay= lay + local;
1863                         base->object->lay= lay;
1864                         if(base->object->type==OB_LAMP) islamp= 1;
1865                 }
1866                 base= base->next;
1867         }
1868         
1869         if(islamp && G.vd->drawtype == OB_SHADED) reshadeall_displist();
1870
1871         countall();
1872         allqueue(REDRAWBUTSEDIT, 0);
1873         allqueue(REDRAWVIEW3D, 0);
1874         allqueue(REDRAWOOPS, 0);
1875         allqueue(REDRAWINFO, 0);
1876         
1877         BIF_undo_push("Move to layer");
1878 }
1879
1880
1881 void special_editmenu(void)
1882 {
1883         extern short editbutflag;
1884         extern float doublimit;
1885         float fac;
1886         int nr,ret;
1887         short randfac;
1888         
1889         if(G.obedit==0) {
1890                 if(G.f & G_FACESELECT) {
1891                         Mesh *me= get_mesh(OBACT);
1892                         TFace *tface;
1893                         int a;
1894                         
1895                         if(me==0 || me->tface==0) return;
1896                         
1897                         nr= pupmenu("Specials%t|Set     Tex%x1|         Shared%x2|         Light%x3|         Invisible%x4|         Collision%x5|Clr     Tex%x6|         Shared%x7|         Light%x8|         Invisible%x9|         Collision%x10");
1898         
1899                         for(a=me->totface, tface= me->tface; a>0; a--, tface++) {
1900                                 if(tface->flag & SELECT) {
1901                                         switch(nr) {
1902                                         case 1:
1903                                                 tface->mode |= TF_TEX; break;
1904                                         case 2:
1905                                                 tface->mode |= TF_SHAREDCOL; break;
1906                                         case 3:
1907                                                 tface->mode |= TF_LIGHT; break; 
1908                                         case 4:
1909                                                 tface->mode |= TF_INVISIBLE; break;
1910                                         case 5:
1911                                                 tface->mode |= TF_DYNAMIC; break;
1912                                         case 6:
1913                                                 tface->mode &= ~TF_TEX;
1914                                                 tface->tpage= 0;
1915                                                 break;
1916                                         case 7:
1917                                                 tface->mode &= ~TF_SHAREDCOL; break;
1918                                         case 8:
1919                                                 tface->mode &= ~TF_LIGHT; break;
1920                                         case 9:
1921                                                 tface->mode &= ~TF_INVISIBLE; break;
1922                                         case 10:
1923                                                 tface->mode &= ~TF_DYNAMIC; break;
1924                                         }
1925                                 }
1926                         }
1927                         allqueue(REDRAWVIEW3D, 0);
1928                         allqueue(REDRAWBUTSEDIT, 0);
1929                         BIF_undo_push("Change texture face");
1930                 }
1931                 else if(G.f & G_VERTEXPAINT) {
1932                         Mesh *me= get_mesh(OBACT);
1933                         
1934                         if(me==0 || (me->mcol==NULL && me->tface==NULL) ) return;
1935                         
1936                         nr= pupmenu("Specials%t|Shared VertexCol%x1");
1937                         if(nr==1) {
1938                                 
1939                                 if(me->tface) tface_to_mcol(me);
1940                                 
1941                                 copy_vpaint_undo( (unsigned int *)me->mcol, me->totface);
1942                                 do_shared_vertexcol(me);
1943                                 
1944                                 if(me->tface) mcol_to_tface(me, 1);
1945                                 BIF_undo_push("Shared VertexCol");
1946                         }
1947                 }
1948                 else {
1949                         Base *base, *base_select= NULL;
1950
1951                         // Get the active object mesh.
1952                         Mesh *me= get_mesh(OBACT);
1953
1954                         // If the active object is a mesh...
1955                         if (me) {
1956                                 // Bring up a little menu with the boolean operation choices on.
1957                                 nr= pupmenu("Boolean %t|Intersect%x1|Union%x2|Difference%x3");
1958
1959                                 if (nr > 0) {
1960                                         // user has made a choice of a menu element.
1961                                         // All of the boolean functions require 2 mesh objects 
1962                                         // we search through the object list to find the other 
1963                                         // selected item and make sure it is distinct and a mesh.
1964
1965                                         base= FIRSTBASE;
1966                                         while(base) {
1967                                                 if(base->flag & SELECT) {
1968                                                         if(base->object != OBACT) base_select= base;
1969                                                 }
1970
1971                                                 base= base->next;
1972                                         }
1973
1974                                         if (base_select) {
1975                                                 if (get_mesh(base_select->object)) {
1976                                                         waitcursor(1);
1977                                                         ret = NewBooleanMesh(BASACT,base_select,nr);
1978                                                         if (ret==0) {
1979                                                                 error("An internal error occurred -- sorry!");
1980                                                         } else if(ret==-1) {
1981                                                                 error("Selected meshes must have faces to perform boolean operations");
1982                                                         }
1983                                                         else BIF_undo_push("Boolean");
1984
1985                                                         waitcursor(0);
1986                                                 } else {
1987                                                         error("Please select 2 meshes");
1988                                                 }
1989                                         } else {
1990                                                 error("Please select 2 meshes");
1991                                         }
1992                                 }
1993
1994                                 allqueue(REDRAWVIEW3D, 0);
1995                         }
1996                 }
1997         }
1998         else if(G.obedit->type==OB_MESH) {
1999
2000                 nr= pupmenu("Specials%t|Subdivide%x1|Subdivide Fractal%x2|Subdivide Smooth%x3|Merge%x4|Remove Doubles%x5|Hide%x6|Reveal%x7|Select Swap%x8|Flip Normals %x9|Smooth %x10|Bevel %x11");
2001                 if(nr>0) waitcursor(1);
2002                 
2003                 switch(nr) {
2004                 case 1:
2005                         subdivideflag(1, 0.0, editbutflag);
2006                         BIF_undo_push("Subdivide");
2007                         break;
2008                 case 2:
2009                         randfac= 10;
2010                         if(button(&randfac, 1, 100, "Rand fac:")==0) return;
2011                         fac= -( (float)randfac )/100;
2012                         subdivideflag(1, fac, editbutflag);
2013                         BIF_undo_push("Subdivide Fractal");
2014                         break;
2015                 case 3:
2016                         subdivideflag(1, 0.0, editbutflag | B_SMOOTH);
2017                         BIF_undo_push("Subdivide Smooth");
2018                         break;
2019                 case 4:
2020                         mergemenu();
2021                         break;
2022                 case 5:
2023                         notice("Removed %d Vertices", removedoublesflag(1, doublimit));
2024                         BIF_undo_push("Remove Doubles");
2025                         break;
2026                 case 6:
2027                         hide_mesh(0);
2028                         break;
2029                 case 7:
2030                         reveal_mesh();
2031                         break;
2032                 case 8:
2033                         selectswap_mesh();
2034                         break;
2035                 case 9:
2036                         flip_editnormals();
2037                         BIF_undo_push("Flip Normals");
2038                         break;
2039                 case 10:
2040                         vertexsmooth();
2041                         break;
2042                 case 11:
2043                         bevel_menu();
2044                         break;
2045                 }               
2046                 
2047                 makeDispList(G.obedit);
2048                 
2049                 if(nr>0) waitcursor(0);
2050                 
2051         }
2052         else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
2053
2054                 nr= pupmenu("Specials%t|Subdivide%x1|Switch Direction%x2");
2055                 
2056                 switch(nr) {
2057                 case 1:
2058                         subdivideNurb();
2059                         break;
2060                 case 2:
2061                         switchdirectionNurb2();
2062                         break;
2063                 }
2064         }
2065
2066         countall();
2067         allqueue(REDRAWVIEW3D, 0);
2068         
2069 }
2070
2071 void convertmenu(void)
2072 {
2073         Base *base, *basen, *basact;
2074         Object *ob, *ob1;
2075         Curve *cu;
2076         MetaBall *mb;
2077         Mesh *me;
2078         DispList *dl;
2079         int ok=0, nr = 0, a;
2080         
2081         if(G.scene->id.lib) return;
2082
2083         ob= OBACT;
2084         if(ob==0) return;
2085         if(G.obedit) return;
2086         
2087         basact= BASACT; /* will be restored */
2088                 
2089         if(ob->type==OB_FONT) {
2090                 nr= pupmenu("Convert Font to%t|Curve");
2091                 if(nr>0) ok= 1;
2092         }
2093         else if(ob->type==OB_MBALL) {
2094                 nr= pupmenu("Convert Metaball to%t|Mesh (keep original)");
2095                 if(nr>0) ok= 1;
2096         }
2097         else if(ob->type==OB_CURVE) {
2098                 nr= pupmenu("Convert Curve to%t|Mesh");
2099                 if(nr>0) ok= 1;
2100         }
2101         else if(ob->type==OB_SURF) {
2102                 nr= pupmenu("Convert Nurbs Surface to%t|Mesh");
2103                 if(nr>0) ok= 1;
2104         }
2105         else if(ob->type==OB_MESH && mesh_uses_displist((Mesh*) ob->data)) {
2106                 nr= pupmenu("Convert SubSurf to%t|Mesh (Keep Original)");
2107                 if(nr>0) ok= 1;
2108         }
2109         if(ok==0) return;
2110
2111         /* don't forget multiple users! */
2112
2113         /* reset flags */
2114         base= FIRSTBASE;
2115         while(base) {
2116                 if TESTBASELIB(base) {
2117                         base->object->flag &= ~OB_DONE;
2118                 }
2119                 base= base->next;
2120         }
2121
2122         base= FIRSTBASE;
2123         while(base) {
2124                 if TESTBASELIB(base) {
2125                         
2126                         ob= base->object;
2127                         
2128                         if(ob->flag & OB_DONE);
2129                         else if(ob->type==OB_MESH) {
2130                                 Mesh *oldme= ob->data;
2131                                 
2132                                 if (mesh_uses_displist(oldme)) {
2133                                         DispListMesh *dlm;
2134
2135                                         ob->flag |= OB_DONE;
2136
2137                                         ob1= copy_object(ob);
2138
2139                                         basen= MEM_mallocN(sizeof(Base), "duplibase");
2140                                         *basen= *base;
2141                                         BLI_addhead(&G.scene->base, basen);     /* addhead: otherwise eternal loop */
2142                                         basen->object= ob1;
2143                                         basen->flag &= ~SELECT;
2144                                                 
2145                                         me= ob1->data;
2146                                         me->id.us--;
2147                                                 
2148                                         ob1->data= add_mesh();
2149                                         G.totmesh++;
2150                                         ob1->type= OB_MESH;
2151
2152                                         me= ob1->data;
2153                                         me->totcol= oldme->totcol;
2154                                         if(ob1->totcol) {
2155                                                 me->mat= MEM_dupallocN(oldme->mat);
2156                                                 for(a=0; a<ob1->totcol; a++) id_us_plus((ID *)me->mat[a]);
2157                                         }
2158                                                 
2159                                         dlm= subsurf_make_dispListMesh_from_mesh(oldme, NULL, oldme->subdiv, oldme->flag);
2160                                         displistmesh_to_mesh(dlm, ob1->data);
2161                                         displistmesh_free(dlm);
2162
2163                                         tex_space_mesh(me);
2164                                 }
2165                         }
2166                         else if(ob->type==OB_FONT) {
2167                                 if(nr==1) {
2168                                 
2169                                         ob->flag |= OB_DONE;
2170                                 
2171                                         ob->type= OB_CURVE;
2172                                         cu= ob->data;
2173                                         
2174                                         if(cu->vfont) {
2175                                                 cu->vfont->id.us--;
2176                                                 cu->vfont= 0;
2177                                         }
2178                                         /* other users */
2179                                         if(cu->id.us>1) {
2180                                                 ob1= G.main->object.first;
2181                                                 while(ob1) {
2182                                                         if(ob1->data==cu) ob1->type= OB_CURVE;
2183                                                         ob1= ob1->id.next;
2184                                                 }
2185                                         }
2186                                 }
2187                         }
2188                         else if ELEM(ob->type, OB_CURVE, OB_SURF) {
2189                                 if(nr==1) {
2190
2191                                         ob->flag |= OB_DONE;
2192                                         cu= ob->data;
2193                                         
2194                                         dl= cu->disp.first;
2195                                         if(dl==0) makeDispList(ob);
2196
2197                                         nurbs_to_mesh(ob); /* also does users */
2198
2199                                         /* texspace and normals */
2200                                         BASACT= base;
2201                                         enter_editmode();
2202                                         exit_editmode(1); // freedata, but no undo
2203                                         BASACT= basact;
2204                                 }
2205                         }
2206                         else if(ob->type==OB_MBALL) {
2207                         
2208                                 if(nr==1) {
2209                                         ob= find_basis_mball(ob);
2210                                         
2211                                         if(ob->disp.first && !(ob->flag&OB_DONE)) {
2212                                         
2213                                                 ob->flag |= OB_DONE;
2214
2215                                                 ob1= copy_object(ob);
2216
2217                                                 basen= MEM_mallocN(sizeof(Base), "duplibase");
2218                                                 *basen= *base;
2219                                                 BLI_addhead(&G.scene->base, basen);     /* addhead: othwise eternal loop */
2220                                                 basen->object= ob1;
2221                                                 basen->flag &= ~SELECT;
2222                                                 
2223                                                 mb= ob1->data;
2224                                                 mb->id.us--;
2225                                                 
2226                                                 ob1->data= add_mesh();
2227                                                 G.totmesh++;
2228                                                 ob1->type= OB_MESH;
2229                                                 
2230                                                 me= ob1->data;
2231                                                 me->totcol= mb->totcol;
2232                                                 if(ob1->totcol) {
2233                                                         me->mat= MEM_dupallocN(mb->mat);
2234                                                         for(a=0; a<ob1->totcol; a++) id_us_plus((ID *)me->mat[a]);
2235                                                 }
2236                                                 
2237                                                 mball_to_mesh(&ob->disp, ob1->data);
2238                                                 tex_space_mesh(me);
2239                                         }
2240                                 }
2241                         }
2242                 }
2243                 base= base->next;
2244         }
2245         
2246         allqueue(REDRAWVIEW3D, 0);
2247         allqueue(REDRAWOOPS, 0);
2248         allqueue(REDRAWBUTSEDIT, 0);
2249         BIF_undo_push("Convert Object");
2250 }
2251
2252         /* Change subdivision properties of mesh object ob, if
2253          * level==-1 then toggle subsurf, else set to level.
2254          */
2255 void flip_subdivison(Object *ob, int level)
2256 {
2257         Mesh *me = ob->data;
2258
2259         if (level == -1) {
2260                 me->flag ^= ME_SUBSURF;
2261         } else {
2262                 me->subdiv = level;
2263         }
2264
2265         allqueue(REDRAWVIEW3D, 0);
2266         allqueue(REDRAWOOPS, 0);
2267         allqueue(REDRAWBUTSEDIT, 0);
2268         makeDispList(ob);
2269         
2270         BIF_undo_push("Switch subsurf on/off");
2271 }
2272  
2273 void copymenu_properties(Object *ob)
2274 {       
2275         bProperty *prop, *propn, *propc;
2276         Base *base;
2277         int nr, tot=0;
2278         char *str;
2279         
2280         prop= ob->prop.first;
2281         while(prop) {
2282                 tot++;
2283                 prop= prop->next;
2284         }
2285         
2286         if(tot==0) {
2287                 error("No properties in the active object to copy");
2288                 return;
2289         }
2290         
2291         str= MEM_callocN(24+32*tot, "copymenu prop");
2292         
2293         strcpy(str, "Copy Property %t");
2294         
2295         tot= 0; 
2296         prop= ob->prop.first;
2297         while(prop) {
2298                 tot++;
2299                 strcat(str, " |");
2300                 strcat(str, prop->name);
2301                 prop= prop->next;
2302         }
2303
2304         nr= pupmenu(str);
2305         if(nr>0) {
2306                 tot= 0;
2307                 prop= ob->prop.first;
2308                 while(prop) {
2309                         tot++;
2310                         if(tot==nr) break;
2311                         prop= prop->next;
2312                 }
2313                 if(prop) {
2314                         propc= prop;
2315                         
2316                         base= FIRSTBASE;
2317                         while(base) {
2318                                 if(base != BASACT) {
2319                                         if(TESTBASELIB(base)) {
2320                                                 prop= get_property(base->object, propc->name);
2321                                                 if(prop) {
2322                                                         free_property(prop);
2323                                                         BLI_remlink(&base->object->prop, prop);
2324                                                 }
2325                                                 propn= copy_property(propc);
2326                                                 BLI_addtail(&base->object->prop, propn);
2327                                         }
2328                                 }
2329                                 base= base->next;
2330                         }
2331                 }
2332         }
2333         MEM_freeN(str);
2334         allqueue(REDRAWVIEW3D, 0);
2335         
2336         BIF_undo_push("Copy properties");
2337 }
2338
2339 void copymenu_logicbricks(Object *ob)
2340 {
2341         Base *base;
2342         
2343         base= FIRSTBASE;
2344         while(base) {
2345                 if(base->object != ob) {
2346                         if(TESTBASELIB(base)) {
2347                                 
2348                                 /* first: free all logic */
2349                                 free_sensors(&base->object->sensors);                           
2350                                 unlink_controllers(&base->object->controllers);
2351                                 free_controllers(&base->object->controllers);
2352                                 unlink_actuators(&base->object->actuators);
2353                                 free_actuators(&base->object->actuators);
2354                                 
2355                                 /* now copy it, this also works without logicbricks! */
2356                                 clear_sca_new_poins_ob(ob);
2357                                 copy_sensors(&base->object->sensors, &ob->sensors);
2358                                 copy_controllers(&base->object->controllers, &ob->controllers);
2359                                 copy_actuators(&base->object->actuators, &ob->actuators);
2360                                 set_sca_new_poins_ob(base->object);
2361                                 
2362                                 /* some menu settings */
2363                                 base->object->scavisflag= ob->scavisflag;
2364                                 base->object->scaflag= ob->scaflag;
2365                                 
2366                         }
2367                 }
2368                 base= base->next;
2369         }
2370         BIF_undo_push("Copy logic");
2371 }
2372
2373 void copy_attr_menu()
2374 {
2375         Object *ob;
2376         short event;
2377         char str[256];
2378
2379         /* If you change this menu, don't forget to update the menu in header_view3d.c
2380          * view3d_edit_object_copyattrmenu() and in toolbox.c
2381          */
2382         strcpy(str, "Copy Attributes %t|Location%x1|Rotation%x2|Size%x3|Drawtype%x4|Time Offset%x5|Dupli%x6|%l|Mass%x7|Damping%x8|Properties%x9|Logic Bricks%x10|%l");
2383
2384         if(!(ob=OBACT)) return;
2385         
2386         strcat (str, "|Object Constraints%x22");
2387         
2388         if ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL) {
2389                 strcat(str, "|Texture Space%x17");
2390         }       
2391         
2392         if(ob->type == OB_FONT) strcat(str, "|Font Settings%x18|Bevel Settings%x19");
2393         if(ob->type == OB_CURVE) strcat(str, "|Bevel Settings%x19");
2394
2395         if(ob->type==OB_MESH){
2396                 strcat(str, "|Subdiv%x21");
2397         }
2398
2399         if( give_parteff(ob) ) strcat(str, "|Particle Settings%x20");
2400
2401         event= pupmenu(str);
2402         if(event<= 0) return;
2403         
2404         copy_attr(event);
2405 }
2406
2407 void copy_attr(short event)
2408 {
2409         Object *ob, *obt;
2410         Base *base;
2411         Curve *cu, *cu1;
2412         void *poin1, *poin2=0;
2413         
2414         if(G.scene->id.lib) return;
2415
2416         if(!(ob=OBACT)) return;
2417         
2418         if(G.obedit) {
2419                 /* obedit_copymenu(); */
2420                 return;
2421         }
2422         
2423         if ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL) {
2424                 if(ob->type==OB_MESH) poin2= &(((Mesh *)ob->data)->texflag);
2425                 else if ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT) poin2= &(((Curve *)ob->data)->texflag);
2426                 else if(ob->type==OB_MBALL) poin2= &(((MetaBall *)ob->data)->texflag);
2427         }       
2428
2429         if(event==9) {
2430                 copymenu_properties(ob);
2431                 return;
2432         }
2433         else if(event==10) {
2434                 copymenu_logicbricks(ob);
2435                 return;
2436         }
2437
2438         base= FIRSTBASE;
2439         while(base) {
2440                 if(base != BASACT) {
2441                         if(TESTBASELIB(base)) {
2442                                 
2443                                 if(event==1) {  /* loc */
2444                                         VECCOPY(base->object->loc, ob->loc);
2445                                         VECCOPY(base->object->dloc, ob->dloc);
2446                                 }
2447                                 else if(event==2) {  /* rot */
2448                                         VECCOPY(base->object->rot, ob->rot);
2449                                         VECCOPY(base->object->drot, ob->drot);
2450                                         VECCOPY(base->object->quat, ob->quat);
2451                                         VECCOPY(base->object->dquat, ob->dquat);
2452                                 }
2453                                 else if(event==3) {  /* size */
2454                                         VECCOPY(base->object->size, ob->size);
2455                                         VECCOPY(base->object->dsize, ob->dsize);
2456                                 }
2457                                 else if(event==4) {  /* drawtype */
2458                                         base->object->dt= ob->dt;
2459                                         base->object->dtx= ob->dtx;
2460                                         }
2461                                 else if(event==5) {  /* time offs */
2462                                         base->object->sf= ob->sf;
2463                                 }
2464                                 else if(event==6) {  /* dupli */
2465                                         base->object->dupon= ob->dupon;
2466                                         base->object->dupoff= ob->dupoff;
2467                                         base->object->dupsta= ob->dupsta;
2468                                         base->object->dupend= ob->dupend;
2469                                         
2470                                         base->object->transflag &= ~OB_DUPLI;
2471                                         base->object->transflag |= (ob->transflag & OB_DUPLI);
2472                                 }
2473                                 else if(event==7) {     /* mass */
2474                                         base->object->mass= ob->mass;
2475                                 }
2476                                 else if(event==8) {     /* damping */
2477                                         base->object->damping= ob->damping;
2478                                         base->object->rdamping= ob->rdamping;
2479                                 }
2480                                 else if(event==17) {    /* tex space */
2481                                         obt= base->object;
2482                                         poin1= 0;
2483                                         if(obt->type==OB_MESH) poin1= &(((Mesh *)obt->data)->texflag);
2484                                         else if ELEM3(obt->type, OB_CURVE, OB_SURF, OB_FONT) poin1= &(((Curve *)obt->data)->texflag);
2485                                         else if(obt->type==OB_MBALL) poin1= &(((MetaBall *)obt->data)->texflag);                                        
2486                                         
2487                                         if(poin1) {
2488                                                 memcpy(poin1, poin2, 4+12+12+12);
2489                                         
2490                                                 if(obt->type==OB_MESH) tex_space_mesh(obt->data);
2491                                                 else if(obt->type==OB_MBALL) tex_space_mball(obt);
2492                                                 else tex_space_curve(obt->data);
2493                                         }
2494                                 }
2495                                 else if(event==18) {    /* font settings */
2496                                         
2497                                         if(base->object->type==ob->type) {
2498                                                 cu= ob->data;
2499                                                 cu1= base->object->data;
2500                                                 
2501                                                 cu1->spacemode= cu->spacemode;
2502                                                 cu1->spacing= cu->spacing;
2503                                                 cu1->linedist= cu->linedist;
2504                                                 cu1->shear= cu->shear;
2505                                                 cu1->fsize= cu->fsize;
2506                                                 cu1->xof= cu->xof;
2507                                                 cu1->yof= cu->yof;
2508                                                 cu1->textoncurve= cu->textoncurve;
2509                                                 if(cu1->vfont) cu1->vfont->id.us--;
2510                                                 cu1->vfont= cu->vfont;
2511                                                 id_us_plus((ID *)cu1->vfont);
2512                                                 text_to_curve(base->object, 0);
2513                                                 
2514                                                 strcpy(cu1->family, cu->family);
2515                                                 
2516                                                 makeDispList(base->object);
2517                                         }
2518                                 }
2519                                 else if(event==19) {    /* bevel settings */
2520                                         
2521                                         if ELEM(base->object->type, OB_CURVE, OB_FONT) {
2522                                                 cu= ob->data;
2523                                                 cu1= base->object->data;
2524                                                 
2525                                                 cu1->bevobj= cu->bevobj;
2526                                                 cu1->taperobj= cu->taperobj;
2527                                                 cu1->width= cu->width;
2528                                                 cu1->bevresol= cu->bevresol;
2529                                                 cu1->ext1= cu->ext1;
2530                                                 cu1->ext2= cu->ext2;
2531                                                 
2532                                                 makeDispList(base->object);
2533                                         }
2534                                 }
2535                                 else if(event==20) {    /* particle settings */
2536                                         PartEff *pa1, *pa2;
2537                                         char *p1, *p2;
2538                                         
2539                                         pa1= give_parteff(ob);
2540                                         pa2= give_parteff(base->object);
2541
2542                                         if(pa1==0 && pa2) {
2543                                                 BLI_remlink( &(base->object->effect), pa2);
2544                                                 free_effect( (Effect *) pa2);
2545                                         }
2546                                         else if(pa1 && pa2==0) {
2547                                                 free_effects(&(base->object->effect));
2548                                                 copy_effects(&(base->object->effect), &ob->effect);
2549                                                 build_particle_system(base->object);
2550                                         }
2551                                         else if(pa1 && pa2) {
2552                                                 if(pa2->keys) MEM_freeN(pa2->keys);
2553                                                 
2554                                                 p1= (char *)pa1; p2= (char *)pa2;
2555                                                 memcpy( p2+8, p1+8, sizeof(PartEff) - 8);
2556                                                 pa2->keys= 0;
2557                                                 
2558                                                 build_particle_system(base->object);
2559                                         }
2560                                 }
2561                                 else if(event==21){
2562                                         if (base->object->type==OB_MESH) {
2563                                                 Mesh *targetme= base->object->data;
2564                                                 Mesh *sourceme= ob->data;
2565
2566                                                 targetme->flag= (targetme->flag&~ME_SUBSURF) | (sourceme->flag&ME_SUBSURF);
2567                                                 targetme->subsurftype = sourceme->subsurftype;
2568                                                 targetme->subdiv= sourceme->subdiv;
2569                                                 targetme->subdivr= sourceme->subdivr;
2570                                                 makeDispList(base->object);
2571                                         }
2572                                 }
2573                                 else if(event==22){
2574                                         /* Clear the constraints on the target */
2575                                         free_constraints(&base->object->constraints);
2576                                         free_constraint_channels(&base->object->constraintChannels);
2577
2578                                         /* Copy the constraint channels over */
2579                                         copy_constraints(&base->object->constraints, &ob->constraints);
2580                                         if (U.dupflag& USER_DUP_IPO)
2581                                                 copy_constraint_channels(&base->object->constraintChannels, &ob->constraintChannels);
2582                                         else
2583                                                 clone_constraint_channels (&base->object->constraintChannels, &ob->constraintChannels, NULL);
2584
2585                                         base->object->activecon = NULL;
2586                                 }
2587                         }
2588                 }
2589                 base= base->next;
2590         }
2591         
2592         allqueue(REDRAWVIEW3D, 0);
2593         if(event==20) {
2594                 allqueue(REDRAWBUTSOBJECT, 0);
2595         }
2596         
2597         BIF_undo_push("Copy attributes");
2598 }
2599
2600 void link_to_scene(unsigned short nr)
2601 {       
2602         Scene *sce= (Scene*) BLI_findlink(&G.main->scene, G.curscreen->scenenr-1);
2603         Base *base, *nbase;
2604         
2605         if(sce==0) return;
2606         if(sce->id.lib) return;
2607         
2608         base= FIRSTBASE;
2609         while(base) {
2610                 if(TESTBASE(base)) {
2611                         
2612                         nbase= MEM_mallocN( sizeof(Base), "newbase");
2613                         *nbase= *base;
2614                         BLI_addhead( &(sce->base), nbase);
2615                         id_us_plus((ID *)base->object);
2616                 }
2617                 base= base->next;
2618         }
2619 }
2620
2621 void make_links_menu()
2622 {
2623         Object *ob;
2624         short event=0;
2625         char str[140];
2626         
2627         if(!(ob=OBACT)) return;
2628         
2629         strcpy(str, "Make Links %t|To Scene...%x1|%l|Object Ipo%x4");
2630         
2631         if(ob->type==OB_MESH)
2632                 strcat(str, "|Mesh Data%x2|Materials%x3");
2633         else if(ob->type==OB_CURVE)
2634                 strcat(str, "|Curve Data%x2|Materials%x3");
2635         else if(ob->type==OB_FONT)
2636                 strcat(str, "|Text Data%x2|Materials%x3");
2637         else if(ob->type==OB_SURF)
2638                 strcat(str, "|Surface Data%x2|Materials%x3");
2639         else if(ob->type==OB_MBALL)
2640                 strcat(str, "|Materials%x3");
2641         else if(ob->type==OB_CAMERA)
2642                 strcat(str, "|Camera Data%x2");
2643         else if(ob->type==OB_LAMP)
2644                 strcat(str, "|Lamp Data%x2");
2645         else if(ob->type==OB_LATTICE)
2646                 strcat(str, "|Lattice Data%x2");
2647         else if(ob->type==OB_ARMATURE)
2648                 strcat(str, "|Armature Data%x2");
2649
2650         event= pupmenu(str);
2651
2652         if(event<= 0) return;
2653         
2654         make_links(event);
2655 }
2656
2657 void make_links(short event)
2658 {
2659         Object *ob, *obt;
2660         Base *base, *nbase, *sbase;
2661         Scene *sce = NULL;
2662         ID *id;
2663         Material ***matarar, ***obmatarar, **matar1, **matar2;
2664         int a;
2665         short *totcolp, nr;
2666         char *strp;
2667
2668         if(!(ob=OBACT)) return;
2669
2670         if(event==1) {
2671                 IDnames_to_pupstring(&strp, NULL, NULL, &(G.main->scene), 0, &nr);
2672                 
2673                 if(strncmp(strp, "DataBrow", 8)==0) {
2674                         MEM_freeN(strp);
2675
2676                         activate_databrowse((ID *)G.scene, ID_SCE, 0, B_INFOSCE, &(G.curscreen->scenenr), link_to_scene );
2677                         
2678                         return;                 
2679                 }
2680                 else {
2681                         event= pupmenu(strp);
2682                         MEM_freeN(strp);
2683                 
2684                         if(event<= 0) return;
2685                 
2686                         nr= 1;
2687                         sce= G.main->scene.first;
2688                         while(sce) {
2689                                 if(nr==event) break;
2690                                 nr++;
2691                                 sce= sce->id.next;
2692                         }
2693                         if(sce==G.scene) {
2694                                 error("This is the current scene");
2695                                 return;
2696                         }
2697                         if(sce==0 || sce->id.lib) return;
2698                         
2699                         /* remember: is needed below */
2700                         event= 1;
2701                 }
2702         }
2703
2704         base= FIRSTBASE;
2705         while(base) {
2706                 if(event==1 || base != BASACT) {
2707                         
2708                         obt= base->object;
2709
2710                         if(TESTBASE(base)) {
2711                                 
2712                                 if(event==1) {          /* to scene */
2713                                         
2714                                         /* test if already linked */
2715                                         sbase= sce->base.first;
2716                                         while(sbase) {
2717                                                 if(sbase->object==base->object) break;
2718                                                 sbase= sbase->next;
2719                                         }
2720                                         if(sbase) {     /* remove */
2721                                                 base= base->next;
2722                                                 continue;
2723                                         }
2724                                         
2725                                         nbase= MEM_mallocN( sizeof(Base), "newbase");
2726                                         *nbase= *base;
2727                                         BLI_addhead( &(sce->base), nbase);
2728                                         id_us_plus((ID *)base->object);
2729                                 }
2730                         }
2731                         if(TESTBASELIB(base)) {
2732                                 if(event==2 || event==5) {  /* obdata */
2733                                         if(ob->type==obt->type) {
2734                                                 
2735                                                         id= obt->data;
2736                                                         id->us--;
2737                                                         
2738                                                         id= ob->data;
2739                                                         id_us_plus(id);
2740                                                         obt->data= id;
2741                                                         
2742                                                         /* if amount of material indices changed: */
2743                                                         test_object_materials(obt->data);
2744                                                 }
2745                                         }
2746                                 else if(event==4) {  /* ob ipo */
2747                                         if(obt->ipo) obt->ipo->id.us--;
2748                                         obt->ipo= ob->ipo;
2749                                         if(obt->ipo) {
2750                                                 id_us_plus((ID *)obt->ipo);
2751                                                 do_ob_ipo(obt);
2752                                         }
2753                                 }
2754                                 else if(event==3) {  /* materials */
2755                                         
2756                                         /* only if obt has no material: make arrays */
2757                                         /* from ob to obt! */
2758                                         
2759                                         obmatarar= give_matarar(ob);
2760                                         matarar= give_matarar(obt);
2761                                         totcolp= give_totcolp(obt);
2762
2763                                         /* if one of the two is zero: no render-able object */                                          
2764                                         if( matarar && obmatarar) {
2765                                                 
2766                                                 /* take care of users! so first a copy of original: */
2767
2768                                                 if(ob->totcol) {
2769                                                         matar1= MEM_dupallocN(ob->mat);
2770                                                         matar2= MEM_dupallocN(*obmatarar);
2771                                                 }
2772                                                 else {
2773                                                         matar1= matar2= 0;
2774                                                 }
2775                                                 
2776                                                 /* remove links from obt */
2777                                                 for(a=0; a<obt->totcol; a++) {
2778                                                         if(obt->mat[a]) obt->mat[a]->id.us--;
2779                                                         if( (*matarar)[a]) (*matarar)[a]->id.us--;
2780                                                 }
2781                                                 
2782                                                 /* free */
2783                                                 if(obt->mat) MEM_freeN(obt->mat);
2784                                                 if(*matarar) MEM_freeN(*matarar);
2785                                                 
2786                                                 /* connect a copy */
2787                                                 obt->mat= matar1;
2788                                                 *matarar= matar2;
2789                                                 obt->totcol= ob->totcol;
2790                                                 *totcolp= ob->totcol;
2791                                         
2792                                                 /* increase users */
2793                                                 for(a=0; a<obt->totcol; a++) {
2794                                                         if(obt->mat[a]) id_us_plus((ID *)obt->mat[a]);
2795                                                         if( (*matarar)[a]) id_us_plus((ID *)(*matarar)[a]);
2796                                                 }
2797
2798                                                 obt->colbits= ob->colbits;
2799                                                 
2800                                                 /* if amount of material indices changed: */
2801                                                 test_object_materials(obt->data);
2802                                         }
2803                                 }
2804                         }
2805                 }
2806                 base= base->next;
2807         }
2808         
2809         allqueue(REDRAWVIEW3D, 0);
2810         allqueue(REDRAWOOPS, 0);
2811         allqueue(REDRAWBUTSHEAD, 0);
2812         
2813         BIF_undo_push("Create links");
2814 }
2815
2816 void make_duplilist_real()
2817 {
2818         Base *base, *basen;
2819         Object *ob;
2820         extern ListBase duplilist;
2821         
2822         if(okee("Make dupli objects real")==0) return;
2823         
2824         base= FIRSTBASE;
2825         while(base) {
2826                 if TESTBASELIB(base) {
2827
2828                         if(base->object->transflag & OB_DUPLI) {
2829                                 
2830                                 make_duplilist(G.scene, base->object);
2831                                 ob= duplilist.first;
2832                                 while(ob) {
2833                                         
2834                                         /* font duplis can have a totcol without material, we get them from parent
2835                                          * should be implemented better...
2836                                          */
2837                                         if(ob->mat==0) ob->totcol= 0;
2838                                         
2839                                         basen= MEM_dupallocN(base);
2840                                         basen->flag &= ~OB_FROMDUPLI;
2841                                         BLI_addhead(&G.scene->base, basen);     /* addhead: othwise eternal loop */
2842                                         ob->ipo= 0;             /* make sure apply works */
2843                                         ob->parent= ob->track= 0;
2844                                         ob->disp.first= ob->disp.last= 0;
2845                                         ob->transflag &= ~OB_DUPLI;
2846                                         basen->object= copy_object(ob);
2847                                         
2848                                         apply_obmat(basen->object);
2849                                         ob= ob->id.next;
2850                                 }
2851                                 
2852                                 free_duplilist();
2853                                 
2854                                 base->object->transflag &= ~OB_DUPLI;   
2855                         }
2856                 }
2857                 base= base->next;
2858         }
2859         
2860         allqueue(REDRAWVIEW3D, 0);
2861         allqueue(REDRAWOOPS, 0);
2862         
2863         BIF_undo_push("Make duplicates real");
2864 }
2865
2866 void apply_object()
2867 {
2868         Base *base, *basact;
2869         Object *ob;
2870         Mesh *me;
2871         Curve *cu;
2872         Nurb *nu;
2873         BPoint *bp;
2874         BezTriple *bezt;
2875         MVert *mvert;
2876         float mat[3][3];
2877         int a;
2878
2879         if(G.scene->id.lib) return;
2880         if(G.obedit) return;
2881         basact= BASACT;
2882         
2883         if(G.qual & LR_SHIFTKEY) {
2884                 ob= OBACT;
2885                 if(ob==0) return;
2886                 
2887                 if(ob->transflag & OB_DUPLI) {
2888                         make_duplilist_real();
2889                 }
2890                 else {
2891                         if(okee("Apply deformation")) {
2892                                 object_apply_deform(ob);
2893                                 BIF_undo_push("Apply deformation");
2894                         }
2895                 }
2896                 allqueue(REDRAWVIEW3D, 0);
2897
2898                 return;