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