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