]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/drag.cpp
d8df7b82c379f05e3072cc93dfa074de401832ed
[xonotic/netradiant.git] / radiant / drag.cpp
1 /*
2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21
22 #include "stdafx.h"
23 //#include "qe3.h"
24
25 /*
26
27   drag either multiple brushes, or select plane points from
28   a single brush.
29
30 */
31
32 extern int g_nPatchClickedView;
33
34 qboolean        drag_ok;
35 vec3_t  drag_xvec;
36 vec3_t  drag_yvec;
37
38 //static        int     buttonstate;
39 int     pressx, pressy;
40 static  vec3_t pressdelta;
41 static  vec3_t vPressStart;
42 //static        int     buttonx, buttony;
43
44
45 //int           num_move_points;
46 //float *move_points[1024];
47
48 int             lastx, lasty;
49
50 qboolean        drag_first;
51
52
53 void    AxializeVector (vec3_t v)
54 {
55         vec3_t  a;
56         float   o;
57         int             i;
58
59         if (!v[0] && !v[1])
60                 return;
61         if (!v[1] && !v[2])
62                 return;
63         if (!v[0] && !v[2])
64                 return;
65
66         for (i=0 ; i<3 ; i++)
67                 a[i] = fabs(v[i]);
68         if (a[0] > a[1] && a[0] > a[2])
69                 i = 0;
70         else if (a[1] > a[0] && a[1] > a[2])
71                 i = 1;
72         else
73                 i = 2;
74
75         o = v[i];
76         VectorCopy (vec3_origin, v);
77         if (o<0)
78                 v[i] = -1;
79         else
80                 v[i] = 1;
81         
82 }
83
84 /*
85 ===========
86 Drag_Setup
87 ===========
88 */
89 extern void SelectCurvePointByRay (vec3_t org, vec3_t dir, int buttons);
90
91 void Drag_Setup (int x, int y, int buttons,
92                  vec3_t xaxis, vec3_t yaxis,
93                  vec3_t origin, vec3_t dir)
94 {
95   trace_t       t;
96   face_t        *f;
97
98   drag_first = true;
99   
100   VectorCopy (vec3_origin, pressdelta);
101   pressx = x;
102   pressy = y;
103
104         // snap to nearest axis for camwindow drags
105   VectorCopy (xaxis, drag_xvec);
106   AxializeVector (drag_xvec);
107   VectorCopy (yaxis, drag_yvec);
108   AxializeVector (drag_yvec);
109
110   if (g_qeglobals.d_select_mode == sel_curvepoint)
111   {
112     SelectCurvePointByRay (origin, dir, buttons);       
113
114     if(g_qeglobals.d_select_mode == sel_area)
115     {
116       drag_ok = true;
117
118                         if(g_nPatchClickedView == W_CAMERA ) {
119                                 VectorSet( g_qeglobals.d_vAreaTL, x, y, 0 );
120                                 VectorSet( g_qeglobals.d_vAreaBR, x, y, 0 );
121                         }
122     }
123     else if (g_qeglobals.d_num_move_points) // don't add an undo if there are no points selected
124     {
125       drag_ok = true;
126       Sys_UpdateWindows(W_ALL);
127       Undo_Start("drag curve point");
128       Undo_AddBrushList(&selected_brushes);
129     }
130     return;
131   }
132   else
133   {
134     g_qeglobals.d_num_move_points = 0;
135   }
136
137   if (g_qeglobals.d_select_mode == sel_areatall)
138   {
139     VectorCopy(origin, g_qeglobals.d_vAreaTL);
140     VectorCopy(origin, g_qeglobals.d_vAreaBR);
141
142     Sys_UpdateWindows(W_ALL);
143
144     drag_ok = true; 
145     return;
146   }
147
148   if (selected_brushes.next == &selected_brushes)
149   {
150     //in this case a new brush is created when the dragging
151     //takes place in the XYWnd, An useless undo is created
152     //when the dragging takes place in the CamWnd
153     Undo_Start("create brush");
154
155     Sys_Status("No selection to drag", 0);
156     return;
157   }
158
159   if (g_qeglobals.d_select_mode == sel_vertex)
160   {
161     SelectVertexByRay (origin, dir);    
162     if (g_qeglobals.d_num_move_points)
163     {
164       drag_ok = true;
165       Undo_Start("drag vertex");
166       Undo_AddBrushList(&selected_brushes);
167       // Need an update here for highlighting selected vertices
168       Sys_UpdateWindows(W_XY | W_CAMERA);
169       return;
170     }
171   }
172
173   if (g_qeglobals.d_select_mode == sel_edge)
174   {
175     SelectEdgeByRay (origin, dir);      
176     if (g_qeglobals.d_num_move_points)
177     {
178       drag_ok = true;
179       Undo_Start("drag edge");
180       Undo_AddBrushList(&selected_brushes);
181       return;
182     }
183   }
184
185   //
186   // check for direct hit first
187   //
188   t = Test_Ray (origin, dir, true);
189   if (t.selected)
190   {
191     drag_ok = true;
192
193     Undo_Start("drag selection");
194     Undo_AddBrushList(&selected_brushes);
195
196     if (buttons == (MK_LBUTTON|MK_CONTROL) )
197     {
198       Sys_Printf ("Shear dragging face\n");
199       Brush_SelectFaceForDragging (t.brush, t.face, true);
200     }
201     else if (buttons == (MK_LBUTTON|MK_CONTROL|MK_SHIFT) )
202     {
203       Sys_Printf ("Sticky dragging brush\n");
204       for (f=t.brush->brush_faces ; f ; f=f->next)
205         Brush_SelectFaceForDragging (t.brush, f, false);
206     }
207     else
208       Sys_Printf ("Dragging entire selection\n");
209     
210     return;
211   }
212
213   if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge)
214     return;
215
216   //
217   // check for side hit
218   //
219   // multiple brushes selected?
220   if (selected_brushes.next->next != &selected_brushes)
221   {
222     // yes, special handling
223     bool bOK = (g_PrefsDlg.m_bALTEdge) ? Sys_AltDown() : true;
224     if (bOK)
225     {
226       for (brush_t* pBrush = selected_brushes.next ; pBrush != &selected_brushes ; pBrush = pBrush->next)
227       {
228         if (buttons & MK_CONTROL)
229           Brush_SideSelect (pBrush, origin, dir, true);
230         else
231           Brush_SideSelect (pBrush, origin, dir, false);
232       }
233     }
234     else
235     {
236       Sys_Printf ("press ALT to drag multiple edges\n");
237       return;
238     }
239   }
240   else
241   {
242     // single select.. trying to drag fixed entities handle themselves and just move
243     if (buttons & MK_CONTROL)
244       Brush_SideSelect (selected_brushes.next, origin, dir, true);
245     else
246       Brush_SideSelect (selected_brushes.next, origin, dir, false);
247   }
248
249   Sys_Printf ("Side stretch\n");
250   drag_ok = true;
251
252   Undo_Start("side stretch");
253   Undo_AddBrushList(&selected_brushes);
254 }
255
256 entity_t *peLink;
257
258 void UpdateTarget(vec3_t origin, vec3_t dir)
259 {
260         trace_t t;
261         entity_t *pe;
262         int i;
263         char sz[128];
264
265         t = Test_Ray (origin, dir, 0);
266
267         if (!t.brush)
268                 return;
269
270         pe = t.brush->owner;
271
272         if (pe == NULL)
273                 return;
274
275         // is this the first?
276         if (peLink != NULL)
277         {
278
279                 // Get the target id from out current target
280                 // if there is no id, make one
281
282                 i = IntForKey(pe, "target");
283                 if (i <= 0)
284                 {
285                         i = GetUniqueTargetId(1);
286                         sprintf(sz, "%d", i);
287
288                         SetKeyValue(pe, "target", sz);
289                 }
290
291                 // set the target # into our src
292
293                 sprintf(sz, "%d", i);
294                 SetKeyValue(peLink, "targetname", sz);
295
296                 Sys_UpdateWindows(W_ENTITY);
297
298         }
299
300         // promote the target to the src
301
302         peLink = pe;
303         
304 }
305
306 /*
307 ===========
308 Drag_Begin
309 //++timo test three button mouse and three button emulation here ?
310 ===========
311 */
312 void Drag_Begin (int x, int y, int buttons,
313                    vec3_t xaxis, vec3_t yaxis,
314                    vec3_t origin, vec3_t dir, bool sf_camera)
315 {
316         trace_t t;
317   bool altdown;
318   int nFlag;
319
320         drag_ok = false;
321         VectorCopy (vec3_origin, pressdelta);
322         VectorCopy (vec3_origin, vPressStart);
323
324         drag_first = true;
325         peLink = NULL;
326
327   altdown = Sys_AltDown();
328
329         // shift-LBUTTON = select entire brush
330   // shift-alt-LBUTTON = drill select
331         if (buttons == (MK_LBUTTON | MK_SHIFT) && g_qeglobals.d_select_mode != sel_curvepoint)
332         {
333     nFlag = altdown ? SF_CYCLE : 0;
334     if (sf_camera)
335       nFlag |= SF_CAMERA;
336     else
337       nFlag |= SF_ENTITIES_FIRST;
338     Select_Ray(origin, dir, nFlag);
339                 return;
340         }
341
342   // (shift-)alt-LBUTTON = area select completely tall
343   if ( !sf_camera &&
344       ( g_PrefsDlg.m_bALTEdge ? buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT) : (buttons == MK_LBUTTON || buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT)) ) &&
345       altdown && g_qeglobals.d_select_mode != sel_curvepoint)
346   {
347     if (g_pParentWnd->ActiveXY()->AreaSelectOK())
348     {
349       g_qeglobals.d_select_mode = sel_areatall;
350
351       Drag_Setup (x, y, buttons, xaxis, yaxis, origin, dir);
352       return;
353     }
354   }
355
356         // ctrl-alt-LBUTTON = multiple brush select without selecting whole entities
357         if (buttons == (MK_LBUTTON | MK_CONTROL) && altdown && g_qeglobals.d_select_mode != sel_curvepoint)
358         {
359     nFlag = 0;
360     if (sf_camera)
361       nFlag |= SF_CAMERA;
362     else
363       nFlag |= SF_ENTITIES_FIRST;
364     Select_Ray (origin, dir, nFlag);
365     UpdateSurfaceDialog();
366     
367                 return;
368         }
369
370         // ctrl-shift LBUTTON = select single face
371         if (sf_camera && buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT) && g_qeglobals.d_select_mode != sel_curvepoint)
372         {
373     if(Sys_AltDown())
374     {
375       brush_t *b;
376       for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
377       {
378         if(b->pPatch)
379           continue;
380
381         for (face_t* pFace = b->brush_faces; pFace; pFace = pFace->next)
382         {
383           g_ptrSelectedFaces.Add(pFace);
384           g_ptrSelectedFaceBrushes.Add(b);
385         }
386       }
387
388       for (b = selected_brushes.next; b != &selected_brushes; )
389       {
390         brush_t *pb = b;
391                           b = b->next;
392         Brush_RemoveFromList (pb);
393         Brush_AddToList (pb, &active_brushes);
394       }
395     }
396     else
397                   Select_Deselect (true);
398
399                 Select_Ray (origin, dir, (SF_SINGLEFACE|SF_CAMERA));
400                 return;
401         }
402
403
404         // LBUTTON + all other modifiers = manipulate selection
405         if (buttons & MK_LBUTTON)
406         {
407                 Drag_Setup (x, y, buttons, xaxis, yaxis, origin, dir);
408                 return;
409         }
410
411         int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON;
412         // middle button = grab texture
413         if (buttons == nMouseButton)
414         {
415                 t = Test_Ray (origin, dir, false);
416                 if (t.face)
417                 {
418       UpdateWorkzone_ForBrush( t.brush );
419                         // use a local brushprimit_texdef fitted to a default 2x2 texture
420                         brushprimit_texdef_t bp_local;
421                         ConvertTexMatWithQTexture( &t.face->brushprimit_texdef, t.face->d_texture, &bp_local, NULL );
422                         Texture_SetTexture ( &t.face->texdef, &bp_local, false, NULL);
423                         UpdateSurfaceDialog();
424                         UpdatePatchInspector();
425                 }
426                 else
427                         Sys_Printf ("Did not select a texture\n");
428                 return;
429         }
430
431         // ctrl-middle button = set entire brush to texture
432         if (buttons == (nMouseButton|MK_CONTROL) )
433         {
434                 t = Test_Ray (origin, dir, false);
435                 if (t.brush)
436                 {
437                         if (t.brush->brush_faces->texdef.GetName()[0] == '(')
438                                 Sys_Printf ("Can't change an entity texture\n");
439                         else
440                         {
441                                 Brush_SetTexture (t.brush, &g_qeglobals.d_texturewin.texdef, &g_qeglobals.d_texturewin.brushprimit_texdef, false, static_cast<IPluginTexdef *>( g_qeglobals.d_texturewin.pTexdef ) );
442                                 Sys_UpdateWindows (W_ALL);
443                         }
444                 }
445                 else
446                         Sys_Printf ("Didn't hit a btrush\n");
447                 return;
448         }
449
450         // ctrl-shift-middle button = set single face to texture
451         if (buttons == (nMouseButton|MK_SHIFT|MK_CONTROL) )
452         {
453                 t = Test_Ray (origin, dir, false);
454                 if (t.brush)
455                 {
456                         if (t.brush->brush_faces->texdef.GetName()[0] == '(')
457                                 Sys_Printf ("Can't change an entity texture\n");
458                         else
459                         {
460                                 SetFaceTexdef (t.face, &g_qeglobals.d_texturewin.texdef, &g_qeglobals.d_texturewin.brushprimit_texdef);
461                                 Brush_Build( t.brush );
462
463                                 Sys_UpdateWindows (W_ALL);
464                         }
465                 }
466                 else
467                         Sys_Printf ("Didn't hit a btrush\n");
468                 return;
469         }
470
471         if (buttons == (nMouseButton | MK_SHIFT))
472         {
473                 Sys_Printf("Set brush face texture info\n");
474                 t = Test_Ray (origin, dir, false);
475                 if (t.brush)
476                 {
477                         if (t.brush->brush_faces->texdef.GetName()[0] == '(')
478       {
479         if (t.brush->owner->eclass->nShowFlags & ECLASS_LIGHT)
480         {
481           CString strBuff;
482           qtexture_t* pTex = g_qeglobals.d_texturewin.pShader->getTexture();
483           if (pTex)
484           {
485             vec3_t vColor;
486             VectorCopy(pTex->color, vColor);
487
488             float fLargest = 0.0f;
489             for (int i = 0; i < 3; i++)
490             {
491                           if (vColor[i] > fLargest)
492                                   fLargest = vColor[i];
493             }
494                         
495                         if (fLargest == 0.0f)
496                         {
497               vColor[0] = vColor[1] = vColor[2] = 1.0f;
498             }
499                         else
500                         {
501                                 float fScale = 1.0f / fLargest;
502               for (int i = 0; i < 3; i++)
503               {
504                 vColor[i] *= fScale;
505               }
506             }
507             strBuff.Format("%f %f %f",pTex->color[0], pTex->color[1], pTex->color[2]);
508             SetKeyValue(t.brush->owner, "_color", strBuff.GetBuffer());
509                                     Sys_UpdateWindows (W_ALL);
510           }
511         }
512         else
513         {
514                                   Sys_Printf ("Can't select an entity brush face\n");
515         }
516       }
517                         else
518                         {
519         // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=425
520         Face_SetShader(t.face, g_qeglobals.d_texturewin.texdef.GetName());
521                                 Brush_Build(t.brush);
522
523                                 Sys_UpdateWindows (W_ALL);
524                         }
525                 }
526                 else
527                         Sys_Printf ("Didn't hit a brush\n");
528                 return;
529         }
530
531 }
532
533
534 //
535 //===========
536 //MoveSelection
537 //===========
538 //
539 void MoveSelection (vec3_t move)
540 {
541         int             i, success;
542         brush_t *b;
543         CString strStatus;
544         vec3_t vTemp, vTemp2, end;
545
546         if (!move[0] && !move[1] && !move[2])
547   {
548                 return;
549   }
550
551   if (!(g_qeglobals.d_select_mode == sel_area || g_qeglobals.d_select_mode == sel_areatall))
552   {
553     move[0] = (g_nScaleHow & SCALE_X) ? 0 : move[0];
554     move[1] = (g_nScaleHow & SCALE_Y) ? 0 : move[1];
555     move[2] = (g_nScaleHow & SCALE_Z) ? 0 : move[2];
556   }
557
558         if (g_pParentWnd->ActiveXY()->RotateMode() || g_bPatchBendMode)
559         {
560                 float fDeg = -move[2];
561                 float fAdj = move[2];
562                 int nAxis = 0;
563                 if (g_pParentWnd->ActiveXY()->GetViewType() == XY)
564                 {
565                         fDeg = -move[1];
566                         fAdj = move[1];
567                         nAxis = 2;
568                 }
569                 else 
570                 if (g_pParentWnd->ActiveXY()->GetViewType() == XZ)
571                 {
572                         fDeg = move[2];
573                         fAdj = move[2];
574                         nAxis = 1;
575                 }
576                 else
577                         nAxis = 0;
578
579                 g_pParentWnd->ActiveXY()->Rotation()[nAxis] += fAdj;
580                 strStatus.Format("%s x:: %.1f  y:: %.1f  z:: %.1f", (g_bPatchBendMode) ? "Bend angle" : "Rotation", g_pParentWnd->ActiveXY()->Rotation()[0], g_pParentWnd->ActiveXY()->Rotation()[1], g_pParentWnd->ActiveXY()->Rotation()[2]);
581                 g_pParentWnd->SetStatusText(2, strStatus);
582
583                 if (g_bPatchBendMode)
584                 {
585                         Patch_SelectBendNormal();
586                         Select_RotateAxis(nAxis, fDeg*2, false, true);
587                         Patch_SelectBendAxis();
588                         Select_RotateAxis(nAxis, fDeg, false, true);
589                 }
590                 else
591                 {
592                         Select_RotateAxis(nAxis, fDeg, false, true);
593                 }
594                 return;
595         }
596
597         if (g_pParentWnd->ActiveXY()->ScaleMode())
598         {
599                 vec3_t v;
600                 v[0] = v[1] = v[2] = 1.0f;
601                 if (move[1] > 0)
602                 {
603                         v[0] = 1.1f;
604                         v[1] = 1.1f;
605                         v[2] = 1.1f;
606                 }
607                 else 
608                         if (move[1] < 0)
609                 {
610                         v[0] = 0.9f;
611                         v[1] = 0.9f;
612                         v[2] = 0.9f;
613                 }
614
615                         Select_Scale((g_nScaleHow & SCALE_X) ? 1.0f : v[0],
616                                                                          (g_nScaleHow & SCALE_Y) ? 1.0f : v[1],
617                                                                  (g_nScaleHow & SCALE_Z) ? 1.0f : v[2]);
618       // is that really necessary???
619                 Sys_UpdateWindows (W_ALL);
620                 return;
621         }
622
623
624         vec3_t vDistance;
625         VectorSubtract(pressdelta, vPressStart, vDistance);
626         strStatus.Format("Distance x: %.1f  y: %.1f  z: %.1f", vDistance[0], vDistance[1], vDistance[2]);
627         g_pParentWnd->SetStatusText(3, strStatus);
628
629         //
630         // dragging only a part of the selection
631         //
632
633         // this is fairly crappy way to deal with curvepoint and area selection
634         // but it touches the smallest amount of code this way
635         // 
636         if (g_qeglobals.d_num_move_points || g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_area || g_qeglobals.d_select_mode == sel_areatall)
637         {
638                 //area selection
639     if (g_qeglobals.d_select_mode == sel_area || g_qeglobals.d_select_mode == sel_areatall)
640                 {
641                         VectorAdd(g_qeglobals.d_vAreaBR, move, g_qeglobals.d_vAreaBR);
642                         return;
643                 }
644                 //curve point selection
645                 if (g_qeglobals.d_select_mode == sel_curvepoint)
646                 {
647                         Patch_UpdateSelected(move);
648                         return;
649                 }
650                 //vertex selection
651                 if (g_qeglobals.d_select_mode == sel_vertex && g_PrefsDlg.m_bVertexSplit)
652                 {
653       if(g_qeglobals.d_num_move_points) {
654                           success = true;
655                           for (b = selected_brushes.next; b != &selected_brushes; b = b->next)
656                           {
657                                   success &= Brush_MoveVertex(b, g_qeglobals.d_move_points[0], move, end, true);
658                           }
659                           if (success)
660                                   VectorCopy(end, g_qeglobals.d_move_points[0]);
661       }
662                         return;
663                 }
664                 //all other selection types
665                 for (i=0 ; i<g_qeglobals.d_num_move_points ; i++)
666                         VectorAdd (g_qeglobals.d_move_points[i], move, g_qeglobals.d_move_points[i]);
667                 for (b = selected_brushes.next; b != &selected_brushes; b = b->next)
668                 {
669       bool bMoved = false;
670       for(face_t *f = b->brush_faces; !bMoved && f!=NULL; f=f->next)
671         for(int p=0; !bMoved && p<3; p++)
672           for (i=0 ; !bMoved && i<g_qeglobals.d_num_move_points ; i++)
673                               if(f->planepts[p] == g_qeglobals.d_move_points[i])
674               bMoved = true;
675                   if(!bMoved) continue;
676
677                         VectorCopy(b->maxs, vTemp);
678                         VectorSubtract(vTemp, b->mins, vTemp);
679       Brush_Build(b,true,true,false,false); // don't filter
680                         for (i=0 ; i<3 ; i++)
681                         {
682                                 if (b->mins[i] > b->maxs[i]
683                                 || b->maxs[i] - b->mins[i] > g_MaxBrushSize)
684                                         break;  // dragged backwards or fucked up
685                         }
686                         if (i != 3)
687                                 break;
688                         if (b->patchBrush)
689                         {
690                                 VectorCopy(b->maxs, vTemp2);
691                                 VectorSubtract(vTemp2, b->mins, vTemp2);
692                                 VectorSubtract(vTemp2, vTemp, vTemp2);
693                                 //if (!Patch_DragScale(b->nPatchID, vTemp2, move))
694                                 if (!Patch_DragScale(b->pPatch, vTemp2, move))
695                                 {
696                                         b = NULL;
697                                         break;
698                                 }
699                         }
700                 }
701                 // if any of the brushes were crushed out of existance
702                 // calcel the entire move
703                 if (b != &selected_brushes)
704                 {
705                         Sys_Printf ("Brush dragged backwards, move canceled\n");
706                         for (i=0 ; i<g_qeglobals.d_num_move_points ; i++)
707                                 VectorSubtract (g_qeglobals.d_move_points[i], move, g_qeglobals.d_move_points[i]);
708
709                         for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
710                                 Brush_Build(b,true,true,false,false); // don't filter
711                 }
712
713         }
714         else
715         {
716                 // reset face originals from vertex edit mode
717                 // this is dirty, but unfortunately necessary because Brush_Build
718                 // can remove windings
719                 for (b = selected_brushes.next; b != &selected_brushes; b = b->next)
720                 {
721                         Brush_ResetFaceOriginals(b);
722                 }
723                 //
724                 // if there are lots of brushes selected, just translate instead
725                 // of rebuilding the brushes
726     // NOTE: this is not actually done, but would be a good idea
727                 //
728           Select_Move (move);
729         }
730 }
731
732 /*
733 ===========
734 Drag_MouseMoved
735 ===========
736 */
737 void Drag_MouseMoved (int x, int y, int buttons)
738 {
739   vec3_t        move, delta;
740   int           i;
741
742   if (!buttons)
743   {
744     drag_ok = false;
745     return;
746   }
747   if (!drag_ok)
748     return;
749
750   // clear along one axis
751   if (buttons & MK_SHIFT && (g_PrefsDlg.m_bALTEdge && g_qeglobals.d_select_mode != sel_areatall))
752   {
753     drag_first = false;
754     if (abs(x-pressx) > abs(y-pressy))
755       y = pressy;
756     else
757       x = pressx;
758   }
759
760         if (g_qeglobals.d_select_mode == sel_area && g_nPatchClickedView == W_CAMERA)
761         {
762                 camera_t *m_pCamera = g_pParentWnd->GetCamWnd()->Camera();
763
764                 // snap to window
765                 if( y > m_pCamera->height ) y = m_pCamera->height - 1; else if( y < 0 ) y = 0;
766                 if( x > m_pCamera->width ) x = m_pCamera->width - 1; else if( x < 0 ) x = 0;
767
768                 VectorSet (move, x - pressx, y - pressy, 0);
769         } else
770         {
771                 for (i=0 ; i<3 ; i++)
772                 {
773                         move[i] = drag_xvec[i]*(x - pressx)     + drag_yvec[i]*(y - pressy);
774                         if (!g_PrefsDlg.m_bNoClamp)
775                         {
776                                 move[i] = floor(move[i]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize;
777                         }
778                 }
779         }
780
781   VectorSubtract (move, pressdelta, delta);
782   VectorCopy (move, pressdelta);
783
784   MoveSelection (delta);
785 }
786
787 /*
788 ===========
789 Drag_MouseUp
790 ===========
791 */
792 void Drag_MouseUp (int nButtons)
793 {
794         Sys_Status ("Drag completed.", 0);
795
796   if (g_qeglobals.d_select_mode == sel_area)
797   {
798     Patch_SelectAreaPoints(nButtons & MK_CONTROL); // adds to selection and/or deselects selected points if ctrl is held
799     g_qeglobals.d_select_mode = sel_curvepoint;
800                 Sys_UpdateWindows (W_ALL);
801   }
802
803   if (g_qeglobals.d_select_mode == sel_areatall)
804   {
805     vec3_t mins, maxs;
806
807     int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0;
808     int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2;
809
810                 // get our rectangle
811     mins[nDim1] = MIN( g_qeglobals.d_vAreaTL[nDim1], g_qeglobals.d_vAreaBR[nDim1] );
812     mins[nDim2] = MIN( g_qeglobals.d_vAreaTL[nDim2], g_qeglobals.d_vAreaBR[nDim2] );
813     maxs[nDim1] = MAX( g_qeglobals.d_vAreaTL[nDim1], g_qeglobals.d_vAreaBR[nDim1] );
814     maxs[nDim2] = MAX( g_qeglobals.d_vAreaTL[nDim2], g_qeglobals.d_vAreaBR[nDim2] );
815
816     // deselect current selection
817     if( !(nButtons & (MK_CONTROL|MK_SHIFT)) )
818       Select_Deselect();
819
820     // select new selection
821     Select_RealCompleteTall( mins, maxs );
822
823     Sys_UpdateWindows (W_ALL);
824   }
825
826   if (g_qeglobals.d_select_translate[0] || g_qeglobals.d_select_translate[1] || g_qeglobals.d_select_translate[2])
827         {
828                 Select_Move (g_qeglobals.d_select_translate);
829                 VectorCopy (vec3_origin, g_qeglobals.d_select_translate);
830                 Sys_UpdateWindows (W_CAMERA);
831         }
832   
833   /* note: added cleanup here, since an edge drag will leave selected vertices 
834            in g_qeglobals.d_num_move_points
835   */
836   if (  g_qeglobals.d_select_mode != sel_vertex && 
837         g_qeglobals.d_select_mode != sel_curvepoint &&
838         g_qeglobals.d_select_mode != sel_edge)
839     g_qeglobals.d_num_move_points = 0;
840   
841   g_pParentWnd->SetStatusText(3, "");
842   Undo_EndBrushList(&selected_brushes);
843   Undo_End();
844   UpdateSurfaceDialog();
845 }