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