/* 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( 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(); }