Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

DRAG.CPP (19546B)


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