]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/tools/radiant/DRAG.CPP
hello world
[icculus/iodoom3.git] / neo / tools / radiant / DRAG.CPP
1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. 
6
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).  
8
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Doom 3 Source Code 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 Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.
23
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25
26 ===========================================================================
27 */
28
29 #include "../../idlib/precompiled.h"
30 #pragma hdrstop
31
32 #include "qe3.h"
33 #include "splines.h"
34
35 /* drag either multiple brushes, or select plane points from a single brush. */
36 bool                    g_moveOnly = false;
37 bool                    drag_ok;
38 idVec3                  drag_xvec;
39 idVec3                  drag_yvec;
40
41 static int              buttonstate;
42 int                             pressx, pressy;
43 static idVec3   pressdelta;
44 static idVec3   vPressStart;
45 static int              buttonx, buttony;
46
47 // int num_move_points; float *move_points[1024];
48 int                             lastx, lasty;
49
50 bool                    drag_first;
51
52 /*
53 ================
54 AxializeVector
55 ================
56 */
57 static void AxializeVector( idVec3 &v ) {
58         idVec3  a;
59         float   o;
60         int             i;
61
62         if (!v[0] && !v[1]) {
63                 return;
64         }
65
66         if (!v[1] && !v[2]) {
67                 return;
68         }
69
70         if (!v[0] && !v[2]) {
71                 return;
72         }
73
74         for (i = 0; i < 3; i++) {
75                 a[i] = idMath::Fabs(v[i]);
76         }
77
78         if (a[0] > a[1] && a[0] > a[2]) {
79                 i = 0;
80         }
81         else if (a[1] > a[0] && a[1] > a[2]) {
82                 i = 1;
83         }
84         else {
85                 i = 2;
86         }
87
88         o = v[i];
89         VectorCopy(vec3_origin, v);
90         if (o < 0) {
91                 v[i] = -1;
92         }
93         else {
94                 v[i] = 1;
95         }
96 }
97
98 extern bool UpdateActiveDragPoint(const idVec3 &move);
99 extern void SetActiveDrag(CDragPoint *p);
100
101 /*
102 ================
103 Draw_Setup
104 ================
105 */
106 static void Drag_Setup( int x, int y, int buttons,
107                                            const idVec3 &xaxis, const idVec3 &yaxis, const idVec3 &origin, const idVec3 &dir ) {
108         qertrace_t      t;
109         face_t          *f;
110
111         drag_first = true;
112
113         VectorCopy(vec3_origin, pressdelta);
114         pressx = x;
115         pressy = y;
116
117         VectorCopy(xaxis, drag_xvec);
118         AxializeVector(drag_xvec);
119         VectorCopy(yaxis, drag_yvec);
120         AxializeVector(drag_yvec);
121
122         if (g_qeglobals.d_select_mode == sel_addpoint) {
123                 if (g_qeglobals.selectObject) {
124                         g_qeglobals.selectObject->addPoint(origin);
125                 }
126                 else {
127                         g_qeglobals.d_select_mode = sel_brush;
128                 }
129
130                 return;
131         }
132
133         if (g_qeglobals.d_select_mode == sel_editpoint) {
134
135                 g_Inspectors->entityDlg.SelectCurvePointByRay( origin, dir, buttons );
136
137                 if ( g_qeglobals.d_num_move_points ) {
138                         drag_ok = true;
139                 }
140
141                 Sys_UpdateWindows(W_ALL);
142
143                 return;
144         }
145
146         if (g_qeglobals.d_select_mode == sel_curvepoint) {
147                 SelectCurvePointByRay(origin, dir, buttons);
148
149                 if (g_qeglobals.d_num_move_points || g_qeglobals.d_select_mode == sel_area) {
150                         drag_ok = true;
151                 }
152
153                 Sys_UpdateWindows(W_ALL);
154
155                 Undo_Start("drag curve point");
156                 Undo_AddBrushList(&selected_brushes);
157
158                 return;
159         }
160         else {
161                 g_qeglobals.d_num_move_points = 0;
162         }
163
164         if (selected_brushes.next == &selected_brushes) {
165                 //
166                 // in this case a new brush is created when the dragging takes place in the XYWnd,
167                 // An useless undo is created when the dragging takes place in the CamWnd
168                 //
169                 Undo_Start("create brush");
170
171                 Sys_Status("No selection to drag\n", 0);
172                 return;
173         }
174
175         if (g_qeglobals.d_select_mode == sel_vertex) {
176                 
177                 if ( radiant_entityMode.GetBool() ) {
178                         return;
179                 }
180
181                 SelectVertexByRay(origin, dir);
182                 if (g_qeglobals.d_num_move_points) {
183                         drag_ok = true;
184                         Undo_Start("drag vertex");
185                         Undo_AddBrushList(&selected_brushes);
186                         return;
187                 }
188         }
189
190         if (g_qeglobals.d_select_mode == sel_edge) {
191                 
192                 if ( radiant_entityMode.GetBool() ) {
193                         return;
194                 }
195
196                 SelectEdgeByRay(origin, dir);
197                 if (g_qeglobals.d_num_move_points) {
198                         drag_ok = true;
199                         Undo_Start("drag edge");
200                         Undo_AddBrushList(&selected_brushes);
201                         return;
202                 }
203         }
204
205         // check for direct hit first
206         t = Test_Ray(origin, dir, true);
207         SetActiveDrag(t.point);
208         if (t.point) {
209                 drag_ok = true;
210
211                 // point was hit
212                 return;
213         }
214
215         if (t.selected) {
216                 drag_ok = true;
217
218                 Undo_Start("drag selection");
219                 Undo_AddBrushList(&selected_brushes);
220
221                 if (buttons == (MK_LBUTTON | MK_CONTROL)) {
222                         Sys_Status("Shear dragging face\n");
223                         Brush_SelectFaceForDragging(t.brush, t.face, true);
224                 }
225                 else if (buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT)) {
226                         Sys_Status("Sticky dragging brush\n");
227                         for (f = t.brush->brush_faces; f; f = f->next) {
228                                 Brush_SelectFaceForDragging(t.brush, f, false);
229                         }
230                 }
231                 else {
232                         Sys_Status("Dragging entire selection\n");
233                 }
234
235                 return;
236         }
237
238         if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge) {
239                 return;
240         }
241
242         if ( radiant_entityMode.GetBool() ) {
243                 return;
244         }
245
246         // check for side hit multiple brushes selected?
247         if (selected_brushes.next->next != &selected_brushes) {
248                 // yes, special handling
249                 bool bOK = ( g_PrefsDlg.m_bALTEdge ) ? ( ::GetAsyncKeyState( VK_MENU ) != 0 ) : true;
250                 if (bOK) {
251                         for (brush_t * pBrush = selected_brushes.next; pBrush != &selected_brushes; pBrush = pBrush->next) {
252                                 if (buttons & MK_CONTROL) {
253                                         Brush_SideSelect(pBrush, origin, dir, true);
254                                 }
255                                 else {
256                                         Brush_SideSelect(pBrush, origin, dir, false);
257                                 }
258                         }
259                 }
260                 else {
261                         Sys_Status("press ALT to drag multiple edges\n");
262                         return;
263                 }
264         }
265         else {
266                 // single select.. trying to drag fixed entities handle themselves and just move
267                 if (buttons & MK_CONTROL) {
268                         Brush_SideSelect(selected_brushes.next, origin, dir, true);
269                 }
270                 else {
271                         Brush_SideSelect(selected_brushes.next, origin, dir, false);
272                 }
273         }
274
275         Sys_Status("Side stretch\n");
276         drag_ok = true;
277
278         Undo_Start("side stretch");
279         Undo_AddBrushList(&selected_brushes);
280 }
281
282 extern void Face_GetScale_BrushPrimit(face_t *face, float *s, float *t, float *rot);
283
284 /*
285 ================
286 Drag_Begin
287 ================
288 */
289 void Drag_Begin( int x, int y, int buttons,
290                                 const idVec3 &xaxis, const idVec3 &yaxis, const idVec3 &origin, const idVec3 &dir ) {
291         qertrace_t      t;
292
293         drag_ok = false;
294         VectorCopy(vec3_origin, pressdelta);
295         VectorCopy(vec3_origin, vPressStart);
296
297         drag_first = true;
298
299         // shift LBUTTON = select entire brush
300         if (buttons == (MK_LBUTTON | MK_SHIFT) && g_qeglobals.d_select_mode != sel_curvepoint) {
301                 int nFlag = ( ::GetAsyncKeyState( VK_MENU ) != 0 ) ? SF_CYCLE : 0;
302                 if (dir[0] == 0 || dir[1] == 0 || dir[2] == 0) {                // extremely low chance of this happening from camera
303                         Select_Ray(origin, dir, nFlag | SF_ENTITIES_FIRST); // hack for XY
304                 }
305                 else {
306                         Select_Ray(origin, dir, nFlag);
307                 }
308
309                 return;
310         }
311
312         // ctrl-shift LBUTTON = select single face
313         if (buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT) && g_qeglobals.d_select_mode != sel_curvepoint) {
314                 if ( radiant_entityMode.GetBool() ) {
315                         return;
316                 }
317
318                 // _D3XP disabled
319                 //Select_Deselect( ( ::GetAsyncKeyState( VK_MENU ) == 0 ) );
320                 Select_Ray(origin, dir, SF_SINGLEFACE);
321                 return;
322         }
323
324         // LBUTTON + all other modifiers = manipulate selection
325         if (buttons & MK_LBUTTON) {
326                 Drag_Setup(x, y, buttons, xaxis, yaxis, origin, dir);
327                 return;
328         }
329
330         if ( radiant_entityMode.GetBool() ) {
331                 return;
332         }
333
334         int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON;
335
336         // middle button = grab texture
337         if (buttons == nMouseButton) {
338                 t = Test_Ray(origin, dir, false);
339                 if (t.face) {
340                         g_qeglobals.d_new_brush_bottom = t.brush->mins;
341                         g_qeglobals.d_new_brush_top = t.brush->maxs;
342
343                         // use a local brushprimit_texdef fitted to a default 2x2 texture
344                         brushprimit_texdef_t bp_local;
345                         if (t.brush && t.brush->pPatch) {
346                                 texdef_t localtd;
347                                 memset(&bp_local.coords, 0, sizeof(bp_local.coords));
348                                 bp_local.coords[0][0] = 1.0f;
349                                 bp_local.coords[1][1] = 1.0f;
350                                 localtd.SetName(t.brush->pPatch->d_texture->GetName());
351                                 Texture_SetTexture(&localtd, &bp_local, false, true);
352                                 Select_CopyPatchTextureCoords ( t.brush->pPatch );
353                         } else {
354                                 Select_ProjectFaceOntoPatch( t.face );
355                                 ConvertTexMatWithQTexture(&t.face->brushprimit_texdef, t.face->d_texture, &bp_local, NULL);
356                                 Texture_SetTexture(&t.face->texdef, &bp_local, false, true);
357                         }
358                         UpdateSurfaceDialog();
359                         UpdatePatchInspector();
360                         UpdateLightInspector();
361                 }
362                 else {
363                         Sys_Status("Did not select a texture\n");
364                 }
365
366                 return;
367         }
368
369         // ctrl-middle button = set entire brush to texture
370         if (buttons == (nMouseButton | MK_CONTROL)) {
371                 t = Test_Ray(origin, dir, false);
372                 if (t.brush) {
373                         if (t.brush->brush_faces->texdef.name[0] == '(') {
374                                 Sys_Status("Can't change an entity texture\n");
375                         }
376                         else {
377                                 Brush_SetTexture
378                                 (
379                                         t.brush,
380                                         &g_qeglobals.d_texturewin.texdef,
381                                         &g_qeglobals.d_texturewin.brushprimit_texdef,
382                                         false
383                                 );
384                                 Sys_UpdateWindows(W_ALL);
385                         }
386                 }
387                 else {
388                         Sys_Status("Didn't hit a btrush\n");
389                 }
390
391                 return;
392         }
393
394         // ctrl-shift-middle button = set single face to texture
395         if (buttons == (nMouseButton | MK_SHIFT | MK_CONTROL)) {
396                 t = Test_Ray(origin, dir, false);
397                 if (t.brush) {
398                         if (t.brush->brush_faces->texdef.name[0] == '(') {
399                                 Sys_Status("Can't change an entity texture\n");
400                         }
401                         else {
402                                 SetFaceTexdef
403                                 (
404                                         t.brush,
405                                         t.face,
406                                         &g_qeglobals.d_texturewin.texdef,
407                                         &g_qeglobals.d_texturewin.brushprimit_texdef
408                                 );
409                                 Brush_Build(t.brush);
410                                 Sys_UpdateWindows(W_ALL);
411                         }
412                 }
413                 else {
414                         Sys_Status("Didn't hit a btrush\n");
415                 }
416
417                 return;
418         }
419
420         if (buttons == (nMouseButton | MK_SHIFT)) {
421                 Sys_Status("Set brush face texture info\n");
422                 t = Test_Ray(origin, dir, false);
423                 if (t.brush && !t.brush->owner->eclass->fixedsize) {
424 /*
425                         if (t.brush->brush_faces->texdef.name[0] == '(') {
426                                 if (t.brush->owner->eclass->nShowFlags & ECLASS_LIGHT) {
427                                         CString         strBuff;
428                                         idMaterial      *pTex = declManager->FindMaterial(g_qeglobals.d_texturewin.texdef.name);
429                                         if (pTex) {
430                                                 idVec3  vColor = pTex->getColor();
431
432                                                 float   fLargest = 0.0f;
433                                                 for (int i = 0; i < 3; i++) {
434                                                         if (vColor[i] > fLargest) {
435                                                                 fLargest = vColor[i];
436                                                         }
437                                                 }
438
439                                                 if (fLargest == 0.0f) {
440                                                         vColor[0] = vColor[1] = vColor[2] = 1.0f;
441                                                 }
442                                                 else {
443                                                         float   fScale = 1.0f / fLargest;
444                                                         for (int i = 0; i < 3; i++) {
445                                                                 vColor[i] *= fScale;
446                                                         }
447                                                 }
448
449                                                 strBuff.Format("%f %f %f", pTex->getColor().x, pTex->getColor().y, pTex->getColor().z);
450                                                 SetKeyValue(t.brush->owner, "_color", strBuff.GetBuffer(0));
451                                                 Sys_UpdateWindows(W_ALL);
452                                         }
453                                 }
454                                 else {
455                                         Sys_Status("Can't select an entity brush face\n");
456                                 }
457                         }
458
459                         else {
460 */
461                                 // strcpy(t.face->texdef.name,g_qeglobals.d_texturewin.texdef.name);
462                                 t.face->texdef.SetName(g_qeglobals.d_texturewin.texdef.name);
463                                 Brush_Build(t.brush);
464                                 Sys_UpdateWindows(W_ALL);
465 //                      }
466                 }
467                 else {
468                         Sys_Status("Didn't hit a brush\n");
469                 }
470
471                 return;
472         }
473 }
474
475
476 void Brush_GetBounds(brush_t *b, idVec3 &mins, idVec3 &maxs) {
477         int             i;
478
479         for (i = 0; i < 3; i++) {
480                 mins[i] = 999999;
481                 maxs[i] = -999999;
482         }
483
484         for (i = 0; i < 3; i++) {
485                 if (b->mins[i] < mins[i]) {
486                         mins[i] = b->mins[i];
487                 }
488
489                 if (b->maxs[i] > maxs[i]) {
490                         maxs[i] = b->maxs[i];
491                 }
492         }
493 }
494
495
496 /*
497 ================
498 MoveSelection
499 ================
500 */
501 static void MoveSelection( const idVec3 &orgMove ) {
502         int             i, success;
503         brush_t *b;
504         CString strStatus;
505         idVec3  vTemp, vTemp2, end, move;
506
507         move = orgMove;
508
509         if (!move[0] && !move[1] && !move[2]) {
510                 return;
511         }
512
513         move[0] = (g_nScaleHow & SCALE_X) ? 0 : move[0];
514         move[1] = (g_nScaleHow & SCALE_Y) ? 0 : move[1];
515         move[2] = (g_nScaleHow & SCALE_Z) ? 0 : move[2];
516
517         if (g_pParentWnd->ActiveXY()->RotateMode() || g_bPatchBendMode) {
518                 float   fDeg = -move[2];
519                 float   fAdj = move[2];
520                 int axis = 0;
521                 if (g_pParentWnd->ActiveXY()->GetViewType() == XY) {
522                         fDeg = -move[1];
523                         fAdj = move[1];
524                         axis = 2;
525                 }
526                 else if (g_pParentWnd->ActiveXY()->GetViewType() == XZ) {
527                         fDeg = move[2];
528                         fAdj = move[2];
529                         axis = 1;
530                 }
531
532                 g_pParentWnd->ActiveXY()->Rotation()[g_qeglobals.rotateAxis] += fAdj;
533                 strStatus.Format
534                         (
535                                 "%s x:: %.1f  y:: %.1f  z:: %.1f",
536                                 (g_bPatchBendMode) ? "Bend angle" : "Rotation",
537                                 g_pParentWnd->ActiveXY()->Rotation()[0],
538                                 g_pParentWnd->ActiveXY()->Rotation()[1],
539                                 g_pParentWnd->ActiveXY()->Rotation()[2]
540                         );
541                 g_pParentWnd->SetStatusText(2, strStatus);
542
543                 if (g_bPatchBendMode) {
544                         Patch_SelectBendNormal();
545                         Select_RotateAxis(axis, fDeg * 2, false, true);
546                         Patch_SelectBendAxis();
547                         Select_RotateAxis(axis, fDeg, false, true);
548                 }
549                 else {
550                         Select_RotateAxis(g_qeglobals.rotateAxis, fDeg, false, true);
551                 }
552
553                 return;
554         }
555
556         if (g_pParentWnd->ActiveXY()->ScaleMode()) {
557                 idVec3  v;
558                 v[0] = v[1] = v[2] = 1.0f;
559                 for (int i = 0; i < 3; i++) {
560                         if ( move[i] > 0.0f ) {
561                                 v[i] = 1.1f;
562                         } else if ( move[i] < 0.0f ) {
563                                 v[i] = 0.9f;
564                         }
565                 }
566
567                 Select_Scale(v.x, v.y, v.z);
568                 Sys_UpdateWindows(W_ALL);
569                 return;
570         }
571
572         idVec3  vDistance;
573         VectorSubtract(pressdelta, vPressStart, vDistance);
574         strStatus.Format("Distance x: %.3f  y: %.3f  z: %.3f", vDistance[0], vDistance[1], vDistance[2]);
575         g_pParentWnd->SetStatusText(3, strStatus);
576
577         // dragging only a part of the selection
578         if (UpdateActiveDragPoint(move)) {
579                 UpdateLightInspector();
580                 return;
581         }
582
583         //
584         // this is fairly crappy way to deal with curvepoint and area selection but it
585         // touches the smallest amount of code this way
586         //
587         if (g_qeglobals.d_num_move_points || g_qeglobals.d_num_move_planes || g_qeglobals.d_select_mode == sel_area) {
588                 // area selection
589                 if (g_qeglobals.d_select_mode == sel_area) {
590                         VectorAdd(g_qeglobals.d_vAreaBR, move, g_qeglobals.d_vAreaBR);
591                         return;
592                 }
593
594                 // curve point selection
595                 if (g_qeglobals.d_select_mode == sel_curvepoint) {
596                         Patch_UpdateSelected(move);
597                         return;
598                 }
599
600                 // vertex selection
601                 if (g_qeglobals.d_select_mode == sel_vertex) {
602                         success = true;
603                         for (b = selected_brushes.next; b != &selected_brushes; b = b->next) {
604                                 success &= Brush_MoveVertex(selected_brushes.next, *g_qeglobals.d_move_points[0], move, end, true);
605                         }
606
607                         // if (success)
608                         VectorCopy(end, *g_qeglobals.d_move_points[0]);
609                         return;
610                 }
611
612                 // all other selection types
613                 for (i = 0; i < g_qeglobals.d_num_move_points; i++) {
614                         VectorAdd(*g_qeglobals.d_move_points[i], move, *g_qeglobals.d_move_points[i]);
615                 }
616
617                 if ( g_qeglobals.d_select_mode == sel_editpoint ) {
618                         g_Inspectors->entityDlg.UpdateEntityCurve();
619                 }
620
621                 //
622                 // VectorScale(move, .5, move); for (i=0 ; i<g_qeglobals.d_num_move_points2 ; i++)
623                 // VectorAdd (g_qeglobals.d_move_points2[i], move, g_qeglobals.d_move_points2[i]);
624                 //
625                 for (b = selected_brushes.next; b != &selected_brushes; b = b->next) {
626                         VectorCopy(b->maxs, vTemp);
627                         VectorSubtract(vTemp, b->mins, vTemp);
628                         Brush_Build(b);
629                         for (i = 0; i < 3; i++) {
630                                 if
631                                 (
632                                         b->mins[i] > b->maxs[i] ||
633                                         b->maxs[i] - b->mins[i] > MAX_WORLD_SIZE ||
634                                         b->maxs[i] - b->mins[i] == 0.0f
635                                 ) {
636                                         break;  // dragged backwards or messed up
637                                 }
638                         }
639
640                         if (i != 3) {
641                                 break;
642                         }
643
644                         if (b->pPatch) {
645                                 VectorCopy(b->maxs, vTemp2);
646                                 VectorSubtract(vTemp2, b->mins, vTemp2);
647                                 VectorSubtract(vTemp2, vTemp, vTemp2);
648
649                                 // if (!Patch_DragScale(b->nPatchID, vTemp2, move))
650                                 if (!Patch_DragScale(b->pPatch, vTemp2, move)) {
651                                         b = NULL;
652                                         break;
653                                 }
654                         }
655                 }
656
657                 // if any of the brushes were crushed out of existance calcel the entire move
658                 if (b != &selected_brushes) {
659                         Sys_Status("Brush dragged backwards, move canceled\n");
660                         for (i = 0; i < g_qeglobals.d_num_move_points; i++) {
661                                 VectorSubtract(*g_qeglobals.d_move_points[i], move, *g_qeglobals.d_move_points[i]);
662                         }
663
664                         for (b = selected_brushes.next; b != &selected_brushes; b = b->next) {
665                                 Brush_Build(b);
666                         }
667                 }
668         }
669         else {
670                 //
671                 // reset face originals from vertex edit mode this is dirty, but unfortunately
672                 // necessary because Brush_Build can remove windings
673                 //
674                 for (b = selected_brushes.next; b != &selected_brushes; b = b->next) {
675                         Brush_ResetFaceOriginals(b);
676                 }
677
678                 Select_Move(move);
679         }
680 }
681
682 /*
683 ================
684 Drag_MouseMoved
685 ================
686 */
687 void Drag_MouseMoved(int x, int y, int buttons) {
688         idVec3  move, delta;
689         int             i;
690
691         if (!buttons || !drag_ok) {
692                 drag_ok = false;
693                 return;
694         }
695
696         // clear along one axis
697         if (buttons & MK_SHIFT) {
698                 drag_first = false;
699                 if (abs(x - pressx) > abs(y - pressy)) {
700                         y = pressy;
701                 }
702                 else {
703                         x = pressx;
704                 }
705         }
706
707         for (i = 0; i < 3; i++) {
708                 move[i] = drag_xvec[i] * (x - pressx) + drag_yvec[i] * (y - pressy);
709                 if (!g_PrefsDlg.m_bNoClamp) {
710                         move[i] = floor(move[i] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
711                 }
712         }
713
714         VectorSubtract(move, pressdelta, delta);
715         VectorCopy(move, pressdelta);
716
717         if (buttons & MK_CONTROL && g_pParentWnd->ActiveXY()->RotateMode()) {
718                 for (i = 0; i < 3; i++) {
719                         if (delta[i] != 0) {
720                                 if (delta[i] > 0) {
721                                         delta[i] = 15;
722                                 }
723                                 else {
724                                         delta[i] = -15;
725                                 }
726                         }
727                 }
728         }
729
730         MoveSelection(delta);
731 }
732
733 /*
734 ================
735 Drag_MouseUp
736 ================
737 */
738 void Drag_MouseUp(int nButtons) {
739         Sys_Status("drag completed.", 0);
740
741         if (g_qeglobals.d_select_mode == sel_area) {
742                 Patch_SelectAreaPoints();
743                 g_qeglobals.d_select_mode = sel_curvepoint;
744                 Sys_UpdateWindows(W_ALL);
745         }
746
747         if (g_qeglobals.d_select_translate[0] || g_qeglobals.d_select_translate[1] || g_qeglobals.d_select_translate[2]) {
748                 Select_Move(g_qeglobals.d_select_translate);
749                 VectorCopy(vec3_origin, g_qeglobals.d_select_translate);
750                 Sys_UpdateWindows(W_CAMERA);
751         }
752
753         g_pParentWnd->SetStatusText(3, "");
754
755 /*
756         if (g_pParentWnd->GetCamera()->UpdateRenderEntities()) {
757                 Sys_UpdateWindows(W_CAMERA);
758         }
759 */
760         
761         Undo_EndBrushList(&selected_brushes);
762         Undo_End();
763 }