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