2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27 drag either multiple brushes, or select plane points from
32 extern int g_nPatchClickedView;
38 //static int buttonstate;
40 static vec3_t pressdelta;
41 static vec3_t vPressStart;
42 //static int buttonx, buttony;
45 //int num_move_points;
46 //float *move_points[1024];
53 void AxializeVector( vec3_t v ){
58 if ( !v[0] && !v[1] ) {
61 if ( !v[1] && !v[2] ) {
64 if ( !v[0] && !v[2] ) {
68 for ( i = 0 ; i < 3 ; i++ )
70 if ( a[0] > a[1] && a[0] > a[2] ) {
73 else if ( a[1] > a[0] && a[1] > a[2] ) {
81 VectorCopy( vec3_origin, v );
96 extern void SelectCurvePointByRay( vec3_t org, vec3_t dir, int buttons );
98 void Drag_Setup( int x, int y, int buttons,
99 vec3_t xaxis, vec3_t yaxis,
100 vec3_t origin, vec3_t dir ){
106 VectorCopy( vec3_origin, pressdelta );
110 // snap to nearest axis for camwindow drags
111 VectorCopy( xaxis, drag_xvec );
112 AxializeVector( drag_xvec );
113 VectorCopy( yaxis, drag_yvec );
114 AxializeVector( drag_yvec );
116 if ( g_qeglobals.d_select_mode == sel_curvepoint ) {
117 SelectCurvePointByRay( origin, dir, buttons );
119 if ( g_qeglobals.d_select_mode == sel_area ) {
122 if ( g_nPatchClickedView == W_CAMERA ) {
123 VectorSet( g_qeglobals.d_vAreaTL, x, y, 0 );
124 VectorSet( g_qeglobals.d_vAreaBR, x, y, 0 );
127 else if ( g_qeglobals.d_num_move_points ) { // don't add an undo if there are no points selected
129 Sys_UpdateWindows( W_ALL );
130 Undo_Start( "drag curve point" );
131 Undo_AddBrushList( &selected_brushes );
137 g_qeglobals.d_num_move_points = 0;
140 if ( g_qeglobals.d_select_mode == sel_areatall ) {
141 VectorCopy( origin, g_qeglobals.d_vAreaTL );
142 VectorCopy( origin, g_qeglobals.d_vAreaBR );
144 Sys_UpdateWindows( W_ALL );
150 if ( selected_brushes.next == &selected_brushes ) {
151 //in this case a new brush is created when the dragging
152 //takes place in the XYWnd, An useless undo is created
153 //when the dragging takes place in the CamWnd
154 Undo_Start( "create brush" );
156 Sys_Status( "No selection to drag", 0 );
160 if ( g_qeglobals.d_select_mode == sel_vertex ) {
161 SelectVertexByRay( origin, dir );
162 if ( g_qeglobals.d_num_move_points ) {
164 Undo_Start( "drag vertex" );
165 Undo_AddBrushList( &selected_brushes );
166 // Need an update here for highlighting selected vertices
167 Sys_UpdateWindows( W_XY | W_CAMERA );
172 if ( g_qeglobals.d_select_mode == sel_edge ) {
173 SelectEdgeByRay( origin, dir );
174 if ( g_qeglobals.d_num_move_points ) {
176 Undo_Start( "drag edge" );
177 Undo_AddBrushList( &selected_brushes );
183 // check for direct hit first
185 t = Test_Ray( origin, dir, true );
189 Undo_Start( "drag selection" );
190 Undo_AddBrushList( &selected_brushes );
192 if ( buttons == ( MK_LBUTTON | MK_CONTROL ) ) {
193 Sys_Printf( "Shear dragging face\n" );
194 Brush_SelectFaceForDragging( t.brush, t.face, true );
196 else if ( buttons == ( MK_LBUTTON | MK_CONTROL | MK_SHIFT ) ) {
197 Sys_Printf( "Sticky dragging brush\n" );
198 for ( f = t.brush->brush_faces ; f ; f = f->next )
199 Brush_SelectFaceForDragging( t.brush, f, false );
202 Sys_Printf( "Dragging entire selection\n" );
208 if ( g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge ) {
213 // check for side hit
215 // multiple brushes selected?
216 if ( selected_brushes.next->next != &selected_brushes ) {
217 // yes, special handling
218 bool bOK = ( g_PrefsDlg.m_bALTEdge ) ? Sys_AltDown() : true;
220 for ( brush_t* pBrush = selected_brushes.next ; pBrush != &selected_brushes ; pBrush = pBrush->next )
222 if ( buttons & MK_CONTROL ) {
223 Brush_SideSelect( pBrush, origin, dir, true );
226 Brush_SideSelect( pBrush, origin, dir, false );
232 Sys_Printf( "press ALT to drag multiple edges\n" );
238 // single select.. trying to drag fixed entities handle themselves and just move
239 if ( buttons & MK_CONTROL ) {
240 Brush_SideSelect( selected_brushes.next, origin, dir, true );
243 Brush_SideSelect( selected_brushes.next, origin, dir, false );
247 Sys_Printf( "Side stretch\n" );
250 Undo_Start( "side stretch" );
251 Undo_AddBrushList( &selected_brushes );
256 void UpdateTarget( vec3_t origin, vec3_t dir ){
262 t = Test_Ray( origin, dir, 0 );
274 // is this the first?
275 if ( peLink != NULL ) {
277 // Get the target id from out current target
278 // if there is no id, make one
280 i = IntForKey( pe, "target" );
282 i = GetUniqueTargetId( 1 );
283 sprintf( sz, "%d", i );
285 SetKeyValue( pe, "target", sz );
288 // set the target # into our src
290 sprintf( sz, "%d", i );
291 SetKeyValue( peLink, "targetname", sz );
293 Sys_UpdateWindows( W_ENTITY );
297 // promote the target to the src
306 //++timo test three button mouse and three button emulation here ?
309 void Drag_Begin( int x, int y, int buttons,
310 vec3_t xaxis, vec3_t yaxis,
311 vec3_t origin, vec3_t dir, bool sf_camera ){
317 VectorCopy( vec3_origin, pressdelta );
318 VectorCopy( vec3_origin, vPressStart );
323 altdown = Sys_AltDown();
325 // shift-LBUTTON = select entire brush
326 // shift-alt-LBUTTON = drill select
327 if ( buttons == ( MK_LBUTTON | MK_SHIFT ) && g_qeglobals.d_select_mode != sel_curvepoint ) {
328 nFlag = altdown ? SF_CYCLE : 0;
333 nFlag |= SF_ENTITIES_FIRST;
335 Select_Ray( origin, dir, nFlag );
339 // (shift-)alt-LBUTTON = area select completely tall
341 ( g_PrefsDlg.m_bALTEdge ? buttons == ( MK_LBUTTON | MK_CONTROL | MK_SHIFT ) : ( buttons == MK_LBUTTON || buttons == ( MK_LBUTTON | MK_CONTROL | MK_SHIFT ) ) ) &&
342 altdown && g_qeglobals.d_select_mode != sel_curvepoint ) {
343 if ( g_pParentWnd->ActiveXY()->AreaSelectOK() ) {
344 g_qeglobals.d_select_mode = sel_areatall;
346 Drag_Setup( x, y, buttons, xaxis, yaxis, origin, dir );
351 // ctrl-alt-LBUTTON = multiple brush select without selecting whole entities
352 if ( buttons == ( MK_LBUTTON | MK_CONTROL ) && altdown && g_qeglobals.d_select_mode != sel_curvepoint ) {
358 nFlag |= SF_ENTITIES_FIRST;
360 Select_Ray( origin, dir, nFlag );
361 UpdateSurfaceDialog();
366 // ctrl-shift LBUTTON = select single face
367 if ( sf_camera && buttons == ( MK_LBUTTON | MK_CONTROL | MK_SHIFT ) && g_qeglobals.d_select_mode != sel_curvepoint ) {
368 if ( Sys_AltDown() ) {
370 for ( b = selected_brushes.next ; b != &selected_brushes ; b = b->next )
376 for ( face_t* pFace = b->brush_faces; pFace; pFace = pFace->next )
378 g_ptrSelectedFaces.Add( pFace );
379 g_ptrSelectedFaceBrushes.Add( b );
383 for ( b = selected_brushes.next; b != &selected_brushes; )
387 Brush_RemoveFromList( pb );
388 Brush_AddToList( pb, &active_brushes );
392 Select_Deselect( true );
395 Select_Ray( origin, dir, ( SF_SINGLEFACE | SF_CAMERA ) );
400 // LBUTTON + all other modifiers = manipulate selection
401 if ( buttons & MK_LBUTTON ) {
402 Drag_Setup( x, y, buttons, xaxis, yaxis, origin, dir );
406 int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON;
407 // middle button = grab texture
408 if ( buttons == nMouseButton ) {
409 t = Test_Ray( origin, dir, false );
411 UpdateWorkzone_ForBrush( t.brush );
412 // use a local brushprimit_texdef fitted to a default 2x2 texture
413 brushprimit_texdef_t bp_local;
414 ConvertTexMatWithQTexture( &t.face->brushprimit_texdef, t.face->d_texture, &bp_local, NULL );
415 Texture_SetTexture( &t.face->texdef, &bp_local, false, NULL );
416 UpdateSurfaceDialog();
417 UpdatePatchInspector();
420 Sys_Printf( "Did not select a texture\n" );
425 // ctrl-middle button = set entire brush to texture
426 if ( buttons == ( nMouseButton | MK_CONTROL ) ) {
427 t = Test_Ray( origin, dir, false );
429 if ( t.brush->brush_faces->texdef.GetName()[0] == '(' ) {
430 Sys_Printf( "Can't change an entity texture\n" );
434 Brush_SetTexture( t.brush, &g_qeglobals.d_texturewin.texdef, &g_qeglobals.d_texturewin.brushprimit_texdef, false, static_cast<IPluginTexdef *>( g_qeglobals.d_texturewin.pTexdef ) );
435 Sys_UpdateWindows( W_ALL );
439 Sys_Printf( "Didn't hit a btrush\n" );
444 // ctrl-shift-middle button = set single face to texture
445 if ( buttons == ( nMouseButton | MK_SHIFT | MK_CONTROL ) ) {
446 t = Test_Ray( origin, dir, false );
448 if ( t.brush->brush_faces->texdef.GetName()[0] == '(' ) {
449 Sys_Printf( "Can't change an entity texture\n" );
453 SetFaceTexdef( t.face, &g_qeglobals.d_texturewin.texdef, &g_qeglobals.d_texturewin.brushprimit_texdef );
454 Brush_Build( t.brush );
456 Sys_UpdateWindows( W_ALL );
460 Sys_Printf( "Didn't hit a btrush\n" );
465 if ( buttons == ( nMouseButton | MK_SHIFT ) ) {
466 Sys_Printf( "Set brush face texture info\n" );
467 t = Test_Ray( origin, dir, false );
469 if ( t.brush->brush_faces->texdef.GetName()[0] == '(' ) {
470 if ( t.brush->owner->eclass->nShowFlags & ECLASS_LIGHT ) {
472 qtexture_t* pTex = g_qeglobals.d_texturewin.pShader->getTexture();
475 VectorCopy( pTex->color, vColor );
477 float fLargest = 0.0f;
478 for ( int i = 0; i < 3; i++ )
480 if ( vColor[i] > fLargest ) {
481 fLargest = vColor[i];
485 if ( fLargest == 0.0f ) {
486 vColor[0] = vColor[1] = vColor[2] = 1.0f;
490 float fScale = 1.0f / fLargest;
491 for ( int i = 0; i < 3; i++ )
496 strBuff.Format( "%f %f %f",pTex->color[0], pTex->color[1], pTex->color[2] );
497 SetKeyValue( t.brush->owner, "_color", strBuff.GetBuffer() );
498 Sys_UpdateWindows( W_ALL );
503 Sys_Printf( "Can't select an entity brush face\n" );
508 Face_SetShader( t.face, g_qeglobals.d_texturewin.texdef.GetName() );
509 Brush_Build( t.brush );
511 Sys_UpdateWindows( W_ALL );
515 Sys_Printf( "Didn't hit a brush\n" );
528 void MoveSelection( vec3_t move ){
532 vec3_t vTemp, vTemp2, end;
534 if ( !move[0] && !move[1] && !move[2] ) {
538 if ( !( g_qeglobals.d_select_mode == sel_area || g_qeglobals.d_select_mode == sel_areatall ) ) {
539 move[0] = ( g_nScaleHow & SCALE_X ) ? 0 : move[0];
540 move[1] = ( g_nScaleHow & SCALE_Y ) ? 0 : move[1];
541 move[2] = ( g_nScaleHow & SCALE_Z ) ? 0 : move[2];
544 if ( g_pParentWnd->ActiveXY()->RotateMode() || g_bPatchBendMode ) {
545 float fDeg = -move[2];
546 float fAdj = move[2];
548 if ( g_pParentWnd->ActiveXY()->GetViewType() == XY ) {
554 if ( g_pParentWnd->ActiveXY()->GetViewType() == XZ ) {
563 g_pParentWnd->ActiveXY()->Rotation()[nAxis] += fAdj;
564 strStatus.Format( "%s x:: %.1f y:: %.1f z:: %.1f", ( g_bPatchBendMode ) ? "Bend angle" : "Rotation", g_pParentWnd->ActiveXY()->Rotation()[0], g_pParentWnd->ActiveXY()->Rotation()[1], g_pParentWnd->ActiveXY()->Rotation()[2] );
565 g_pParentWnd->SetStatusText( 2, strStatus );
567 if ( g_bPatchBendMode ) {
568 Patch_SelectBendNormal();
569 Select_RotateAxis( nAxis, fDeg * 2, false, true );
570 Patch_SelectBendAxis();
571 Select_RotateAxis( nAxis, fDeg, false, true );
575 Select_RotateAxis( nAxis, fDeg, false, true );
580 if ( g_pParentWnd->ActiveXY()->ScaleMode() ) {
582 v[0] = v[1] = v[2] = 1.0f;
595 Select_Scale( ( g_nScaleHow & SCALE_X ) ? 1.0f : v[0],
596 ( g_nScaleHow & SCALE_Y ) ? 1.0f : v[1],
597 ( g_nScaleHow & SCALE_Z ) ? 1.0f : v[2] );
598 // is that really necessary???
599 Sys_UpdateWindows( W_ALL );
605 VectorSubtract( pressdelta, vPressStart, vDistance );
606 strStatus.Format( "Distance x: %.1f y: %.1f z: %.1f", vDistance[0], vDistance[1], vDistance[2] );
607 g_pParentWnd->SetStatusText( 3, strStatus );
610 // dragging only a part of the selection
613 // this is fairly crappy way to deal with curvepoint and area selection
614 // but it touches the smallest amount of code this way
616 if ( g_qeglobals.d_num_move_points || g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_area || g_qeglobals.d_select_mode == sel_areatall ) {
618 if ( g_qeglobals.d_select_mode == sel_area || g_qeglobals.d_select_mode == sel_areatall ) {
619 VectorAdd( g_qeglobals.d_vAreaBR, move, g_qeglobals.d_vAreaBR );
622 //curve point selection
623 if ( g_qeglobals.d_select_mode == sel_curvepoint ) {
624 Patch_UpdateSelected( move );
628 if ( g_qeglobals.d_select_mode == sel_vertex && g_PrefsDlg.m_bVertexSplit ) {
629 if ( g_qeglobals.d_num_move_points ) {
631 for ( b = selected_brushes.next; b != &selected_brushes; b = b->next )
633 success &= Brush_MoveVertex( b, g_qeglobals.d_move_points[0], move, end, true );
636 VectorCopy( end, g_qeglobals.d_move_points[0] );
641 //all other selection types
642 for ( i = 0 ; i < g_qeglobals.d_num_move_points ; i++ )
643 VectorAdd( g_qeglobals.d_move_points[i], move, g_qeglobals.d_move_points[i] );
644 for ( b = selected_brushes.next; b != &selected_brushes; b = b->next )
647 for ( face_t *f = b->brush_faces; !bMoved && f != NULL; f = f->next )
648 for ( int p = 0; !bMoved && p < 3; p++ )
649 for ( i = 0 ; !bMoved && i < g_qeglobals.d_num_move_points ; i++ )
650 if ( f->planepts[p] == g_qeglobals.d_move_points[i] ) {
657 VectorCopy( b->maxs, vTemp );
658 VectorSubtract( vTemp, b->mins, vTemp );
659 Brush_Build( b,true,true,false,false ); // don't filter
660 for ( i = 0 ; i < 3 ; i++ )
662 if ( b->mins[i] > b->maxs[i]
663 || b->maxs[i] - b->mins[i] > g_MaxBrushSize ) {
664 break; // dragged backwards or fucked up
670 if ( b->patchBrush ) {
671 VectorCopy( b->maxs, vTemp2 );
672 VectorSubtract( vTemp2, b->mins, vTemp2 );
673 VectorSubtract( vTemp2, vTemp, vTemp2 );
674 //if (!Patch_DragScale(b->nPatchID, vTemp2, move))
675 if ( !Patch_DragScale( b->pPatch, vTemp2, move ) ) {
681 // if any of the brushes were crushed out of existance
682 // calcel the entire move
683 if ( b != &selected_brushes ) {
684 Sys_Printf( "Brush dragged backwards, move canceled\n" );
685 for ( i = 0 ; i < g_qeglobals.d_num_move_points ; i++ )
686 VectorSubtract( g_qeglobals.d_move_points[i], move, g_qeglobals.d_move_points[i] );
688 for ( b = selected_brushes.next ; b != &selected_brushes ; b = b->next )
689 Brush_Build( b,true,true,false,false ); // don't filter
695 // reset face originals from vertex edit mode
696 // this is dirty, but unfortunately necessary because Brush_Build
697 // can remove windings
698 for ( b = selected_brushes.next; b != &selected_brushes; b = b->next )
700 Brush_ResetFaceOriginals( b );
703 // if there are lots of brushes selected, just translate instead
704 // of rebuilding the brushes
705 // NOTE: this is not actually done, but would be a good idea
716 void Drag_MouseMoved( int x, int y, int buttons ){
728 // clear along one axis
729 if ( buttons & MK_SHIFT && ( g_PrefsDlg.m_bALTEdge && g_qeglobals.d_select_mode != sel_areatall ) ) {
731 if ( abs( x - pressx ) > abs( y - pressy ) ) {
739 if ( g_qeglobals.d_select_mode == sel_area && g_nPatchClickedView == W_CAMERA ) {
740 camera_t *m_pCamera = g_pParentWnd->GetCamWnd()->Camera();
743 if ( y > m_pCamera->height ) {
744 y = m_pCamera->height - 1;
749 if ( x > m_pCamera->width ) {
750 x = m_pCamera->width - 1;
756 VectorSet( move, x - pressx, y - pressy, 0 );
760 for ( i = 0 ; i < 3 ; i++ )
762 move[i] = drag_xvec[i] * ( x - pressx ) + drag_yvec[i] * ( y - pressy );
763 if ( g_PrefsDlg.m_bSnap ) {
764 move[i] = floor( move[i] / g_qeglobals.d_gridsize + 0.5 ) * g_qeglobals.d_gridsize;
769 VectorSubtract( move, pressdelta, delta );
770 VectorCopy( move, pressdelta );
772 MoveSelection( delta );
780 void Drag_MouseUp( int nButtons ){
781 Sys_Status( "Drag completed.", 0 );
783 if ( g_qeglobals.d_select_mode == sel_area ) {
784 Patch_SelectAreaPoints( nButtons & MK_CONTROL ); // adds to selection and/or deselects selected points if ctrl is held
785 g_qeglobals.d_select_mode = sel_curvepoint;
786 Sys_UpdateWindows( W_ALL );
789 if ( g_qeglobals.d_select_mode == sel_areatall ) {
792 int nDim1 = ( g_pParentWnd->ActiveXY()->GetViewType() == YZ ) ? 1 : 0;
793 int nDim2 = ( g_pParentWnd->ActiveXY()->GetViewType() == XY ) ? 1 : 2;
796 mins[nDim1] = MIN( g_qeglobals.d_vAreaTL[nDim1], g_qeglobals.d_vAreaBR[nDim1] );
797 mins[nDim2] = MIN( g_qeglobals.d_vAreaTL[nDim2], g_qeglobals.d_vAreaBR[nDim2] );
798 maxs[nDim1] = MAX( g_qeglobals.d_vAreaTL[nDim1], g_qeglobals.d_vAreaBR[nDim1] );
799 maxs[nDim2] = MAX( g_qeglobals.d_vAreaTL[nDim2], g_qeglobals.d_vAreaBR[nDim2] );
801 // deselect current selection
802 if ( !( nButtons & ( MK_CONTROL | MK_SHIFT ) ) ) {
806 // select new selection
807 Select_RealCompleteTall( mins, maxs );
809 Sys_UpdateWindows( W_ALL );
812 if ( g_qeglobals.d_select_translate[0] || g_qeglobals.d_select_translate[1] || g_qeglobals.d_select_translate[2] ) {
813 Select_Move( g_qeglobals.d_select_translate );
814 VectorCopy( vec3_origin, g_qeglobals.d_select_translate );
815 Sys_UpdateWindows( W_CAMERA );
818 /* note: added cleanup here, since an edge drag will leave selected vertices
819 in g_qeglobals.d_num_move_points
821 if ( g_qeglobals.d_select_mode != sel_vertex &&
822 g_qeglobals.d_select_mode != sel_curvepoint &&
823 g_qeglobals.d_select_mode != sel_edge ) {
824 g_qeglobals.d_num_move_points = 0;
827 g_pParentWnd->SetStatusText( 3, "" );
828 Undo_EndBrushList( &selected_brushes );
830 UpdateSurfaceDialog();