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