7e9787a3b079c329d8561afec50511d3970f1365
[blender.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_ipo_types.h"
56 #include "DNA_lattice_types.h"
57 #include "DNA_meta_types.h"
58 #include "DNA_mesh_types.h"
59 #include "DNA_modifier_types.h"
60 #include "DNA_object_types.h"
61 #include "DNA_screen_types.h"
62 #include "DNA_scene_types.h"
63 #include "DNA_space_types.h"
64 #include "DNA_view3d_types.h"
65
66 #include "BLI_blenlib.h"
67 #include "BLI_arithb.h"
68 #include "BLI_editVert.h"
69
70 #include "BKE_action.h"
71 #include "BKE_armature.h"
72 #include "BKE_anim.h"
73 #include "BKE_curve.h"
74 #include "BKE_depsgraph.h"
75 #include "BKE_displist.h"
76 #include "BKE_global.h"
77 #include "BKE_ipo.h"
78 #include "BKE_lattice.h"
79 #include "BKE_mesh.h"
80 #include "BKE_modifier.h"
81 #include "BKE_object.h"
82 #include "BKE_utildefines.h"
83
84 #include "BIF_editmesh.h"
85 #include "BIF_editview.h"
86 #include "BIF_editarmature.h"
87 #include "BIF_gl.h"
88 #include "BIF_glutil.h"
89 #include "BIF_interface.h"
90 #include "BIF_mywindow.h"
91 #include "BIF_resources.h"
92 #include "BIF_space.h"
93 #include "BIF_screen.h"
94 #include "BIF_toolbox.h"
95
96 #include "BSE_edit.h"
97 #include "BSE_drawipo.h"
98 #include "BSE_drawview.h"
99 #include "BSE_trans_types.h"
100 #include "BSE_view.h"
101
102 #include "BDR_editobject.h"
103 #include "BDR_editmball.h"
104 #include "BDR_editcurve.h"
105
106 /* old stuff */
107 #include "blendef.h"
108 #include "mydevice.h"
109
110 /*#include "armature.h"*/
111 /*  #include "edit.h" */
112 #include "nla.h"
113
114 #ifdef __NLA
115 #include "BIF_editarmature.h"
116 #endif
117
118
119 /* circle selection callback */
120 typedef void (*select_CBfunc)(short selecting, Object *editobj, short *mval, float rad);
121
122 extern void obedit_selectionCB(short selecting, Object *editobj, 
123                                short *mval, float rad);
124 extern void uvedit_selectionCB(short selecting, Object *editobj, 
125                                short *mval, float rad);
126
127 void circle_selectCB(select_CBfunc func);
128
129 /* local protos ---------------*/
130 void snap_curs_to_firstsel(void);
131
132
133 int get_border(rcti *rect, short col)
134 {
135         float dvec[4], fac1, fac2;
136         int retval=1;
137         unsigned short event;
138         short mval[2], mvalo[4], val, x1, y1;
139         char str[64];
140
141         mywinset(G.curscreen->mainwin);
142         
143         /* slightly larger, 1 pixel at the edge */
144         glReadBuffer(GL_FRONT);
145         glDrawBuffer(GL_FRONT);
146
147         /* removed my_get_frontbuffer, this crashes when it gets a part outside the screen */
148         /* solved it with just a redraw! */
149
150         mywinset(curarea->win);
151         
152         glDrawBuffer(GL_FRONT);
153         persp(PERSP_WIN);
154         initgrabz(0.0, 0.0, 0.0);
155         
156         getmouseco_areawin(mvalo);
157
158         /* draws the selection initial cross */
159         sdrawXORline4(0, 0,  mvalo[1],  curarea->winx,  mvalo[1]);
160         sdrawXORline4(1, mvalo[0],  0,  mvalo[0],  curarea->winy); 
161         glFlush();
162         
163         while(TRUE) {
164         
165                 /* selection loop while mouse pressed */
166                 getmouseco_areawin(mval);
167
168                 if(mvalo[0]!=mval[0] || mvalo[1]!=mval[1]) {
169
170                         /* aiming cross */
171                         sdrawXORline4(0, 0,  mval[1],  curarea->winx,  mval[1]);
172                         sdrawXORline4(1, mval[0],  0,  mval[0],  curarea->winy);
173                         glFlush();
174
175                         mvalo[0]= mval[0];
176                         mvalo[1]= mval[1];
177                 }
178                 event= extern_qread(&val);
179
180                 if(event && val) {
181
182                         /* for when a renderwindow is open, and a mouse cursor activates it */
183                         persp(PERSP_VIEW);
184                         mywinset(curarea->win);
185                         persp(PERSP_WIN);
186                         
187                         if(event==ESCKEY) {
188                                 retval= 0;
189                                 break;
190                         }
191                         else if(event==BKEY) {
192                                 /* b has been pressed twice: proceed with circle select */
193                                 retval= 0;
194                                 break;
195                         }
196                         else if(event==LEFTMOUSE) break;
197                         else if(event==MIDDLEMOUSE) break;
198                         else if(event==RIGHTMOUSE) break;
199                 }
200                 else PIL_sleep_ms(10);
201                 
202         } /* end while (TRUE) */
203
204         /* erase XORed lines */
205         sdrawXORline4(-1, 0, 0, 0, 0);
206         
207         if(retval) {
208                 /* box select */
209                 x1= mval[0];
210                 y1= mval[1];
211                 
212                 getmouseco_areawin(mvalo);
213
214                 sdrawXORline4(0, x1, y1, x1, mvalo[1]); 
215                 sdrawXORline4(1, x1, mvalo[1], mvalo[0], mvalo[1]); 
216                 sdrawXORline4(2, mvalo[0], mvalo[1], mvalo[0], y1); 
217                 sdrawXORline4(3,  mvalo[0], y1, x1, y1); 
218                 glFlush();
219                         
220                 while(TRUE) {
221                         getmouseco_areawin(mval);
222                         if(mvalo[0]!=mval[0] || mvalo[1]!=mval[1]) {
223
224                                 sdrawXORline4(0, x1, y1, x1, mval[1]); 
225                                 sdrawXORline4(1, x1, mval[1], mval[0], mval[1]); 
226                                 sdrawXORline4(2, mval[0], mval[1], mval[0], y1); 
227                                 sdrawXORline4(3,  mval[0], y1, x1, y1); 
228                                 
229                                 /* draw size information in corner */
230                                 if(curarea->spacetype==SPACE_VIEW3D) {
231                                         BIF_ThemeColor(TH_BACK);
232                                         glRecti(10, 25, 250, 40);
233         
234                                         if(G.vd->persp==0) {
235                                                 window_to_3d(dvec, mvalo[0]-x1, mvalo[1]-y1);
236         
237                                                 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]));
238                                                 glColor3f(0.0, 0.0, 0.0); 
239                                                 glRasterPos2i(15,  27);
240                                                 BMF_DrawString(G.fonts, str);
241                                                 glColor3f(0.7, 0.7, 0.7); 
242                                                 glRasterPos2i(16,  28);
243                                                 BMF_DrawString(G.fonts, str);
244                                         }
245                                         else if(G.vd->persp==2) {
246                                                 rcti vb;
247         
248                                                 calc_viewborder(G.vd, &vb);
249         
250                                                 fac1= (mvalo[0]-x1)/( (float) (vb.xmax-vb.xmin) );
251                                                 fac1*= 0.01*G.scene->r.size*G.scene->r.xsch;
252                                                 
253                                                 fac2= (mvalo[1]-y1)/( (float) (vb.ymax-vb.ymin) );
254                                                 fac2*= 0.01*G.scene->r.size*G.scene->r.ysch;
255                                                 
256                                                 sprintf(str, "X %.1f  Y %.1f  Dia %.1f", fabs(fac1), fabs(fac2), sqrt(fac1*fac1 + fac2*fac2) );
257                                                 glColor3f(0.0, 0.0, 0.0); 
258                                                 glRasterPos2i(15,  27);
259                                                 BMF_DrawString(G.fonts, str);
260                                                 glColor3f(0.7, 0.7, 0.7); 
261                                                 glRasterPos2i(16,  28);
262                                                 BMF_DrawString(G.fonts, str);
263                                         }
264                                 }
265                                 else if(curarea->spacetype==SPACE_IPO) {
266                                         SpaceIpo *sipo= curarea->spacedata.first;
267         
268                                         BIF_ThemeColor(TH_BACK);
269                                         glRecti(20, 30, 170, 40);
270                                                                 
271                                         mvalo[2]= x1;
272                                         mvalo[3]= y1;
273                                         areamouseco_to_ipoco(&sipo->v2d, mval, dvec, dvec+1);
274                                         areamouseco_to_ipoco(&sipo->v2d, mvalo+2, dvec+2, dvec+3);
275
276                                         sprintf(str, "Time: %.4f  Y %.4f", dvec[0]-dvec[2], dvec[1]-dvec[3]);
277                                         glRasterPos2i(30,  30);
278                                         glColor3f(0.0, 0.0, 0.0); 
279                                         BMF_DrawString(G.fonts, str);
280                                         glRasterPos2i(31,  31);
281                                         glColor3f(0.9, 0.9, 0.9); 
282                                         BMF_DrawString(G.fonts, str);
283                                 }
284
285                                 glFlush();
286
287                                 mvalo[0]= mval[0];
288                                 mvalo[1]= mval[1];
289                         }
290                         
291                         event= extern_qread(&val);
292                         
293                         if(event && val==0) {
294                                 /* still because of the renderwindow... */
295                                 persp(PERSP_VIEW);
296                                 mywinset(curarea->win);
297                                 persp(PERSP_WIN);
298                                 
299                                 if(event==ESCKEY) {
300                                         retval= 0;
301                                         break;
302                                 }
303                                 else if(event==LEFTMOUSE) break;
304                                 else if(event==MIDDLEMOUSE) break;
305                                 else if(event==RIGHTMOUSE) break;
306                         }
307                         
308                 } /* end while (TRUE) */
309                 sdrawXORline4(-1, 0, 0, 0, 0);
310                 
311                 if(retval) {
312                         rect->xmin= x1;
313                         rect->ymin= y1;
314                         rect->xmax= mval[0];
315                         rect->ymax= mval[1];
316                         retval= event;
317
318                         /* normalise */
319                         if(rect->xmin>rect->xmax) SWAP(int, rect->xmin, rect->xmax);
320                         if(rect->ymin>rect->ymax) SWAP(int, rect->ymin, rect->ymax);
321                         
322                         if(rect->xmin==rect->xmax) retval= 0;
323                         if(rect->ymin==rect->ymax) retval= 0;
324                 }
325         }
326
327
328         /* clear */
329         if(event!=BKEY) {
330                 if ELEM(curarea->spacetype, SPACE_VIEW3D, SPACE_IPO) {
331                         scrarea_queue_winredraw(curarea);
332                 }
333         }
334         
335         glFlush();
336         glReadBuffer(GL_BACK);
337         glDrawBuffer(GL_BACK);
338
339         persp(PERSP_VIEW);
340         
341         /* pressed B again ? -> brush select */
342         if(event==BKEY) {
343                 setlinestyle(0);
344                 switch (curarea->spacetype) {
345                 case SPACE_VIEW3D:
346                         if (G.obedit) {
347                                 if ELEM4(G.obedit->type, OB_MESH, OB_CURVE, OB_SURF, OB_LATTICE) {
348                                         circle_selectCB(&obedit_selectionCB);
349                                 }
350                         }
351                         else if (G.f&G_FACESELECT) {
352                                 circle_selectCB(&obedit_selectionCB);
353                         }
354                         return 0;
355                         
356                 case SPACE_IMAGE: // brush select in UV editor
357                         circle_selectCB(&uvedit_selectionCB);
358                         // this is a hack; we return 0 that the caller from get_border
359                         // doesn't execute the selection code for border select..
360                         return 0;
361                 }
362         }
363         return retval;
364 }
365
366 void draw_sel_circle(short *mval, short *mvalo, float rad, float rado, int selecting)
367 {
368         static short no_mvalo=0;
369
370         if(mval==NULL && mvalo==NULL) { /* signal */
371                 no_mvalo= 1;
372                 return;
373         }
374
375         persp(PERSP_WIN);
376         glReadBuffer(GL_FRONT);
377         glDrawBuffer(GL_FRONT);
378         //setlinestyle(2);
379
380         /* draw circle */
381         if(mvalo && no_mvalo==0) {
382                 fdrawXORcirc(mvalo[0], mvalo[1], rado);
383         }
384         
385         if(mval) {
386                 fdrawXORcirc(mval[0], mval[1], rad);
387         }
388         //setlinestyle(0);
389
390         glFlush();
391         persp(PERSP_VIEW);
392         glDrawBuffer(GL_BACK);
393         glReadBuffer(GL_BACK);
394
395         no_mvalo= 0;
396 }
397
398 /** This function does the same as editview.c:circle_select(),
399   * but the selection actions are defined by a callback, making
400   * it (hopefully) reusable for other windows than the 3D view.
401   */
402
403 void circle_selectCB(select_CBfunc callback)
404 {
405         static float rad= 40.0;
406         float rado;
407         int firsttime=1;
408         int escape= 0;
409         unsigned short event;
410         short mvalo[2], mval[2], val;
411         short selecting=0;
412         Object *obj;
413         
414         if(G.obedit) obj = G.obedit;
415         else obj = OBACT;
416
417         mywinset(curarea->win);
418         
419         getmouseco_areawin(mvalo);
420         mval[0]= mvalo[0]; mval[1]= mvalo[1];
421
422         draw_sel_circle(mval, NULL, rad, 0.0, selecting); // draws frontbuffer, but sets backbuf again
423         
424         rado= rad;
425         
426         while(TRUE) {
427                 
428                 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || rado!=rad || firsttime) {
429                         firsttime= 0;
430                         
431                         if(selecting) {
432                                 callback(selecting, obj, mval, rad);
433                         }
434
435                         draw_sel_circle(mval, mvalo, rad, rado, selecting);
436                 
437                         mvalo[0]= mval[0];
438                         mvalo[1]= mval[1];
439                         rado= rad;
440
441                 }
442                 
443                 while(qtest()) {
444                         event= extern_qread(&val);
445                         if (event) {
446
447                                 /* for when another window is open and a mouse cursor activates it */
448                                 if(event!=MOUSEY && event!=MOUSEX) mywinset(curarea->win);
449                                 
450                                 getmouseco_areawin(mval);       // important to do here, trust events!
451                                 
452                                 switch(event) {
453                         
454                                 case LEFTMOUSE:
455                                 case MIDDLEMOUSE:
456                                         if(val) selecting= event;
457                                         else selecting= 0;
458                                         firsttime= 1;
459                                         
460                                         break;
461                                 case WHEELDOWNMOUSE:
462                                 case PADPLUSKEY:
463                                 case EQUALKEY:
464                                         if(val) if(rad<200.0) rad*= 1.2;
465                                         break;
466                                 case WHEELUPMOUSE:
467                                 case PADMINUS:
468                                 case MINUSKEY:
469                                         if(val) if(rad>5.0) rad/= 1.2;
470                                         break;
471                                 
472                                 case ESCKEY: case SPACEKEY: case RIGHTMOUSE: case INPUTCHANGE: 
473                                 case GKEY: case SKEY: case RKEY: case XKEY: case EKEY: case TABKEY:
474                                         escape= 1;
475                                         break;
476
477                                 }
478                                 
479                                 if(escape) break;
480                         }
481                 }
482                 PIL_sleep_ms(10);
483                 
484                 if(escape) break;
485         }
486         
487         /* clear circle */
488         draw_sel_circle(NULL, mvalo, 0, rad, 1);
489         BIF_undo_push("Circle Select");
490         countall();
491         allqueue(REDRAWINFO, 0);
492 }
493
494 static void count_object(Object *ob, int sel, int totob)
495 {
496         Mesh *me;
497         Curve *cu;
498         int tot=0, totf=0, subsurf;
499         
500         switch(ob->type) {
501         case OB_MESH:
502                 G.totmesh+=totob;
503                 me= get_mesh(ob);
504                 if(me) {
505                         ModifierData *md = modifiers_findByType(ob, eModifierType_Subsurf);
506                         int totvert, totface;
507                         
508                         if (md) {
509                                 SubsurfModifierData *smd = (SubsurfModifierData*) md;
510                                 
511                                 subsurf= 1<<(2*smd->levels);
512                         }
513                         else subsurf= 1;
514                         
515                         totvert= subsurf*me->totvert*totob;
516                         totface= subsurf*me->totface*totob;
517                         
518                         G.totvert+= totvert;
519                         G.totface+= totface;
520                         if(sel) {
521                                 G.totvertsel+= totvert;
522                                 G.totfacesel+= totface;
523                         }
524                 }
525                 break;
526
527         case OB_LAMP:
528                 G.totlamp+=totob;
529                 break;
530         case OB_SURF:
531         case OB_CURVE:
532         case OB_FONT:
533                 G.totcurve+=totob;
534                 tot=totf= 0;
535                 cu= ob->data;
536                 if(cu->disp.first)
537                         count_displist( &cu->disp, &tot, &totf);
538                 tot*= totob;
539                 totf*= totob;
540                 G.totvert+= tot;
541                 G.totface+= totf;
542                 if(sel) {
543                         G.totvertsel+= tot;
544                         G.totfacesel+= totf;
545                 }
546                 break;
547         case OB_MBALL:
548                 count_displist( &ob->disp, &tot, &totf);
549                 tot*= totob;
550                 totf*= totob;
551                 G.totvert+= tot;
552                 G.totface+= totf;
553                 if(sel) {
554                         G.totvertsel+= tot;
555                         G.totfacesel+= totf;
556                 }
557                 break;
558         }
559         
560 }
561
562 /* countall does statistics */
563 /* is called on most actions, like select/add/delete/layermove */
564 void countall()
565 {
566         extern ListBase editNurb;
567         Base *base;
568         Object *ob= OBACT;
569         Mesh *me;
570         Nurb *nu;
571         BezTriple *bezt;
572         BPoint *bp;
573         MetaElem *ml;
574         struct EditBone *ebo;
575         int a;
576
577         G.totvert= G.totvertsel= G.totedge= G.totedgesel= G.totfacesel= G.totface= G.totobj= 
578             G.totmesh= G.totlamp= G.totcurve= G.totobjsel= G.totbone= G.totbonesel=  0;
579
580         if(G.obedit) {
581                 
582                 if(G.obedit->type==OB_MESH) {
583                         EditMesh *em = G.editMesh;
584                         EditVert *eve;
585                         EditEdge *eed;
586                         EditFace *efa;
587                         
588                         for(eve= em->verts.first; eve; eve= eve->next) {
589                                 G.totvert++;
590                                 if(eve->f & SELECT) G.totvertsel++;
591                         }
592                         for(eed= em->edges.first; eed; eed= eed->next) {
593                                 G.totedge++;
594                                 if(eed->f & SELECT) G.totedgesel++;
595                         }
596                         for(efa= em->faces.first; efa; efa= efa->next) {
597                                 G.totface++;
598                                 if(efa->f & SELECT) G.totfacesel++;
599                         }
600                 }
601                 else if (G.obedit->type==OB_ARMATURE){
602                         for (ebo=G.edbo.first;ebo;ebo=ebo->next){
603                                 G.totbone++;
604                                 
605                                 /* Sync selection to parent for connected children */
606                                 if ((ebo->flag & BONE_CONNECTED) && ebo->parent){
607                                         G.totvert--;
608                                         if (ebo->parent->flag & BONE_TIPSEL)
609                                                 ebo->flag |= BONE_ROOTSEL;
610                                         else
611                                                 ebo->flag &= ~BONE_ROOTSEL;
612                                 }
613                                 
614                                 if (ebo->flag & BONE_TIPSEL)
615                                         G.totvertsel++;
616                                 if (ebo->flag & BONE_ROOTSEL)
617                                         G.totvertsel++;
618                                 
619                                 if ((ebo->flag & BONE_TIPSEL) && (ebo->flag & BONE_ROOTSEL))
620                                         ebo->flag |= BONE_SELECTED;
621                                 else
622                                         ebo->flag &= ~BONE_SELECTED;
623                                 
624                                 if(ebo->flag & BONE_SELECTED) G.totbonesel++;
625
626                                 //      If this is a connected child and it's parent is being moved, remove our root
627                                 if ((ebo->flag & BONE_CONNECTED)&& (ebo->flag & BONE_ROOTSEL) && ebo->parent && (ebo->parent->flag & BONE_TIPSEL)){
628                                         G.totvertsel--;
629                                 }
630
631                                 G.totvert+=2;
632                         }
633                 }
634                 else if ELEM3(G.obedit->type, OB_CURVE, OB_SURF, OB_FONT) {
635                         nu= editNurb.first;
636                         while(nu) {
637                                 if((nu->type & 7)==CU_BEZIER) {
638                                         bezt= nu->bezt;
639                                         a= nu->pntsu;
640                                         while(a--) {
641                                                 G.totvert+=3;
642                                                 if(bezt->f1) G.totvertsel++;
643                                                 if(bezt->f2) G.totvertsel++;
644                                                 if(bezt->f3) G.totvertsel++;
645                                                 bezt++;
646                                         }
647                                 }
648                                 else {
649                                         bp= nu->bp;
650                                         a= nu->pntsu*nu->pntsv;
651                                         while(a--) {
652                                                 G.totvert++;
653                                                 if(bp->f1 & 1) G.totvertsel++;
654                                                 bp++;
655                                         }
656                                 }
657                                 nu= nu->next;
658                         }
659                 }
660                 else if(G.obedit->type==OB_MBALL) {
661                         /* editmball.c */
662                         extern ListBase editelems;  /* go away ! */
663                         
664                         ml= editelems.first;
665                         while(ml) {
666                                 G.totvert++;
667                                 if(ml->flag & SELECT) G.totvertsel++;
668                                 ml= ml->next;
669                         }
670                 }
671                 else if(G.obedit->type==OB_LATTICE) {
672                         bp= editLatt->def;
673                         
674                         a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
675                         while(a--) {
676                                 G.totvert++;
677                                 if(bp->f1 & 1) G.totvertsel++;
678                                 bp++;
679                         }
680                 }
681                 
682                 allqueue(REDRAWINFO, 1);        /* 1, because header->win==0! */
683                 return;
684         }
685         else if(ob && (ob->flag & OB_POSEMODE)) {
686                 if(ob->pose) {
687                         bPoseChannel *pchan;
688                         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
689                                 G.totbone++;
690                                 if(pchan->bone && (pchan->bone->flag & BONE_SELECTED)) G.totbonesel++;
691                         }
692                 }
693                 allqueue(REDRAWINFO, 1);        /* 1, because header->win==0! */
694                 return;
695         }
696         else if(G.f & (G_FACESELECT + G_VERTEXPAINT + G_TEXTUREPAINT +G_WEIGHTPAINT)) {
697                 me= get_mesh((G.scene->basact) ? (G.scene->basact->object) : 0);
698                 if(me) {
699                         G.totface= me->totface;
700                         G.totvert= me->totvert;
701                 }
702                 allqueue(REDRAWINFO, 1);        /* 1, because header->win==0! */
703                 return;
704         }
705
706         if(G.scene==NULL) return;
707
708         base= (G.scene->base.first);
709         while(base) {
710                 if(G.scene->lay & base->lay) {
711                         ob= base->object;       /* warning, ob not is obact anymore */
712                         
713                         if(base->flag & SELECT) G.totobjsel++;
714                         
715                         if(ob->parent && (ob->parent->transflag & OB_DUPLIVERTS)) {
716                                 int tot= count_duplilist(ob->parent);
717                                 G.totobj+=tot;
718                                 count_object(ob, base->flag & SELECT, tot);
719                         }
720                         else if(ob->transflag & OB_DUPLIFRAMES) {
721                                 int tot= count_duplilist(ob);
722                                 G.totobj+=tot;
723                                 count_object(ob, base->flag & SELECT, tot);
724                         }
725                         else {
726                                 count_object(ob, base->flag & SELECT, 1);
727                                 G.totobj++;
728                         }
729                 }
730                 base= base->next;
731         }
732         allqueue(REDRAWINFO, 1);        /* 1, because header->win==0! */
733 }
734
735 /* ************************************************** */
736 /* ********************* old transform stuff ******** */
737 /* ************************************************** */
738
739 static TransVert *transvmain=NULL;
740 static int tottrans= 0;
741
742 /* copied from editobject.c, now uses (almost) proper depgraph */
743 static void special_transvert_update(void)
744 {
745         
746         if(G.obedit) {
747                 
748                 DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
749                 
750                 if(G.obedit->type==OB_MESH) {
751                         recalc_editnormals();   // does face centers too
752                 }
753                 else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
754                         extern ListBase editNurb;
755                         Nurb *nu= editNurb.first;
756                         while(nu) {
757                                 test2DNurb(nu);
758                                 testhandlesNurb(nu); /* test for bezier too */
759                                 nu= nu->next;
760                         }
761                 }
762                 else if(G.obedit->type==OB_ARMATURE){
763                         EditBone *ebo;
764                         
765                         /* Ensure all bones are correctly adjusted */
766                         for (ebo=G.edbo.first; ebo; ebo=ebo->next){
767                                 
768                                 if ((ebo->flag & BONE_CONNECTED) && ebo->parent){
769                                         /* If this bone has a parent tip that has been moved */
770                                         if (ebo->parent->flag & BONE_TIPSEL){
771                                                 VECCOPY (ebo->head, ebo->parent->tail);
772                                         }
773                                         /* If this bone has a parent tip that has NOT been moved */
774                                         else{
775                                                 VECCOPY (ebo->parent->tail, ebo->head);
776                                         }
777                                 }
778                         }
779                 }
780                 else if(G.obedit->type==OB_LATTICE) {
781                         if(editLatt->flag & LT_OUTSIDE) outside_lattice(editLatt);
782                 }
783         }
784 }
785
786 /* copied from editobject.c, needs to be replaced with new transform code still */
787 /* mode: 1 = proportional */
788 static void make_trans_verts(float *min, float *max, int mode)  
789 {
790         extern ListBase editNurb;
791         EditMesh *em = G.editMesh;
792         Nurb *nu;
793         BezTriple *bezt;
794         BPoint *bp;
795         TransVert *tv=NULL;
796         MetaElem *ml;
797         EditVert *eve;
798         EditBone        *ebo;
799         float total, centre[3], centroid[3];
800         int a;
801
802         tottrans= 0; // global!
803         
804         INIT_MINMAX(min, max);
805         centroid[0]=centroid[1]=centroid[2]= 0.0;
806         
807         /* note for transform refactor: dont rely on countall anymore... its ancient */
808         /* I skip it for editmesh now (ton) */
809         if(G.obedit->type!=OB_MESH) {
810                 countall();
811                 if(mode) tottrans= G.totvert;
812                 else tottrans= G.totvertsel;
813
814                 if(G.totvertsel==0) {
815                         tottrans= 0;
816                         return;
817                 }
818                 tv=transvmain= MEM_callocN(tottrans*sizeof(TransVert), "maketransverts");
819         }
820         
821         /* we count again because of hide (old, not for mesh!) */
822         tottrans= 0;
823         
824         if(G.obedit->type==OB_MESH) {
825                 int proptrans= 0;
826                 
827                 // transform now requires awareness for select mode, so we tag the f1 flags in verts
828                 tottrans= 0;
829                 if(G.scene->selectmode & SCE_SELECT_VERTEX) {
830                         for(eve= em->verts.first; eve; eve= eve->next) {
831                                 if(eve->h==0 && (eve->f & SELECT)) {
832                                         eve->f1= SELECT;
833                                         tottrans++;
834                                 }
835                                 else eve->f1= 0;
836                         }
837                 }
838                 else if(G.scene->selectmode & SCE_SELECT_EDGE) {
839                         EditEdge *eed;
840                         for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
841                         for(eed= em->edges.first; eed; eed= eed->next) {
842                                 if(eed->h==0 && (eed->f & SELECT)) eed->v1->f1= eed->v2->f1= SELECT;
843                         }
844                         for(eve= em->verts.first; eve; eve= eve->next) if(eve->f1) tottrans++;
845                 }
846                 else {
847                         EditFace *efa;
848                         for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
849                         for(efa= em->faces.first; efa; efa= efa->next) {
850                                 if(efa->h==0 && (efa->f & SELECT)) {
851                                         efa->v1->f1= efa->v2->f1= efa->v3->f1= SELECT;
852                                         if(efa->v4) efa->v4->f1= SELECT;
853                                 }
854                         }
855                         for(eve= em->verts.first; eve; eve= eve->next) if(eve->f1) tottrans++;
856                 }
857                 
858                 /* proportional edit exception... */
859                 if(mode==1 && tottrans) {
860                         for(eve= em->verts.first; eve; eve= eve->next) {
861                                 if(eve->h==0) {
862                                         eve->f1 |= 2;
863                                         proptrans++;
864                                 }
865                         }
866                         if(proptrans>tottrans) tottrans= proptrans;
867                 }
868                 
869                 /* and now make transverts */
870                 if(tottrans) {
871                         tv=transvmain= MEM_callocN(tottrans*sizeof(TransVert), "maketransverts");
872
873                         for(eve= em->verts.first; eve; eve= eve->next) {
874                                 if(eve->f1) {
875                                         VECCOPY(tv->oldloc, eve->co);
876                                         tv->loc= eve->co;
877                                         if(eve->no[0]!=0.0 || eve->no[1]!=0.0 ||eve->no[2]!=0.0)
878                                                 tv->nor= eve->no; // note this is a hackish signal (ton)
879                                         tv->flag= eve->f1 & SELECT;
880                                         tv++;
881                                 }
882                         }
883                 }
884         }
885         else if (G.obedit->type==OB_ARMATURE){
886                 for (ebo=G.edbo.first;ebo;ebo=ebo->next){
887                         if (ebo->flag & BONE_TIPSEL){
888                                 VECCOPY (tv->oldloc, ebo->tail);
889                                 tv->loc= ebo->tail;
890                                 tv->nor= NULL;
891                                 tv->flag= 1;
892                                 tv++;
893                                 tottrans++;
894                         }
895
896                         /*  Only add the root if there is no connection */
897                         if (ebo->flag & BONE_ROOTSEL){
898                                 if (!(ebo->parent && (ebo->flag & BONE_CONNECTED) && ebo->parent->flag & BONE_TIPSEL)){
899                                         VECCOPY (tv->oldloc, ebo->head);
900                                         tv->loc= ebo->head;
901                                         tv->nor= NULL;
902                                         tv->flag= 1;
903                                         tv++;
904                                         tottrans++;
905                                 }               
906                         }
907                         
908                 }
909         }
910         else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
911                 nu= editNurb.first;
912                 while(nu) {
913                         if((nu->type & 7)==CU_BEZIER) {
914                                 a= nu->pntsu;
915                                 bezt= nu->bezt;
916                                 while(a--) {
917                                         if(bezt->hide==0) {
918                                                 if(mode==1 || (bezt->f1 & 1)) {
919                                                         VECCOPY(tv->oldloc, bezt->vec[0]);
920                                                         tv->loc= bezt->vec[0];
921                                                         tv->flag= bezt->f1 & 1;
922                                                         tv++;
923                                                         tottrans++;
924                                                 }
925                                                 if(mode==1 || (bezt->f2 & 1)) {
926                                                         VECCOPY(tv->oldloc, bezt->vec[1]);
927                                                         tv->loc= bezt->vec[1];
928                                                         tv->val= &(bezt->alfa);
929                                                         tv->oldval= bezt->alfa;
930                                                         tv->flag= bezt->f2 & 1;
931                                                         tv++;
932                                                         tottrans++;
933                                                 }
934                                                 if(mode==1 || (bezt->f3 & 1)) {
935                                                         VECCOPY(tv->oldloc, bezt->vec[2]);
936                                                         tv->loc= bezt->vec[2];
937                                                         tv->flag= bezt->f3 & 1;
938                                                         tv++;
939                                                         tottrans++;
940                                                 }
941                                         }
942                                         bezt++;
943                                 }
944                         }
945                         else {
946                                 a= nu->pntsu*nu->pntsv;
947                                 bp= nu->bp;
948                                 while(a--) {
949                                         if(bp->hide==0) {
950                                                 if(mode==1 || (bp->f1 & 1)) {
951                                                         VECCOPY(tv->oldloc, bp->vec);
952                                                         tv->loc= bp->vec;
953                                                         tv->val= &(bp->alfa);
954                                                         tv->oldval= bp->alfa;
955                                                         tv->flag= bp->f1 & 1;
956                                                         tv++;
957                                                         tottrans++;
958                                                 }
959                                         }
960                                         bp++;
961                                 }
962                         }
963                         nu= nu->next;
964                 }
965         }
966         else if(G.obedit->type==OB_MBALL) {
967                 extern ListBase editelems;  /* go away ! */
968                 ml= editelems.first;
969                 while(ml) {
970                         if(ml->flag & SELECT) {
971                                 tv->loc= &ml->x;
972                                 VECCOPY(tv->oldloc, tv->loc);
973                                 tv->val= &(ml->rad);
974                                 tv->oldval= ml->rad;
975                                 tv->flag= 1;
976                                 tv++;
977                                 tottrans++;
978                         }
979                         ml= ml->next;
980                 }
981         }
982         else if(G.obedit->type==OB_LATTICE) {
983                 bp= editLatt->def;
984                 
985                 a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
986                 
987                 while(a--) {
988                         if(mode==1 || (bp->f1 & 1)) {
989                                 if(bp->hide==0) {
990                                         VECCOPY(tv->oldloc, bp->vec);
991                                         tv->loc= bp->vec;
992                                         tv->flag= bp->f1 & 1;
993                                         tv++;
994                                         tottrans++;
995                                 }
996                         }
997                         bp++;
998                 }
999         }
1000         
1001         /* cent etc */
1002         tv= transvmain;
1003         total= 0.0;
1004         for(a=0; a<tottrans; a++, tv++) {
1005                 if(tv->flag & SELECT) {
1006                         centroid[0]+= tv->oldloc[0];
1007                         centroid[1]+= tv->oldloc[1];
1008                         centroid[2]+= tv->oldloc[2];
1009                         total+= 1.0;
1010                         DO_MINMAX(tv->oldloc, min, max);
1011                 }
1012         }
1013         if(total!=0.0) {
1014                 centroid[0]/= total;
1015                 centroid[1]/= total;
1016                 centroid[2]/= total;
1017         }
1018
1019         centre[0]= (min[0]+max[0])/2.0;
1020         centre[1]= (min[1]+max[1])/2.0;
1021         centre[2]= (min[2]+max[2])/2.0;
1022         
1023 }
1024
1025 void snap_sel_to_grid()
1026 {
1027         extern float originmat[3][3];   /* object.c */
1028         TransVert *tv;
1029         Base *base;
1030         Object *ob;
1031         float gridf, imat[3][3], bmat[3][3], vec[3];
1032         int a;
1033
1034         gridf= G.vd->gridview;
1035
1036
1037         if(G.obedit) {
1038                 tottrans= 0;
1039                 
1040                 if ELEM6(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) 
1041                         make_trans_verts(bmat[0], bmat[1], 0);
1042                 if(tottrans==0) return;
1043
1044                 Mat3CpyMat4(bmat, G.obedit->obmat);
1045                 Mat3Inv(imat, bmat);
1046
1047                 tv= transvmain;
1048                 for(a=0; a<tottrans; a++, tv++) {
1049
1050                         VECCOPY(vec, tv->loc);
1051                         Mat3MulVecfl(bmat, vec);
1052                         VecAddf(vec, vec, G.obedit->obmat[3]);
1053                         vec[0]= G.vd->gridview*floor(.5+ vec[0]/gridf);
1054                         vec[1]= G.vd->gridview*floor(.5+ vec[1]/gridf);
1055                         vec[2]= G.vd->gridview*floor(.5+ vec[2]/gridf);
1056                         VecSubf(vec, vec, G.obedit->obmat[3]);
1057
1058                         Mat3MulVecfl(imat, vec);
1059                         VECCOPY(tv->loc, vec);
1060
1061                 }
1062
1063                 MEM_freeN(transvmain);
1064                 transvmain= 0;
1065                 
1066                 special_transvert_update();
1067
1068                 allqueue(REDRAWVIEW3D, 0);
1069                 return;
1070         }
1071
1072         base= (G.scene->base.first);
1073         while(base) {
1074                 if( ( ((base)->flag & SELECT) && ((base)->lay & G.vd->lay) && ((base)->object->id.lib==0))) {
1075                         ob= base->object;
1076                         if(ob->flag & OB_POSEMODE) {
1077                                 ;       // todo
1078                         }
1079                         else {
1080                                 ob->recalc |= OB_RECALC_OB;
1081                                 
1082                                 vec[0]= -ob->obmat[3][0]+G.vd->gridview*floor(.5+ ob->obmat[3][0]/gridf);
1083                                 vec[1]= -ob->obmat[3][1]+G.vd->gridview*floor(.5+ ob->obmat[3][1]/gridf);
1084                                 vec[2]= -ob->obmat[3][2]+G.vd->gridview*floor(.5+ ob->obmat[3][2]/gridf);
1085
1086                                 if(ob->parent) {
1087                                         where_is_object(ob);
1088
1089                                         Mat3Inv(imat, originmat);
1090                                         Mat3MulVecfl(imat, vec);
1091                                         ob->loc[0]+= vec[0];
1092                                         ob->loc[1]+= vec[1];
1093                                         ob->loc[2]+= vec[2];
1094                                 }
1095                                 else {
1096                                         ob->loc[0]+= vec[0];
1097                                         ob->loc[1]+= vec[1];
1098                                         ob->loc[2]+= vec[2];
1099                                 }
1100                         }
1101                 }
1102
1103                 base= base->next;
1104         }
1105         DAG_scene_flush_update(G.scene);
1106         allqueue(REDRAWVIEW3D, 0);
1107 }
1108
1109 void snap_sel_to_curs()
1110 {
1111         extern float originmat[3][3];   /* object.c */
1112         TransVert *tv;
1113         Base *base;
1114         Object *ob;
1115         float *curs, imat[3][3], bmat[3][3], vec[3];
1116         int a;
1117
1118         curs= give_cursor();
1119
1120         if(G.obedit) {
1121                 tottrans= 0;
1122
1123                 if ELEM6(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) 
1124                         make_trans_verts(bmat[0], bmat[1], 0);
1125                 if(tottrans==0) return;
1126
1127                 Mat3CpyMat4(bmat, G.obedit->obmat);
1128                 Mat3Inv(imat, bmat);
1129
1130                 tv= transvmain;
1131                 for(a=0; a<tottrans; a++, tv++) {
1132
1133                         vec[0]= curs[0]-G.obedit->obmat[3][0];
1134                         vec[1]= curs[1]-G.obedit->obmat[3][1];
1135                         vec[2]= curs[2]-G.obedit->obmat[3][2];
1136
1137                         Mat3MulVecfl(imat, vec);
1138                         VECCOPY(tv->loc, vec);
1139
1140                 }
1141                 MEM_freeN(transvmain);
1142                 transvmain= 0;
1143
1144                 special_transvert_update();
1145
1146                 allqueue(REDRAWVIEW3D, 0);
1147                 return;
1148         }
1149
1150         base= (G.scene->base.first);
1151         while(base) {
1152                 if( ( ((base)->flag & SELECT) && ((base)->lay & G.vd->lay) && ((base)->object->id.lib==0))) {
1153                         ob= base->object;
1154                         if(ob->flag & OB_POSEMODE) {
1155                                 ; // todo
1156                         }
1157                         else {
1158                                 ob->recalc |= OB_RECALC_OB;
1159                                 
1160                                 vec[0]= -ob->obmat[3][0] + curs[0];
1161                                 vec[1]= -ob->obmat[3][1] + curs[1];
1162                                 vec[2]= -ob->obmat[3][2] + curs[2];
1163
1164                                 if(ob->parent) {
1165                                         where_is_object(ob);
1166
1167                                         Mat3Inv(imat, originmat);
1168                                         Mat3MulVecfl(imat, vec);
1169                                         ob->loc[0]+= vec[0];
1170                                         ob->loc[1]+= vec[1];
1171                                         ob->loc[2]+= vec[2];
1172                                 }
1173                                 else {
1174                                         ob->loc[0]+= vec[0];
1175                                         ob->loc[1]+= vec[1];
1176                                         ob->loc[2]+= vec[2];
1177                                 }
1178                         }
1179                 }
1180
1181                 base= base->next;
1182         }
1183         DAG_scene_flush_update(G.scene);
1184         allqueue(REDRAWVIEW3D, 0);
1185 }
1186
1187 void snap_curs_to_grid()
1188 {
1189         float gridf, *curs;
1190
1191         gridf= G.vd->gridview;
1192         curs= give_cursor();
1193
1194         curs[0]= G.vd->gridview*floor(.5+curs[0]/gridf);
1195         curs[1]= G.vd->gridview*floor(.5+curs[1]/gridf);
1196         curs[2]= G.vd->gridview*floor(.5+curs[2]/gridf);
1197
1198         allqueue(REDRAWVIEW3D, 0);
1199
1200 }
1201
1202 void snap_curs_to_sel()
1203 {
1204         TransVert *tv;
1205         Base *base;
1206         float *curs, bmat[3][3], vec[3], min[3], max[3], centroid[3];
1207         int count, a;
1208
1209         curs= give_cursor();
1210
1211         count= 0;
1212         INIT_MINMAX(min, max);
1213         centroid[0]= centroid[1]= centroid[2]= 0.0;
1214
1215         if(G.obedit) {
1216                 tottrans=0;
1217
1218                 if ELEM6(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) 
1219                         make_trans_verts(bmat[0], bmat[1], 0);
1220                 if(tottrans==0) return;
1221
1222                 Mat3CpyMat4(bmat, G.obedit->obmat);
1223
1224                 tv= transvmain;
1225                 for(a=0; a<tottrans; a++, tv++) {
1226                         VECCOPY(vec, tv->loc);
1227                         Mat3MulVecfl(bmat, vec);
1228                         VecAddf(vec, vec, G.obedit->obmat[3]);
1229                         VecAddf(centroid, centroid, vec);
1230                         DO_MINMAX(vec, min, max);
1231                 }
1232
1233                 if(G.vd->around==V3D_CENTROID) {
1234                         VecMulf(centroid, 1.0/(float)tottrans);
1235                         VECCOPY(curs, centroid);
1236                 }
1237                 else {
1238                         curs[0]= (min[0]+max[0])/2;
1239                         curs[1]= (min[1]+max[1])/2;
1240                         curs[2]= (min[2]+max[2])/2;
1241                 }
1242                 MEM_freeN(transvmain);
1243                 transvmain= 0;
1244         }
1245         else {
1246                 Object *ob= OBACT;
1247                 
1248                 if(ob && (ob->flag & OB_POSEMODE)) {
1249                         bPoseChannel *pchan;
1250                         for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) {
1251                                 if(pchan->bone->flag & BONE_SELECTED) {
1252                                         VECCOPY(vec, pchan->pose_head);
1253                                         Mat4MulVecfl(ob->obmat, vec);
1254                                         VecAddf(centroid, centroid, vec);
1255                                         DO_MINMAX(vec, min, max);
1256                                         count++;
1257                                 }
1258                         }
1259                 }
1260                 else {
1261                         for(base= G.scene->base.first; base; base= base->next) {
1262                                 if(((base)->flag & SELECT) && ((base)->lay & G.vd->lay) ) {
1263                                         VECCOPY(vec, base->object->obmat[3]);
1264                                         VecAddf(centroid, centroid, vec);
1265                                         DO_MINMAX(vec, min, max);
1266                                         count++;
1267                                 }
1268                         }
1269                 }
1270                 if(count) {
1271                         if(G.vd->around==V3D_CENTROID) {
1272                                 VecMulf(centroid, 1.0/(float)count);
1273                                 VECCOPY(curs, centroid);
1274                         }
1275                         else {
1276                                 curs[0]= (min[0]+max[0])/2;
1277                                 curs[1]= (min[1]+max[1])/2;
1278                                 curs[2]= (min[2]+max[2])/2;
1279                         }
1280                 }
1281         }
1282         allqueue(REDRAWVIEW3D, 0);
1283 }
1284
1285 void snap_curs_to_firstsel()
1286 {
1287         TransVert *tv;
1288         Base *base;
1289         float *curs, bmat[3][3], vec[3], min[3], max[3], centroid[3];
1290         int count;
1291
1292         curs= give_cursor();
1293
1294         count= 0;
1295         INIT_MINMAX(min, max);
1296         centroid[0]= centroid[1]= centroid[2]= 0.0;
1297
1298         if(G.obedit) {
1299                 tottrans=0;
1300
1301                 if ELEM6(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) 
1302                         make_trans_verts(bmat[0], bmat[1], 0);
1303                 if(tottrans==0) return;
1304
1305                 Mat3CpyMat4(bmat, G.obedit->obmat);
1306
1307                 tv= transvmain;
1308                 VECCOPY(vec, tv->loc);
1309                         /*Mat3MulVecfl(bmat, vec);
1310                         VecAddf(vec, vec, G.obedit->obmat[3]);
1311                         VecAddf(centroid, centroid, vec);
1312                         DO_MINMAX(vec, min, max);*/
1313
1314                 if(G.vd->around==V3D_CENTROID) {
1315                         VecMulf(vec, 1.0/(float)tottrans);
1316                         VECCOPY(curs, vec);
1317                 }
1318                 else {
1319                         curs[0]= vec[0];
1320                         curs[1]= vec[1];
1321                         curs[2]= vec[2];
1322                 }
1323                 MEM_freeN(transvmain);
1324                 transvmain= 0;
1325         }
1326         else {
1327                 base= (G.scene->base.first);
1328                 while(base) {
1329                         if(((base)->flag & SELECT) && ((base)->lay & G.vd->lay) ) {
1330                                 VECCOPY(vec, base->object->obmat[3]);
1331                                 VecAddf(centroid, centroid, vec);
1332                                 DO_MINMAX(vec, min, max);
1333                                 count++;
1334                         }
1335                         base= base->next;
1336                 }
1337                 if(count) {
1338                         if(G.vd->around==V3D_CENTROID) {
1339                                 VecMulf(centroid, 1.0/(float)count);
1340                                 VECCOPY(curs, centroid);
1341                         }
1342                         else {
1343                                 curs[0]= (min[0]+max[0])/2;
1344                                 curs[1]= (min[1]+max[1])/2;
1345                                 curs[2]= (min[2]+max[2])/2;
1346                         }
1347                 }
1348         }
1349         allqueue(REDRAWVIEW3D, 0);
1350 }
1351
1352 void snap_to_center()
1353 {
1354         extern float originmat[3][3];
1355         TransVert *tv;
1356         Base *base;
1357         Object *ob;
1358         float snaploc[3], imat[3][3], bmat[3][3], vec[3], min[3], max[3], centroid[3];
1359         int count, a;
1360
1361         /*calculate the snaplocation (centerpoint) */
1362         count= 0;
1363         INIT_MINMAX(min, max);
1364         centroid[0]= centroid[1]= centroid[2]= 0.0;
1365
1366         if(G.obedit) {
1367                 tottrans= 0;
1368
1369                 if ELEM6(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) 
1370                         make_trans_verts(bmat[0], bmat[1], 0);
1371                 if(tottrans==0) return;
1372
1373                 Mat3CpyMat4(bmat, G.obedit->obmat);
1374                 Mat3Inv(imat, bmat);
1375
1376                 tv= transvmain;
1377                 for(a=0; a<tottrans; a++, tv++) {
1378                         VECCOPY(vec, tv->loc);
1379                         Mat3MulVecfl(bmat, vec);
1380                         VecAddf(vec, vec, G.obedit->obmat[3]);
1381                         VecAddf(centroid, centroid, vec);
1382                         DO_MINMAX(vec, min, max);
1383                 }
1384
1385                 if(G.vd->around==V3D_CENTROID) {
1386                         VecMulf(centroid, 1.0/(float)tottrans);
1387                         VECCOPY(snaploc, centroid);
1388                 }
1389                 else {
1390                         snaploc[0]= (min[0]+max[0])/2;
1391                         snaploc[1]= (min[1]+max[1])/2;
1392                         snaploc[2]= (min[2]+max[2])/2;
1393                 }
1394                 
1395                 MEM_freeN(transvmain);
1396                 transvmain= 0;
1397
1398         }
1399         else {
1400                 base= (G.scene->base.first);
1401                 while(base) {
1402                         if(((base)->flag & SELECT) && ((base)->lay & G.vd->lay) ) {
1403                                 VECCOPY(vec, base->object->obmat[3]);
1404                                 VecAddf(centroid, centroid, vec);
1405                                 DO_MINMAX(vec, min, max);
1406                                 count++;
1407                         }
1408                         base= base->next;
1409                 }
1410                 if(count) {
1411                         if(G.vd->around==V3D_CENTROID) {
1412                                 VecMulf(centroid, 1.0/(float)count);
1413                                 VECCOPY(snaploc, centroid);
1414                         }
1415                         else {
1416                                 snaploc[0]= (min[0]+max[0])/2;
1417                                 snaploc[1]= (min[1]+max[1])/2;
1418                                 snaploc[2]= (min[2]+max[2])/2;
1419                         }
1420                 }
1421         }
1422
1423         /* Snap the selection to the snaplocation (duh!) */
1424         if(G.obedit) {
1425                 tottrans= 0;
1426
1427                 if ELEM6(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) 
1428                         make_trans_verts(bmat[0], bmat[1], 0);
1429                 if(tottrans==0) return;
1430
1431                 Mat3CpyMat4(bmat, G.obedit->obmat);
1432                 Mat3Inv(imat, bmat);
1433
1434                 tv= transvmain;
1435                 for(a=0; a<tottrans; a++, tv++) {
1436
1437                         vec[0]= snaploc[0]-G.obedit->obmat[3][0];
1438                         vec[1]= snaploc[1]-G.obedit->obmat[3][1];
1439                         vec[2]= snaploc[2]-G.obedit->obmat[3][2];
1440
1441                         Mat3MulVecfl(imat, vec);
1442                         VECCOPY(tv->loc, vec);
1443                 }
1444                 MEM_freeN(transvmain);
1445                 transvmain= 0;
1446
1447                 special_transvert_update();
1448
1449                 allqueue(REDRAWVIEW3D, 0);
1450                 return;
1451         }
1452
1453         base= (G.scene->base.first);
1454         while(base) {
1455                 if( ( ((base)->flag & SELECT) && ((base)->lay & G.vd->lay) && ((base)->object->id.lib==0))) {
1456                         ob= base->object;
1457                         if(ob->flag & OB_POSEMODE) {
1458                                 ; // todo
1459                         }
1460                         else {
1461                                 ob->recalc |= OB_RECALC_OB;
1462                                 
1463                                 vec[0]= -ob->obmat[3][0] + snaploc[0];
1464                                 vec[1]= -ob->obmat[3][1] + snaploc[1];
1465                                 vec[2]= -ob->obmat[3][2] + snaploc[2];
1466
1467                                 if(ob->parent) {
1468                                         where_is_object(ob);
1469
1470                                         Mat3Inv(imat, originmat);
1471                                         Mat3MulVecfl(imat, vec);
1472                                         ob->loc[0]+= vec[0];
1473                                         ob->loc[1]+= vec[1];
1474                                         ob->loc[2]+= vec[2];
1475                                 }
1476                                 else {
1477                                         ob->loc[0]+= vec[0];
1478                                         ob->loc[1]+= vec[1];
1479                                         ob->loc[2]+= vec[2];
1480                                 }
1481                         }
1482                 }
1483
1484                 base= base->next;
1485         }
1486         DAG_scene_flush_update(G.scene);
1487         allqueue(REDRAWVIEW3D, 0);
1488 }
1489
1490
1491 void snapmenu()
1492 {
1493         short event;
1494
1495         event = pupmenu("Snap %t|Selection -> Grid%x1|Selection -> Cursor%x2|Cursor-> Grid%x3|Cursor-> Selection%x4|Selection-> Center%x5");
1496
1497         switch (event) {
1498                 case 1: /*Selection to grid*/
1499                     snap_sel_to_grid();
1500                         BIF_undo_push("Snap selection to grid");
1501                     break;
1502                 case 2: /*Selection to cursor*/
1503                     snap_sel_to_curs();
1504                         BIF_undo_push("Snap selection to cursor");
1505                     break;          
1506                 case 3: /*Cursor to grid*/
1507                     snap_curs_to_grid();
1508                     break;
1509                 case 4: /*Cursor to selection*/
1510                     snap_curs_to_sel();
1511                     break;
1512                 case 5: /*Selection to center of selection*/
1513                     snap_to_center();
1514                         BIF_undo_push("Snap selection to center");
1515                     break;
1516         }
1517 }
1518
1519
1520 void mergemenu(void)
1521 {
1522         short event;
1523
1524         event = pupmenu("Merge %t|At Center%x1|At Cursor%x2");
1525
1526         if (event==-1) return; /* Return if the menu is closed without any choices */
1527
1528         if (event==1) 
1529                 snap_to_center(); /*Merge at Center*/
1530         else
1531                 snap_sel_to_curs(); /*Merge at Cursor*/
1532
1533         notice("Removed %d Vertices", removedoublesflag(1, G.scene->toolsettings->doublimit));
1534         allqueue(REDRAWVIEW3D, 0);
1535         countall();
1536         BIF_undo_push("Merge"); /* push the mesh down the undo pipe */
1537
1538 }
1539
1540 void delete_context_selected(void) 
1541 {
1542         if(G.obedit) {
1543                 if(G.obedit->type==OB_MESH) delete_mesh();
1544                 else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) delNurb();
1545                 else if(G.obedit->type==OB_MBALL) delete_mball();
1546                 else if (G.obedit->type==OB_ARMATURE) delete_armature();
1547         }
1548         else delete_obj(0);
1549 }
1550
1551 void duplicate_context_selected(void) 
1552 {
1553         if(G.obedit) {
1554                 if(G.obedit->type==OB_MESH) adduplicate_mesh();
1555                 else if(G.obedit->type==OB_ARMATURE) adduplicate_armature();
1556                 else if(G.obedit->type==OB_MBALL) adduplicate_mball();
1557                 else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) adduplicate_nurb();
1558         }
1559         else {
1560                 adduplicate(0);
1561         }
1562 }
1563
1564 void toggle_shading(void) 
1565 {
1566         if(G.qual & LR_SHIFTKEY) {
1567                 if(G.qual & LR_ALTKEY) {
1568                         reshadeall_displist();
1569                         G.vd->drawtype= OB_SHADED;
1570                 }
1571                 else {
1572                         if(G.vd->drawtype== OB_SHADED) G.vd->drawtype= OB_WIRE;
1573                         else G.vd->drawtype= OB_SHADED;
1574                 }
1575         }
1576         else if(G.qual & LR_ALTKEY) {
1577                 if(G.vd->drawtype== OB_TEXTURE) G.vd->drawtype= OB_SOLID;
1578                 else G.vd->drawtype= OB_TEXTURE;
1579         }
1580         else {
1581                 if(G.vd->drawtype==OB_SOLID || G.vd->drawtype==OB_SHADED) G.vd->drawtype= OB_WIRE;
1582                 else G.vd->drawtype= OB_SOLID;
1583         }
1584 }
1585
1586 void minmax_verts(float *min, float *max)
1587 {
1588         TransVert *tv;
1589         float centroid[3], vec[3], bmat[3][3];
1590         int a;
1591
1592         tottrans=0;
1593         if ELEM5(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE) 
1594                 make_trans_verts(bmat[0], bmat[1], 0);
1595         if(tottrans==0) return;
1596
1597         Mat3CpyMat4(bmat, G.obedit->obmat);
1598         
1599         tv= transvmain;
1600         for(a=0; a<tottrans; a++, tv++) {               
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         
1608         MEM_freeN(transvmain);
1609         transvmain= 0;
1610 }
1611