- replaced G.{edve,eded,edvl} with G.editMesh, atm just a structure to
[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
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #ifndef WIN32
40 #include <unistd.h>
41 #else
42 #include <io.h>
43 #include "BLI_winstuff.h"
44 #endif   
45 #include "MEM_guardedalloc.h"
46
47 #include "BMF_Api.h"
48
49 #include "DNA_armature_types.h"
50 #include "DNA_curve_types.h"
51 #include "DNA_lattice_types.h"
52 #include "DNA_meta_types.h"
53 #include "DNA_mesh_types.h"
54 #include "DNA_object_types.h"
55 #include "DNA_screen_types.h"
56 #include "DNA_scene_types.h"
57 #include "DNA_space_types.h"
58 #include "DNA_view3d_types.h"
59
60 #include "BLI_blenlib.h"
61 #include "BLI_arithb.h"
62 #include "BLI_editVert.h"
63
64 #include "BKE_utildefines.h"
65 #include "BKE_anim.h"
66 #include "BKE_object.h"
67 #include "BKE_displist.h"
68 #include "BKE_global.h"
69 #include "BKE_lattice.h"
70 #include "BKE_mesh.h"
71
72 #include "BIF_gl.h"
73 #include "BIF_mywindow.h"
74 #include "BIF_screen.h"
75 #include "BIF_interface.h"
76 #include "BIF_space.h"
77 #include "BIF_editview.h"
78 #include "BIF_glutil.h"
79 #include "BIF_toolbox.h"
80 #include "BIF_editmesh.h"
81
82 #include "BSE_view.h"
83 #include "BSE_edit.h"
84 #include "BSE_trans_types.h"
85 #include "BSE_drawipo.h"
86 #include "BSE_drawview.h"
87
88 #include "BDR_editobject.h"
89 #include "BDR_editmball.h"
90 #include "BDR_editcurve.h"
91
92 /* old stuff */
93 #include "blendef.h"
94 #include "mydevice.h"
95
96 /*#include "armature.h"*/
97 /*  #include "edit.h" */
98 #include "nla.h"
99
100 #ifdef __NLA
101 #include "BIF_editarmature.h"
102 #endif
103
104 /* editmball.c */
105 extern ListBase editelems;  /* go away ! */
106
107
108 /* from editobject */
109 extern void make_trans_verts(float *min, float *max, int mode);     
110
111 /* circle selection callback */
112 typedef void (*select_CBfunc)(short selecting, Object *editobj, short *mval, float rad);
113
114 extern void obedit_selectionCB(short selecting, Object *editobj, 
115                                short *mval, float rad);
116 extern void uvedit_selectionCB(short selecting, Object *editobj, 
117                                short *mval, float rad);
118
119 void circle_selectCB(select_CBfunc func);
120
121 int get_border(rcti *rect, short col)
122 {
123         float dvec[4], fac1, fac2;
124         int retval=1;
125         unsigned short event;
126         short mval[2], mvalo[4], val, x1, y1;
127         char str[64];
128
129         mywinset(G.curscreen->mainwin);
130         
131         /* slightly larger, 1 pixel at the edge */
132         glReadBuffer(GL_FRONT);
133         glDrawBuffer(GL_FRONT);
134
135         /* removed my_get_frontbuffer, this crashes when it gets a part outside the screen */
136         /* solved it with just a redraw! */
137
138         mywinset(curarea->win);
139         
140         glDrawBuffer(GL_FRONT);
141         persp(PERSP_WIN);
142         initgrabz(0.0, 0.0, 0.0);
143         
144         getmouseco_areawin(mvalo);
145
146         /* draws the selection initial cross */
147         sdrawXORline4(0, 0,  mvalo[1],  curarea->winx,  mvalo[1]);
148         sdrawXORline4(1, mvalo[0],  0,  mvalo[0],  curarea->winy); 
149
150         while(TRUE) {
151         
152                 /* for when a renderwindow is open, and a mouse cursor activates it */
153                 persp(PERSP_VIEW);
154                 mywinset(curarea->win);
155                 persp(PERSP_WIN);
156                 
157                 /* selection loop while mouse pressed */
158                 getmouseco_areawin(mval);
159
160                 if(mvalo[0]!=mval[0] || mvalo[1]!=mval[1]) {
161
162                         /* aiming cross */
163                         sdrawXORline4(0, 0,  mval[1],  curarea->winx,  mval[1]);
164                         sdrawXORline4(1, mval[0],  0,  mval[0],  curarea->winy);
165                         glFlush();
166
167                         mvalo[0]= mval[0];
168                         mvalo[1]= mval[1];
169                 }
170                 event= extern_qread(&val);
171
172                 if(event && val) {
173                         if(event==ESCKEY) {
174                                 retval= 0;
175                                 break;
176                         }
177                         else if(event==BKEY) {
178                                 /* b has been pressed twice: proceed with circle select */
179                                 retval= 0;
180                                 break;
181                         }
182                         else if(event==LEFTMOUSE) break;
183                         else if(event==MIDDLEMOUSE) break;
184                         else if(event==RIGHTMOUSE) break;
185                 }
186         } /* end while (TRUE) */
187
188         /* erase XORed lines */
189         sdrawXORline4(-1, 0, 0, 0, 0);
190         
191         if(retval) {
192                 /* box select */
193                 x1= mval[0];
194                 y1= mval[1];
195                 
196                 getmouseco_areawin(mvalo);
197
198                 sdrawXORline4(0, x1, y1, x1, mvalo[1]); 
199                 sdrawXORline4(1, x1, mvalo[1], mvalo[0], mvalo[1]); 
200                 sdrawXORline4(2, mvalo[0], mvalo[1], mvalo[0], y1); 
201                 sdrawXORline4(3,  mvalo[0], y1, x1, y1); 
202                 glFlush();
203                         
204                 while(TRUE) {
205                         getmouseco_areawin(mval);
206                         if(mvalo[0]!=mval[0] || mvalo[1]!=mval[1]) {
207
208                                 sdrawXORline4(0, x1, y1, x1, mval[1]); 
209                                 sdrawXORline4(1, x1, mval[1], mval[0], mval[1]); 
210                                 sdrawXORline4(2, mval[0], mval[1], mval[0], y1); 
211                                 sdrawXORline4(3,  mval[0], y1, x1, y1); 
212                                 glFlush();
213
214                                 mvalo[0]= mval[0];
215                                 mvalo[1]= mval[1];
216                         }
217                         
218                         event= extern_qread(&val);
219                         
220                         /* still because of the renderwindow... */
221                         persp(PERSP_VIEW);
222                         mywinset(curarea->win);
223                         persp(PERSP_WIN);
224                                 
225                         if(val==0) {
226                                 if(event==ESCKEY) {
227                                         retval= 0;
228                                         break;
229                                 }
230                                 else if(event==LEFTMOUSE) break;
231                                 else if(event==MIDDLEMOUSE) break;
232                                 else if(event==RIGHTMOUSE) break;
233                         }
234                         
235                         if(curarea->spacetype==SPACE_VIEW3D) {
236                                 glColor3f(0.4375, 0.4375, 0.4375); 
237                                 glRecti(0, 10, 250, 20);
238                                 glColor3f(0.0, 0.0, 0.0); 
239
240                                 if(G.vd->persp==0) {
241                                         window_to_3d(dvec, mvalo[0]-x1, mvalo[1]-y1);
242
243                                         glRasterPos2i(10,  10);
244                                         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]));
245                                         BMF_DrawString(G.fonts, str);
246                                 }
247                                 else if(G.vd->persp==2) {
248                                         rcti vb;
249
250                                         calc_viewborder(G.vd, &vb);
251
252                                         fac1= (mvalo[0]-x1)/( (float) (vb.xmax-vb.xmin) );
253                                         fac1*= 0.01*G.scene->r.size*G.scene->r.xsch;
254                                         
255                                         fac2= (mvalo[1]-y1)/( (float) (vb.ymax-vb.ymin) );
256                                         fac2*= 0.01*G.scene->r.size*G.scene->r.ysch;
257                                         
258                                         glRasterPos2i(10,  10);
259                                         sprintf(str, "X %.1f  Y %.1f  Dia %.1f", fabs(fac1), fabs(fac2), sqrt(fac1*fac1 + fac2*fac2) );
260                                         BMF_DrawString(G.fonts, str);
261                                 }
262                         }
263                         else if(curarea->spacetype==SPACE_IPO) {
264                                 SpaceIpo *sipo= curarea->spacedata.first;
265
266                                 glColor3f(.40625, .40625, .40625);
267                                 glRecti(20, 30, 170, 40);
268                                 glColor3f(0.0, 0.0, 0.0); 
269                                                         
270                                 mvalo[2]= x1;
271                                 mvalo[3]= y1;
272                                 areamouseco_to_ipoco(&sipo->v2d, mval, dvec, dvec+1);
273                                 areamouseco_to_ipoco(&sipo->v2d, mvalo+2, dvec+2, dvec+3);
274
275                                 glRasterPos2i(30,  30);
276                                 sprintf(str, "Time: %.4f  Y %.4f", dvec[0]-dvec[2], dvec[1]-dvec[3]);
277                                 BMF_DrawString(G.fonts, str);
278                         }
279                 } /* end while (TRUE) */
280                 sdrawXORline4(-1, 0, 0, 0, 0);
281                 
282                 if(retval) {
283                         rect->xmin= x1;
284                         rect->ymin= y1;
285                         rect->xmax= mval[0];
286                         rect->ymax= mval[1];
287                         retval= event;
288
289                         /* normalise */
290                         if(rect->xmin>rect->xmax) SWAP(int, rect->xmin, rect->xmax);
291                         if(rect->ymin>rect->ymax) SWAP(int, rect->ymin, rect->ymax);
292                         
293                         if(rect->xmin==rect->xmax) retval= 0;
294                         if(rect->ymin==rect->ymax) retval= 0;
295                 }
296         }
297
298
299         /* clear */
300         if(event!=BKEY) {
301                 if ELEM(curarea->spacetype, SPACE_VIEW3D, SPACE_IPO) {
302                         scrarea_queue_winredraw(curarea);
303                 }
304         }
305         
306         glFlush();
307         glReadBuffer(GL_BACK);
308         glDrawBuffer(GL_BACK);
309
310         persp(PERSP_VIEW);
311         
312         /* pressed B again ? -> brush select */
313         if(event==BKEY) {
314                 switch (curarea->spacetype) {
315                 case SPACE_VIEW3D:
316                         if (G.obedit)
317                                 circle_selectCB(&obedit_selectionCB);
318                         return 0;
319                 case SPACE_IMAGE: // brush select in UV editor
320                         circle_selectCB(&uvedit_selectionCB);
321                         // this is a hack; we return 0 that the caller from get_border
322                         // doesn't execute the selection code for border select..
323                         return 0;
324                 }
325         }
326         return retval;
327 }
328
329 void draw_sel_circle(short *mval, short *mvalo, float rad, float rado, int selecting)
330 {
331         static short no_mvalo=0;
332
333         if(mval==0 && mvalo==0) {       /* signal */
334                 no_mvalo= 1;
335                 return;
336         }
337
338         persp(PERSP_WIN);
339         glDrawBuffer(GL_FRONT);
340
341         /* draw circle */
342
343         if(mvalo && no_mvalo==0) {
344                 sdrawXORcirc(mvalo[0], mvalo[1], rado);
345         }
346         
347         if(mval) {
348                 sdrawXORcirc(mval[0], mval[1], rad);
349         }
350
351         glFlush();
352         persp(PERSP_VIEW);
353         glDrawBuffer(GL_BACK);
354         
355         no_mvalo= 0;
356 }
357
358 /** This function does the same as editview.c:circle_select(),
359   * but the selection actions are defined by a callback, making
360   * it (hopefully) reusable for other windows than the 3D view.
361   */
362
363 void circle_selectCB(select_CBfunc callback)
364 {
365         static float rad= 40.0;
366         float rado;
367         int firsttime=1;
368         unsigned short event;
369         short mvalo[2], mval[2], val;
370         short selecting=0;
371         Object *obj;
372         
373         if(G.obedit) obj = G.obedit;
374         else obj = OBACT;
375
376         
377         getmouseco_areawin(mvalo);
378         draw_sel_circle(mvalo, 0, rad, 0.0, selecting);
379         
380         rado= rad;
381         
382         while(TRUE) {
383                 
384                 /* for when another window is open and a mouse cursor activates it */
385
386                 mywinset(curarea->win);
387
388                 getmouseco_areawin(mval);
389                 
390                 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || rado!=rad || firsttime) {
391                         firsttime= 0;
392                         
393                         draw_sel_circle(mval, mvalo, rad, rado, selecting);
394                 
395                         mvalo[0]= mval[0];
396                         mvalo[1]= mval[1];
397                         rado= rad;
398
399                         if(selecting) {
400                                 callback(selecting, obj, mval, rad);
401                         }
402                 }
403                 event= extern_qread(&val);
404                 if (event) {
405                         int afbreek= 0;
406                         
407                         switch(event) {
408                         case LEFTMOUSE:
409                         case MIDDLEMOUSE:
410                                 if(val) selecting= event;
411                                 else selecting= 0;
412                                 firsttime= 1;
413                                 
414                                 break;
415                         case WHEELDOWNMOUSE:
416                         case PADPLUSKEY:
417                                 if(val) if(rad<200.0) rad*= 1.2;
418                                 break;
419                         case WHEELUPMOUSE:
420                         case PADMINUS:
421                                 if(val) if(rad>5.0) rad/= 1.2;
422                                 break;
423                         
424                         case ESCKEY: case SPACEKEY: case RIGHTMOUSE:
425                         case GKEY: case SKEY: case RKEY: case XKEY: case EKEY: case TABKEY:
426                                 afbreek= 1;
427                                 break;
428
429                         }
430                         
431                         if(afbreek) break;
432                 }
433         }
434         
435         /* clear circle */
436         draw_sel_circle(0, mvalo, 0, rad, 1);
437
438         countall();
439         allqueue(REDRAWINFO, 0);
440 }
441
442 void count_object(Object *ob, int sel)
443 {
444         Mesh *me;
445         Curve *cu;
446         int tot=0, totf=0;
447         
448         switch(ob->type) {
449         case OB_MESH:
450                 G.totmesh++;
451                 me= get_mesh(ob);
452                 if(me) {
453                         int totvert, totface;
454                                 /* hack, should be getting displistmesh from a central function */
455                         if (mesh_uses_displist(me) && me->disp.first && ((DispList*)me->disp.first)->type==DL_MESH) {
456                                 DispListMesh *dlm= ((DispList*)me->disp.first)->mesh;
457                                 totvert= dlm->totvert;
458                                 totface= dlm->totface;
459                         } else {
460                                 totvert= me->totvert;
461                                 totface= me->totface;
462                         }
463                         
464                         G.totvert+= totvert;
465                         G.totface+= totface;
466                         if(sel) {
467                                 G.totvertsel+= totvert;
468                                 G.totfacesel+= totface;
469                         }
470                 }
471                 break;
472
473         case OB_LAMP:
474                 G.totlamp++;
475                 break;
476         case OB_SURF:
477         case OB_CURVE:
478         case OB_FONT:
479                 G.totcurve++;
480                 tot=totf= 0;
481                 cu= ob->data;
482                 if(cu->disp.first==0) makeDispList(ob);
483                 count_displist( &cu->disp, &tot, &totf);
484                 G.totvert+= tot;
485                 G.totface+= totf;
486                 if(sel) {
487                         G.totvertsel+= tot;
488                         G.totfacesel+= totf;
489                 }
490                 break;
491         case OB_MBALL:
492                 count_displist( &ob->disp, &tot, &totf);
493                 G.totvert+= tot;
494                 G.totface+= totf;
495                 if(sel) {
496                         G.totvertsel+= tot;
497                         G.totfacesel+= totf;
498                 }
499                 
500                 break;
501         }
502         
503 }
504
505 void countall()
506 {
507 /*      extern Lattice *editLatt; in BKE_lattice.h*/
508         extern ListBase editNurb;
509         /* extern ListBase bpbase; */
510         Base *base;
511         Object *ob;
512         Mesh *me;
513         Nurb *nu;
514         BezTriple *bezt;
515         BPoint *bp;
516         MetaElem *ml;
517         /* struct BodyPoint *bop; */
518         struct EditVert *eve;
519         struct EditVlak *evl;
520 #ifdef __NLA
521         struct EditBone *ebo;
522 #endif
523         int a;
524
525         G.totvert= G.totvertsel= G.totfacesel= G.totface= G.totobj= 
526             G.totmesh= G.totlamp= G.totcurve= G.totobjsel=  0;
527
528         if(G.obedit) {
529                 
530                 if(G.obedit->type==OB_MESH) {
531                         EditMesh *em = G.editMesh;
532                         eve= em->verts.first;
533                         while(eve) {
534                                 G.totvert++;
535                                 if(eve->f & 1) G.totvertsel++;
536                                 eve= eve->next;
537                         }
538                         evl= em->faces.first;
539                         while(evl) {
540                                 G.totface++;
541                                 if(evl->v1->f & 1) {
542                                         if(evl->v2->f & 1) {
543                                                 if(evl->v3->f & 1) {
544                                                         if(evl->v4)  {
545                                                                 if(evl->v4->f & 1) G.totfacesel++;
546                                                         }
547                                                         else {
548                                                                 G.totfacesel++;
549                                                         }
550                                                 }
551                                         }
552                                 }
553                                 evl= evl->next;
554                         }
555                 }
556 #ifdef __NLA
557                 else if (G.obedit->type==OB_ARMATURE){
558                         for (ebo=G.edbo.first;ebo;ebo=ebo->next){
559                                 
560                                 /* Sync selection to parent for ik children */
561                                 if ((ebo->flag & BONE_IK_TOPARENT) && ebo->parent){
562                                         G.totvert--;
563                                         if (ebo->parent->flag & BONE_TIPSEL)
564                                                 ebo->flag |= BONE_ROOTSEL;
565                                         else
566                                                 ebo->flag &= ~BONE_ROOTSEL;
567                                 }
568                                 
569                                 if (ebo->flag & BONE_TIPSEL)
570                                         G.totvertsel++;
571                                 if (ebo->flag & BONE_ROOTSEL)
572                                         G.totvertsel++;
573                                 
574                                 if ((ebo->flag & BONE_TIPSEL) && (ebo->flag & BONE_ROOTSEL))
575                                         ebo->flag |= BONE_SELECTED;
576                                 else
577                                         ebo->flag &= ~BONE_SELECTED;
578                                 
579                                 //      If this is an IK child and it's parent is being moved, remove our root
580                                 if ((ebo->flag & BONE_IK_TOPARENT)&& (ebo->flag & BONE_ROOTSEL) && ebo->parent && (ebo->parent->flag & BONE_TIPSEL)){
581                                         G.totvertsel--;
582                                 }
583
584                                 G.totvert+=2;
585                                 G.totface++;
586                                 
587
588                         }
589                 }
590 #endif
591                 else if ELEM3(G.obedit->type, OB_CURVE, OB_SURF, OB_FONT) {
592                         nu= editNurb.first;
593                         while(nu) {
594                                 if((nu->type & 7)==CU_BEZIER) {
595                                         bezt= nu->bezt;
596                                         a= nu->pntsu;
597                                         while(a--) {
598                                         G.totvert+=3;
599                                         if(bezt->f1) G.totvertsel++;
600                                         if(bezt->f2) G.totvertsel++;
601                                         if(bezt->f3) G.totvertsel++;
602                                         bezt++;
603                                 }
604                         }
605                         else {
606                                 bp= nu->bp;
607                                 a= nu->pntsu*nu->pntsv;
608                                 while(a--) {
609                                         G.totvert++;
610                                         if(bp->f1 & 1) G.totvertsel++;
611                                         bp++;
612                                 }
613                         }
614                         nu= nu->next;
615                 }
616         }
617         else if(G.obedit->type==OB_MBALL) {
618                 ml= editelems.first;
619                 while(ml) {
620                         G.totvert++;
621                         if(ml->flag & SELECT) G.totvertsel++;
622                         ml= ml->next;
623                 }
624         }
625         else if(G.obedit->type==OB_LATTICE) {
626                 bp= editLatt->def;
627                 
628                 a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
629                 while(a--) {
630                         G.totvert++;
631                         if(bp->f1 & 1) G.totvertsel++;
632                         bp++;
633                 }
634         }
635         
636         allqueue(REDRAWINFO, 1);        /* 1, because header->win==0! */
637                 return;
638         }
639         else if(G.f & (G_FACESELECT + G_VERTEXPAINT + G_TEXTUREPAINT +G_WEIGHTPAINT)) {
640                 me= get_mesh((G.scene->basact) ? (G.scene->basact->object) : 0);
641                 if(me) {
642                         G.totface= me->totface;
643                         G.totvert= me->totvert;
644                 }
645                 allqueue(REDRAWINFO, 1);        /* 1, because header->win==0! */
646                 return;
647         }
648
649         if(G.vd==0) return;
650         if(G.scene==0) return;
651
652         base= (G.scene->base.first);
653         while(base) {
654                 if(G.vd->lay & base->lay) {
655                         
656                         G.totobj++;
657                         if(base->flag & SELECT) G.totobjsel++;
658                         
659                         count_object(base->object, base->flag & SELECT);
660                         
661                         if(base->object->transflag & OB_DUPLI) {
662                                 extern ListBase duplilist;
663
664                                 make_duplilist(G.scene, base->object);
665                                 ob= duplilist.first;
666                                 while(ob) {
667                                         G.totobj++;
668                                         count_object(ob, base->flag & SELECT);
669                                         ob= ob->id.next;
670                                 }
671                                 free_duplilist();
672                         }
673                 }
674                 base= base->next;
675         }
676         allqueue(REDRAWINFO, 1);        /* 1, because header->win==0! */
677 }
678
679
680 void snap_sel_to_grid()
681 {
682         extern TransVert *transvmain;
683         extern int tottrans;
684         extern float originmat[3][3];   /* object.c */
685         TransVert *tv;
686         Base *base;
687         Object *ob;
688         float gridf, imat[3][3], bmat[3][3], vec[3];
689         int a;
690
691         gridf= G.vd->grid;
692
693
694                 if(G.obedit) {
695 #ifdef __NLA
696                         if ELEM5(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE) make_trans_verts(bmat[0], bmat[1], 0);
697 #else
698                         if ELEM4(G.obedit->type, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE) make_trans_verts(bmat[0], bmat[1], 0);
699 #endif
700                         if(tottrans==0) return;
701
702                         Mat3CpyMat4(bmat, G.obedit->obmat);
703                         Mat3Inv(imat, bmat);
704
705                         tv= transvmain;
706                         for(a=0; a<tottrans; a++, tv++) {
707
708                         VECCOPY(vec, tv->loc);
709                         Mat3MulVecfl(bmat, vec);
710                         VecAddf(vec, vec, G.obedit->obmat[3]);
711                         vec[0]= G.vd->grid*floor(.5+ vec[0]/gridf);
712                         vec[1]= G.vd->grid*floor(.5+ vec[1]/gridf);
713                         vec[2]= G.vd->grid*floor(.5+ vec[2]/gridf);
714                         VecSubf(vec, vec, G.obedit->obmat[3]);
715
716                         Mat3MulVecfl(imat, vec);
717                         VECCOPY(tv->loc, vec);
718
719                         }
720
721                         MEM_freeN(transvmain);
722                         transvmain= 0;
723
724                         if ELEM(G.obedit->type, OB_SURF, OB_CURVE) makeDispList(G.obedit);
725
726                         if (G.obedit->type == OB_ARMATURE)
727                                 special_trans_update(0);
728
729                         allqueue(REDRAWVIEW3D, 0);
730                         return;
731                 }
732 #ifdef __NLA
733                 if (G.obpose){
734                         allqueue(REDRAWVIEW3D, 0);
735                         return;
736                 }
737 #endif
738                 base= (G.scene->base.first);
739                 while(base) {
740                         if( ( ((base)->flag & SELECT) && ((base)->lay & G.vd->lay) && ((base)->object->id.lib==0))) {
741                                 ob= base->object;
742
743                                 vec[0]= -ob->obmat[3][0]+G.vd->grid*floor(.5+ ob->obmat[3][0]/gridf);
744                                 vec[1]= -ob->obmat[3][1]+G.vd->grid*floor(.5+ ob->obmat[3][1]/gridf);
745                                 vec[2]= -ob->obmat[3][2]+G.vd->grid*floor(.5+ ob->obmat[3][2]/gridf);
746
747                                 if(ob->parent) {
748                                         where_is_object(ob);
749
750                                         Mat3Inv(imat, originmat);
751                                         Mat3MulVecfl(imat, vec);
752                                         ob->loc[0]+= vec[0];
753                                         ob->loc[1]+= vec[1];
754                                         ob->loc[2]+= vec[2];
755                                 }
756                                 else {
757                                         ob->loc[0]+= vec[0];
758                                         ob->loc[1]+= vec[1];
759                                         ob->loc[2]+= vec[2];
760                                 }
761                         }
762
763                         base= base->next;
764                 }
765                 allqueue(REDRAWVIEW3D, 0);
766 }
767
768 void snap_sel_to_curs()
769 {
770         extern TransVert *transvmain;
771         extern int tottrans;
772         extern float originmat[3][3];   /* object.c */
773         TransVert *tv;
774         Base *base;
775         Object *ob;
776         float *curs, imat[3][3], bmat[3][3], vec[3];
777         int a;
778
779         curs= give_cursor();
780
781                 if(G.obedit) {
782 #ifdef __NLA
783                         if ELEM5(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE) make_trans_verts(bmat[0], bmat[1], 0);
784 #else
785                         if ELEM4(G.obedit->type, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE) make_trans_verts(bmat[0], bmat[1], 0);
786 #endif
787                         if(tottrans==0) return;
788
789                         Mat3CpyMat4(bmat, G.obedit->obmat);
790                         Mat3Inv(imat, bmat);
791
792                         tv= transvmain;
793                         for(a=0; a<tottrans; a++, tv++) {
794
795
796                                 vec[0]= curs[0]-G.obedit->obmat[3][0];
797                                 vec[1]= curs[1]-G.obedit->obmat[3][1];
798                                 vec[2]= curs[2]-G.obedit->obmat[3][2];
799
800
801                                 Mat3MulVecfl(imat, vec);
802                                 VECCOPY(tv->loc, vec);
803
804                         }
805                         MEM_freeN(transvmain);
806                         transvmain= 0;
807
808                         if ELEM(G.obedit->type, OB_SURF, OB_CURVE) makeDispList(G.obedit);
809
810                         if (G.obedit->type == OB_ARMATURE)
811                                 special_trans_update(0);
812
813                         allqueue(REDRAWVIEW3D, 0);
814                         return;
815                 }
816 #ifdef __NLA
817                 if (G.obpose){
818                         allqueue(REDRAWVIEW3D, 0);
819                         return;
820                 }
821 #endif
822                 base= (G.scene->base.first);
823                 while(base) {
824                         if( ( ((base)->flag & SELECT) && ((base)->lay & G.vd->lay) && ((base)->object->id.lib==0))) {
825                                 ob= base->object;
826
827                                 vec[0]= -ob->obmat[3][0] + curs[0];
828                                 vec[1]= -ob->obmat[3][1] + curs[1];
829                                 vec[2]= -ob->obmat[3][2] + curs[2];
830
831
832                                 if(ob->parent) {
833                                         where_is_object(ob);
834
835                                         Mat3Inv(imat, originmat);
836                                         Mat3MulVecfl(imat, vec);
837                                         ob->loc[0]+= vec[0];
838                                         ob->loc[1]+= vec[1];
839                                         ob->loc[2]+= vec[2];
840                                 }
841                                 else {
842                                         ob->loc[0]+= vec[0];
843                                         ob->loc[1]+= vec[1];
844                                         ob->loc[2]+= vec[2];
845                                 }
846                         }
847
848                         base= base->next;
849                 }
850                 allqueue(REDRAWVIEW3D, 0);
851 }
852
853 void snap_curs_to_grid()
854 {
855         float gridf, *curs;
856
857         gridf= G.vd->grid;
858         curs= give_cursor();
859
860         curs[0]= G.vd->grid*floor(.5+curs[0]/gridf);
861         curs[1]= G.vd->grid*floor(.5+curs[1]/gridf);
862         curs[2]= G.vd->grid*floor(.5+curs[2]/gridf);
863
864         allqueue(REDRAWVIEW3D, 0);
865
866 }
867
868 void snap_curs_to_sel()
869 {
870         extern TransVert *transvmain;
871         extern int tottrans;
872         TransVert *tv;
873         Base *base;
874         float *curs, bmat[3][3], vec[3], min[3], max[3], centroid[3];
875         int count, a;
876
877         curs= give_cursor();
878
879         count= 0;
880         INIT_MINMAX(min, max);
881         centroid[0]= centroid[1]= centroid[2]= 0.0;
882
883                 if(G.obedit) {
884                         tottrans=0;
885 #ifdef __NLA
886                         if ELEM5(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE) make_trans_verts(bmat[0], bmat[1], 0);
887 #else
888                         if ELEM4(G.obedit->type, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE) make_trans_verts(bmat[0], bmat[1], 0);
889 #endif
890                         if(tottrans==0) return;
891
892                         Mat3CpyMat4(bmat, G.obedit->obmat);
893
894                         tv= transvmain;
895                         for(a=0; a<tottrans; a++, tv++) {
896                                 VECCOPY(vec, tv->loc);
897                                 Mat3MulVecfl(bmat, vec);
898                                 VecAddf(vec, vec, G.obedit->obmat[3]);
899                                 VecAddf(centroid, centroid, vec);
900                                 DO_MINMAX(vec, min, max);
901                         }
902
903                         if(G.vd->around==V3D_CENTROID) {
904                                 VecMulf(centroid, 1.0/(float)tottrans);
905                                 VECCOPY(curs, centroid);
906                         }
907                         else {
908                                 curs[0]= (min[0]+max[0])/2;
909                                 curs[1]= (min[1]+max[1])/2;
910                                 curs[2]= (min[2]+max[2])/2;
911                         }
912                         MEM_freeN(transvmain);
913                         transvmain= 0;
914                 }
915                 else {
916                         base= (G.scene->base.first);
917                         while(base) {
918                                 if(((base)->flag & SELECT) && ((base)->lay & G.vd->lay) ) {
919                                         VECCOPY(vec, base->object->obmat[3]);
920                                         VecAddf(centroid, centroid, vec);
921                                         DO_MINMAX(vec, min, max);
922                                         count++;
923                                 }
924                                 base= base->next;
925                         }
926                         if(count) {
927                                 if(G.vd->around==V3D_CENTROID) {
928                                         VecMulf(centroid, 1.0/(float)count);
929                                         VECCOPY(curs, centroid);
930                                 }
931                                 else {
932                                         curs[0]= (min[0]+max[0])/2;
933                                         curs[1]= (min[1]+max[1])/2;
934                                         curs[2]= (min[2]+max[2])/2;
935                                 }
936                         }
937                 }
938                 allqueue(REDRAWVIEW3D, 0);
939 }
940
941 void snap_curs_to_firstsel()
942 {
943         extern TransVert *transvmain;
944         extern int tottrans;
945         TransVert *tv;
946         Base *base;
947         float *curs, bmat[3][3], vec[3], min[3], max[3], centroid[3];
948         int count;
949
950         curs= give_cursor();
951
952         count= 0;
953         INIT_MINMAX(min, max);
954         centroid[0]= centroid[1]= centroid[2]= 0.0;
955
956                 if(G.obedit) {
957                         tottrans=0;
958 #ifdef __NLA
959                         if ELEM5(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE) make_trans_verts(bmat[0], bmat[1], 0);
960 #else
961                         if ELEM4(G.obedit->type, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE) make_trans_verts(bmat[0], bmat[1], 0);
962 #endif
963                         if(tottrans==0) return;
964
965                         Mat3CpyMat4(bmat, G.obedit->obmat);
966
967                         tv= transvmain;
968                         VECCOPY(vec, tv->loc);
969                                 /*Mat3MulVecfl(bmat, vec);
970                                 VecAddf(vec, vec, G.obedit->obmat[3]);
971                                 VecAddf(centroid, centroid, vec);
972                                 DO_MINMAX(vec, min, max);*/
973
974                         if(G.vd->around==V3D_CENTROID) {
975                                 VecMulf(vec, 1.0/(float)tottrans);
976                                 VECCOPY(curs, vec);
977                         }
978                         else {
979                                 curs[0]= vec[0];
980                                 curs[1]= vec[1];
981                                 curs[2]= vec[2];
982                         }
983                         MEM_freeN(transvmain);
984                         transvmain= 0;
985                 }
986                 else {
987                         base= (G.scene->base.first);
988                         while(base) {
989                                 if(((base)->flag & SELECT) && ((base)->lay & G.vd->lay) ) {
990                                         VECCOPY(vec, base->object->obmat[3]);
991                                         VecAddf(centroid, centroid, vec);
992                                         DO_MINMAX(vec, min, max);
993                                         count++;
994                                 }
995                                 base= base->next;
996                         }
997                         if(count) {
998                                 if(G.vd->around==V3D_CENTROID) {
999                                         VecMulf(centroid, 1.0/(float)count);
1000                                         VECCOPY(curs, centroid);
1001                                 }
1002                                 else {
1003                                         curs[0]= (min[0]+max[0])/2;
1004                                         curs[1]= (min[1]+max[1])/2;
1005                                         curs[2]= (min[2]+max[2])/2;
1006                                 }
1007                         }
1008                 }
1009                 allqueue(REDRAWVIEW3D, 0);
1010 }
1011
1012 void snap_to_center()
1013 {
1014         extern TransVert *transvmain;
1015         extern int tottrans;
1016         extern float originmat[3][3];
1017         TransVert *tv;
1018         Base *base;
1019         Object *ob;
1020         float snaploc[3], imat[3][3], bmat[3][3], vec[3], min[3], max[3], centroid[3];
1021         int count, a;
1022
1023
1024 /*calculate the snaplocation (centerpoint) */
1025         count= 0;
1026         INIT_MINMAX(min, max);
1027         centroid[0]= centroid[1]= centroid[2]= 0.0;
1028
1029                 if(G.obedit) {
1030                         /*tottrans=0;*/
1031 #ifdef __NLA
1032                         if ELEM5(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE) make_trans_verts(bmat[0], bmat[1], 0);
1033 #else
1034                         if ELEM4(G.obedit->type, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE) make_trans_verts(bmat[0], bmat[1], 0);
1035 #endif
1036                         if(tottrans==0) return;
1037
1038                         Mat3CpyMat4(bmat, G.obedit->obmat);
1039                         Mat3Inv(imat, bmat);
1040
1041                         tv= transvmain;
1042                         for(a=0; a<tottrans; a++, tv++) {
1043                                 VECCOPY(vec, tv->loc);
1044                                 Mat3MulVecfl(bmat, vec);
1045                                 VecAddf(vec, vec, G.obedit->obmat[3]);
1046                                 VecAddf(centroid, centroid, vec);
1047                                 DO_MINMAX(vec, min, max);
1048                         }
1049
1050                         if(G.vd->around==V3D_CENTROID) {
1051                                 VecMulf(centroid, 1.0/(float)tottrans);
1052                                 VECCOPY(snaploc, centroid);
1053                         }
1054                         else {
1055                                 snaploc[0]= (min[0]+max[0])/2;
1056                                 snaploc[1]= (min[1]+max[1])/2;
1057                                 snaploc[2]= (min[2]+max[2])/2;
1058                         }
1059                         
1060                         MEM_freeN(transvmain);
1061                         transvmain= 0;
1062
1063                 }
1064                 else {
1065                         base= (G.scene->base.first);
1066                         while(base) {
1067                                 if(((base)->flag & SELECT) && ((base)->lay & G.vd->lay) ) {
1068                                         VECCOPY(vec, base->object->obmat[3]);
1069                                         VecAddf(centroid, centroid, vec);
1070                                         DO_MINMAX(vec, min, max);
1071                                         count++;
1072                                 }
1073                                 base= base->next;
1074                         }
1075                         if(count) {
1076                                 if(G.vd->around==V3D_CENTROID) {
1077                                         VecMulf(centroid, 1.0/(float)count);
1078                                         VECCOPY(snaploc, centroid);
1079                                 }
1080                                 else {
1081                                         snaploc[0]= (min[0]+max[0])/2;
1082                                         snaploc[1]= (min[1]+max[1])/2;
1083                                         snaploc[2]= (min[2]+max[2])/2;
1084                                 }
1085                         }
1086                 }
1087
1088
1089 /* Snap the selection to the snaplocation (duh!) */
1090
1091                 if(G.obedit) {
1092 #ifdef __NLA
1093                         if ELEM5(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE) make_trans_verts(bmat[0], bmat[1], 0);
1094 #else
1095                         if ELEM4(G.obedit->type, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE) make_trans_verts(bmat[0], bmat[1], 0);
1096 #endif
1097                         if(tottrans==0) return;
1098
1099                         Mat3CpyMat4(bmat, G.obedit->obmat);
1100                         Mat3Inv(imat, bmat);
1101
1102                         tv= transvmain;
1103                         for(a=0; a<tottrans; a++, tv++) {
1104
1105
1106                                 vec[0]= snaploc[0]-G.obedit->obmat[3][0];
1107                                 vec[1]= snaploc[1]-G.obedit->obmat[3][1];
1108                                 vec[2]= snaploc[2]-G.obedit->obmat[3][2];
1109
1110
1111                                 Mat3MulVecfl(imat, vec);
1112                                 VECCOPY(tv->loc, vec);
1113
1114                         }
1115                         MEM_freeN(transvmain);
1116                         transvmain= 0;
1117
1118                         if ELEM(G.obedit->type, OB_SURF, OB_CURVE) makeDispList(G.obedit);
1119
1120                         if (G.obedit->type == OB_ARMATURE)
1121                                 special_trans_update(0);
1122
1123                         allqueue(REDRAWVIEW3D, 0);
1124                         return;
1125                 }
1126 #ifdef __NLA
1127                 if (G.obpose){
1128                         allqueue(REDRAWVIEW3D, 0);
1129                         return;
1130                 }
1131 #endif
1132                 base= (G.scene->base.first);
1133                 while(base) {
1134                         if( ( ((base)->flag & SELECT) && ((base)->lay & G.vd->lay) && ((base)->object->id.lib==0))) {
1135                                 ob= base->object;
1136
1137                                 vec[0]= -ob->obmat[3][0] + snaploc[0];
1138                                 vec[1]= -ob->obmat[3][1] + snaploc[1];
1139                                 vec[2]= -ob->obmat[3][2] + snaploc[2];
1140
1141
1142                                 if(ob->parent) {
1143                                         where_is_object(ob);
1144
1145                                         Mat3Inv(imat, originmat);
1146                                         Mat3MulVecfl(imat, vec);
1147                                         ob->loc[0]+= vec[0];
1148                                         ob->loc[1]+= vec[1];
1149                                         ob->loc[2]+= vec[2];
1150                                 }
1151                                 else {
1152                                         ob->loc[0]+= vec[0];
1153                                         ob->loc[1]+= vec[1];
1154                                         ob->loc[2]+= vec[2];
1155                                 }
1156                         }
1157
1158                         base= base->next;
1159                 }
1160
1161                 allqueue(REDRAWVIEW3D, 0);
1162 }
1163
1164
1165 void snapmenu()
1166 {
1167         short event;
1168
1169         event = pupmenu("Snap %t|Selection -> Grid%x1|Selection -> Cursor%x2|Cursor-> Grid%x3|Cursor-> Selection%x4|Selection-> Center%x5");
1170
1171         switch (event) {
1172                 case 1: /*Selection to grid*/
1173                     snap_sel_to_grid();
1174                     break;
1175                 case 2: /*Selection to cursor*/
1176                     snap_sel_to_curs();
1177                     break;          
1178                 case 3: /*Cursor to grid*/
1179                     snap_curs_to_grid();
1180                     break;
1181                 case 4: /*Cursor to selection*/
1182                     snap_curs_to_sel();
1183                     break;
1184                 case 5: /*Selection to center of selection*/
1185                     snap_to_center();
1186                     break;
1187         }
1188 }
1189
1190
1191 void mergemenu(void)
1192 {
1193         extern float doublimit;
1194         short event;
1195
1196         event = pupmenu("MERGE %t|At Center%x1|At Cursor%x2");
1197
1198         if (event==-1) return; /* Return if the menu is closed without any choices */
1199
1200         undo_push_mesh("Merge"); /* The action has been confirmed, push the mesh down the undo pipe */
1201
1202         if (event==1) 
1203                 snap_to_center(); /*Merge at Center*/
1204         else
1205                 snap_sel_to_curs(); /*Merge at Cursor*/
1206
1207         notice("Removed: %d", removedoublesflag(1, doublimit));
1208         allqueue(REDRAWVIEW3D, 0);
1209         countall();
1210 }
1211
1212 void delete_context_selected(void) {
1213         if(G.obedit) {
1214                 if(G.obedit->type==OB_MESH) delete_mesh();
1215                 else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) delNurb();
1216                 else if(G.obedit->type==OB_MBALL) delete_mball();
1217                 else if (G.obedit->type==OB_ARMATURE) delete_armature();
1218         }
1219         else delete_obj(0);
1220 }
1221
1222 void duplicate_context_selected(void) {
1223         if(G.obedit) {
1224                 if(G.obedit->type==OB_MESH) adduplicate_mesh();
1225                 else if(G.obedit->type==OB_ARMATURE) adduplicate_armature();
1226                 else if(G.obedit->type==OB_MBALL) adduplicate_mball();
1227                 else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) adduplicate_nurb();
1228         }
1229         else if(G.obpose){
1230                 error ("Duplicate not possible in posemode.");
1231         }
1232         else adduplicate(0);
1233 }
1234
1235 void toggle_shading(void) {
1236         if(G.qual & LR_CTRLKEY) {
1237                 reshadeall_displist();
1238                 G.vd->drawtype= OB_SHADED;
1239         }
1240         else if(G.qual & LR_SHIFTKEY) {
1241                 if(G.vd->drawtype== OB_SHADED) G.vd->drawtype= OB_WIRE;
1242                 else G.vd->drawtype= OB_SHADED;
1243         }
1244         else if(G.qual & LR_ALTKEY) {
1245                 if(G.vd->drawtype== OB_TEXTURE) G.vd->drawtype= OB_SOLID;
1246                 else G.vd->drawtype= OB_TEXTURE;
1247         }
1248         else {
1249                 if(G.vd->drawtype==OB_SOLID || G.vd->drawtype==OB_SHADED) G.vd->drawtype= OB_WIRE;
1250                 else G.vd->drawtype= OB_SOLID;
1251         }
1252 }
1253
1254 void minmax_verts(float *min, float *max)
1255 {
1256         extern TransVert *transvmain;
1257         extern int tottrans;
1258         TransVert *tv;
1259         float centroid[3], vec[3], bmat[3][3];
1260         int a;
1261
1262         tottrans=0;
1263 #ifdef __NLA
1264         if ELEM5(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE) make_trans_verts(bmat[0], bmat[1], 0);
1265 #else
1266         if ELEM4(G.obedit->type, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE) make_trans_verts(bmat[0], bmat[1], 0);
1267 #endif
1268         if(tottrans==0) return;
1269
1270         Mat3CpyMat4(bmat, G.obedit->obmat);
1271         
1272         tv= transvmain;
1273         for(a=0; a<tottrans; a++, tv++) {               
1274                 VECCOPY(vec, tv->loc);
1275                 Mat3MulVecfl(bmat, vec);
1276                 VecAddf(vec, vec, G.obedit->obmat[3]);
1277                 VecAddf(centroid, centroid, vec);
1278                 DO_MINMAX(vec, min, max);               
1279         }
1280         
1281         MEM_freeN(transvmain);
1282         transvmain= 0;
1283 }