OK. Here's the long awaited first step (V0.01!) of SoftBody. It is called
[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(BASACT);
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(BASACT);
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         countall();
1441         
1442         if(ok) {
1443                 setcursor_space(SPACE_VIEW3D, CURSOR_EDIT);
1444         
1445                 allqueue(REDRAWVIEW3D, 0);
1446         }
1447         else G.obedit= 0;
1448
1449         if (G.obpose)
1450                 exit_posemode (1);
1451         scrarea_queue_headredraw(curarea);
1452 }
1453
1454 void make_displists_by_parent(Object *ob) {
1455         Base *base;
1456         
1457         for (base= FIRSTBASE; base; base= base->next)
1458                 if (ob==base->object->parent)
1459                         makeDispList(base->object);
1460 }
1461
1462 void exit_editmode(int freedata)        /* freedata==0 at render, 1= freedata, 2= do undo buffer too */
1463 {
1464         Base *base;
1465         Object *ob;
1466         Curve *cu;
1467
1468         if(G.obedit==NULL) return;
1469
1470         if(G.obedit->type==OB_MESH) {
1471
1472                 /* temporal */
1473                 countall();
1474
1475                 if(G.totvert>MESH_MAX_VERTS) {
1476                         error("Too many vertices");
1477                         return;
1478                 }
1479                 load_editMesh();        /* makes new displist */
1480
1481                 if(freedata) free_editMesh(G.editMesh);
1482
1483                 if(G.f & G_FACESELECT) {
1484                         set_seamtface();
1485                         allqueue(REDRAWIMAGE, 0);
1486                 }
1487
1488                 build_particle_system(G.obedit);
1489         }
1490         else if (G.obedit->type==OB_ARMATURE){  
1491                 load_editArmature();
1492                 if (freedata) free_editArmature();
1493         }
1494         else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
1495                 load_editNurb();
1496                 if(freedata) freeNurblist(&editNurb);
1497         }
1498         else if(G.obedit->type==OB_FONT && freedata) {
1499                 load_editText();
1500         }
1501         else if(G.obedit->type==OB_LATTICE) {
1502                 load_editLatt();
1503                 if(freedata) free_editLatt();
1504         }
1505         else if(G.obedit->type==OB_MBALL) {
1506                 load_editMball();
1507                 if(freedata) BLI_freelistN(&editelems);
1508         }
1509
1510         ob= G.obedit;
1511         
1512         /* displist make is different in editmode */
1513         if(freedata) G.obedit= NULL;
1514         makeDispList(ob);
1515
1516         /* has this influence at other objects? */
1517         if(ob->type==OB_CURVE) {
1518
1519                 /* test if ob is use as bevelcurve r textoncurve */
1520                 base= FIRSTBASE;
1521                 while(base) {
1522                         if ELEM(base->object->type, OB_CURVE, OB_FONT) {
1523                                 cu= base->object->data;
1524                                 
1525                                 if(cu->textoncurve==ob) {
1526                                         text_to_curve(base->object, 0);
1527                                         makeDispList(base->object);
1528                                 }
1529                                 if(cu->bevobj==ob || cu->taperobj==ob) {
1530                                         makeDispList(base->object);
1531                                 }
1532                         }
1533                         base= base->next;
1534                 }
1535                 
1536         }
1537         else if(ob->type==OB_LATTICE) {
1538                 make_displists_by_parent(ob);
1539         }
1540
1541         if(freedata) {
1542                 setcursor_space(SPACE_VIEW3D, CURSOR_STD);
1543         
1544                 countall();
1545                 allqueue(REDRAWVIEW3D, 0);
1546                 allqueue(REDRAWBUTSEDIT, 0);
1547                 allqueue(REDRAWBUTSLOGIC, 0);
1548         }
1549         scrarea_queue_headredraw(curarea);
1550
1551         if(ob->softflag) object_to_softbody(ob);
1552         
1553         if(G.obedit==NULL && freedata==2) 
1554                 BIF_undo_push("Editmode");
1555 }
1556
1557 void check_editmode(int type)
1558 {
1559         
1560         if (G.obedit==0 || G.obedit->type==type) return;
1561
1562         exit_editmode(2); // freedata, and undo
1563 }
1564
1565 /* 0 == do centre, 1 == centre new, 2 == centre cursor */
1566
1567 void docentre(int centremode)
1568 {
1569         EditMesh *em = G.editMesh;
1570         Base *base;
1571         Object *ob;
1572         Mesh *me, *tme;
1573         Curve *cu;
1574 //      BezTriple *bezt;
1575 //      BPoint *bp;
1576         Nurb *nu, *nu1;
1577         EditVert *eve;
1578         float cent[3], centn[3], min[3], max[3], omat[3][3];
1579         int a;
1580         MVert *mvert;
1581
1582         if(G.scene->id.lib) return;
1583
1584         if(G.obedit) {
1585
1586                 INIT_MINMAX(min, max);
1587         
1588                 if(G.obedit->type==OB_MESH) {
1589                         eve= em->verts.first;
1590                         while(eve) {
1591                                 DO_MINMAX(eve->co, min, max);
1592                                 eve= eve->next;
1593                         }
1594                         cent[0]= (min[0]+max[0])/2.0f;
1595                         cent[1]= (min[1]+max[1])/2.0f;
1596                         cent[2]= (min[2]+max[2])/2.0f;
1597                         
1598                         eve= em->verts.first;
1599                         while(eve) {
1600                                 VecSubf(eve->co, eve->co, cent);                        
1601                                 eve= eve->next;
1602                         }
1603                 }
1604         }
1605         
1606         /* reset flags */
1607         base= FIRSTBASE;
1608         while(base) {
1609                 if TESTBASELIB(base) {
1610                         base->object->flag &= ~OB_DONE;
1611                 }
1612                 base= base->next;
1613         }
1614         me= G.main->mesh.first;
1615         while(me) {
1616                 me->flag &= ~ME_ISDONE;
1617                 me= me->id.next;
1618         }
1619         
1620         base= FIRSTBASE;
1621         while(base) {
1622                 
1623                 if TESTBASELIB(base) {
1624                         if((base->object->flag & OB_DONE)==0) {
1625                                 
1626                                 base->object->flag |= OB_DONE;
1627                                 
1628                                 if(G.obedit==0 && (me=get_mesh(base->object)) ) {
1629                                         
1630                                         if(me->key) {
1631                                                 error("Can't change the center of a mesh with vertex keys");
1632                                                 return;
1633                                         }
1634                                         
1635                                         if(centremode==2) {
1636                                                 VECCOPY(cent, give_cursor());
1637                                                 Mat4Invert(base->object->imat, base->object->obmat);
1638                                                 Mat4MulVecfl(base->object->imat, cent);
1639                                         } else {
1640                                                 INIT_MINMAX(min, max);
1641                 
1642                                                 mvert= me->mvert;
1643                                                 for(a=0; a<me->totvert; a++, mvert++) {
1644                                                         DO_MINMAX(mvert->co, min, max);
1645                                                 }
1646                                 
1647                                                 cent[0]= (min[0]+max[0])/2.0f;
1648                                                 cent[1]= (min[1]+max[1])/2.0f;
1649                                                 cent[2]= (min[2]+max[2])/2.0f;
1650                                         }
1651                                                 
1652                                         mvert= me->mvert;
1653                                         for(a=0; a<me->totvert; a++, mvert++) {
1654                                                 VecSubf(mvert->co, mvert->co, cent);
1655                                         }
1656                                         me->flag |= ME_ISDONE;
1657                                         
1658                                         if(centremode) {
1659                                                 Mat3CpyMat4(omat, base->object->obmat);
1660                                                 
1661                                                 VECCOPY(centn, cent);
1662                                                 Mat3MulVecfl(omat, centn);
1663                                                 base->object->loc[0]+= centn[0];
1664                                                 base->object->loc[1]+= centn[1];
1665                                                 base->object->loc[2]+= centn[2];
1666                                                 
1667                                                 /* other users? */
1668                                                 ob= G.main->object.first;
1669                                                 while(ob) {
1670                                                         if((ob->flag & OB_DONE)==0) {
1671                                                                 tme= get_mesh(ob);
1672                                                                 
1673                                                                 if(tme==me) {
1674                                                                         
1675                                                                         ob->flag |= OB_DONE;
1676
1677                                                                         Mat3CpyMat4(omat, ob->obmat);
1678                                                                         VECCOPY(centn, cent);
1679                                                                         Mat3MulVecfl(omat, centn);
1680                                                                         ob->loc[0]+= centn[0];
1681                                                                         ob->loc[1]+= centn[1];
1682                                                                         ob->loc[2]+= centn[2];
1683                                                                         
1684                                                                         if(tme && (tme->flag & ME_ISDONE)==0) {
1685                                                                                 mvert= tme->mvert;
1686                                                                                 for(a=0; a<tme->totvert; a++, mvert++) {
1687                                                                                         VecSubf(mvert->co, mvert->co, cent);
1688                                                                                 }
1689                                                                                 tme->flag |= ME_ISDONE;
1690                                                                         }
1691                                                                 }
1692                                                         }
1693                                                         
1694                                                         ob= ob->id.next;
1695                                                 }
1696                                         }
1697                                 
1698                                         /* displist of all users, also this one */
1699                                         makeDispList(base->object);
1700                                         
1701                                         /* DO: check all users... */
1702                                         tex_space_mesh(me);
1703                 
1704                                 }
1705                                 else if ELEM(base->object->type, OB_CURVE, OB_SURF) {
1706                                                                         
1707                                         if(G.obedit) {
1708                                                 nu1= editNurb.first;
1709                                         }
1710                                         else {
1711                                                 cu= base->object->data;
1712                                                 nu1= cu->nurb.first;
1713                                         }
1714                                         
1715                                         if(centremode==2) {
1716                                                 VECCOPY(cent, give_cursor());
1717                                                 Mat4Invert(base->object->imat, base->object->obmat);
1718                                                 Mat4MulVecfl(base->object->imat, cent);
1719                                                         
1720                                                         /* Curves need to be 2d, never offset in
1721                                                          * Z. Is a somewhat arbitrary restriction, 
1722                                                          * would probably be nice to remove.
1723                                                          */
1724                                                 cent[2]= 0.0;
1725                                         } else {
1726                                                 INIT_MINMAX(min, max);
1727         
1728                                                 nu= nu1;
1729                                                 while(nu) {
1730                                                         minmaxNurb(nu, min, max);
1731                                                         nu= nu->next;
1732                                                 }
1733                                                 
1734                                                 cent[0]= (min[0]+max[0])/2.0f;
1735                                                 cent[1]= (min[1]+max[1])/2.0f;
1736                                                 cent[2]= (min[2]+max[2])/2.0f;
1737                                         }
1738                                         
1739                                         nu= nu1;
1740                                         while(nu) {
1741                                                 if( (nu->type & 7)==1) {
1742                                                         a= nu->pntsu;
1743                                                         while (a--) {
1744                                                                 VecSubf(nu->bezt[a].vec[0], nu->bezt[a].vec[0], cent);
1745                                                                 VecSubf(nu->bezt[a].vec[1], nu->bezt[a].vec[1], cent);
1746                                                                 VecSubf(nu->bezt[a].vec[2], nu->bezt[a].vec[2], cent);
1747                                                         }
1748                                                 }
1749                                                 else {
1750                                                         a= nu->pntsu*nu->pntsv;
1751                                                         while (a--)
1752                                                                 VecSubf(nu->bp[a].vec, nu->bp[a].vec, cent);
1753                                                 }
1754                                                 nu= nu->next;
1755                                         }
1756                         
1757                                         if(centremode && G.obedit==0) {
1758                                                 Mat3CpyMat4(omat, base->object->obmat);
1759                                                 
1760                                                 Mat3MulVecfl(omat, cent);
1761                                                 base->object->loc[0]+= cent[0];
1762                                                 base->object->loc[1]+= cent[1];
1763                                                 base->object->loc[2]+= cent[2];
1764                                         }
1765                         
1766                                         if(G.obedit) {
1767                                                 makeDispList(G.obedit);
1768                                                 break;
1769                                         }
1770                                         else makeDispList(base->object);
1771         
1772                                 }
1773                                 else if(base->object->type==OB_FONT) {
1774                                         /* get from bb */
1775                                         
1776                                         cu= base->object->data;
1777                                         if(cu->bb==0) return;
1778                                         
1779                                         cu->xof= -0.5f*( cu->bb->vec[4][0] - cu->bb->vec[0][0]);
1780                                         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 */
1781                                         
1782                                         /* not really ok, do this better once! */
1783                                         cu->xof /= cu->fsize;
1784                                         cu->yof /= cu->fsize;
1785                                         
1786                                         text_to_curve(base->object, 0);
1787                                         makeDispList(base->object);
1788                                         
1789                                         allqueue(REDRAWBUTSEDIT, 0);
1790                                 }
1791                         }
1792                 }
1793                 base= base->next;
1794         }
1795
1796         allqueue(REDRAWVIEW3D, 0);
1797         BIF_undo_push("Do Centre");     
1798 }
1799
1800 void docentre_new(void)
1801 {
1802         if(G.scene->id.lib) return;
1803
1804         if(G.obedit) {
1805                 error("Unable to center new in Edit Mode");
1806         }
1807         else {
1808                 docentre(1);
1809         }
1810 }
1811
1812 void docentre_cursor(void)
1813 {
1814         if(G.scene->id.lib) return;
1815
1816         if(G.obedit) {
1817                 error("Unable to center cursor in Edit Mode");
1818         }
1819         else {
1820                 docentre(2);
1821         }
1822 }
1823
1824 void movetolayer(void)
1825 {
1826         Base *base;
1827         unsigned int lay= 0, local;
1828
1829         if(G.scene->id.lib) return;
1830
1831         base= FIRSTBASE;
1832         while(base) {
1833                 if TESTBASE(base) lay |= base->lay;
1834                 base= base->next;
1835         }
1836         if(lay==0) return;
1837         lay &= 0xFFFFFF;
1838         
1839         if( movetolayer_buts(&lay)==0 ) return;
1840         if(lay==0) return;
1841
1842         base= FIRSTBASE;
1843         while(base) {
1844                 if TESTBASE(base) {
1845                         local= base->lay & 0xFF000000;
1846                         base->lay= lay + local;
1847
1848                         base->object->lay= lay;
1849                 }
1850                 base= base->next;
1851         }
1852         countall();
1853         allqueue(REDRAWBUTSEDIT, 0);
1854         allqueue(REDRAWVIEW3D, 0);
1855         allqueue(REDRAWOOPS, 0);
1856         allqueue(REDRAWINFO, 0);
1857         
1858         BIF_undo_push("Move to layer");
1859 }
1860
1861
1862 void special_editmenu(void)
1863 {
1864         extern short editbutflag;
1865         extern float doublimit;
1866         float fac;
1867         int nr,ret;
1868         short randfac;
1869         
1870         if(G.obedit==0) {
1871                 if(G.f & G_FACESELECT) {
1872                         Mesh *me= get_mesh(OBACT);
1873                         TFace *tface;
1874                         int a;
1875                         
1876                         if(me==0 || me->tface==0) return;
1877                         
1878                         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");
1879         
1880                         for(a=me->totface, tface= me->tface; a>0; a--, tface++) {
1881                                 if(tface->flag & SELECT) {
1882                                         switch(nr) {
1883                                         case 1:
1884                                                 tface->mode |= TF_TEX; break;
1885                                         case 2:
1886                                                 tface->mode |= TF_SHAREDCOL; break;
1887                                         case 3:
1888                                                 tface->mode |= TF_LIGHT; break; 
1889                                         case 4:
1890                                                 tface->mode |= TF_INVISIBLE; break;
1891                                         case 5:
1892                                                 tface->mode |= TF_DYNAMIC; break;
1893                                         case 6:
1894                                                 tface->mode &= ~TF_TEX;
1895                                                 tface->tpage= 0;
1896                                                 break;
1897                                         case 7:
1898                                                 tface->mode &= ~TF_SHAREDCOL; break;
1899                                         case 8:
1900                                                 tface->mode &= ~TF_LIGHT; break;
1901                                         case 9:
1902                                                 tface->mode &= ~TF_INVISIBLE; break;
1903                                         case 10:
1904                                                 tface->mode &= ~TF_DYNAMIC; break;
1905                                         }
1906                                 }
1907                         }
1908                         allqueue(REDRAWVIEW3D, 0);
1909                         allqueue(REDRAWBUTSEDIT, 0);
1910                         BIF_undo_push("Change texture face");
1911                 }
1912                 else if(G.f & G_VERTEXPAINT) {
1913                         Mesh *me= get_mesh(OBACT);
1914                         
1915                         if(me==0 || (me->mcol==NULL && me->tface==NULL) ) return;
1916                         
1917                         nr= pupmenu("Specials%t|Shared VertexCol%x1");
1918                         if(nr==1) {
1919                                 
1920                                 if(me->tface) tface_to_mcol(me);
1921                                 
1922                                 copy_vpaint_undo( (unsigned int *)me->mcol, me->totface);
1923                                 do_shared_vertexcol(me);
1924                                 
1925                                 if(me->tface) mcol_to_tface(me, 1);
1926                                 BIF_undo_push("Shared VertexCol");
1927                         }
1928                 }
1929                 else {
1930                         Base *base, *base_select= NULL;
1931
1932                         // Get the active object mesh.
1933                         Mesh *me= get_mesh(OBACT);
1934
1935                         // If the active object is a mesh...
1936                         if (me) {
1937                                 // Bring up a little menu with the boolean operation choices on.
1938                                 nr= pupmenu("Boolean %t|Intersect%x1|Union%x2|Difference%x3");
1939
1940                                 if (nr > 0) {
1941                                         // user has made a choice of a menu element.
1942                                         // All of the boolean functions require 2 mesh objects 
1943                                         // we search through the object list to find the other 
1944                                         // selected item and make sure it is distinct and a mesh.
1945
1946                                         base= FIRSTBASE;
1947                                         while(base) {
1948                                                 if(base->flag & SELECT) {
1949                                                         if(base->object != OBACT) base_select= base;
1950                                                 }
1951
1952                                                 base= base->next;
1953                                         }
1954
1955                                         if (base_select) {
1956                                                 if (get_mesh(base_select->object)) {
1957                                                         waitcursor(1);
1958                                                         ret = NewBooleanMesh(BASACT,base_select,nr);
1959                                                         if (ret==0) {
1960                                                                 error("An internal error occurred -- sorry!");
1961                                                         } else if(ret==-1) {
1962                                                                 error("Selected meshes must have faces to perform boolean operations");
1963                                                         }
1964                                                         else BIF_undo_push("Boolean");
1965
1966                                                         waitcursor(0);
1967                                                 } else {
1968                                                         error("Please select 2 meshes");
1969                                                 }
1970                                         } else {
1971                                                 error("Please select 2 meshes");
1972                                         }
1973                                 }
1974
1975                                 allqueue(REDRAWVIEW3D, 0);
1976                         }
1977                 }
1978         }
1979         else if(G.obedit->type==OB_MESH) {
1980
1981                 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");
1982                 if(nr>0) waitcursor(1);
1983                 
1984                 switch(nr) {
1985                 case 1:
1986                         subdivideflag(1, 0.0, editbutflag);
1987                         BIF_undo_push("Subdivide");
1988                         break;
1989                 case 2:
1990                         randfac= 10;
1991                         if(button(&randfac, 1, 100, "Rand fac:")==0) return;
1992                         fac= -( (float)randfac )/100;
1993                         subdivideflag(1, fac, editbutflag);
1994                         BIF_undo_push("Subdivide Fractal");
1995                         break;
1996                 case 3:
1997                         subdivideflag(1, 0.0, editbutflag | B_SMOOTH);
1998                         BIF_undo_push("Subdivide Smooth");
1999                         break;
2000                 case 4:
2001                         mergemenu();
2002                         break;
2003                 case 5:
2004                         notice("Removed %d Vertices", removedoublesflag(1, doublimit));
2005                         BIF_undo_push("Remove Doubles");
2006                         break;
2007                 case 6:
2008                         hide_mesh(0);
2009                         break;
2010                 case 7:
2011                         reveal_mesh();
2012                         break;
2013                 case 8:
2014                         selectswap_mesh();
2015                         break;
2016                 case 9:
2017                         flip_editnormals();
2018                         BIF_undo_push("Flip Normals");
2019                         break;
2020                 case 10:
2021                         vertexsmooth();
2022                         break;
2023                 case 11:
2024                         bevel_menu();
2025                         break;
2026                 }               
2027                 
2028                 makeDispList(G.obedit);
2029                 
2030                 if(nr>0) waitcursor(0);
2031                 
2032         }
2033         else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
2034
2035                 nr= pupmenu("Specials%t|Subdivide%x1|Switch Direction%x2");
2036                 
2037                 switch(nr) {
2038                 case 1:
2039                         subdivideNurb();
2040                         break;
2041                 case 2:
2042                         switchdirectionNurb2();
2043                         break;
2044                 }
2045         }
2046
2047         countall();
2048         allqueue(REDRAWVIEW3D, 0);
2049         
2050 }
2051
2052 void convertmenu(void)
2053 {
2054         Base *base, *basen, *basact;
2055         Object *ob, *ob1;
2056         Curve *cu;
2057         MetaBall *mb;
2058         Mesh *me;
2059         DispList *dl;
2060         int ok=0, nr = 0, a;
2061         
2062         if(G.scene->id.lib) return;
2063
2064         ob= OBACT;
2065         if(ob==0) return;
2066         if(G.obedit) return;
2067         
2068         basact= BASACT; /* will be restored */
2069                 
2070         if(ob->type==OB_FONT) {
2071                 nr= pupmenu("Convert Font to%t|Curve");
2072                 if(nr>0) ok= 1;
2073         }
2074         else if(ob->type==OB_MBALL) {
2075                 nr= pupmenu("Convert Metaball to%t|Mesh (keep original)");
2076                 if(nr>0) ok= 1;
2077         }
2078         else if(ob->type==OB_CURVE) {
2079                 nr= pupmenu("Convert Curve to%t|Mesh");
2080                 if(nr>0) ok= 1;
2081         }
2082         else if(ob->type==OB_SURF) {
2083                 nr= pupmenu("Convert Nurbs Surface to%t|Mesh");
2084                 if(nr>0) ok= 1;
2085         }
2086         else if(ob->type==OB_MESH && mesh_uses_displist((Mesh*) ob->data)) {
2087                 nr= pupmenu("Convert SubSurf to%t|Mesh (Keep Original)");
2088                 if(nr>0) ok= 1;
2089         }
2090         if(ok==0) return;
2091
2092         /* don't forget multiple users! */
2093
2094         /* reset flags */
2095         base= FIRSTBASE;
2096         while(base) {
2097                 if TESTBASELIB(base) {
2098                         base->object->flag &= ~OB_DONE;
2099                 }
2100                 base= base->next;
2101         }
2102
2103         base= FIRSTBASE;
2104         while(base) {
2105                 if TESTBASELIB(base) {
2106                         
2107                         ob= base->object;
2108                         
2109                         if(ob->flag & OB_DONE);
2110                         else if(ob->type==OB_MESH) {
2111                                 Mesh *oldme= ob->data;
2112                                 
2113                                 if (mesh_uses_displist(oldme)) {
2114                                         DispListMesh *dlm;
2115
2116                                         ob->flag |= OB_DONE;
2117
2118                                         ob1= copy_object(ob);
2119
2120                                         basen= MEM_mallocN(sizeof(Base), "duplibase");
2121                                         *basen= *base;
2122                                         BLI_addhead(&G.scene->base, basen);     /* addhead: otherwise eternal loop */
2123                                         basen->object= ob1;
2124                                         basen->flag &= ~SELECT;
2125                                                 
2126                                         me= ob1->data;
2127                                         me->id.us--;
2128                                                 
2129                                         ob1->data= add_mesh();
2130                                         G.totmesh++;
2131                                         ob1->type= OB_MESH;
2132
2133                                         me= ob1->data;
2134                                         me->totcol= oldme->totcol;
2135                                         if(ob1->totcol) {
2136                                                 me->mat= MEM_dupallocN(oldme->mat);
2137                                                 for(a=0; a<ob1->totcol; a++) id_us_plus((ID *)me->mat[a]);
2138                                         }
2139                                                 
2140                                         dlm= subsurf_make_dispListMesh_from_mesh(oldme, NULL, oldme->subdiv, oldme->flag);
2141                                         displistmesh_to_mesh(dlm, ob1->data);
2142                                         displistmesh_free(dlm);
2143
2144                                         tex_space_mesh(me);
2145                                 }
2146                         }
2147                         else if(ob->type==OB_FONT) {
2148                                 if(nr==1) {
2149                                 
2150                                         ob->flag |= OB_DONE;
2151                                 
2152                                         ob->type= OB_CURVE;
2153                                         cu= ob->data;
2154                                         
2155                                         if(cu->vfont) {
2156                                                 cu->vfont->id.us--;
2157                                                 cu->vfont= 0;
2158                                         }
2159                                         /* other users */
2160                                         if(cu->id.us>1) {
2161                                                 ob1= G.main->object.first;
2162                                                 while(ob1) {
2163                                                         if(ob1->data==cu) ob1->type= OB_CURVE;
2164                                                         ob1= ob1->id.next;
2165                                                 }
2166                                         }
2167                                 }
2168                         }
2169                         else if ELEM(ob->type, OB_CURVE, OB_SURF) {
2170                                 if(nr==1) {
2171
2172                                         ob->flag |= OB_DONE;
2173                                         cu= ob->data;
2174                                         
2175                                         dl= cu->disp.first;
2176                                         if(dl==0) makeDispList(ob);
2177
2178                                         nurbs_to_mesh(ob); /* also does users */
2179
2180                                         /* texspace and normals */
2181                                         BASACT= base;
2182                                         enter_editmode();
2183                                         exit_editmode(1); // freedata, but no undo
2184                                         BASACT= basact;
2185                                 }
2186                         }
2187                         else if(ob->type==OB_MBALL) {
2188                         
2189                                 if(nr==1) {
2190                                         ob= find_basis_mball(ob);
2191                                         
2192                                         if(ob->disp.first && !(ob->flag&OB_DONE)) {
2193                                         
2194                                                 ob->flag |= OB_DONE;
2195
2196                                                 ob1= copy_object(ob);
2197
2198                                                 basen= MEM_mallocN(sizeof(Base), "duplibase");
2199                                                 *basen= *base;
2200                                                 BLI_addhead(&G.scene->base, basen);     /* addhead: othwise eternal loop */
2201                                                 basen->object= ob1;
2202                                                 basen->flag &= ~SELECT;
2203                                                 
2204                                                 mb= ob1->data;
2205                                                 mb->id.us--;
2206                                                 
2207                                                 ob1->data= add_mesh();
2208                                                 G.totmesh++;
2209                                                 ob1->type= OB_MESH;
2210                                                 
2211                                                 me= ob1->data;
2212                                                 me->totcol= mb->totcol;
2213                                                 if(ob1->totcol) {
2214                                                         me->mat= MEM_dupallocN(mb->mat);
2215                                                         for(a=0; a<ob1->totcol; a++) id_us_plus((ID *)me->mat[a]);
2216                                                 }
2217                                                 
2218                                                 mball_to_mesh(&ob->disp, ob1->data);
2219                                                 tex_space_mesh(me);
2220                                         }
2221                                 }
2222                         }
2223                 }
2224                 base= base->next;
2225         }
2226         
2227         allqueue(REDRAWVIEW3D, 0);
2228         allqueue(REDRAWOOPS, 0);
2229         allqueue(REDRAWBUTSEDIT, 0);
2230         BIF_undo_push("Convert Object");
2231 }
2232
2233         /* Change subdivision properties of mesh object ob, if
2234          * level==-1 then toggle subsurf, else set to level.
2235          */
2236 void flip_subdivison(Object *ob, int level)
2237 {
2238         Mesh *me = ob->data;
2239
2240         if (level == -1) {
2241                 me->flag ^= ME_SUBSURF;
2242         } else {
2243                 me->subdiv = level;
2244         }
2245
2246         allqueue(REDRAWVIEW3D, 0);
2247         allqueue(REDRAWOOPS, 0);
2248         allqueue(REDRAWBUTSEDIT, 0);
2249         makeDispList(ob);
2250         
2251         BIF_undo_push("Switch subsurf on/off");
2252 }
2253  
2254 void copymenu_properties(Object *ob)
2255 {       
2256         bProperty *prop, *propn, *propc;
2257         Base *base;
2258         int nr, tot=0;
2259         char *str;
2260         
2261         prop= ob->prop.first;
2262         while(prop) {
2263                 tot++;
2264                 prop= prop->next;
2265         }
2266         
2267         if(tot==0) {
2268                 error("No properties in the active object to copy");
2269                 return;
2270         }
2271         
2272         str= MEM_callocN(24+32*tot, "copymenu prop");
2273         
2274         strcpy(str, "Copy Property %t");
2275         
2276         tot= 0; 
2277         prop= ob->prop.first;
2278         while(prop) {
2279                 tot++;
2280                 strcat(str, " |");
2281                 strcat(str, prop->name);
2282                 prop= prop->next;
2283         }
2284
2285         nr= pupmenu(str);
2286         if(nr>0) {
2287                 tot= 0;
2288                 prop= ob->prop.first;
2289                 while(prop) {
2290                         tot++;
2291                         if(tot==nr) break;
2292                         prop= prop->next;
2293                 }
2294                 if(prop) {
2295                         propc= prop;
2296                         
2297                         base= FIRSTBASE;
2298                         while(base) {
2299                                 if(base != BASACT) {
2300                                         if(TESTBASELIB(base)) {
2301                                                 prop= get_property(base->object, propc->name);
2302                                                 if(prop) {
2303                                                         free_property(prop);
2304                                                         BLI_remlink(&base->object->prop, prop);
2305                                                 }
2306                                                 propn= copy_property(propc);
2307                                                 BLI_addtail(&base->object->prop, propn);
2308                                         }
2309                                 }
2310                                 base= base->next;
2311                         }
2312                 }
2313         }
2314         MEM_freeN(str);
2315         allqueue(REDRAWVIEW3D, 0);
2316         
2317         BIF_undo_push("Copy properties");
2318 }
2319
2320 void copymenu_logicbricks(Object *ob)
2321 {
2322         Base *base;
2323         
2324         base= FIRSTBASE;
2325         while(base) {
2326                 if(base->object != ob) {
2327                         if(TESTBASELIB(base)) {
2328                                 
2329                                 /* first: free all logic */
2330                                 free_sensors(&base->object->sensors);                           
2331                                 unlink_controllers(&base->object->controllers);
2332                                 free_controllers(&base->object->controllers);
2333                                 unlink_actuators(&base->object->actuators);
2334                                 free_actuators(&base->object->actuators);
2335                                 
2336                                 /* now copy it, this also works without logicbricks! */
2337                                 clear_sca_new_poins_ob(ob);
2338                                 copy_sensors(&base->object->sensors, &ob->sensors);
2339                                 copy_controllers(&base->object->controllers, &ob->controllers);
2340                                 copy_actuators(&base->object->actuators, &ob->actuators);
2341                                 set_sca_new_poins_ob(base->object);
2342                                 
2343                                 /* some menu settings */
2344                                 base->object->scavisflag= ob->scavisflag;
2345                                 base->object->scaflag= ob->scaflag;
2346                                 
2347                         }
2348                 }
2349                 base= base->next;
2350         }
2351         BIF_undo_push("Copy logic");
2352 }
2353
2354 void copy_attr_menu()
2355 {
2356         Object *ob;
2357         short event;
2358         char str[256];
2359
2360         /* If you change this menu, don't forget to update the menu in header_view3d.c
2361          * view3d_edit_object_copyattrmenu() and in toolbox.c
2362          */
2363         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");
2364
2365         if(!(ob=OBACT)) return;
2366         
2367         strcat (str, "|Object Constraints%x22");
2368         
2369         if ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL) {
2370                 strcat(str, "|Texture Space%x17");
2371         }       
2372         
2373         if(ob->type == OB_FONT) strcat(str, "|Font Settings%x18|Bevel Settings%x19");
2374         if(ob->type == OB_CURVE) strcat(str, "|Bevel Settings%x19");
2375
2376         if(ob->type==OB_MESH){
2377                 strcat(str, "|Subdiv%x21");
2378         }
2379
2380         if( give_parteff(ob) ) strcat(str, "|Particle Settings%x20");
2381
2382         event= pupmenu(str);
2383         if(event<= 0) return;
2384         
2385         copy_attr(event);
2386 }
2387
2388 void copy_attr(short event)
2389 {
2390         Object *ob, *obt;
2391         Base *base;
2392         Curve *cu, *cu1;
2393         void *poin1, *poin2=0;
2394         
2395         if(G.scene->id.lib) return;
2396
2397         if(!(ob=OBACT)) return;
2398         
2399         if(G.obedit) {
2400                 /* obedit_copymenu(); */
2401                 return;
2402         }
2403         
2404         if ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL) {
2405                 if(ob->type==OB_MESH) poin2= &(((Mesh *)ob->data)->texflag);
2406                 else if ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT) poin2= &(((Curve *)ob->data)->texflag);
2407                 else if(ob->type==OB_MBALL) poin2= &(((MetaBall *)ob->data)->texflag);
2408         }       
2409
2410         if(event==9) {
2411                 copymenu_properties(ob);
2412                 return;
2413         }
2414         else if(event==10) {
2415                 copymenu_logicbricks(ob);
2416                 return;
2417         }
2418
2419         base= FIRSTBASE;
2420         while(base) {
2421                 if(base != BASACT) {
2422                         if(TESTBASELIB(base)) {
2423                                 
2424                                 if(event==1) {  /* loc */
2425                                         VECCOPY(base->object->loc, ob->loc);
2426                                         VECCOPY(base->object->dloc, ob->dloc);
2427                                 }
2428                                 else if(event==2) {  /* rot */
2429                                         VECCOPY(base->object->rot, ob->rot);
2430                                         VECCOPY(base->object->drot, ob->drot);
2431                                         VECCOPY(base->object->quat, ob->quat);
2432                                         VECCOPY(base->object->dquat, ob->dquat);
2433                                 }
2434                                 else if(event==3) {  /* size */
2435                                         VECCOPY(base->object->size, ob->size);
2436                                         VECCOPY(base->object->dsize, ob->dsize);
2437                                 }
2438                                 else if(event==4) {  /* drawtype */
2439                                         base->object->dt= ob->dt;
2440                                         base->object->dtx= ob->dtx;
2441                                         }
2442                                 else if(event==5) {  /* time offs */
2443                                         base->object->sf= ob->sf;
2444                                 }
2445                                 else if(event==6) {  /* dupli */
2446                                         base->object->dupon= ob->dupon;
2447                                         base->object->dupoff= ob->dupoff;
2448                                         base->object->dupsta= ob->dupsta;
2449                                         base->object->dupend= ob->dupend;
2450                                         
2451                                         base->object->transflag &= ~OB_DUPLI;
2452                                         base->object->transflag |= (ob->transflag & OB_DUPLI);
2453                                 }
2454                                 else if(event==7) {     /* mass */
2455                                         base->object->mass= ob->mass;
2456                                 }
2457                                 else if(event==8) {     /* damping */
2458                                         base->object->damping= ob->damping;
2459                                         base->object->rdamping= ob->rdamping;
2460                                 }
2461                                 else if(event==17) {    /* tex space */
2462                                         obt= base->object;
2463                                         poin1= 0;
2464                                         if(obt->type==OB_MESH) poin1= &(((Mesh *)obt->data)->texflag);
2465                                         else if ELEM3(obt->type, OB_CURVE, OB_SURF, OB_FONT) poin1= &(((Curve *)obt->data)->texflag);
2466                                         else if(obt->type==OB_MBALL) poin1= &(((MetaBall *)obt->data)->texflag);                                        
2467                                         
2468                                         if(poin1) {
2469                                                 memcpy(poin1, poin2, 4+12+12+12);
2470                                         
2471                                                 if(obt->type==OB_MESH) tex_space_mesh(obt->data);
2472                                                 else if(obt->type==OB_MBALL) tex_space_mball(obt);
2473                                                 else tex_space_curve(obt->data);
2474                                         }
2475                                 }
2476                                 else if(event==18) {    /* font settings */
2477                                         
2478                                         if(base->object->type==ob->type) {
2479                                                 cu= ob->data;
2480                                                 cu1= base->object->data;
2481                                                 
2482                                                 cu1->spacemode= cu->spacemode;
2483                                                 cu1->spacing= cu->spacing;
2484                                                 cu1->linedist= cu->linedist;
2485                                                 cu1->shear= cu->shear;
2486                                                 cu1->fsize= cu->fsize;
2487                                                 cu1->xof= cu->xof;
2488                                                 cu1->yof= cu->yof;
2489                                                 cu1->textoncurve= cu->textoncurve;
2490                                                 if(cu1->vfont) cu1->vfont->id.us--;
2491                                                 cu1->vfont= cu->vfont;
2492                                                 id_us_plus((ID *)cu1->vfont);
2493                                                 text_to_curve(base->object, 0);
2494                                                 
2495                                                 strcpy(cu1->family, cu->family);
2496                                                 
2497                                                 makeDispList(base->object);
2498                                         }
2499                                 }
2500                                 else if(event==19) {    /* bevel settings */
2501                                         
2502                                         if ELEM(base->object->type, OB_CURVE, OB_FONT) {
2503                                                 cu= ob->data;
2504                                                 cu1= base->object->data;
2505                                                 
2506                                                 cu1->bevobj= cu->bevobj;
2507                                                 cu1->taperobj= cu->taperobj;
2508                                                 cu1->width= cu->width;
2509                                                 cu1->bevresol= cu->bevresol;
2510                                                 cu1->ext1= cu->ext1;
2511                                                 cu1->ext2= cu->ext2;
2512                                                 
2513                                                 makeDispList(base->object);
2514                                         }
2515                                 }
2516                                 else if(event==20) {    /* particle settings */
2517                                         PartEff *pa1, *pa2;
2518                                         char *p1, *p2;
2519                                         
2520                                         pa1= give_parteff(ob);
2521                                         pa2= give_parteff(base->object);
2522
2523                                         if(pa1==0 && pa2) {
2524                                                 BLI_remlink( &(base->object->effect), pa2);
2525                                                 free_effect( (Effect *) pa2);
2526                                         }
2527                                         else if(pa1 && pa2==0) {
2528                                                 free_effects(&(base->object->effect));
2529                                                 copy_effects(&(base->object->effect), &ob->effect);
2530                                                 build_particle_system(base->object);
2531                                         }
2532                                         else if(pa1 && pa2) {
2533                                                 if(pa2->keys) MEM_freeN(pa2->keys);
2534                                                 
2535                                                 p1= (char *)pa1; p2= (char *)pa2;
2536                                                 memcpy( p2+8, p1+8, sizeof(PartEff) - 8);
2537                                                 pa2->keys= 0;
2538                                                 
2539                                                 build_particle_system(base->object);
2540                                         }
2541                                 }
2542                                 else if(event==21){
2543                                         if (base->object->type==OB_MESH) {
2544                                                 Mesh *targetme= base->object->data;
2545                                                 Mesh *sourceme= ob->data;
2546
2547                                                 targetme->flag= (targetme->flag&~ME_SUBSURF) | (sourceme->flag&ME_SUBSURF);
2548                                                 targetme->subsurftype = sourceme->subsurftype;
2549                                                 targetme->subdiv= sourceme->subdiv;
2550                                                 targetme->subdivr= sourceme->subdivr;
2551                                                 makeDispList(base->object);
2552                                         }
2553                                 }
2554                                 else if(event==22){
2555                                         /* Clear the constraints on the target */
2556                                         free_constraints(&base->object->constraints);
2557                                         free_constraint_channels(&base->object->constraintChannels);
2558
2559                                         /* Copy the constraint channels over */
2560                                         copy_constraints(&base->object->constraints, &ob->constraints);
2561                                         if (U.dupflag& USER_DUP_IPO)
2562                                                 copy_constraint_channels(&base->object->constraintChannels, &ob->constraintChannels);
2563                                         else
2564                                                 clone_constraint_channels (&base->object->constraintChannels, &ob->constraintChannels, NULL);
2565
2566                                         base->object->activecon = NULL;
2567                                 }
2568                         }
2569                 }
2570                 base= base->next;
2571         }
2572         
2573         allqueue(REDRAWVIEW3D, 0);
2574         if(event==20) {
2575                 allqueue(REDRAWBUTSOBJECT, 0);
2576         }
2577         
2578         BIF_undo_push("Copy attributes");
2579 }
2580
2581 void link_to_scene(unsigned short nr)
2582 {       
2583         Scene *sce= (Scene*) BLI_findlink(&G.main->scene, G.curscreen->scenenr-1);
2584         Base *base, *nbase;
2585         
2586         if(sce==0) return;
2587         if(sce->id.lib) return;
2588         
2589         base= FIRSTBASE;
2590         while(base) {
2591                 if(TESTBASE(base)) {
2592                         
2593                         nbase= MEM_mallocN( sizeof(Base), "newbase");
2594                         *nbase= *base;
2595                         BLI_addhead( &(sce->base), nbase);
2596                         id_us_plus((ID *)base->object);
2597                 }
2598                 base= base->next;
2599         }
2600 }
2601
2602 void make_links_menu()
2603 {
2604         Object *ob;
2605         short event=0;
2606         char str[140];
2607         
2608         if(!(ob=OBACT)) return;
2609         
2610         strcpy(str, "Make Links %t|To Scene...%x1|%l|Object Ipo%x4");
2611         
2612         if(ob->type==OB_MESH)
2613                 strcat(str, "|Mesh Data%x2|Materials%x3");
2614         else if(ob->type==OB_CURVE)
2615                 strcat(str, "|Curve Data%x2|Materials%x3");
2616         else if(ob->type==OB_FONT)
2617                 strcat(str, "|Text Data%x2|Materials%x3");
2618         else if(ob->type==OB_SURF)
2619                 strcat(str, "|Surface Data%x2|Materials%x3");
2620         else if(ob->type==OB_MBALL)
2621                 strcat(str, "|Materials%x3");
2622         else if(ob->type==OB_CAMERA)
2623                 strcat(str, "|Camera Data%x2");
2624         else if(ob->type==OB_LAMP)
2625                 strcat(str, "|Lamp Data%x2");
2626         else if(ob->type==OB_LATTICE)
2627                 strcat(str, "|Lattice Data%x2");
2628         else if(ob->type==OB_ARMATURE)
2629                 strcat(str, "|Armature Data%x2");
2630
2631         event= pupmenu(str);
2632
2633         if(event<= 0) return;
2634         
2635         make_links(event);
2636 }
2637
2638 void make_links(short event)
2639 {
2640         Object *ob, *obt;
2641         Base *base, *nbase, *sbase;
2642         Scene *sce = NULL;
2643         ID *id;
2644         Material ***matarar, ***obmatarar, **matar1, **matar2;
2645         int a;
2646         short *totcolp, nr;
2647         char *strp;
2648
2649         if(!(ob=OBACT)) return;
2650
2651         if(event==1) {
2652                 IDnames_to_pupstring(&strp, NULL, NULL, &(G.main->scene), 0, &nr);
2653                 
2654                 if(strncmp(strp, "DataBrow", 8)==0) {
2655                         MEM_freeN(strp);
2656
2657                         activate_databrowse((ID *)G.scene, ID_SCE, 0, B_INFOSCE, &(G.curscreen->scenenr), link_to_scene );
2658                         
2659                         return;                 
2660                 }
2661                 else {
2662                         event= pupmenu(strp);
2663                         MEM_freeN(strp);
2664                 
2665                         if(event<= 0) return;
2666                 
2667                         nr= 1;
2668                         sce= G.main->scene.first;
2669                         while(sce) {
2670                                 if(nr==event) break;
2671                                 nr++;
2672                                 sce= sce->id.next;
2673                         }
2674                         if(sce==G.scene) {
2675                                 error("This is the current scene");
2676                                 return;
2677                         }
2678                         if(sce==0 || sce->id.lib) return;
2679                         
2680                         /* remember: is needed below */
2681                         event= 1;
2682                 }
2683         }
2684
2685         base= FIRSTBASE;
2686         while(base) {
2687                 if(event==1 || base != BASACT) {
2688                         
2689                         obt= base->object;
2690
2691                         if(TESTBASE(base)) {
2692                                 
2693                                 if(event==1) {          /* to scene */
2694                                         
2695                                         /* test if already linked */
2696                                         sbase= sce->base.first;
2697                                         while(sbase) {
2698                                                 if(sbase->object==base->object) break;
2699                                                 sbase= sbase->next;
2700                                         }
2701                                         if(sbase) {     /* remove */
2702                                                 base= base->next;
2703                                                 continue;
2704                                         }
2705                                         
2706                                         nbase= MEM_mallocN( sizeof(Base), "newbase");
2707                                         *nbase= *base;
2708                                         BLI_addhead( &(sce->base), nbase);
2709                                         id_us_plus((ID *)base->object);
2710                                 }
2711                         }
2712                         if(TESTBASELIB(base)) {
2713                                 if(event==2 || event==5) {  /* obdata */
2714                                         if(ob->type==obt->type) {
2715                                                 
2716                                                         id= obt->data;
2717                                                         id->us--;
2718                                                         
2719                                                         id= ob->data;
2720                                                         id_us_plus(id);
2721                                                         obt->data= id;
2722                                                         
2723                                                         /* if amount of material indices changed: */
2724                                                         test_object_materials(obt->data);
2725                                                 }
2726                                         }
2727                                 else if(event==4) {  /* ob ipo */
2728                                         if(obt->ipo) obt->ipo->id.us--;
2729                                         obt->ipo= ob->ipo;
2730                                         if(obt->ipo) {
2731                                                 id_us_plus((ID *)obt->ipo);
2732                                                 do_ob_ipo(obt);
2733                                         }
2734                                 }
2735                                 else if(event==3) {  /* materials */
2736                                         
2737                                         /* only if obt has no material: make arrays */
2738                                         /* from ob to obt! */
2739                                         
2740                                         obmatarar= give_matarar(ob);
2741                                         matarar= give_matarar(obt);
2742                                         totcolp= give_totcolp(obt);
2743
2744                                         /* if one of the two is zero: no render-able object */                                          
2745                                         if( matarar && obmatarar) {
2746                                                 
2747                                                 /* take care of users! so first a copy of original: */
2748
2749                                                 if(ob->totcol) {
2750                                                         matar1= MEM_dupallocN(ob->mat);
2751                                                         matar2= MEM_dupallocN(*obmatarar);
2752                                                 }
2753                                                 else {
2754                                                         matar1= matar2= 0;
2755                                                 }
2756                                                 
2757                                                 /* remove links from obt */
2758                                                 for(a=0; a<obt->totcol; a++) {
2759                                                         if(obt->mat[a]) obt->mat[a]->id.us--;
2760                                                         if( (*matarar)[a]) (*matarar)[a]->id.us--;
2761                                                 }
2762                                                 
2763                                                 /* free */
2764                                                 if(obt->mat) MEM_freeN(obt->mat);
2765                                                 if(*matarar) MEM_freeN(*matarar);
2766                                                 
2767                                                 /* connect a copy */
2768                                                 obt->mat= matar1;
2769                                                 *matarar= matar2;
2770                                                 obt->totcol= ob->totcol;
2771                                                 *totcolp= ob->totcol;
2772                                         
2773                                                 /* increase users */
2774                                                 for(a=0; a<obt->totcol; a++) {
2775                                                         if(obt->mat[a]) id_us_plus((ID *)obt->mat[a]);
2776                                                         if( (*matarar)[a]) id_us_plus((ID *)(*matarar)[a]);
2777                                                 }
2778
2779                                                 obt->colbits= ob->colbits;
2780                                                 
2781                                                 /* if amount of material indices changed: */
2782                                                 test_object_materials(obt->data);
2783                                         }
2784                                 }
2785                         }
2786                 }
2787                 base= base->next;
2788         }
2789         
2790         allqueue(REDRAWVIEW3D, 0);
2791         allqueue(REDRAWOOPS, 0);
2792         allqueue(REDRAWBUTSHEAD, 0);
2793         
2794         BIF_undo_push("Create links");
2795 }
2796
2797 void make_duplilist_real()
2798 {
2799         Base *base, *basen;
2800         Object *ob;
2801         extern ListBase duplilist;
2802         
2803         if(okee("Make dupli objects real")==0) return;
2804         
2805         base= FIRSTBASE;
2806         while(base) {
2807                 if TESTBASELIB(base) {
2808
2809                         if(base->object->transflag & OB_DUPLI) {
2810                                 
2811                                 make_duplilist(G.scene, base->object);
2812                                 ob= duplilist.first;
2813                                 while(ob) {
2814                                         
2815                                         /* font duplis can have a totcol without material, we get them from parent
2816                                          * should be implemented better...
2817                                          */
2818                                         if(ob->mat==0) ob->totcol= 0;
2819                                         
2820                                         basen= MEM_dupallocN(base);
2821                                         basen->flag &= ~OB_FROMDUPLI;
2822                                         BLI_addhead(&G.scene->base, basen);     /* addhead: othwise eternal loop */
2823                                         ob->ipo= 0;             /* make sure apply works */
2824                                         ob->parent= ob->track= 0;
2825                                         ob->disp.first= ob->disp.last= 0;
2826                                         ob->transflag &= ~OB_DUPLI;
2827                                         basen->object= copy_object(ob);
2828                                         
2829                                         apply_obmat(basen->object);
2830                                         ob= ob->id.next;
2831                                 }
2832                                 
2833                                 free_duplilist();
2834                                 
2835                                 base->object->transflag &= ~OB_DUPLI;   
2836                         }
2837                 }
2838                 base= base->next;
2839         }
2840         
2841         allqueue(REDRAWVIEW3D, 0);
2842         allqueue(REDRAWOOPS, 0);
2843         
2844         BIF_undo_push("Make duplicates real");
2845 }
2846
2847 void apply_object()
2848 {
2849         Base *base, *basact;
2850         Object *ob;
2851         Mesh *me;
2852         Curve *cu;
2853         Nurb *nu;
2854         BPoint *bp;
2855         BezTriple *bezt;
2856         MVert *mvert;
2857         float mat[3][3];
2858         int a;
2859
2860         if(G.scene->id.lib) return;
2861         if(G.obedit) return;
2862         basact= BASACT;
2863         
2864         if(G.qual & LR_SHIFTKEY) {
2865                 ob= OBACT;
2866                 if(ob==0) return;
2867                 
2868                 if(ob->transflag & OB_DUPLI) make_duplilist_real();
2869                 else {
2870                         if(okee("Apply deformation")==0) return;
2871                         object_apply_deform(ob);
2872                         allqueue(REDRAWVIEW3D, 0);
2873
2874                         return;
2875                 }
2876         }
2877
2878         if(okee("Apply size and rotation")==0) return;
2879
2880         base= FIRSTBASE;
2881         while(base) {
2882                 if TESTBASELIB(base) {
2883                         ob= base->object;
2884         
2885                         if(ob->type==OB_MESH) {
2886                                 object_to_mat3(ob, mat);
2887                                 me= ob->data;
2888                                 
2889                                 if(me->id.us>1) {
2890                                         error("Can't apply to a multi user mesh");
2891                                         return;
2892                                 }
2893                                 if(me->key) {
2894                                         error("Can't apply to a mesh with vertex keys");
2895                                         return;
2896                                 }
2897