mirror of
https://github.com/UberGames/GtkRadiant.git
synced 2024-12-18 16:31:25 +00:00
995f6a1011
* Quote http://zerowing.idsoftware.com/pipermail/gtkradiant/2008-July/011094.html : Attached to this message is a patch for a "somewhat working" brush primitives surface dialog. It is an ugly hack, as it converts between fake texdef notations and brush primitives whenever values are needed. Had to fix an accuracy bug: the surface dialog rounded all rotation values to integer angles, which SEVERELY broke things for me (changed the Gtk spin object to use 4 digits, which is enough for me). Also, I changed the fake texdef / brush primitives conversions to use long double internally, as float's roundoff errors were quite visible to me when testing. Hope the remaining roundoff errors from converting back and forth won't kill me, but it worked for a simple map example. Also, I had to separate out "Snap to grid" and "Don't clamp" into two separare options. They now mean: - Snap to grid: snaps drag/etc. actions to the grid - Don't clamp: disable brush point snapping during many operations, like merely shifting brushes, editing texturing parameters, map loading, etc. The reason is that I do need the grid, but I don't want to get my objects messed up by the snapping in my map. As I am using free rotations, this DOES change quite much. The config.py change is needed for compilation on Debian stable; Debian's scons does not use the CFLAGS variable, but just CCFLAGS and CXXFLAGS. In newer scons versions, CFLAGS is _shared_ flags for C and C++, so if you want to require these, you don't need to include the CFLAGS in CXXFLAGS too. git-svn-id: svn://svn.icculus.org/gtkradiant/GtkRadiant/trunk@301 8a3a26a2-13c4-0310-b231-cf6edde360e5
844 lines
20 KiB
C++
844 lines
20 KiB
C++
/*
|
|
Copyright (C) 1999-2007 id Software, Inc. and contributors.
|
|
For a list of contributors, see the accompanying CONTRIBUTORS file.
|
|
|
|
This file is part of GtkRadiant.
|
|
|
|
GtkRadiant is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
GtkRadiant is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with GtkRadiant; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
//#include "qe3.h"
|
|
|
|
/*
|
|
|
|
drag either multiple brushes, or select plane points from
|
|
a single brush.
|
|
|
|
*/
|
|
|
|
extern int g_nPatchClickedView;
|
|
|
|
qboolean drag_ok;
|
|
vec3_t drag_xvec;
|
|
vec3_t drag_yvec;
|
|
|
|
//static int buttonstate;
|
|
int pressx, pressy;
|
|
static vec3_t pressdelta;
|
|
static vec3_t vPressStart;
|
|
//static int buttonx, buttony;
|
|
|
|
|
|
//int num_move_points;
|
|
//float *move_points[1024];
|
|
|
|
int lastx, lasty;
|
|
|
|
qboolean drag_first;
|
|
|
|
|
|
void AxializeVector (vec3_t v)
|
|
{
|
|
vec3_t a;
|
|
float o;
|
|
int i;
|
|
|
|
if (!v[0] && !v[1])
|
|
return;
|
|
if (!v[1] && !v[2])
|
|
return;
|
|
if (!v[0] && !v[2])
|
|
return;
|
|
|
|
for (i=0 ; i<3 ; i++)
|
|
a[i] = fabs(v[i]);
|
|
if (a[0] > a[1] && a[0] > a[2])
|
|
i = 0;
|
|
else if (a[1] > a[0] && a[1] > a[2])
|
|
i = 1;
|
|
else
|
|
i = 2;
|
|
|
|
o = v[i];
|
|
VectorCopy (vec3_origin, v);
|
|
if (o<0)
|
|
v[i] = -1;
|
|
else
|
|
v[i] = 1;
|
|
|
|
}
|
|
|
|
/*
|
|
===========
|
|
Drag_Setup
|
|
===========
|
|
*/
|
|
extern void SelectCurvePointByRay (vec3_t org, vec3_t dir, int buttons);
|
|
|
|
void Drag_Setup (int x, int y, int buttons,
|
|
vec3_t xaxis, vec3_t yaxis,
|
|
vec3_t origin, vec3_t dir)
|
|
{
|
|
trace_t t;
|
|
face_t *f;
|
|
|
|
drag_first = true;
|
|
|
|
VectorCopy (vec3_origin, pressdelta);
|
|
pressx = x;
|
|
pressy = y;
|
|
|
|
// snap to nearest axis for camwindow drags
|
|
VectorCopy (xaxis, drag_xvec);
|
|
AxializeVector (drag_xvec);
|
|
VectorCopy (yaxis, drag_yvec);
|
|
AxializeVector (drag_yvec);
|
|
|
|
if (g_qeglobals.d_select_mode == sel_curvepoint)
|
|
{
|
|
SelectCurvePointByRay (origin, dir, buttons);
|
|
|
|
if(g_qeglobals.d_select_mode == sel_area)
|
|
{
|
|
drag_ok = true;
|
|
|
|
if(g_nPatchClickedView == W_CAMERA ) {
|
|
VectorSet( g_qeglobals.d_vAreaTL, x, y, 0 );
|
|
VectorSet( g_qeglobals.d_vAreaBR, x, y, 0 );
|
|
}
|
|
}
|
|
else if (g_qeglobals.d_num_move_points) // don't add an undo if there are no points selected
|
|
{
|
|
drag_ok = true;
|
|
Sys_UpdateWindows(W_ALL);
|
|
Undo_Start("drag curve point");
|
|
Undo_AddBrushList(&selected_brushes);
|
|
}
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
g_qeglobals.d_num_move_points = 0;
|
|
}
|
|
|
|
if (g_qeglobals.d_select_mode == sel_areatall)
|
|
{
|
|
VectorCopy(origin, g_qeglobals.d_vAreaTL);
|
|
VectorCopy(origin, g_qeglobals.d_vAreaBR);
|
|
|
|
Sys_UpdateWindows(W_ALL);
|
|
|
|
drag_ok = true;
|
|
return;
|
|
}
|
|
|
|
if (selected_brushes.next == &selected_brushes)
|
|
{
|
|
//in this case a new brush is created when the dragging
|
|
//takes place in the XYWnd, An useless undo is created
|
|
//when the dragging takes place in the CamWnd
|
|
Undo_Start("create brush");
|
|
|
|
Sys_Status("No selection to drag", 0);
|
|
return;
|
|
}
|
|
|
|
if (g_qeglobals.d_select_mode == sel_vertex)
|
|
{
|
|
SelectVertexByRay (origin, dir);
|
|
if (g_qeglobals.d_num_move_points)
|
|
{
|
|
drag_ok = true;
|
|
Undo_Start("drag vertex");
|
|
Undo_AddBrushList(&selected_brushes);
|
|
// Need an update here for highlighting selected vertices
|
|
Sys_UpdateWindows(W_XY | W_CAMERA);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (g_qeglobals.d_select_mode == sel_edge)
|
|
{
|
|
SelectEdgeByRay (origin, dir);
|
|
if (g_qeglobals.d_num_move_points)
|
|
{
|
|
drag_ok = true;
|
|
Undo_Start("drag edge");
|
|
Undo_AddBrushList(&selected_brushes);
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// check for direct hit first
|
|
//
|
|
t = Test_Ray (origin, dir, true);
|
|
if (t.selected)
|
|
{
|
|
drag_ok = true;
|
|
|
|
Undo_Start("drag selection");
|
|
Undo_AddBrushList(&selected_brushes);
|
|
|
|
if (buttons == (MK_LBUTTON|MK_CONTROL) )
|
|
{
|
|
Sys_Printf ("Shear dragging face\n");
|
|
Brush_SelectFaceForDragging (t.brush, t.face, true);
|
|
}
|
|
else if (buttons == (MK_LBUTTON|MK_CONTROL|MK_SHIFT) )
|
|
{
|
|
Sys_Printf ("Sticky dragging brush\n");
|
|
for (f=t.brush->brush_faces ; f ; f=f->next)
|
|
Brush_SelectFaceForDragging (t.brush, f, false);
|
|
}
|
|
else
|
|
Sys_Printf ("Dragging entire selection\n");
|
|
|
|
return;
|
|
}
|
|
|
|
if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge)
|
|
return;
|
|
|
|
//
|
|
// check for side hit
|
|
//
|
|
// multiple brushes selected?
|
|
if (selected_brushes.next->next != &selected_brushes)
|
|
{
|
|
// yes, special handling
|
|
bool bOK = (g_PrefsDlg.m_bALTEdge) ? Sys_AltDown() : true;
|
|
if (bOK)
|
|
{
|
|
for (brush_t* pBrush = selected_brushes.next ; pBrush != &selected_brushes ; pBrush = pBrush->next)
|
|
{
|
|
if (buttons & MK_CONTROL)
|
|
Brush_SideSelect (pBrush, origin, dir, true);
|
|
else
|
|
Brush_SideSelect (pBrush, origin, dir, false);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Sys_Printf ("press ALT to drag multiple edges\n");
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// single select.. trying to drag fixed entities handle themselves and just move
|
|
if (buttons & MK_CONTROL)
|
|
Brush_SideSelect (selected_brushes.next, origin, dir, true);
|
|
else
|
|
Brush_SideSelect (selected_brushes.next, origin, dir, false);
|
|
}
|
|
|
|
Sys_Printf ("Side stretch\n");
|
|
drag_ok = true;
|
|
|
|
Undo_Start("side stretch");
|
|
Undo_AddBrushList(&selected_brushes);
|
|
}
|
|
|
|
entity_t *peLink;
|
|
|
|
void UpdateTarget(vec3_t origin, vec3_t dir)
|
|
{
|
|
trace_t t;
|
|
entity_t *pe;
|
|
int i;
|
|
char sz[128];
|
|
|
|
t = Test_Ray (origin, dir, 0);
|
|
|
|
if (!t.brush)
|
|
return;
|
|
|
|
pe = t.brush->owner;
|
|
|
|
if (pe == NULL)
|
|
return;
|
|
|
|
// is this the first?
|
|
if (peLink != NULL)
|
|
{
|
|
|
|
// Get the target id from out current target
|
|
// if there is no id, make one
|
|
|
|
i = IntForKey(pe, "target");
|
|
if (i <= 0)
|
|
{
|
|
i = GetUniqueTargetId(1);
|
|
sprintf(sz, "%d", i);
|
|
|
|
SetKeyValue(pe, "target", sz);
|
|
}
|
|
|
|
// set the target # into our src
|
|
|
|
sprintf(sz, "%d", i);
|
|
SetKeyValue(peLink, "targetname", sz);
|
|
|
|
Sys_UpdateWindows(W_ENTITY);
|
|
|
|
}
|
|
|
|
// promote the target to the src
|
|
|
|
peLink = pe;
|
|
|
|
}
|
|
|
|
/*
|
|
===========
|
|
Drag_Begin
|
|
//++timo test three button mouse and three button emulation here ?
|
|
===========
|
|
*/
|
|
void Drag_Begin (int x, int y, int buttons,
|
|
vec3_t xaxis, vec3_t yaxis,
|
|
vec3_t origin, vec3_t dir, bool sf_camera)
|
|
{
|
|
trace_t t;
|
|
bool altdown;
|
|
int nFlag;
|
|
|
|
drag_ok = false;
|
|
VectorCopy (vec3_origin, pressdelta);
|
|
VectorCopy (vec3_origin, vPressStart);
|
|
|
|
drag_first = true;
|
|
peLink = NULL;
|
|
|
|
altdown = Sys_AltDown();
|
|
|
|
// shift-LBUTTON = select entire brush
|
|
// shift-alt-LBUTTON = drill select
|
|
if (buttons == (MK_LBUTTON | MK_SHIFT) && g_qeglobals.d_select_mode != sel_curvepoint)
|
|
{
|
|
nFlag = altdown ? SF_CYCLE : 0;
|
|
if (sf_camera)
|
|
nFlag |= SF_CAMERA;
|
|
else
|
|
nFlag |= SF_ENTITIES_FIRST;
|
|
Select_Ray(origin, dir, nFlag);
|
|
return;
|
|
}
|
|
|
|
// (shift-)alt-LBUTTON = area select completely tall
|
|
if ( !sf_camera &&
|
|
( g_PrefsDlg.m_bALTEdge ? buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT) : (buttons == MK_LBUTTON || buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT)) ) &&
|
|
altdown && g_qeglobals.d_select_mode != sel_curvepoint)
|
|
{
|
|
if (g_pParentWnd->ActiveXY()->AreaSelectOK())
|
|
{
|
|
g_qeglobals.d_select_mode = sel_areatall;
|
|
|
|
Drag_Setup (x, y, buttons, xaxis, yaxis, origin, dir);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// ctrl-alt-LBUTTON = multiple brush select without selecting whole entities
|
|
if (buttons == (MK_LBUTTON | MK_CONTROL) && altdown && g_qeglobals.d_select_mode != sel_curvepoint)
|
|
{
|
|
nFlag = 0;
|
|
if (sf_camera)
|
|
nFlag |= SF_CAMERA;
|
|
else
|
|
nFlag |= SF_ENTITIES_FIRST;
|
|
Select_Ray (origin, dir, nFlag);
|
|
UpdateSurfaceDialog();
|
|
|
|
return;
|
|
}
|
|
|
|
// ctrl-shift LBUTTON = select single face
|
|
if (sf_camera && buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT) && g_qeglobals.d_select_mode != sel_curvepoint)
|
|
{
|
|
if(Sys_AltDown())
|
|
{
|
|
brush_t *b;
|
|
for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
|
|
{
|
|
if(b->pPatch)
|
|
continue;
|
|
|
|
for (face_t* pFace = b->brush_faces; pFace; pFace = pFace->next)
|
|
{
|
|
g_ptrSelectedFaces.Add(pFace);
|
|
g_ptrSelectedFaceBrushes.Add(b);
|
|
}
|
|
}
|
|
|
|
for (b = selected_brushes.next; b != &selected_brushes; )
|
|
{
|
|
brush_t *pb = b;
|
|
b = b->next;
|
|
Brush_RemoveFromList (pb);
|
|
Brush_AddToList (pb, &active_brushes);
|
|
}
|
|
}
|
|
else
|
|
Select_Deselect (true);
|
|
|
|
Select_Ray (origin, dir, (SF_SINGLEFACE|SF_CAMERA));
|
|
return;
|
|
}
|
|
|
|
|
|
// LBUTTON + all other modifiers = manipulate selection
|
|
if (buttons & MK_LBUTTON)
|
|
{
|
|
Drag_Setup (x, y, buttons, xaxis, yaxis, origin, dir);
|
|
return;
|
|
}
|
|
|
|
int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON;
|
|
// middle button = grab texture
|
|
if (buttons == nMouseButton)
|
|
{
|
|
t = Test_Ray (origin, dir, false);
|
|
if (t.face)
|
|
{
|
|
UpdateWorkzone_ForBrush( t.brush );
|
|
// use a local brushprimit_texdef fitted to a default 2x2 texture
|
|
brushprimit_texdef_t bp_local;
|
|
ConvertTexMatWithQTexture( &t.face->brushprimit_texdef, t.face->d_texture, &bp_local, NULL );
|
|
Texture_SetTexture ( &t.face->texdef, &bp_local, false, NULL);
|
|
UpdateSurfaceDialog();
|
|
UpdatePatchInspector();
|
|
}
|
|
else
|
|
Sys_Printf ("Did not select a texture\n");
|
|
return;
|
|
}
|
|
|
|
// ctrl-middle button = set entire brush to texture
|
|
if (buttons == (nMouseButton|MK_CONTROL) )
|
|
{
|
|
t = Test_Ray (origin, dir, false);
|
|
if (t.brush)
|
|
{
|
|
if (t.brush->brush_faces->texdef.GetName()[0] == '(')
|
|
Sys_Printf ("Can't change an entity texture\n");
|
|
else
|
|
{
|
|
Brush_SetTexture (t.brush, &g_qeglobals.d_texturewin.texdef, &g_qeglobals.d_texturewin.brushprimit_texdef, false, static_cast<IPluginTexdef *>( g_qeglobals.d_texturewin.pTexdef ) );
|
|
Sys_UpdateWindows (W_ALL);
|
|
}
|
|
}
|
|
else
|
|
Sys_Printf ("Didn't hit a btrush\n");
|
|
return;
|
|
}
|
|
|
|
// ctrl-shift-middle button = set single face to texture
|
|
if (buttons == (nMouseButton|MK_SHIFT|MK_CONTROL) )
|
|
{
|
|
t = Test_Ray (origin, dir, false);
|
|
if (t.brush)
|
|
{
|
|
if (t.brush->brush_faces->texdef.GetName()[0] == '(')
|
|
Sys_Printf ("Can't change an entity texture\n");
|
|
else
|
|
{
|
|
SetFaceTexdef (t.face, &g_qeglobals.d_texturewin.texdef, &g_qeglobals.d_texturewin.brushprimit_texdef);
|
|
Brush_Build( t.brush );
|
|
|
|
Sys_UpdateWindows (W_ALL);
|
|
}
|
|
}
|
|
else
|
|
Sys_Printf ("Didn't hit a btrush\n");
|
|
return;
|
|
}
|
|
|
|
if (buttons == (nMouseButton | MK_SHIFT))
|
|
{
|
|
Sys_Printf("Set brush face texture info\n");
|
|
t = Test_Ray (origin, dir, false);
|
|
if (t.brush)
|
|
{
|
|
if (t.brush->brush_faces->texdef.GetName()[0] == '(')
|
|
{
|
|
if (t.brush->owner->eclass->nShowFlags & ECLASS_LIGHT)
|
|
{
|
|
CString strBuff;
|
|
qtexture_t* pTex = g_qeglobals.d_texturewin.pShader->getTexture();
|
|
if (pTex)
|
|
{
|
|
vec3_t vColor;
|
|
VectorCopy(pTex->color, vColor);
|
|
|
|
float fLargest = 0.0f;
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
if (vColor[i] > fLargest)
|
|
fLargest = vColor[i];
|
|
}
|
|
|
|
if (fLargest == 0.0f)
|
|
{
|
|
vColor[0] = vColor[1] = vColor[2] = 1.0f;
|
|
}
|
|
else
|
|
{
|
|
float fScale = 1.0f / fLargest;
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
vColor[i] *= fScale;
|
|
}
|
|
}
|
|
strBuff.Format("%f %f %f",pTex->color[0], pTex->color[1], pTex->color[2]);
|
|
SetKeyValue(t.brush->owner, "_color", strBuff.GetBuffer());
|
|
Sys_UpdateWindows (W_ALL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Sys_Printf ("Can't select an entity brush face\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Face_SetShader(t.face, g_qeglobals.d_texturewin.texdef.GetName());
|
|
Brush_Build(t.brush);
|
|
|
|
Sys_UpdateWindows (W_ALL);
|
|
}
|
|
}
|
|
else
|
|
Sys_Printf ("Didn't hit a brush\n");
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
//===========
|
|
//MoveSelection
|
|
//===========
|
|
//
|
|
void MoveSelection (vec3_t move)
|
|
{
|
|
int i, success;
|
|
brush_t *b;
|
|
CString strStatus;
|
|
vec3_t vTemp, vTemp2, end;
|
|
|
|
if (!move[0] && !move[1] && !move[2])
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!(g_qeglobals.d_select_mode == sel_area || g_qeglobals.d_select_mode == sel_areatall))
|
|
{
|
|
move[0] = (g_nScaleHow & SCALE_X) ? 0 : move[0];
|
|
move[1] = (g_nScaleHow & SCALE_Y) ? 0 : move[1];
|
|
move[2] = (g_nScaleHow & SCALE_Z) ? 0 : move[2];
|
|
}
|
|
|
|
if (g_pParentWnd->ActiveXY()->RotateMode() || g_bPatchBendMode)
|
|
{
|
|
float fDeg = -move[2];
|
|
float fAdj = move[2];
|
|
int nAxis = 0;
|
|
if (g_pParentWnd->ActiveXY()->GetViewType() == XY)
|
|
{
|
|
fDeg = -move[1];
|
|
fAdj = move[1];
|
|
nAxis = 2;
|
|
}
|
|
else
|
|
if (g_pParentWnd->ActiveXY()->GetViewType() == XZ)
|
|
{
|
|
fDeg = move[2];
|
|
fAdj = move[2];
|
|
nAxis = 1;
|
|
}
|
|
else
|
|
nAxis = 0;
|
|
|
|
g_pParentWnd->ActiveXY()->Rotation()[nAxis] += fAdj;
|
|
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]);
|
|
g_pParentWnd->SetStatusText(2, strStatus);
|
|
|
|
if (g_bPatchBendMode)
|
|
{
|
|
Patch_SelectBendNormal();
|
|
Select_RotateAxis(nAxis, fDeg*2, false, true);
|
|
Patch_SelectBendAxis();
|
|
Select_RotateAxis(nAxis, fDeg, false, true);
|
|
}
|
|
else
|
|
{
|
|
Select_RotateAxis(nAxis, fDeg, false, true);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (g_pParentWnd->ActiveXY()->ScaleMode())
|
|
{
|
|
vec3_t v;
|
|
v[0] = v[1] = v[2] = 1.0f;
|
|
if (move[1] > 0)
|
|
{
|
|
v[0] = 1.1f;
|
|
v[1] = 1.1f;
|
|
v[2] = 1.1f;
|
|
}
|
|
else
|
|
if (move[1] < 0)
|
|
{
|
|
v[0] = 0.9f;
|
|
v[1] = 0.9f;
|
|
v[2] = 0.9f;
|
|
}
|
|
|
|
Select_Scale((g_nScaleHow & SCALE_X) ? 1.0f : v[0],
|
|
(g_nScaleHow & SCALE_Y) ? 1.0f : v[1],
|
|
(g_nScaleHow & SCALE_Z) ? 1.0f : v[2]);
|
|
// is that really necessary???
|
|
Sys_UpdateWindows (W_ALL);
|
|
return;
|
|
}
|
|
|
|
|
|
vec3_t vDistance;
|
|
VectorSubtract(pressdelta, vPressStart, vDistance);
|
|
strStatus.Format("Distance x: %.1f y: %.1f z: %.1f", vDistance[0], vDistance[1], vDistance[2]);
|
|
g_pParentWnd->SetStatusText(3, strStatus);
|
|
|
|
//
|
|
// dragging only a part of the selection
|
|
//
|
|
|
|
// this is fairly crappy way to deal with curvepoint and area selection
|
|
// but it touches the smallest amount of code this way
|
|
//
|
|
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)
|
|
{
|
|
//area selection
|
|
if (g_qeglobals.d_select_mode == sel_area || g_qeglobals.d_select_mode == sel_areatall)
|
|
{
|
|
VectorAdd(g_qeglobals.d_vAreaBR, move, g_qeglobals.d_vAreaBR);
|
|
return;
|
|
}
|
|
//curve point selection
|
|
if (g_qeglobals.d_select_mode == sel_curvepoint)
|
|
{
|
|
Patch_UpdateSelected(move);
|
|
return;
|
|
}
|
|
//vertex selection
|
|
if (g_qeglobals.d_select_mode == sel_vertex && g_PrefsDlg.m_bVertexSplit)
|
|
{
|
|
if(g_qeglobals.d_num_move_points) {
|
|
success = true;
|
|
for (b = selected_brushes.next; b != &selected_brushes; b = b->next)
|
|
{
|
|
success &= Brush_MoveVertex(b, g_qeglobals.d_move_points[0], move, end, true);
|
|
}
|
|
if (success)
|
|
VectorCopy(end, g_qeglobals.d_move_points[0]);
|
|
}
|
|
return;
|
|
}
|
|
//all other selection types
|
|
for (i=0 ; i<g_qeglobals.d_num_move_points ; i++)
|
|
VectorAdd (g_qeglobals.d_move_points[i], move, g_qeglobals.d_move_points[i]);
|
|
for (b = selected_brushes.next; b != &selected_brushes; b = b->next)
|
|
{
|
|
bool bMoved = false;
|
|
for(face_t *f = b->brush_faces; !bMoved && f!=NULL; f=f->next)
|
|
for(int p=0; !bMoved && p<3; p++)
|
|
for (i=0 ; !bMoved && i<g_qeglobals.d_num_move_points ; i++)
|
|
if(f->planepts[p] == g_qeglobals.d_move_points[i])
|
|
bMoved = true;
|
|
if(!bMoved) continue;
|
|
|
|
VectorCopy(b->maxs, vTemp);
|
|
VectorSubtract(vTemp, b->mins, vTemp);
|
|
Brush_Build(b,true,true,false,false); // don't filter
|
|
for (i=0 ; i<3 ; i++)
|
|
{
|
|
if (b->mins[i] > b->maxs[i]
|
|
|| b->maxs[i] - b->mins[i] > g_MaxBrushSize)
|
|
break; // dragged backwards or fucked up
|
|
}
|
|
if (i != 3)
|
|
break;
|
|
if (b->patchBrush)
|
|
{
|
|
VectorCopy(b->maxs, vTemp2);
|
|
VectorSubtract(vTemp2, b->mins, vTemp2);
|
|
VectorSubtract(vTemp2, vTemp, vTemp2);
|
|
//if (!Patch_DragScale(b->nPatchID, vTemp2, move))
|
|
if (!Patch_DragScale(b->pPatch, vTemp2, move))
|
|
{
|
|
b = NULL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
// if any of the brushes were crushed out of existance
|
|
// calcel the entire move
|
|
if (b != &selected_brushes)
|
|
{
|
|
Sys_Printf ("Brush dragged backwards, move canceled\n");
|
|
for (i=0 ; i<g_qeglobals.d_num_move_points ; i++)
|
|
VectorSubtract (g_qeglobals.d_move_points[i], move, g_qeglobals.d_move_points[i]);
|
|
|
|
for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
|
|
Brush_Build(b,true,true,false,false); // don't filter
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// reset face originals from vertex edit mode
|
|
// this is dirty, but unfortunately necessary because Brush_Build
|
|
// can remove windings
|
|
for (b = selected_brushes.next; b != &selected_brushes; b = b->next)
|
|
{
|
|
Brush_ResetFaceOriginals(b);
|
|
}
|
|
//
|
|
// if there are lots of brushes selected, just translate instead
|
|
// of rebuilding the brushes
|
|
// NOTE: this is not actually done, but would be a good idea
|
|
//
|
|
Select_Move (move);
|
|
}
|
|
}
|
|
|
|
/*
|
|
===========
|
|
Drag_MouseMoved
|
|
===========
|
|
*/
|
|
void Drag_MouseMoved (int x, int y, int buttons)
|
|
{
|
|
vec3_t move, delta;
|
|
int i;
|
|
|
|
if (!buttons)
|
|
{
|
|
drag_ok = false;
|
|
return;
|
|
}
|
|
if (!drag_ok)
|
|
return;
|
|
|
|
// clear along one axis
|
|
if (buttons & MK_SHIFT && (g_PrefsDlg.m_bALTEdge && g_qeglobals.d_select_mode != sel_areatall))
|
|
{
|
|
drag_first = false;
|
|
if (abs(x-pressx) > abs(y-pressy))
|
|
y = pressy;
|
|
else
|
|
x = pressx;
|
|
}
|
|
|
|
if (g_qeglobals.d_select_mode == sel_area && g_nPatchClickedView == W_CAMERA)
|
|
{
|
|
camera_t *m_pCamera = g_pParentWnd->GetCamWnd()->Camera();
|
|
|
|
// snap to window
|
|
if( y > m_pCamera->height ) y = m_pCamera->height - 1; else if( y < 0 ) y = 0;
|
|
if( x > m_pCamera->width ) x = m_pCamera->width - 1; else if( x < 0 ) x = 0;
|
|
|
|
VectorSet (move, x - pressx, y - pressy, 0);
|
|
} else
|
|
{
|
|
for (i=0 ; i<3 ; i++)
|
|
{
|
|
move[i] = drag_xvec[i]*(x - pressx) + drag_yvec[i]*(y - pressy);
|
|
if (g_PrefsDlg.m_bSnap)
|
|
{
|
|
move[i] = floor(move[i]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize;
|
|
}
|
|
}
|
|
}
|
|
|
|
VectorSubtract (move, pressdelta, delta);
|
|
VectorCopy (move, pressdelta);
|
|
|
|
MoveSelection (delta);
|
|
}
|
|
|
|
/*
|
|
===========
|
|
Drag_MouseUp
|
|
===========
|
|
*/
|
|
void Drag_MouseUp (int nButtons)
|
|
{
|
|
Sys_Status ("Drag completed.", 0);
|
|
|
|
if (g_qeglobals.d_select_mode == sel_area)
|
|
{
|
|
Patch_SelectAreaPoints(nButtons & MK_CONTROL); // adds to selection and/or deselects selected points if ctrl is held
|
|
g_qeglobals.d_select_mode = sel_curvepoint;
|
|
Sys_UpdateWindows (W_ALL);
|
|
}
|
|
|
|
if (g_qeglobals.d_select_mode == sel_areatall)
|
|
{
|
|
vec3_t mins, maxs;
|
|
|
|
int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0;
|
|
int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2;
|
|
|
|
// get our rectangle
|
|
mins[nDim1] = MIN( g_qeglobals.d_vAreaTL[nDim1], g_qeglobals.d_vAreaBR[nDim1] );
|
|
mins[nDim2] = MIN( g_qeglobals.d_vAreaTL[nDim2], g_qeglobals.d_vAreaBR[nDim2] );
|
|
maxs[nDim1] = MAX( g_qeglobals.d_vAreaTL[nDim1], g_qeglobals.d_vAreaBR[nDim1] );
|
|
maxs[nDim2] = MAX( g_qeglobals.d_vAreaTL[nDim2], g_qeglobals.d_vAreaBR[nDim2] );
|
|
|
|
// deselect current selection
|
|
if( !(nButtons & (MK_CONTROL|MK_SHIFT)) )
|
|
Select_Deselect();
|
|
|
|
// select new selection
|
|
Select_RealCompleteTall( mins, maxs );
|
|
|
|
Sys_UpdateWindows (W_ALL);
|
|
}
|
|
|
|
if (g_qeglobals.d_select_translate[0] || g_qeglobals.d_select_translate[1] || g_qeglobals.d_select_translate[2])
|
|
{
|
|
Select_Move (g_qeglobals.d_select_translate);
|
|
VectorCopy (vec3_origin, g_qeglobals.d_select_translate);
|
|
Sys_UpdateWindows (W_CAMERA);
|
|
}
|
|
|
|
/* note: added cleanup here, since an edge drag will leave selected vertices
|
|
in g_qeglobals.d_num_move_points
|
|
*/
|
|
if ( g_qeglobals.d_select_mode != sel_vertex &&
|
|
g_qeglobals.d_select_mode != sel_curvepoint &&
|
|
g_qeglobals.d_select_mode != sel_edge)
|
|
g_qeglobals.d_num_move_points = 0;
|
|
|
|
g_pParentWnd->SetStatusText(3, "");
|
|
Undo_EndBrushList(&selected_brushes);
|
|
Undo_End();
|
|
UpdateSurfaceDialog();
|
|
}
|