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