f681b65925f2aeb9aecde776c82b29841e583b85
[blender.git] / source / blender / src / edit.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <math.h>
31 #include <string.h>
32
33 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif
36
37 #ifndef WIN32
38 #include <unistd.h>
39 #else
40 #include <io.h>
41 #endif   
42
43 #include "MEM_guardedalloc.h"
44
45 #include "BMF_Api.h"
46
47 #include "PIL_time.h"
48
49 #include "DNA_action_types.h"
50 #include "DNA_armature_types.h"
51 #include "DNA_curve_types.h"
52 #include "DNA_group_types.h"
53 #include "DNA_ipo_types.h"
54 #include "DNA_lattice_types.h"
55 #include "DNA_meta_types.h"
56 #include "DNA_mesh_types.h"
57 #include "DNA_modifier_types.h"
58 #include "DNA_object_types.h"
59 #include "DNA_particle_types.h"
60 #include "DNA_screen_types.h"
61 #include "DNA_scene_types.h"
62 #include "DNA_space_types.h"
63 #include "DNA_view3d_types.h"
64 #include "DNA_userdef_types.h"  /* for U.dupflag */
65 #include "BLI_blenlib.h"
66 #include "BLI_arithb.h"
67 #include "BLI_editVert.h"
68 #include "BLI_linklist.h"
69
70 #include "BKE_action.h"
71 #include "BKE_armature.h"
72 #include "BKE_anim.h"
73 #include "BKE_curve.h"
74 #include "BKE_depsgraph.h"
75 #include "BKE_DerivedMesh.h"
76 #include "BKE_displist.h"
77 #include "BKE_global.h"
78 #include "BKE_ipo.h"
79 #include "BKE_lattice.h"
80 #include "BKE_mesh.h"
81 #include "BKE_modifier.h"
82 #include "BKE_object.h"
83 #include "BKE_particle.h"
84 #include "BKE_utildefines.h"
85
86 #ifdef WITH_VERSE
87 #include "BKE_verse.h"
88 #endif
89
90 #include "BIF_editmesh.h"
91 #include "BIF_editview.h"
92 #include "BIF_editarmature.h"
93 #include "BIF_editparticle.h"
94 #include "BIF_gl.h"
95 #include "BIF_glutil.h"
96 #include "BIF_interface.h"
97 #include "BIF_mywindow.h"
98 #include "BIF_resources.h"
99 #include "BIF_space.h"
100 #include "BIF_screen.h"
101 #include "BIF_toolbox.h"
102 #include "BIF_sketch.h"
103
104 #ifdef WITH_VERSE
105 #include "BIF_verse.h"
106 #endif
107
108 #include "BSE_edit.h"
109 #include "BSE_drawipo.h"
110 #include "BSE_drawview.h"
111 #include "BSE_trans_types.h"
112 #include "BSE_view.h"
113
114 #include "BDR_editobject.h"
115 #include "BDR_editmball.h"
116 #include "BDR_editcurve.h"
117
118 /* old stuff */
119 #include "blendef.h"
120 #include "mydevice.h"
121
122 /*#include "armature.h"*/
123 /*  #include "edit.h" */
124 #include "nla.h"
125 #include "transform.h"
126
127 #ifdef __NLA
128 #include "BIF_editarmature.h"
129 #endif
130
131
132 /* circle selection callback */
133 typedef void (*select_CBfunc)(short selecting, Object *editobj, short *mval, float rad);
134
135 extern void obedit_selectionCB(short selecting, Object *editobj, 
136                                short *mval, float rad);
137 extern void uvedit_selectionCB(short selecting, Object *editobj, 
138                                short *mval, float rad);
139
140 static void circle_selectCB(select_CBfunc func);
141
142
143 /* flag==2 only border, flag==3 cross+border
144    flag==5 cross + border + start&end frame
145  */
146 int get_border(rcti *rect, short flag)
147 {
148         float dvec[4], fac1, fac2;
149         int retval=1;
150         unsigned short event= 0;
151         short mval[2], mvalo[4], val, x1, y1;
152         char str[64];
153
154         mywinset(G.curscreen->mainwin);
155         
156         /* slightly larger, 1 pixel at the edge */
157         glReadBuffer(GL_FRONT);
158         glDrawBuffer(GL_FRONT);
159
160         /* removed my_get_frontbuffer, this crashes when it gets a part outside the screen */
161         /* solved it with just a redraw! */
162
163         mywinset(curarea->win);
164         
165         glDrawBuffer(GL_FRONT);
166         persp(PERSP_WIN);
167         initgrabz(0.0, 0.0, 0.0);
168         
169         if(flag & 1) {
170                 getmouseco_areawin(mvalo);
171
172                 /* draws the selection initial cross */
173                 sdrawXORline4(0, 0,  mvalo[1],  curarea->winx,  mvalo[1]);
174                 sdrawXORline4(1, mvalo[0],  0,  mvalo[0],  curarea->winy); 
175                 bglFlush();
176                 
177                 while(TRUE) {
178                 
179                         /* selection loop while mouse pressed */
180                         getmouseco_areawin(mval);
181                         
182                         if(mvalo[0]!=mval[0] || mvalo[1]!=mval[1]) {
183
184                                 /* aiming cross */
185                                 sdrawXORline4(0, 0,  mval[1],  curarea->winx,  mval[1]);
186                                 sdrawXORline4(1, mval[0],  0,  mval[0],  curarea->winy);
187                                 bglFlush();
188
189                                 mvalo[0]= mval[0];
190                                 mvalo[1]= mval[1];
191                         }
192                         event= extern_qread(&val);
193
194                         if(event && val) {
195
196                                 /* for when a renderwindow is open, and a mouse cursor activates it */
197                                 persp(PERSP_VIEW);
198                                 mywinset(curarea->win);
199                                 persp(PERSP_WIN);
200                                 
201                                 if(event==ESCKEY) {
202                                         retval= 0;
203                                         break;
204                                 }
205                                 else if(event==BKEY) {
206                                         /* b has been pressed twice: proceed with circle select */
207                                         retval= 0;
208                                         break;
209                                 }
210                                 else if(event==LEFTMOUSE) break;
211                                 else if(event==MIDDLEMOUSE) break;
212                                 else if(event==RIGHTMOUSE) break;
213                         }
214                         else PIL_sleep_ms(10);
215                         
216                 } /* end while (TRUE) */
217
218                 /* erase XORed lines */
219                 sdrawXORline4(-1, 0, 0, 0, 0);
220         }
221         else getmouseco_areawin(mval);
222         
223         if(retval) {
224                 /* box select */
225                 x1= mval[0];
226                 y1= mval[1];
227                 
228                 getmouseco_areawin(mvalo);
229
230                 sdrawXORline4(0, x1, y1, x1, mvalo[1]); 
231                 sdrawXORline4(1, x1, mvalo[1], mvalo[0], mvalo[1]); 
232                 sdrawXORline4(2, mvalo[0], mvalo[1], mvalo[0], y1); 
233                 sdrawXORline4(3,  mvalo[0], y1, x1, y1); 
234                 bglFlush();
235                         
236                 while(TRUE) {
237                         getmouseco_areawin(mval);
238                         if(mvalo[0]!=mval[0] || mvalo[1]!=mval[1]) {
239
240                                 sdrawXORline4(0, x1, y1, x1, mval[1]); 
241                                 sdrawXORline4(1, x1, mval[1], mval[0], mval[1]); 
242                                 sdrawXORline4(2, mval[0], mval[1], mval[0], y1); 
243                                 sdrawXORline4(3,  mval[0], y1, x1, y1); 
244                                 
245                                 /* draw size information in corner */
246                                 if(curarea->spacetype==SPACE_VIEW3D) {
247                                         BIF_ThemeColor(TH_BACK);
248                                         glRecti(10, 25, 250, 40);
249         
250                                         if(G.vd->persp==V3D_ORTHO) {
251                                                 window_to_3d(dvec, mvalo[0]-x1, mvalo[1]-y1);
252         
253                                                 sprintf(str, "X %.4f  Y %.4f  Z %.4f  Dia %.4f", dvec[0], dvec[1], dvec[2], sqrt(dvec[0]*dvec[0]+dvec[1]*dvec[1]+dvec[2]*dvec[2]));
254                                                 glColor3f(0.0, 0.0, 0.0); 
255                                                 glRasterPos2i(15,  27);
256                                                 BMF_DrawString(G.fonts, str);
257                                                 glColor3f(0.7, 0.7, 0.7); 
258                                                 glRasterPos2i(16,  28);
259                                                 BMF_DrawString(G.fonts, str);
260                                         }
261                                         else if(G.vd->persp==V3D_CAMOB) {
262                                                 rctf vb;
263         
264                                                 calc_viewborder(G.vd, &vb);
265         
266                                                 fac1= (mvalo[0]-x1)/( (float) (vb.xmax-vb.xmin) );
267                                                 fac1*= 0.01*G.scene->r.size*G.scene->r.xsch;
268                                                 
269                                                 fac2= (mvalo[1]-y1)/( (float) (vb.ymax-vb.ymin) );
270                                                 fac2*= 0.01*G.scene->r.size*G.scene->r.ysch;
271                                                 
272                                                 sprintf(str, "X %.1f  Y %.1f  Dia %.1f", fabs(fac1), fabs(fac2), sqrt(fac1*fac1 + fac2*fac2) );
273                                                 glColor3f(0.0, 0.0, 0.0); 
274                                                 glRasterPos2i(15,  27);
275                                                 BMF_DrawString(G.fonts, str);
276                                                 glColor3f(0.7, 0.7, 0.7); 
277                                                 glRasterPos2i(16,  28);
278                                                 BMF_DrawString(G.fonts, str);
279                                         }
280                                 }
281                                 else if(curarea->spacetype==SPACE_IPO) {
282                                         SpaceIpo *sipo= curarea->spacedata.first;
283         
284                                         BIF_ThemeColor(TH_BACK);
285                                         glRecti(20, 30, 170, 40);
286                                                                 
287                                         mvalo[2]= x1;
288                                         mvalo[3]= y1;
289                                         areamouseco_to_ipoco(&sipo->v2d, mval, dvec, dvec+1);
290                                         areamouseco_to_ipoco(&sipo->v2d, mvalo+2, dvec+2, dvec+3);
291
292                                         if (flag == 5) {
293                                                 /* setting preview range */
294                                                 if (dvec[0] < dvec[2])
295                                                         sprintf(str, "Preview Range: %d to %d", (int)dvec[0], (int)dvec[2]);
296                                                 else
297                                                         sprintf(str, "Preview Range: %d to %d", (int)dvec[2], (int)dvec[0]);
298                                         }
299                                         else
300                                                 sprintf(str, "Time: %.4f  Y %.4f", dvec[0]-dvec[2], dvec[1]-dvec[3]);
301                                         
302                                         BIF_ThemeColor(TH_BACK);
303                                         glRecti(14, 24, 165, 38);
304                                         
305                                         glColor3f(0.0, 0.0, 0.0); 
306                                         glRasterPos2i(15,  27);
307                                         BMF_DrawString(G.fonts, str);
308                                         glColor3f(0.8, 0.8, 0.8); 
309                                         glRasterPos2i(16,  28);
310                                         BMF_DrawString(G.fonts, str);
311                                 }
312                                 else if ((ELEM3(curarea->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_TIME)) && flag==5) {
313                                         /* only while setting preview range */
314                                         View2D *v2d;
315                                         
316                                         switch (curarea->spacetype) 
317                                         {
318                                                 case SPACE_ACTION:
319                                                 {
320                                                         SpaceAction *saaction= curarea->spacedata.first;
321                                                         v2d= &saaction->v2d;
322                                                 }
323                                                         break;
324                                                 case SPACE_NLA:
325                                                 {
326                                                         SpaceNla *snla= curarea->spacedata.first;
327                                                         v2d= &snla->v2d;
328                                                 }
329                                                         break;
330                                                 default:
331                                                         v2d= G.v2d;
332                                                         break;
333                                         }
334                                         
335                                         mvalo[2]= x1;
336                                         mvalo[3]= y1;
337                                         areamouseco_to_ipoco(v2d, mval, dvec, dvec+1);
338                                         areamouseco_to_ipoco(v2d, mvalo+2, dvec+2, dvec+3);
339                                         
340                                         if (dvec[0] < dvec[2])
341                                                 sprintf(str, "Preview Range: %d to %d", (int)dvec[0], (int)dvec[2]);
342                                         else
343                                                 sprintf(str, "Preview Range: %d to %d", (int)dvec[2], (int)dvec[0]);
344                                         
345                                         BIF_ThemeColor(TH_BACK);
346                                         glRecti(14, 24, 165, 38);
347                                         
348                                         glColor3f(0.0, 0.0, 0.0); 
349                                         glRasterPos2i(15,  27);
350                                         BMF_DrawString(G.fonts, str);
351                                         glColor3f(0.8, 0.8, 0.8); 
352                                         glRasterPos2i(16,  28);
353                                         BMF_DrawString(G.fonts, str);
354                                 }
355
356                                 bglFlush();
357
358                                 mvalo[0]= mval[0];
359                                 mvalo[1]= mval[1];
360                         }
361                         
362                         event= extern_qread(&val);
363                         
364                         if(event && val==0) {
365                                 /* still because of the renderwindow... */
366                                 persp(PERSP_VIEW);
367                                 mywinset(curarea->win);
368                                 persp(PERSP_WIN);
369                                 
370                                 if(event==ESCKEY) {
371                                         retval= 0;
372                                         break;
373                                 }
374                                 else if(event==LEFTMOUSE) break;
375                                 else if(event==MIDDLEMOUSE) break;
376                                 else if(event==RIGHTMOUSE) break;
377                         }
378                         
379                 } /* end while (TRUE) */
380                 sdrawXORline4(-1, 0, 0, 0, 0);
381                 
382                 if(retval) {
383                         rect->xmin= x1;
384                         rect->ymin= y1;
385                         rect->xmax= mval[0];
386                         rect->ymax= mval[1];
387                         retval= event;
388
389                         /* normalize */
390                         if(rect->xmin>rect->xmax) SWAP(int, rect->xmin, rect->xmax);
391                         if(rect->ymin>rect->ymax) SWAP(int, rect->ymin, rect->ymax);
392                         
393                         if(rect->xmin==rect->xmax) retval= 0;
394                         if(rect->ymin==rect->ymax) retval= 0;
395                 }
396         }
397
398
399         /* clear */
400         if(event!=BKEY) {
401                 if ELEM(curarea->spacetype, SPACE_VIEW3D, SPACE_IPO) {
402                         scrarea_queue_winredraw(curarea);
403                 }
404                 else if ELEM3(curarea->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_TIME) {
405                         scrarea_queue_winredraw(curarea); // only really needed for 
406                 }
407         }
408         
409         bglFlush();
410         glReadBuffer(GL_BACK);
411         glDrawBuffer(GL_BACK);
412
413         persp(PERSP_VIEW);
414         
415         /* pressed B again ? -> brush select */
416         if(event==BKEY) {
417                 setlinestyle(0);
418                 switch (curarea->spacetype) {
419                 case SPACE_VIEW3D:
420                         if (G.obedit) {
421                                 if ELEM4(G.obedit->type, OB_MESH, OB_CURVE, OB_SURF, OB_LATTICE) {
422                                         circle_selectCB(&obedit_selectionCB);
423                                 }
424                         }
425                         else if (FACESEL_PAINT_TEST) {
426                                 circle_selectCB(&obedit_selectionCB);
427                         }
428                         else if (G.f&G_PARTICLEEDIT) {
429                                 circle_selectCB(&PE_selectionCB);
430                         }
431                         return 0;
432                         
433                 case SPACE_IMAGE: // brush select in UV editor
434                         circle_selectCB(&uvedit_selectionCB);
435                         // this is a hack; we return 0 that the caller from get_border
436                         // doesn't execute the selection code for border select..
437                         return 0;
438                 }
439         }
440         return retval;
441 }
442
443 void draw_sel_circle(short *mval, short *mvalo, float rad, float rado, int selecting)
444 {
445         static short no_mvalo=0;
446
447         if(mval==NULL && mvalo==NULL) { /* signal */
448                 no_mvalo= 1;
449                 return;
450         }
451
452         persp(PERSP_WIN);
453         glReadBuffer(GL_FRONT);
454         glDrawBuffer(GL_FRONT);
455         //setlinestyle(2);
456
457         /* draw circle */
458         if(mvalo && no_mvalo==0) {
459                 fdrawXORcirc(mvalo[0], mvalo[1], rado);
460         }
461         
462         if(mval) {
463                 fdrawXORcirc(mval[0], mval[1], rad);
464         }
465         //setlinestyle(0);
466
467         bglFlush();
468         persp(PERSP_VIEW);
469         glDrawBuffer(GL_BACK);
470         glReadBuffer(GL_BACK);
471
472         no_mvalo= 0;
473 }
474
475 /** This function does the same as editview.c:circle_select(),
476   * but the selection actions are defined by a callback, making
477   * it (hopefully) reusable for other windows than the 3D view.
478   */
479
480 static void circle_selectCB(select_CBfunc callback)
481 {
482         static float rad= 40.0;
483         float rado= rad;
484         int firsttime=1;
485         int escape= 0;
486         unsigned short event;
487         short mvalo[2], mval[2], val;
488         short selecting=0;
489         Object *obj;
490         
491         if(G.obedit) obj = G.obedit;
492         else obj = OBACT;
493
494         mywinset(curarea->win);
495         
496         getmouseco_areawin(mvalo);
497         mval[0]= mvalo[0]; mval[1]= mvalo[1];
498
499         draw_sel_circle(mval, NULL, rad, 0.0, selecting); // draws frontbuffer, but sets backbuf again
500         
501         while(TRUE) {
502                 
503                 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || rado!=rad || firsttime) {
504                         firsttime= 0;
505                         
506                         if(selecting) {
507                                 callback(selecting, obj, mval, rad);
508                         }
509
510                         draw_sel_circle(mval, mvalo, rad, rado, selecting);
511                 
512                         mvalo[0]= mval[0];
513                         mvalo[1]= mval[1];
514                         rado= rad;
515
516                 }
517                 
518                 while(qtest()) {
519                         event= extern_qread(&val);
520                         if (event) {
521
522                                 /* for when another window is open and a mouse cursor activates it */
523                                 if(event!=MOUSEY && event!=MOUSEX) mywinset(curarea->win);
524                                 
525                                 getmouseco_areawin(mval);       // important to do here, trust events!
526                                 
527                                 switch(event) {
528                         
529                                 case LEFTMOUSE:
530                                 case MIDDLEMOUSE:
531                                         if(val) selecting= event;
532                                         else selecting= 0;
533                                         firsttime= 1;
534                                         
535                                         break;
536                                 case PAGEUPKEY:
537                                 case WHEELDOWNMOUSE:
538                                 case PADPLUSKEY:
539                                 case EQUALKEY:
540                                         if(val) if(rad<200.0) rad*= 1.2;
541                                         break;
542                                 case PAGEDOWNKEY:
543                                 case WHEELUPMOUSE:
544                                 case PADMINUS:
545                                 case MINUSKEY:
546                                         if(val) if(rad>5.0) rad/= 1.2;
547                                         break;
548                                 
549                                 case ESCKEY: case SPACEKEY: case RIGHTMOUSE: case INPUTCHANGE: 
550                                 case GKEY: case SKEY: case RKEY: case XKEY: case EKEY: case TABKEY:
551                                         escape= 1;
552                                         break;
553
554                                 }
555                                 
556                                 if(escape) break;
557                         }
558                 }
559                 PIL_sleep_ms(10);
560                 
561                 if(escape) break;
562         }
563         
564         /* clear circle */
565         draw_sel_circle(NULL, mvalo, 0, rad, 1);
566         BIF_undo_push("Circle Select");
567         countall();
568         allqueue(REDRAWINFO, 0);
569 }
570
571 static void count_object(Object *ob, int sel, int totob)
572 {
573         Mesh *me;
574         Curve *cu;
575         DerivedMesh *dm;
576         int tot=0, totf=0;
577
578         switch(ob->type) {
579         case OB_MESH:
580                         G.totmesh+=totob;
581                         me= get_mesh(ob);
582                         if(me) {
583                                         int totvert, totedge, totface;
584                                         dm = mesh_get_derived_final(ob, get_viewedit_datamask());
585                                         totvert = dm->getNumVerts(dm);
586                                         totedge = dm->getNumEdges(dm);
587                                         totface = dm->getNumFaces(dm);
588
589                                         G.totvert+= totvert*totob;
590                                         G.totedge+= totedge*totob;
591                                         G.totface+= totface*totob;
592                                         if(sel) {
593                                                         G.totvertsel+= totvert;
594                                                         G.totfacesel+= totface;
595                                         }
596                         }
597                         break;
598
599         case OB_LAMP:
600                 G.totlamp+=totob;
601                 break;
602         case OB_SURF:
603         case OB_CURVE:
604         case OB_FONT:
605                 G.totcurve+=totob;
606                 tot=totf= 0;
607                 cu= ob->data;
608                 if(cu->disp.first)
609                         count_displist( &cu->disp, &tot, &totf);
610                 tot*= totob;
611                 totf*= totob;
612                 G.totvert+= tot;
613                 G.totface+= totf;
614                 if(sel) {
615                         G.totvertsel+= tot;
616                         G.totfacesel+= totf;
617                 }
618                 break;
619         case OB_MBALL:
620                 count_displist( &ob->disp, &tot, &totf);
621                 tot*= totob;
622                 totf*= totob;
623                 G.totvert+= tot;
624                 G.totface+= totf;
625                 if(sel) {
626                         G.totvertsel+= tot;
627                         G.totfacesel+= totf;
628                 }
629                 break;
630         }
631         
632 }
633
634 /* countall does statistics */
635 /* is called on most actions, like select/add/delete/layermove */
636 void countall()
637 {
638         extern ListBase editNurb;
639         Base *base;
640         Object *ob= OBACT;
641         Mesh *me;
642         Nurb *nu;
643         BezTriple *bezt;
644         BPoint *bp;
645         MetaElem *ml;
646         struct EditBone *ebo;
647         int a;
648
649         G.totvert= G.totvertsel= G.totedge= G.totedgesel= G.totfacesel= G.totface= G.totobj= 
650             G.totmesh= G.totlamp= G.totcurve= G.totobjsel= G.totbone= G.totbonesel=  0;
651
652         if(G.obedit) {
653                 
654                 if(G.obedit->type==OB_MESH) {
655                         EditMesh *em = G.editMesh;
656                         EditVert *eve;
657                         EditEdge *eed;
658                         EditFace *efa;
659                         
660                         for(eve= em->verts.first; eve; eve= eve->next) {
661                                 G.totvert++;
662                                 if(eve->f & SELECT) G.totvertsel++;
663                         }
664                         for(eed= em->edges.first; eed; eed= eed->next) {
665                                 G.totedge++;
666                                 if(eed->f & SELECT) G.totedgesel++;
667                         }
668                         for(efa= em->faces.first; efa; efa= efa->next) {
669                                 G.totface++;
670                                 if(efa->f & SELECT) G.totfacesel++;
671                         }
672                         
673                         EM_validate_selections();
674                 }
675                 else if (G.obedit->type==OB_ARMATURE){
676                         for (ebo=G.edbo.first;ebo;ebo=ebo->next){
677                                 G.totbone++;
678                                 
679                                 /* Sync selection to parent for connected children */
680                                 if ((ebo->flag & BONE_CONNECTED) && ebo->parent){
681                                         G.totvert--;
682                                         if (ebo->parent->flag & BONE_TIPSEL)
683                                                 ebo->flag |= BONE_ROOTSEL;
684                                         else
685                                                 ebo->flag &= ~BONE_ROOTSEL;
686                                 }
687                                 
688                                 if (ebo->flag & BONE_TIPSEL)
689                                         G.totvertsel++;
690                                 if (ebo->flag & BONE_ROOTSEL)
691                                         G.totvertsel++;
692                                 
693                                 if ((ebo->flag & BONE_TIPSEL) && (ebo->flag & BONE_ROOTSEL))
694                                         ebo->flag |= BONE_SELECTED;
695                                 else
696                                         ebo->flag &= ~BONE_SELECTED;
697                                 
698                                 if(ebo->flag & BONE_SELECTED) G.totbonesel++;
699
700                                 //      If this is a connected child and it's parent is being moved, remove our root
701                                 if ((ebo->flag & BONE_CONNECTED)&& (ebo->flag & BONE_ROOTSEL) && ebo->parent && (ebo->parent->flag & BONE_TIPSEL)){
702                                         G.totvertsel--;
703                                 }
704
705                                 G.totvert+=2;
706                         }
707                 }
708                 else if ELEM3(G.obedit->type, OB_CURVE, OB_SURF, OB_FONT) {
709                         nu= editNurb.first;
710                         while(nu) {
711                                 if((nu->type & 7)==CU_BEZIER) {
712                                         bezt= nu->bezt;
713                                         a= nu->pntsu;
714                                         while(a--) {
715                                                 G.totvert+=3;
716                                                 if(bezt->f1) G.totvertsel++;
717                                                 if(bezt->f2) G.totvertsel++;
718                                                 if(bezt->f3) G.totvertsel++;
719                                                 bezt++;
720                                         }
721                                 }
722                                 else {
723                                         bp= nu->bp;
724                                         a= nu->pntsu*nu->pntsv;
725                                         while(a--) {
726                                                 G.totvert++;
727                                                 if(bp->f1 & SELECT) G.totvertsel++;
728                                                 bp++;
729                                         }
730                                 }
731                                 nu= nu->next;
732                         }
733                 }
734                 else if(G.obedit->type==OB_MBALL) {
735                         /* editmball.c */
736                         extern ListBase editelems;  /* go away ! */
737                         
738                         ml= editelems.first;
739                         while(ml) {
740                                 G.totvert++;
741                                 if(ml->flag & SELECT) G.totvertsel++;
742                                 ml= ml->next;
743                         }
744                 }
745                 else if(G.obedit->type==OB_LATTICE) {
746                         bp= editLatt->def;
747                         
748                         a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
749                         while(a--) {
750                                 G.totvert++;
751                                 if(bp->f1 & SELECT) G.totvertsel++;
752                                 bp++;
753                         }
754                 }
755                 
756                 allqueue(REDRAWINFO, 1);        /* 1, because header->win==0! */
757                 return;
758         }
759         else if(ob && (ob->flag & OB_POSEMODE)) {
760                 if(ob->pose) {
761                         bArmature *arm= ob->data;
762                         bPoseChannel *pchan;
763                         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
764                                 G.totbone++;
765                                 if(pchan->bone && (pchan->bone->flag & BONE_SELECTED))
766                                         if(pchan->bone->layer & arm->layer)
767                                                 G.totbonesel++;
768                         }
769                 }
770                 allqueue(REDRAWINFO, 1);        /* 1, because header->win==0! */
771                 return;
772         }
773         else if(FACESEL_PAINT_TEST) {
774                 me= get_mesh((G.scene->basact) ? (G.scene->basact->object) : 0);
775                 if(me) {
776                         G.totface= me->totface;
777                         G.totvert= me->totvert;
778                 }
779                 allqueue(REDRAWINFO, 1);        /* 1, because header->win==0! */
780                 return;
781         }
782
783         if(G.scene==NULL) return;
784
785         base= (G.scene->base.first);
786         while(base) {
787                 if(G.scene->lay & base->lay) {
788                         ob= base->object;       /* warning, ob not is obact anymore */
789                         
790                         if(base->flag & SELECT) G.totobjsel++;
791
792                         if(ob->transflag & OB_DUPLIPARTS) {
793                                 ParticleSystem *psys;
794                                 ParticleSettings *part;
795                                 int step_nbr;
796
797                                 for(psys=ob->particlesystem.first; psys; psys=psys->next){
798                                         part=psys->part;
799                                         
800                                         //if(psys->flag&PSYS_BAKED && part->draw&PART_DRAW_KEYS)
801                                         //      step_nbr=part->keys_step;
802                                         //else
803                                                 step_nbr=1;
804
805                                         if(part->draw_as==PART_DRAW_OB && part->dup_ob){
806                                                 int tot=count_particles(psys);
807                                                 count_object(part->dup_ob, 0, tot*step_nbr);
808                                         }
809                                         else if(part->draw_as==PART_DRAW_GR && part->dup_group){
810                                                 GroupObject *go;
811                                                 int tot, totgroup=0, cur=0;
812                                                 
813                                                 go= part->dup_group->gobject.first;
814                                                 while(go){
815                                                         go=go->next;
816                                                         totgroup++;
817                                                 }
818                                                 go= part->dup_group->gobject.first;
819                                                 while(go){
820                                                         tot=count_particles_mod(psys,totgroup,cur);
821                                                         count_object(go->ob, 0, tot*step_nbr);
822                                                         cur++;
823                                                         go=go->next;
824                                                 }
825                                         }
826                                 }
827                                 
828                                 count_object(ob, base->flag & SELECT, 1);
829                                 G.totobj++;
830                         }
831                         else if(ob->parent && (ob->parent->transflag & (OB_DUPLIVERTS|OB_DUPLIFACES))) {
832                                 int tot= count_duplilist(ob->parent);
833                                 G.totobj+=tot;
834                                 count_object(ob, base->flag & SELECT, tot);
835                         }
836                         else if(ob->transflag & OB_DUPLIFRAMES) {
837                                 int tot= count_duplilist(ob);
838                                 G.totobj+=tot;
839                                 count_object(ob, base->flag & SELECT, tot);
840                         }
841                         else if((ob->transflag & OB_DUPLIGROUP) && ob->dup_group) {
842                                 int tot= count_duplilist(ob);
843                                 G.totobj+=tot;
844                                 count_object(ob, base->flag & SELECT, tot);
845                         }
846                         else {
847                                 count_object(ob, base->flag & SELECT, 1);
848                                 G.totobj++;
849                         }
850                 }
851                 base= base->next;
852         }
853         allqueue(REDRAWINFO, 1);        /* 1, because header->win==0! */
854 }
855
856 /* ************************************************** */
857 /* ********************* old transform stuff ******** */
858 /* ************************************************** */
859
860 static TransVert *transvmain=NULL;
861 static int tottrans= 0;
862
863 /* copied from editobject.c, now uses (almost) proper depgraph */
864 static void special_transvert_update(void)
865 {
866         
867         if(G.obedit) {
868                 
869                 DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
870                 
871                 if(G.obedit->type==OB_MESH) {
872 #ifdef WITH_VERSE
873                         if(G.editMesh->vnode)
874                                 sync_all_verseverts_with_editverts((VNode*)G.editMesh->vnode);
875 #endif
876                         recalc_editnormals();   // does face centers too
877                 }
878                 else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
879                         extern ListBase editNurb;
880                         Nurb *nu= editNurb.first;
881                         while(nu) {
882                                 test2DNurb(nu);
883                                 testhandlesNurb(nu); /* test for bezier too */
884                                 nu= nu->next;
885                         }
886                 }
887                 else if(G.obedit->type==OB_ARMATURE){
888                         bArmature *arm= G.obedit->data;
889                         EditBone *ebo;
890                         TransVert *tv= transvmain;
891                         int a=0;
892                         
893                         /* Ensure all bone tails are correctly adjusted */
894                         for (ebo=G.edbo.first; ebo; ebo=ebo->next) {
895                                 /* adjust tip if both ends selected */
896                                 if ((ebo->flag & BONE_ROOTSEL) && (ebo->flag & BONE_TIPSEL)) {
897                                         if (tv) {
898                                                 float diffvec[3];
899                                                 
900                                                 VecSubf(diffvec, tv->loc, tv->oldloc);
901                                                 VecAddf(ebo->tail, ebo->tail, diffvec);
902                                                 
903                                                 a++;
904                                                 if (a<tottrans) tv++;
905                                         }
906                                 }
907                         }
908                         
909                         /* Ensure all bones are correctly adjusted */
910                         for (ebo=G.edbo.first; ebo; ebo=ebo->next) {
911                                 if ((ebo->flag & BONE_CONNECTED) && ebo->parent){
912                                         /* If this bone has a parent tip that has been moved */
913                                         if (ebo->parent->flag & BONE_TIPSEL){
914                                                 VECCOPY (ebo->head, ebo->parent->tail);
915                                         }
916                                         /* If this bone has a parent tip that has NOT been moved */
917                                         else{
918                                                 VECCOPY (ebo->parent->tail, ebo->head);
919                                         }
920                                 }
921                         }
922                         if(arm->flag & ARM_MIRROR_EDIT) 
923                                 transform_armature_mirror_update();
924                 }
925                 else if(G.obedit->type==OB_LATTICE) {
926                         if(editLatt->flag & LT_OUTSIDE) outside_lattice(editLatt);
927                 }
928         }
929 }
930
931 /* copied from editobject.c, needs to be replaced with new transform code still */
932 /* mode: 1 = proportional, 2 = all joints (for bones only) */
933 static void make_trans_verts(float *min, float *max, int mode)  
934 {
935         extern ListBase editNurb;
936         EditMesh *em = G.editMesh;
937         Nurb *nu;
938         BezTriple *bezt;
939         BPoint *bp;
940         TransVert *tv=NULL;
941         MetaElem *ml;
942         EditVert *eve;
943         EditBone        *ebo;
944         float total, center[3], centroid[3];
945         int a;
946
947         tottrans= 0; // global!
948         
949         INIT_MINMAX(min, max);
950         centroid[0]=centroid[1]=centroid[2]= 0.0;
951         
952         /* note for transform refactor: dont rely on countall anymore... its ancient */
953         /* I skip it for editmesh now (ton) */
954         if(G.obedit->type!=OB_MESH) {
955                 countall();
956                 if(mode) tottrans= G.totvert;
957                 else tottrans= G.totvertsel;
958
959                 if(G.totvertsel==0) {
960                         tottrans= 0;
961                         return;
962                 }
963                 tv=transvmain= MEM_callocN(tottrans*sizeof(TransVert), "maketransverts");
964         }
965         
966         /* we count again because of hide (old, not for mesh!) */
967         tottrans= 0;
968         
969         if(G.obedit->type==OB_MESH) {
970                 int proptrans= 0;
971                 
972                 // transform now requires awareness for select mode, so we tag the f1 flags in verts
973                 tottrans= 0;
974                 if(G.scene->selectmode & SCE_SELECT_VERTEX) {
975                         for(eve= em->verts.first; eve; eve= eve->next) {
976                                 if(eve->h==0 && (eve->f & SELECT)) {
977                                         eve->f1= SELECT;
978                                         tottrans++;
979                                 }
980                                 else eve->f1= 0;
981                         }
982                 }
983                 else if(G.scene->selectmode & SCE_SELECT_EDGE) {
984                         EditEdge *eed;
985                         for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
986                         for(eed= em->edges.first; eed; eed= eed->next) {
987                                 if(eed->h==0 && (eed->f & SELECT)) eed->v1->f1= eed->v2->f1= SELECT;
988                         }
989                         for(eve= em->verts.first; eve; eve= eve->next) if(eve->f1) tottrans++;
990                 }
991                 else {
992                         EditFace *efa;
993                         for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
994                         for(efa= em->faces.first; efa; efa= efa->next) {
995                                 if(efa->h==0 && (efa->f & SELECT)) {
996                                         efa->v1->f1= efa->v2->f1= efa->v3->f1= SELECT;
997                                         if(efa->v4) efa->v4->f1= SELECT;
998                                 }
999                         }
1000                         for(eve= em->verts.first; eve; eve= eve->next) if(eve->f1) tottrans++;
1001                 }
1002                 
1003                 /* proportional edit exception... */
1004                 if((mode & 1) && tottrans) {
1005                         for(eve= em->verts.first; eve; eve= eve->next) {
1006                                 if(eve->h==0) {
1007                                         eve->f1 |= 2;
1008                                         proptrans++;
1009                                 }
1010                         }
1011                         if(proptrans>tottrans) tottrans= proptrans;
1012                 }
1013                 
1014                 /* and now make transverts */
1015                 if(tottrans) {
1016                         tv=transvmain= MEM_callocN(tottrans*sizeof(TransVert), "maketransverts");
1017
1018                         for(eve= em->verts.first; eve; eve= eve->next) {
1019                                 if(eve->f1) {
1020                                         VECCOPY(tv->oldloc, eve->co);
1021                                         tv->loc= eve->co;
1022                                         if(eve->no[0]!=0.0 || eve->no[1]!=0.0 ||eve->no[2]!=0.0)
1023                                                 tv->nor= eve->no; // note this is a hackish signal (ton)
1024                                         tv->flag= eve->f1 & SELECT;
1025                                         tv++;
1026                                 }
1027                         }
1028                 }
1029         }
1030         else if (G.obedit->type==OB_ARMATURE){
1031                 bArmature *arm= G.obedit->data;
1032                 
1033                 for (ebo=G.edbo.first;ebo;ebo=ebo->next){
1034                         if(ebo->layer & arm->layer) {
1035                                 short tipsel= (ebo->flag & BONE_TIPSEL);
1036                                 short rootsel= (ebo->flag & BONE_ROOTSEL);
1037                                 short rootok= (!(ebo->parent && (ebo->flag & BONE_CONNECTED) && ebo->parent->flag & BONE_TIPSEL));
1038                                 
1039                                 if ((tipsel && rootsel) || (rootsel)) {
1040                                         /* Don't add the tip (unless mode & 2, for getting all joints), 
1041                                          * otherwise we get zero-length bones as tips will snap to the same
1042                                          * location as heads. 
1043                                          */
1044                                         if (rootok) {
1045                                                 VECCOPY (tv->oldloc, ebo->head);
1046                                                 tv->loc= ebo->head;
1047                                                 tv->nor= NULL;
1048                                                 tv->flag= 1;
1049                                                 tv++;
1050                                                 tottrans++;
1051                                         }       
1052                                         
1053                                         if ((mode & 2) && (tipsel)) {
1054                                                 VECCOPY (tv->oldloc, ebo->tail);
1055                                                 tv->loc= ebo->tail;
1056                                                 tv->nor= NULL;
1057                                                 tv->flag= 1;
1058                                                 tv++;
1059                                                 tottrans++;
1060                                         }                                       
1061                                 }
1062                                 else if (tipsel) {
1063                                         VECCOPY (tv->oldloc, ebo->tail);
1064                                         tv->loc= ebo->tail;
1065                                         tv->nor= NULL;
1066                                         tv->flag= 1;
1067                                         tv++;
1068                                         tottrans++;
1069                                 }
1070                         }                       
1071                 }
1072         }
1073         else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
1074                 nu= editNurb.first;
1075                 while(nu) {
1076                         if((nu->type & 7)==CU_BEZIER) {
1077                                 a= nu->pntsu;
1078                                 bezt= nu->bezt;
1079                                 while(a--) {
1080                                         if(bezt->hide==0) {
1081                                                 if((mode & 1) || (bezt->f1 & SELECT)) {
1082                                                         VECCOPY(tv->oldloc, bezt->vec[0]);
1083                                                         tv->loc= bezt->vec[0];
1084                                                         tv->flag= bezt->f1 & SELECT;
1085                                                         tv++;
1086                                                         tottrans++;
1087                                                 }
1088                                                 if((mode & 1) || (bezt->f2 & SELECT)) {
1089                                                         VECCOPY(tv->oldloc, bezt->vec[1]);
1090                                                         tv->loc= bezt->vec[1];
1091                                                         tv->val= &(bezt->alfa);
1092                                                         tv->oldval= bezt->alfa;
1093                                                         tv->flag= bezt->f2 & SELECT;
1094                                                         tv++;
1095                                                         tottrans++;
1096                                                 }
1097                                                 if((mode & 1) || (bezt->f3 & SELECT)) {
1098                                                         VECCOPY(tv->oldloc, bezt->vec[2]);
1099                                                         tv->loc= bezt->vec[2];
1100                                                         tv->flag= bezt->f3 & SELECT;
1101                                                         tv++;
1102                                                         tottrans++;
1103                                                 }
1104                                         }
1105                                         bezt++;
1106                                 }
1107                         }
1108                         else {
1109                                 a= nu->pntsu*nu->pntsv;
1110                                 bp= nu->bp;
1111                                 while(a--) {
1112                                         if(bp->hide==0) {
1113                                                 if((mode & 1) || (bp->f1 & SELECT)) {
1114                                                         VECCOPY(tv->oldloc, bp->vec);
1115                                                         tv->loc= bp->vec;
1116                                                         tv->val= &(bp->alfa);
1117                                                         tv->oldval= bp->alfa;
1118                                                         tv->flag= bp->f1 & SELECT;
1119                                                         tv++;
1120                                                         tottrans++;
1121                                                 }
1122                                         }
1123                                         bp++;
1124                                 }
1125                         }
1126                         nu= nu->next;
1127                 }
1128         }
1129         else if(G.obedit->type==OB_MBALL) {
1130                 extern ListBase editelems;  /* go away ! */
1131                 ml= editelems.first;
1132                 while(ml) {
1133                         if(ml->flag & SELECT) {
1134                                 tv->loc= &ml->x;
1135                                 VECCOPY(tv->oldloc, tv->loc);
1136                                 tv->val= &(ml->rad);
1137                                 tv->oldval= ml->rad;
1138                                 tv->flag= 1;
1139                                 tv++;
1140                                 tottrans++;
1141                         }
1142                         ml= ml->next;
1143                 }
1144         }
1145         else if(G.obedit->type==OB_LATTICE) {
1146                 bp= editLatt->def;
1147                 
1148                 a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
1149                 
1150                 while(a--) {
1151                         if((mode & 1) || (bp->f1 & SELECT)) {
1152                                 if(bp->hide==0) {
1153                                         VECCOPY(tv->oldloc, bp->vec);
1154                                         tv->loc= bp->vec;
1155                                         tv->flag= bp->f1 & SELECT;
1156                                         tv++;
1157                                         tottrans++;
1158                                 }
1159                         }
1160                         bp++;
1161                 }
1162         }
1163         
1164         /* cent etc */
1165         tv= transvmain;
1166         total= 0.0;
1167         for(a=0; a<tottrans; a++, tv++) {
1168                 if(tv->flag & SELECT) {
1169                         centroid[0]+= tv->oldloc[0];
1170                         centroid[1]+= tv->oldloc[1];
1171                         centroid[2]+= tv->oldloc[2];
1172                         total+= 1.0;
1173                         DO_MINMAX(tv->oldloc, min, max);
1174                 }
1175         }
1176         if(total!=0.0) {
1177                 centroid[0]/= total;
1178                 centroid[1]/= total;
1179                 centroid[2]/= total;
1180         }
1181
1182         center[0]= (min[0]+max[0])/2.0;
1183         center[1]= (min[1]+max[1])/2.0;
1184         center[2]= (min[2]+max[2])/2.0;
1185         
1186 }
1187
1188 void snap_sel_to_grid()
1189 {
1190         extern float originmat[3][3];   /* object.c */
1191         TransVert *tv;
1192         Base *base;
1193         Object *ob;
1194         float gridf, imat[3][3], bmat[3][3], vec[3];
1195         int a;
1196
1197         gridf= G.vd->gridview;
1198
1199
1200         if(G.obedit) {
1201                 tottrans= 0;
1202                 
1203                 if ELEM6(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) 
1204                         make_trans_verts(bmat[0], bmat[1], 0);
1205                 if(tottrans==0) return;
1206                 
1207                 Mat3CpyMat4(bmat, G.obedit->obmat);
1208                 Mat3Inv(imat, bmat);
1209                 
1210                 tv= transvmain;
1211                 for(a=0; a<tottrans; a++, tv++) {
1212                         
1213                         VECCOPY(vec, tv->loc);
1214                         Mat3MulVecfl(bmat, vec);
1215                         VecAddf(vec, vec, G.obedit->obmat[3]);
1216                         vec[0]= G.vd->gridview*floor(.5+ vec[0]/gridf);
1217                         vec[1]= G.vd->gridview*floor(.5+ vec[1]/gridf);
1218                         vec[2]= G.vd->gridview*floor(.5+ vec[2]/gridf);
1219                         VecSubf(vec, vec, G.obedit->obmat[3]);
1220                         
1221                         Mat3MulVecfl(imat, vec);
1222                         VECCOPY(tv->loc, vec);
1223                         
1224                 }
1225                 
1226                 special_transvert_update();
1227                 
1228                 MEM_freeN(transvmain);
1229                 transvmain= 0;
1230         
1231                 allqueue(REDRAWVIEW3D, 0);
1232                 return;
1233         }
1234
1235         base= (G.scene->base.first);
1236         while(base) {
1237                 if( ( ((base)->flag & SELECT) && ((base)->lay & G.vd->lay) && ((base)->object->id.lib==0))) {
1238                         ob= base->object;
1239                         if(ob->flag & OB_POSEMODE) {
1240                                 bPoseChannel *pchan;
1241                                 bArmature *arm= ob->data;
1242                                 
1243                                 for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
1244                                         if(pchan->bone->flag & BONE_SELECTED) {
1245                                                 if(pchan->bone->layer & arm->layer) {
1246                                                         if((pchan->bone->flag & BONE_CONNECTED)==0) { 
1247                                                                 float vecN[3], nLoc[3]; 
1248                                                                 
1249                                                                 /* get nearest grid point to snap to */
1250                                                                 VECCOPY(nLoc, pchan->pose_mat[3]);
1251                                                                 vec[0]= gridf * (float)(floor(.5+ nLoc[0]/gridf));
1252                                                                 vec[1]= gridf * (float)(floor(.5+ nLoc[1]/gridf));
1253                                                                 vec[2]= gridf * (float)(floor(.5+ nLoc[2]/gridf));
1254                                                                 
1255                                                                 /* get bone-space location of grid point */
1256                                                                 armature_loc_pose_to_bone(pchan, vec, vecN);
1257                                                                 
1258                                                                 /* adjust location */
1259                                                                 VECCOPY(pchan->loc, vecN);
1260                                                         }
1261                                                         /* if the bone has a parent and is connected to the parent, 
1262                                                          * don't do anything - will break chain unless we do auto-ik. 
1263                                                          */
1264                                                 }
1265                                         }
1266                                 }
1267                                 ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK);
1268                                 
1269                                 /* auto-keyframing */
1270                                 autokeyframe_pose_cb_func(ob, TFM_TRANSLATION, 0);
1271                                 DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
1272                         }
1273                         else {
1274                                 ob->recalc |= OB_RECALC_OB;
1275                                 
1276                                 vec[0]= -ob->obmat[3][0]+G.vd->gridview*floor(.5+ ob->obmat[3][0]/gridf);
1277                                 vec[1]= -ob->obmat[3][1]+G.vd->gridview*floor(.5+ ob->obmat[3][1]/gridf);
1278                                 vec[2]= -ob->obmat[3][2]+G.vd->gridview*floor(.5+ ob->obmat[3][2]/gridf);
1279                                 
1280                                 if(ob->parent) {
1281                                         where_is_object(ob);
1282                                         
1283                                         Mat3Inv(imat, originmat);
1284                                         Mat3MulVecfl(imat, vec);
1285                                         ob->loc[0]+= vec[0];
1286                                         ob->loc[1]+= vec[1];
1287                                         ob->loc[2]+= vec[2];
1288                                 }
1289                                 else {
1290                                         ob->loc[0]+= vec[0];
1291                                         ob->loc[1]+= vec[1];
1292                                         ob->loc[2]+= vec[2];
1293                                 }
1294 #ifdef WITH_VERSE
1295                                 if(ob->vnode) b_verse_send_transformation(ob);
1296 #endif
1297                         
1298                                 /* auto-keyframing */
1299                                 autokeyframe_ob_cb_func(ob, TFM_TRANSLATION);
1300                         }
1301                 }
1302
1303                 base= base->next;
1304         }
1305         DAG_scene_flush_update(G.scene, screen_view3d_layers(), 0);
1306         allqueue(REDRAWVIEW3D, 0);
1307 }
1308
1309 void snap_sel_to_curs()
1310 {
1311         extern float originmat[3][3];   /* object.c */
1312         TransVert *tv;
1313         Base *base;
1314         Object *ob;
1315         float *curs, imat[3][3], bmat[3][3], vec[3];
1316         int a;
1317
1318         curs= give_cursor();
1319
1320         if(G.obedit) {
1321                 tottrans= 0;
1322                 
1323                 if ELEM6(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) 
1324                         make_trans_verts(bmat[0], bmat[1], 0);
1325                 if(tottrans==0) return;
1326                 
1327                 Mat3CpyMat4(bmat, G.obedit->obmat);
1328                 Mat3Inv(imat, bmat);
1329                 
1330                 tv= transvmain;
1331                 for(a=0; a<tottrans; a++, tv++) {
1332                         vec[0]= curs[0]-G.obedit->obmat[3][0];
1333                         vec[1]= curs[1]-G.obedit->obmat[3][1];
1334                         vec[2]= curs[2]-G.obedit->obmat[3][2];
1335                         
1336                         Mat3MulVecfl(imat, vec);
1337                         VECCOPY(tv->loc, vec);
1338                 }
1339                 
1340                 special_transvert_update();
1341                 
1342                 MEM_freeN(transvmain);
1343                 transvmain= 0;
1344                 
1345                 allqueue(REDRAWVIEW3D, 0);
1346                 return;
1347         }
1348
1349         base= (G.scene->base.first);
1350         while(base) {
1351                 if( ( ((base)->flag & SELECT) && ((base)->lay & G.vd->lay) && ((base)->object->id.lib==0))) {
1352                         ob= base->object;
1353                         if(ob->flag & OB_POSEMODE) {
1354                                 bPoseChannel *pchan;
1355                                 bArmature *arm= ob->data;
1356                                 float cursp[3];
1357                                 
1358                                 Mat4Invert(ob->imat, ob->obmat);
1359                                 VECCOPY(cursp, curs);
1360                                 Mat4MulVecfl(ob->imat, cursp);
1361                                 
1362                                 for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) {
1363                                         if(pchan->bone->flag & BONE_SELECTED) {
1364                                                 if(pchan->bone->layer & arm->layer) {
1365                                                         if((pchan->bone->flag & BONE_CONNECTED)==0) { 
1366                                                                 float curspn[3];
1367                                                                 
1368                                                                 /* get location of cursor in bone-space */
1369                                                                 armature_loc_pose_to_bone(pchan, cursp, curspn);
1370                                                                 
1371                                                                 /* calculate new position */
1372                                                                 VECCOPY(pchan->loc, curspn);
1373                                                         }
1374                                                         /* if the bone has a parent and is connected to the parent, 
1375                                                          * don't do anything - will break chain unless we do auto-ik. 
1376                                                          */
1377                                                 }
1378                                         }
1379                                 }
1380                                 ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK);
1381                                 
1382                                 /* auto-keyframing */
1383                                 autokeyframe_pose_cb_func(ob, TFM_TRANSLATION, 0);
1384                                 DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
1385                         }
1386                         else {
1387                                 ob->recalc |= OB_RECALC_OB;
1388                                 
1389                                 vec[0]= -ob->obmat[3][0] + curs[0];
1390                                 vec[1]= -ob->obmat[3][1] + curs[1];
1391                                 vec[2]= -ob->obmat[3][2] + curs[2];
1392                                 
1393                                 if(ob->parent) {
1394                                         where_is_object(ob);
1395                                         
1396                                         Mat3Inv(imat, originmat);
1397                                         Mat3MulVecfl(imat, vec);
1398                                         ob->loc[0]+= vec[0];
1399                                         ob->loc[1]+= vec[1];
1400                                         ob->loc[2]+= vec[2];
1401                                 }
1402                                 else {
1403                                         ob->loc[0]+= vec[0];
1404                                         ob->loc[1]+= vec[1];
1405                                         ob->loc[2]+= vec[2];
1406                                 }
1407 #ifdef WITH_VERSE
1408                                 if(ob->vnode) b_verse_send_transformation(ob);
1409 #endif
1410                                 
1411                                 /* auto-keyframing */
1412                                 autokeyframe_ob_cb_func(ob, TFM_TRANSLATION);
1413                         }
1414                 }
1415
1416                 base= base->next;
1417         }
1418         DAG_scene_flush_update(G.scene, screen_view3d_layers(), 0);
1419         allqueue(REDRAWVIEW3D, 0);
1420 }
1421
1422 void snap_curs_to_grid()
1423 {
1424         float gridf, *curs;
1425
1426         gridf= G.vd->gridview;
1427         curs= give_cursor();
1428
1429         curs[0]= G.vd->gridview*floor(.5+curs[0]/gridf);
1430         curs[1]= G.vd->gridview*floor(.5+curs[1]/gridf);
1431         curs[2]= G.vd->gridview*floor(.5+curs[2]/gridf);
1432
1433         allqueue(REDRAWVIEW3D, 0);
1434 }
1435
1436 void snap_curs_to_sel()
1437 {
1438         TransVert *tv;
1439         Base *base;
1440         float *curs, bmat[3][3], vec[3], min[3], max[3], centroid[3];
1441         int count, a;
1442
1443         curs= give_cursor();
1444
1445         count= 0;
1446         INIT_MINMAX(min, max);
1447         centroid[0]= centroid[1]= centroid[2]= 0.0;
1448
1449         if(G.obedit) {
1450                 tottrans=0;
1451                 
1452                 if ELEM6(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) 
1453                         make_trans_verts(bmat[0], bmat[1], 2);
1454                 if(tottrans==0) return;
1455                 
1456                 Mat3CpyMat4(bmat, G.obedit->obmat);
1457                 
1458                 tv= transvmain;
1459                 for(a=0; a<tottrans; a++, tv++) {
1460                         VECCOPY(vec, tv->loc);
1461                         Mat3MulVecfl(bmat, vec);
1462                         VecAddf(vec, vec, G.obedit->obmat[3]);
1463                         VecAddf(centroid, centroid, vec);
1464                         DO_MINMAX(vec, min, max);
1465                 }
1466                 
1467                 if(G.vd->around==V3D_CENTROID) {
1468                         VecMulf(centroid, 1.0/(float)tottrans);
1469                         VECCOPY(curs, centroid);
1470                 }
1471                 else {
1472                         curs[0]= (min[0]+max[0])/2;
1473                         curs[1]= (min[1]+max[1])/2;
1474                         curs[2]= (min[2]+max[2])/2;
1475                 }
1476                 MEM_freeN(transvmain);
1477                 transvmain= 0;
1478         }
1479         else {
1480                 Object *ob= OBACT;
1481                 
1482                 if(ob && (ob->flag & OB_POSEMODE)) {
1483                         bArmature *arm= ob->data;
1484                         bPoseChannel *pchan;
1485                         for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) {
1486                                 if(arm->layer & pchan->bone->layer) {
1487                                         if(pchan->bone->flag & BONE_SELECTED) {
1488                                                 VECCOPY(vec, pchan->pose_head);
1489                                                 Mat4MulVecfl(ob->obmat, vec);
1490                                                 VecAddf(centroid, centroid, vec);
1491                                                 DO_MINMAX(vec, min, max);
1492                                                 count++;
1493                                         }
1494                                 }
1495                         }
1496                 }
1497                 else {
1498                         for(base= G.scene->base.first; base; base= base->next) {
1499                                 if(((base)->flag & SELECT) && ((base)->lay & G.vd->lay) ) {
1500                                         VECCOPY(vec, base->object->obmat[3]);
1501                                         VecAddf(centroid, centroid, vec);
1502                                         DO_MINMAX(vec, min, max);
1503                                         count++;
1504                                 }
1505                         }
1506                 }
1507                 if(count) {
1508                         if(G.vd->around==V3D_CENTROID) {
1509                                 VecMulf(centroid, 1.0/(float)count);
1510                                 VECCOPY(curs, centroid);
1511                         }
1512                         else {
1513                                 curs[0]= (min[0]+max[0])/2;
1514                                 curs[1]= (min[1]+max[1])/2;
1515                                 curs[2]= (min[2]+max[2])/2;
1516                         }
1517                 }
1518         }
1519         allqueue(REDRAWVIEW3D, 0);
1520 }
1521
1522 void snap_curs_to_active()
1523 {
1524         float *curs;
1525         curs = give_cursor();
1526
1527         if (G.obedit)
1528         {
1529                 if (G.obedit->type == OB_MESH)
1530                 {
1531                         /* check active */
1532                         EditSelection ese;
1533                         if (EM_get_actSelection(&ese)) {
1534                                 EM_editselection_center(curs, &ese);
1535                         }
1536                         
1537                         Mat4MulVecfl(G.obedit->obmat, curs);
1538                 }
1539         }
1540         else
1541         {
1542                 if (BASACT)
1543                 {
1544                         VECCOPY(curs, BASACT->object->obmat[3]);
1545                 }
1546         }
1547         allqueue(REDRAWVIEW3D, 0);
1548 }
1549
1550
1551 void snap_to_center()
1552 {
1553         extern float originmat[3][3];
1554         TransVert *tv;
1555         Base *base;
1556         Object *ob;
1557         float snaploc[3], imat[3][3], bmat[3][3], vec[3], min[3], max[3], centroid[3];
1558         int count, a;
1559
1560         /*calculate the snaplocation (centerpoint) */
1561         count= 0;
1562         INIT_MINMAX(min, max);
1563         centroid[0]= centroid[1]= centroid[2]= 0.0f;
1564         snaploc[0]= snaploc[1]= snaploc[2]= 0.0f;
1565
1566         if(G.obedit) {
1567                 tottrans= 0;
1568                 
1569                 if ELEM6(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) 
1570                         make_trans_verts(bmat[0], bmat[1], 0);
1571                 if(tottrans==0) return;
1572                 
1573                 Mat3CpyMat4(bmat, G.obedit->obmat);
1574                 Mat3Inv(imat, bmat);
1575                 
1576                 tv= transvmain;
1577                 for(a=0; a<tottrans; a++, tv++) {
1578                         VECCOPY(vec, tv->loc);
1579                         Mat3MulVecfl(bmat, vec);
1580                         VecAddf(vec, vec, G.obedit->obmat[3]);
1581                         VecAddf(centroid, centroid, vec);
1582                         DO_MINMAX(vec, min, max);
1583                 }
1584                 
1585                 if(G.vd->around==V3D_CENTROID) {
1586                         VecMulf(centroid, 1.0/(float)tottrans);
1587                         VECCOPY(snaploc, centroid);
1588                 }
1589                 else {
1590                         snaploc[0]= (min[0]+max[0])/2;
1591                         snaploc[1]= (min[1]+max[1])/2;
1592                         snaploc[2]= (min[2]+max[2])/2;
1593                 }
1594                 
1595                 MEM_freeN(transvmain);
1596                 transvmain= 0;
1597         }
1598         else {
1599                 base= (G.scene->base.first);
1600                 while(base) {
1601                         if(((base)->flag & SELECT) && ((base)->lay & G.vd->lay) ) {
1602                                 ob= base->object;
1603                                 if(ob->flag & OB_POSEMODE) {
1604                                         bPoseChannel *pchan;
1605                                         bArmature *arm= ob->data;
1606                                         
1607                                         for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) {
1608                                                 if(pchan->bone->flag & BONE_SELECTED) {
1609                                                         if(pchan->bone->layer & arm->layer) {
1610                                                                 VECCOPY(vec, pchan->pose_mat[3]);
1611                                                                 VecAddf(centroid, centroid, vec);
1612                                                                 DO_MINMAX(vec, min, max);
1613                                                                 count++;
1614                                                         }
1615                                                 }
1616                                         }
1617                                 }
1618                                 else {
1619                                         /* not armature bones (i.e. objects) */
1620                                         VECCOPY(vec, base->object->obmat[3]);
1621                                         VecAddf(centroid, centroid, vec);
1622                                         DO_MINMAX(vec, min, max);
1623                                         count++;
1624                                 }
1625                         }
1626                         base= base->next;
1627                 }
1628                 if(count) {
1629                         if(G.vd->around==V3D_CENTROID) {
1630                                 VecMulf(centroid, 1.0/(float)count);
1631                                 VECCOPY(snaploc, centroid);
1632                         }
1633                         else {
1634                                 snaploc[0]= (min[0]+max[0])/2;
1635                                 snaploc[1]= (min[1]+max[1])/2;
1636                                 snaploc[2]= (min[2]+max[2])/2;
1637                         }
1638                 }
1639         }
1640
1641         /* Snap the selection to the snaplocation (duh!) */
1642         if(G.obedit) {
1643                 tottrans= 0;
1644                 
1645                 if ELEM6(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) 
1646                         make_trans_verts(bmat[0], bmat[1], 0);
1647                 if(tottrans==0) return;
1648                 
1649                 Mat3CpyMat4(bmat, G.obedit->obmat);
1650                 Mat3Inv(imat, bmat);
1651                 
1652                 tv= transvmain;
1653                 for(a=0; a<tottrans; a++, tv++) {
1654                         vec[0]= snaploc[0]-G.obedit->obmat[3][0];
1655                         vec[1]= snaploc[1]-G.obedit->obmat[3][1];
1656                         vec[2]= snaploc[2]-G.obedit->obmat[3][2];
1657                         
1658                         Mat3MulVecfl(imat, vec);
1659                         VECCOPY(tv->loc, vec);
1660                 }
1661                 
1662                 special_transvert_update();
1663                 
1664                 MEM_freeN(transvmain);
1665                 transvmain= 0;
1666                 
1667                 allqueue(REDRAWVIEW3D, 0);
1668                 return;
1669         }
1670
1671         base= (G.scene->base.first);
1672         while(base) {
1673                 if( ( ((base)->flag & SELECT) && ((base)->lay & G.vd->lay) && ((base)->object->id.lib==0))) {
1674                         ob= base->object;
1675                         if(ob->flag & OB_POSEMODE) {
1676                                 bPoseChannel *pchan;
1677                                 bArmature *arm= ob->data;
1678                                 
1679                                 for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) {
1680                                         if(pchan->bone->flag & BONE_SELECTED) {
1681                                                 if(pchan->bone->layer & arm->layer) {
1682                                                         if((pchan->bone->flag & BONE_CONNECTED)==0) { 
1683                                                                 /* get location of cursor in bone-space */
1684                                                                 armature_loc_pose_to_bone(pchan, snaploc, vec);
1685                                                                 
1686                                                                 /* calculate new position */
1687                                                                 VECCOPY(pchan->loc, vec);
1688                                                         }
1689                                                         /* if the bone has a parent and is connected to the parent, 
1690                                                          * don't do anything - will break chain unless we do auto-ik. 
1691                                                          */
1692                                                 }
1693                                         }
1694                                 }
1695                                 
1696                                 /* auto-keyframing */
1697                                 ob->pose->flag |= POSE_DO_UNLOCK;
1698                                 autokeyframe_pose_cb_func(ob, TFM_TRANSLATION, 0);
1699                                 DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
1700                         }
1701                         else {
1702                                 ob->recalc |= OB_RECALC_OB;
1703                                 
1704                                 vec[0]= -ob->obmat[3][0] + snaploc[0];
1705                                 vec[1]= -ob->obmat[3][1] + snaploc[1];
1706                                 vec[2]= -ob->obmat[3][2] + snaploc[2];
1707                                 
1708                                 if(ob->parent) {
1709                                         where_is_object(ob);
1710                                         
1711                                         Mat3Inv(imat, originmat);
1712                                         Mat3MulVecfl(imat, vec);
1713                                         ob->loc[0]+= vec[0];
1714                                         ob->loc[1]+= vec[1];
1715                                         ob->loc[2]+= vec[2];
1716                                 }
1717                                 else {
1718                                         ob->loc[0]+= vec[0];
1719                                         ob->loc[1]+= vec[1];
1720                                         ob->loc[2]+= vec[2];
1721                                 }
1722 #ifdef WITH_VERSE
1723                                 if(ob->vnode) b_verse_send_transformation(ob);
1724 #endif
1725                                 
1726                                 /* auto-keyframing */
1727                                 autokeyframe_ob_cb_func(ob, TFM_TRANSLATION);
1728                         }
1729                 }
1730                 
1731                 base= base->next;
1732         }
1733         DAG_scene_flush_update(G.scene, screen_view3d_layers(), 0);
1734         allqueue(REDRAWVIEW3D, 0);
1735 }
1736
1737
1738 void snapmenu()
1739 {
1740         short event;
1741
1742         event = pupmenu("Snap %t|Selection -> Grid%x1|Selection -> Cursor%x2|Selection -> Center%x3|%l|Cursor -> Selection%x4|Cursor -> Grid%x5|Cursor -> Active%x6");
1743
1744         switch (event) {
1745                 case 1: /*Selection to grid*/
1746                     snap_sel_to_grid();
1747                         BIF_undo_push("Snap selection to grid");
1748                     break;
1749                 case 2: /*Selection to cursor*/
1750                     snap_sel_to_curs();
1751                         BIF_undo_push("Snap selection to cursor");
1752                     break;
1753                 case 3: /*Selection to center of selection*/
1754                     snap_to_center();
1755                         BIF_undo_push("Snap selection to center");
1756                     break;
1757                 case 4: /*Cursor to selection*/
1758                     snap_curs_to_sel();
1759                     break;
1760                 case 5: /*Cursor to grid*/
1761                     snap_curs_to_grid();
1762                     break;
1763                 case 6: /*Cursor to Active*/
1764                     snap_curs_to_active();
1765                         BIF_undo_push("Snap selection to center");
1766                     break;
1767         }
1768 }
1769
1770 void alignmenu()
1771 {
1772         short val;
1773         char *str_menu = BIF_menustringTransformOrientation("Align");
1774         val= pupmenu(str_menu);
1775         MEM_freeN(str_menu);
1776
1777         if (val >= 0)
1778         {
1779                 short old_val = G.vd->twmode; 
1780                 G.vd->twmode = val;
1781                 initTransform(TFM_ALIGN, CTX_NO_PET|CTX_AUTOCONFIRM);
1782                 Transform();
1783                 G.vd->twmode = old_val;
1784         }
1785 }
1786
1787 #define MERGELIMIT 0.001
1788 void mergemenu(void)
1789 {       
1790
1791         short event;
1792         int remCount = 0;
1793         
1794         if(G.scene->selectmode & SCE_SELECT_VERTEX)
1795                 if(G.editMesh->selected.first && G.editMesh->selected.last && 
1796                         ((EditSelection*)G.editMesh->selected.first)->type == EDITVERT && ((EditSelection*)G.editMesh->selected.last)->type == EDITVERT) 
1797                                 event = pupmenu("Merge %t|At First %x6|At Last%x1|At Center%x3|At Cursor%x4|Collapse%x2");
1798                 else if (G.editMesh->selected.first && ((EditSelection*)G.editMesh->selected.first)->type == EDITVERT) 
1799                         event = pupmenu("Merge %t|At First %x6|At Center%x3|At Cursor%x4|Collapse%x2");
1800                 else if (G.editMesh->selected.last && ((EditSelection*)G.editMesh->selected.last)->type == EDITVERT) 
1801                         event = pupmenu("Merge %t|At Last %x1|At Center%x3|At Cursor%x4|Collapse%x2");
1802                 else event = pupmenu("Merge %t|At Center%x3|At Cursor%x4|Collapse%x2");
1803         else event = pupmenu("Merge %t|At Center%x3|At Cursor%x4|Collapse%x2");
1804         switch (event)
1805         {
1806                 case -1:
1807                         return;
1808                 case 3:
1809                         if(G.qual & LR_CTRLKEY) remCount = merge_target(0,1);
1810                         else remCount = merge_target(0,0);
1811                         BIF_undo_push("Merge at center");
1812                         break;
1813                 case 4:
1814                         if(G.qual & LR_CTRLKEY) remCount = merge_target(1,1);
1815                         else remCount = merge_target(1,0);
1816                         BIF_undo_push("Merge at cursor");
1817                         break;
1818                 case 1:
1819                         if(G.qual & LR_CTRLKEY) remCount = merge_firstlast(0,1);
1820                         else remCount = merge_firstlast(0,0);
1821                         BIF_undo_push("Merge at last selected");
1822                         break;
1823                 case 6:
1824                         if(G.qual & LR_CTRLKEY) remCount = merge_firstlast(1,1);
1825                         else remCount = merge_firstlast(1,0);
1826                         BIF_undo_push("Merge at first selected");
1827                         break;
1828                 case 2:
1829                         remCount = collapseEdges();
1830                         BIF_undo_push("Collapse");
1831                         break;
1832         }
1833         notice("Removed %d Vertices", remCount);
1834         allqueue(REDRAWVIEW3D, 0);
1835         countall();
1836 }
1837 #undef MERGELIMIT
1838
1839
1840 void delete_context_selected(void) 
1841 {
1842         if(BIF_fullSketchMode())
1843         {
1844                 BIF_deleteSketch();
1845         }
1846         else if(G.obedit) {
1847                 if(G.obedit->type==OB_MESH) delete_mesh();
1848                 else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) delNurb();
1849                 else if(G.obedit->type==OB_MBALL) delete_mball();
1850                 else if (G.obedit->type==OB_ARMATURE) delete_armature();
1851         }
1852         else if(G.f & G_PARTICLEEDIT){
1853                 PE_delete_particle();
1854         }
1855         else delete_obj(0);
1856 }
1857
1858 void duplicate_context_selected(void) 
1859 {
1860         if(G.obedit) {
1861                 if(G.obedit->type==OB_MESH) adduplicate_mesh();
1862                 else if(G.obedit->type==OB_ARMATURE) adduplicate_armature();
1863                 else if(G.obedit->type==OB_MBALL) adduplicate_mball();
1864                 else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) adduplicate_nurb();
1865         }
1866         else if(G.f & G_PARTICLEEDIT);
1867         else
1868                 adduplicate(0, U.dupflag);
1869 }
1870
1871 void toggle_shading(void) 
1872 {
1873         if(G.qual & LR_SHIFTKEY) {
1874                 if(G.qual & LR_ALTKEY) {
1875                         reshadeall_displist();
1876                         G.vd->drawtype= OB_SHADED;
1877                 }
1878                 else {
1879                         if(G.vd->drawtype== OB_SHADED) G.vd->drawtype= OB_WIRE;
1880                         else G.vd->drawtype= OB_SHADED;
1881                 }
1882         }
1883         else if(G.qual & LR_ALTKEY) {
1884                 if(G.vd->drawtype== OB_TEXTURE) G.vd->drawtype= OB_SOLID;
1885                 else G.vd->drawtype= OB_TEXTURE;
1886         }
1887         else {
1888                 if(G.vd->drawtype==OB_SOLID || G.vd->drawtype==OB_SHADED) G.vd->drawtype= OB_WIRE;
1889                 else G.vd->drawtype= OB_SOLID;
1890         }
1891         
1892         if(G.vd->drawtype != OB_WIRE && G.vd->depths) {
1893                 G.vd->depths->damaged= 1;
1894         }
1895 }
1896
1897 int minmax_verts(float *min, float *max)
1898 {
1899         TransVert *tv;
1900         float centroid[3], vec[3], bmat[3][3];
1901         int a;
1902
1903         tottrans=0;
1904         if ELEM5(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE) 
1905                 make_trans_verts(bmat[0], bmat[1], 2);
1906         if(tottrans==0) return 0;
1907
1908         Mat3CpyMat4(bmat, G.obedit->obmat);
1909         
1910         tv= transvmain;
1911         for(a=0; a<tottrans; a++, tv++) {               
1912                 VECCOPY(vec, tv->loc);
1913                 Mat3MulVecfl(bmat, vec);
1914                 VecAddf(vec, vec, G.obedit->obmat[3]);
1915                 VecAddf(centroid, centroid, vec);
1916                 DO_MINMAX(vec, min, max);               
1917         }
1918         
1919         MEM_freeN(transvmain);
1920         transvmain= 0;
1921         return 1;
1922 }
1923