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