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)
68 if (a[0] > a[1] && a[0] > a[2])
70 else if (a[1] > a[0] && a[1] > a[2])
76 VectorCopy (vec3_origin, v);
89 extern void SelectCurvePointByRay (vec3_t org, vec3_t dir, int buttons);
91 void Drag_Setup (int x, int y, int buttons,
92 vec3_t xaxis, vec3_t yaxis,
93 vec3_t origin, vec3_t dir)
100 VectorCopy (vec3_origin, pressdelta);
104 // snap to nearest axis for camwindow drags
105 VectorCopy (xaxis, drag_xvec);
106 AxializeVector (drag_xvec);
107 VectorCopy (yaxis, drag_yvec);
108 AxializeVector (drag_yvec);
110 if (g_qeglobals.d_select_mode == sel_curvepoint)
112 SelectCurvePointByRay (origin, dir, buttons);
114 if(g_qeglobals.d_select_mode == sel_area)
118 if(g_nPatchClickedView == W_CAMERA ) {
119 VectorSet( g_qeglobals.d_vAreaTL, x, y, 0 );
120 VectorSet( g_qeglobals.d_vAreaBR, x, y, 0 );
123 else if (g_qeglobals.d_num_move_points) // don't add an undo if there are no points selected
126 Sys_UpdateWindows(W_ALL);
127 Undo_Start("drag curve point");
128 Undo_AddBrushList(&selected_brushes);
134 g_qeglobals.d_num_move_points = 0;
137 if (g_qeglobals.d_select_mode == sel_areatall)
139 VectorCopy(origin, g_qeglobals.d_vAreaTL);
140 VectorCopy(origin, g_qeglobals.d_vAreaBR);
142 Sys_UpdateWindows(W_ALL);
148 if (selected_brushes.next == &selected_brushes)
150 //in this case a new brush is created when the dragging
151 //takes place in the XYWnd, An useless undo is created
152 //when the dragging takes place in the CamWnd
153 Undo_Start("create brush");
155 Sys_Status("No selection to drag", 0);
159 if (g_qeglobals.d_select_mode == sel_vertex)
161 SelectVertexByRay (origin, dir);
162 if (g_qeglobals.d_num_move_points)
165 Undo_Start("drag vertex");
166 Undo_AddBrushList(&selected_brushes);
167 // Need an update here for highlighting selected vertices
168 Sys_UpdateWindows(W_XY | W_CAMERA);
173 if (g_qeglobals.d_select_mode == sel_edge)
175 SelectEdgeByRay (origin, dir);
176 if (g_qeglobals.d_num_move_points)
179 Undo_Start("drag edge");
180 Undo_AddBrushList(&selected_brushes);
186 // check for direct hit first
188 t = Test_Ray (origin, dir, true);
193 Undo_Start("drag selection");
194 Undo_AddBrushList(&selected_brushes);
196 if (buttons == (MK_LBUTTON|MK_CONTROL) )
198 Sys_Printf ("Shear dragging face\n");
199 Brush_SelectFaceForDragging (t.brush, t.face, true);
201 else if (buttons == (MK_LBUTTON|MK_CONTROL|MK_SHIFT) )
203 Sys_Printf ("Sticky dragging brush\n");
204 for (f=t.brush->brush_faces ; f ; f=f->next)
205 Brush_SelectFaceForDragging (t.brush, f, false);
208 Sys_Printf ("Dragging entire selection\n");
213 if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge)
217 // check for side hit
219 // multiple brushes selected?
220 if (selected_brushes.next->next != &selected_brushes)
222 // yes, special handling
223 bool bOK = (g_PrefsDlg.m_bALTEdge) ? Sys_AltDown() : true;
226 for (brush_t* pBrush = selected_brushes.next ; pBrush != &selected_brushes ; pBrush = pBrush->next)
228 if (buttons & MK_CONTROL)
229 Brush_SideSelect (pBrush, origin, dir, true);
231 Brush_SideSelect (pBrush, origin, dir, false);
236 Sys_Printf ("press ALT to drag multiple edges\n");
242 // single select.. trying to drag fixed entities handle themselves and just move
243 if (buttons & MK_CONTROL)
244 Brush_SideSelect (selected_brushes.next, origin, dir, true);
246 Brush_SideSelect (selected_brushes.next, origin, dir, false);
249 Sys_Printf ("Side stretch\n");
252 Undo_Start("side stretch");
253 Undo_AddBrushList(&selected_brushes);
258 void UpdateTarget(vec3_t origin, vec3_t dir)
265 t = Test_Ray (origin, dir, 0);
275 // is this the first?
279 // Get the target id from out current target
280 // if there is no id, make one
282 i = IntForKey(pe, "target");
285 i = GetUniqueTargetId(1);
286 sprintf(sz, "%d", i);
288 SetKeyValue(pe, "target", sz);
291 // set the target # into our src
293 sprintf(sz, "%d", i);
294 SetKeyValue(peLink, "targetname", sz);
296 Sys_UpdateWindows(W_ENTITY);
300 // promote the target to the src
309 //++timo test three button mouse and three button emulation here ?
312 void Drag_Begin (int x, int y, int buttons,
313 vec3_t xaxis, vec3_t yaxis,
314 vec3_t origin, vec3_t dir, bool sf_camera)
321 VectorCopy (vec3_origin, pressdelta);
322 VectorCopy (vec3_origin, vPressStart);
327 altdown = Sys_AltDown();
329 // shift-LBUTTON = select entire brush
330 // shift-alt-LBUTTON = drill select
331 if (buttons == (MK_LBUTTON | MK_SHIFT) && g_qeglobals.d_select_mode != sel_curvepoint)
333 nFlag = altdown ? SF_CYCLE : 0;
337 nFlag |= SF_ENTITIES_FIRST;
338 Select_Ray(origin, dir, nFlag);
342 // (shift-)alt-LBUTTON = area select completely tall
344 ( g_PrefsDlg.m_bALTEdge ? buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT) : (buttons == MK_LBUTTON || buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT)) ) &&
345 altdown && g_qeglobals.d_select_mode != sel_curvepoint)
347 if (g_pParentWnd->ActiveXY()->AreaSelectOK())
349 g_qeglobals.d_select_mode = sel_areatall;
351 Drag_Setup (x, y, buttons, xaxis, yaxis, origin, dir);
356 // ctrl-alt-LBUTTON = multiple brush select without selecting whole entities
357 if (buttons == (MK_LBUTTON | MK_CONTROL) && altdown && g_qeglobals.d_select_mode != sel_curvepoint)
363 nFlag |= SF_ENTITIES_FIRST;
364 Select_Ray (origin, dir, nFlag);
365 UpdateSurfaceDialog();
370 // ctrl-shift LBUTTON = select single face
371 if (sf_camera && buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT) && g_qeglobals.d_select_mode != sel_curvepoint)
376 for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
381 for (face_t* pFace = b->brush_faces; pFace; pFace = pFace->next)
383 g_ptrSelectedFaces.Add(pFace);
384 g_ptrSelectedFaceBrushes.Add(b);
388 for (b = selected_brushes.next; b != &selected_brushes; )
392 Brush_RemoveFromList (pb);
393 Brush_AddToList (pb, &active_brushes);
397 Select_Deselect (true);
399 Select_Ray (origin, dir, (SF_SINGLEFACE|SF_CAMERA));
404 // LBUTTON + all other modifiers = manipulate selection
405 if (buttons & MK_LBUTTON)
407 Drag_Setup (x, y, buttons, xaxis, yaxis, origin, dir);
411 int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON;
412 // middle button = grab texture
413 if (buttons == nMouseButton)
415 t = Test_Ray (origin, dir, false);
418 UpdateWorkzone_ForBrush( t.brush );
419 // use a local brushprimit_texdef fitted to a default 2x2 texture
420 brushprimit_texdef_t bp_local;
421 ConvertTexMatWithQTexture( &t.face->brushprimit_texdef, t.face->d_texture, &bp_local, NULL );
422 Texture_SetTexture ( &t.face->texdef, &bp_local, false, NULL);
423 UpdateSurfaceDialog();
424 UpdatePatchInspector();
427 Sys_Printf ("Did not select a texture\n");
431 // ctrl-middle button = set entire brush to texture
432 if (buttons == (nMouseButton|MK_CONTROL) )
434 t = Test_Ray (origin, dir, false);
437 if (t.brush->brush_faces->texdef.GetName()[0] == '(')
438 Sys_Printf ("Can't change an entity texture\n");
441 Brush_SetTexture (t.brush, &g_qeglobals.d_texturewin.texdef, &g_qeglobals.d_texturewin.brushprimit_texdef, false, static_cast<IPluginTexdef *>( g_qeglobals.d_texturewin.pTexdef ) );
442 Sys_UpdateWindows (W_ALL);
446 Sys_Printf ("Didn't hit a btrush\n");
450 // ctrl-shift-middle button = set single face to texture
451 if (buttons == (nMouseButton|MK_SHIFT|MK_CONTROL) )
453 t = Test_Ray (origin, dir, false);
456 if (t.brush->brush_faces->texdef.GetName()[0] == '(')
457 Sys_Printf ("Can't change an entity texture\n");
460 SetFaceTexdef (t.face, &g_qeglobals.d_texturewin.texdef, &g_qeglobals.d_texturewin.brushprimit_texdef);
461 Brush_Build( t.brush );
463 Sys_UpdateWindows (W_ALL);
467 Sys_Printf ("Didn't hit a btrush\n");
471 if (buttons == (nMouseButton | MK_SHIFT))
473 Sys_Printf("Set brush face texture info\n");
474 t = Test_Ray (origin, dir, false);
477 if (t.brush->brush_faces->texdef.GetName()[0] == '(')
479 if (t.brush->owner->eclass->nShowFlags & ECLASS_LIGHT)
482 qtexture_t* pTex = g_qeglobals.d_texturewin.pShader->getTexture();
486 VectorCopy(pTex->color, vColor);
488 float fLargest = 0.0f;
489 for (int i = 0; i < 3; i++)
491 if (vColor[i] > fLargest)
492 fLargest = vColor[i];
495 if (fLargest == 0.0f)
497 vColor[0] = vColor[1] = vColor[2] = 1.0f;
501 float fScale = 1.0f / fLargest;
502 for (int i = 0; i < 3; i++)
507 strBuff.Format("%f %f %f",pTex->color[0], pTex->color[1], pTex->color[2]);
508 SetKeyValue(t.brush->owner, "_color", strBuff.GetBuffer());
509 Sys_UpdateWindows (W_ALL);
514 Sys_Printf ("Can't select an entity brush face\n");
519 Face_SetShader(t.face, g_qeglobals.d_texturewin.texdef.GetName());
520 Brush_Build(t.brush);
522 Sys_UpdateWindows (W_ALL);
526 Sys_Printf ("Didn't hit a brush\n");
538 void MoveSelection (vec3_t move)
543 vec3_t vTemp, vTemp2, end;
545 if (!move[0] && !move[1] && !move[2])
550 if (!(g_qeglobals.d_select_mode == sel_area || g_qeglobals.d_select_mode == sel_areatall))
552 move[0] = (g_nScaleHow & SCALE_X) ? 0 : move[0];
553 move[1] = (g_nScaleHow & SCALE_Y) ? 0 : move[1];
554 move[2] = (g_nScaleHow & SCALE_Z) ? 0 : move[2];
557 if (g_pParentWnd->ActiveXY()->RotateMode() || g_bPatchBendMode)
559 float fDeg = -move[2];
560 float fAdj = move[2];
562 if (g_pParentWnd->ActiveXY()->GetViewType() == XY)
569 if (g_pParentWnd->ActiveXY()->GetViewType() == XZ)
578 g_pParentWnd->ActiveXY()->Rotation()[nAxis] += fAdj;
579 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]);
580 g_pParentWnd->SetStatusText(2, strStatus);
582 if (g_bPatchBendMode)
584 Patch_SelectBendNormal();
585 Select_RotateAxis(nAxis, fDeg*2, false, true);
586 Patch_SelectBendAxis();
587 Select_RotateAxis(nAxis, fDeg, false, true);
591 Select_RotateAxis(nAxis, fDeg, false, true);
596 if (g_pParentWnd->ActiveXY()->ScaleMode())
599 v[0] = v[1] = v[2] = 1.0f;
614 Select_Scale((g_nScaleHow & SCALE_X) ? 1.0f : v[0],
615 (g_nScaleHow & SCALE_Y) ? 1.0f : v[1],
616 (g_nScaleHow & SCALE_Z) ? 1.0f : v[2]);
617 // is that really necessary???
618 Sys_UpdateWindows (W_ALL);
624 VectorSubtract(pressdelta, vPressStart, vDistance);
625 strStatus.Format("Distance x: %.1f y: %.1f z: %.1f", vDistance[0], vDistance[1], vDistance[2]);
626 g_pParentWnd->SetStatusText(3, strStatus);
629 // dragging only a part of the selection
632 // this is fairly crappy way to deal with curvepoint and area selection
633 // but it touches the smallest amount of code this way
635 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)
638 if (g_qeglobals.d_select_mode == sel_area || g_qeglobals.d_select_mode == sel_areatall)
640 VectorAdd(g_qeglobals.d_vAreaBR, move, g_qeglobals.d_vAreaBR);
643 //curve point selection
644 if (g_qeglobals.d_select_mode == sel_curvepoint)
646 Patch_UpdateSelected(move);
650 if (g_qeglobals.d_select_mode == sel_vertex && g_PrefsDlg.m_bVertexSplit)
652 if(g_qeglobals.d_num_move_points) {
654 for (b = selected_brushes.next; b != &selected_brushes; b = b->next)
656 success &= Brush_MoveVertex(b, g_qeglobals.d_move_points[0], move, end, true);
659 VectorCopy(end, g_qeglobals.d_move_points[0]);
663 //all other selection types
664 for (i=0 ; i<g_qeglobals.d_num_move_points ; i++)
665 VectorAdd (g_qeglobals.d_move_points[i], move, g_qeglobals.d_move_points[i]);
666 for (b = selected_brushes.next; b != &selected_brushes; b = b->next)
669 for(face_t *f = b->brush_faces; !bMoved && f!=NULL; f=f->next)
670 for(int p=0; !bMoved && p<3; p++)
671 for (i=0 ; !bMoved && i<g_qeglobals.d_num_move_points ; i++)
672 if(f->planepts[p] == g_qeglobals.d_move_points[i])
674 if(!bMoved) continue;
676 VectorCopy(b->maxs, vTemp);
677 VectorSubtract(vTemp, b->mins, vTemp);
678 Brush_Build(b,true,true,false,false); // don't filter
679 for (i=0 ; i<3 ; i++)
681 if (b->mins[i] > b->maxs[i]
682 || b->maxs[i] - b->mins[i] > g_MaxBrushSize)
683 break; // dragged backwards or fucked up
689 VectorCopy(b->maxs, vTemp2);
690 VectorSubtract(vTemp2, b->mins, vTemp2);
691 VectorSubtract(vTemp2, vTemp, vTemp2);
692 //if (!Patch_DragScale(b->nPatchID, vTemp2, move))
693 if (!Patch_DragScale(b->pPatch, vTemp2, move))
700 // if any of the brushes were crushed out of existance
701 // calcel the entire move
702 if (b != &selected_brushes)
704 Sys_Printf ("Brush dragged backwards, move canceled\n");
705 for (i=0 ; i<g_qeglobals.d_num_move_points ; i++)
706 VectorSubtract (g_qeglobals.d_move_points[i], move, g_qeglobals.d_move_points[i]);
708 for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
709 Brush_Build(b,true,true,false,false); // don't filter
715 // reset face originals from vertex edit mode
716 // this is dirty, but unfortunately necessary because Brush_Build
717 // can remove windings
718 for (b = selected_brushes.next; b != &selected_brushes; b = b->next)
720 Brush_ResetFaceOriginals(b);
723 // if there are lots of brushes selected, just translate instead
724 // of rebuilding the brushes
725 // NOTE: this is not actually done, but would be a good idea
736 void Drag_MouseMoved (int x, int y, int buttons)
749 // clear along one axis
750 if (buttons & MK_SHIFT && (g_PrefsDlg.m_bALTEdge && g_qeglobals.d_select_mode != sel_areatall))
753 if (abs(x-pressx) > abs(y-pressy))
759 if (g_qeglobals.d_select_mode == sel_area && g_nPatchClickedView == W_CAMERA)
761 camera_t *m_pCamera = g_pParentWnd->GetCamWnd()->Camera();
764 if( y > m_pCamera->height ) y = m_pCamera->height - 1; else if( y < 0 ) y = 0;
765 if( x > m_pCamera->width ) x = m_pCamera->width - 1; else if( x < 0 ) x = 0;
767 VectorSet (move, x - pressx, y - pressy, 0);
770 for (i=0 ; i<3 ; i++)
772 move[i] = drag_xvec[i]*(x - pressx) + drag_yvec[i]*(y - pressy);
773 if (!g_PrefsDlg.m_bNoClamp)
775 move[i] = floor(move[i]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize;
780 VectorSubtract (move, pressdelta, delta);
781 VectorCopy (move, pressdelta);
783 MoveSelection (delta);
791 void Drag_MouseUp (int nButtons)
793 Sys_Status ("Drag completed.", 0);
795 if (g_qeglobals.d_select_mode == sel_area)
797 Patch_SelectAreaPoints(nButtons & MK_CONTROL); // adds to selection and/or deselects selected points if ctrl is held
798 g_qeglobals.d_select_mode = sel_curvepoint;
799 Sys_UpdateWindows (W_ALL);
802 if (g_qeglobals.d_select_mode == sel_areatall)
806 int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0;
807 int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2;
810 mins[nDim1] = MIN( g_qeglobals.d_vAreaTL[nDim1], g_qeglobals.d_vAreaBR[nDim1] );
811 mins[nDim2] = MIN( g_qeglobals.d_vAreaTL[nDim2], g_qeglobals.d_vAreaBR[nDim2] );
812 maxs[nDim1] = MAX( g_qeglobals.d_vAreaTL[nDim1], g_qeglobals.d_vAreaBR[nDim1] );
813 maxs[nDim2] = MAX( g_qeglobals.d_vAreaTL[nDim2], g_qeglobals.d_vAreaBR[nDim2] );
815 // deselect current selection
816 if( !(nButtons & (MK_CONTROL|MK_SHIFT)) )
819 // select new selection
820 Select_RealCompleteTall( mins, maxs );
822 Sys_UpdateWindows (W_ALL);
825 if (g_qeglobals.d_select_translate[0] || g_qeglobals.d_select_translate[1] || g_qeglobals.d_select_translate[2])
827 Select_Move (g_qeglobals.d_select_translate);
828 VectorCopy (vec3_origin, g_qeglobals.d_select_translate);
829 Sys_UpdateWindows (W_CAMERA);
832 /* note: added cleanup here, since an edge drag will leave selected vertices
833 in g_qeglobals.d_num_move_points
835 if ( g_qeglobals.d_select_mode != sel_vertex &&
836 g_qeglobals.d_select_mode != sel_curvepoint &&
837 g_qeglobals.d_select_mode != sel_edge)
838 g_qeglobals.d_num_move_points = 0;
840 g_pParentWnd->SetStatusText(3, "");
841 Undo_EndBrushList(&selected_brushes);
843 UpdateSurfaceDialog();