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