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 // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=425
520 Face_SetShader(t.face, g_qeglobals.d_texturewin.texdef.GetName());
521 Brush_Build(t.brush);
523 Sys_UpdateWindows (W_ALL);
527 Sys_Printf ("Didn't hit a brush\n");
539 void MoveSelection (vec3_t move)
544 vec3_t vTemp, vTemp2, end;
546 if (!move[0] && !move[1] && !move[2])
551 if (!(g_qeglobals.d_select_mode == sel_area || g_qeglobals.d_select_mode == sel_areatall))
553 move[0] = (g_nScaleHow & SCALE_X) ? 0 : move[0];
554 move[1] = (g_nScaleHow & SCALE_Y) ? 0 : move[1];
555 move[2] = (g_nScaleHow & SCALE_Z) ? 0 : move[2];
558 if (g_pParentWnd->ActiveXY()->RotateMode() || g_bPatchBendMode)
560 float fDeg = -move[2];
561 float fAdj = move[2];
563 if (g_pParentWnd->ActiveXY()->GetViewType() == XY)
570 if (g_pParentWnd->ActiveXY()->GetViewType() == XZ)
579 g_pParentWnd->ActiveXY()->Rotation()[nAxis] += fAdj;
580 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]);
581 g_pParentWnd->SetStatusText(2, strStatus);
583 if (g_bPatchBendMode)
585 Patch_SelectBendNormal();
586 Select_RotateAxis(nAxis, fDeg*2, false, true);
587 Patch_SelectBendAxis();
588 Select_RotateAxis(nAxis, fDeg, false, true);
592 Select_RotateAxis(nAxis, fDeg, false, true);
597 if (g_pParentWnd->ActiveXY()->ScaleMode())
600 v[0] = v[1] = v[2] = 1.0f;
615 Select_Scale((g_nScaleHow & SCALE_X) ? 1.0f : v[0],
616 (g_nScaleHow & SCALE_Y) ? 1.0f : v[1],
617 (g_nScaleHow & SCALE_Z) ? 1.0f : v[2]);
618 // is that really necessary???
619 Sys_UpdateWindows (W_ALL);
625 VectorSubtract(pressdelta, vPressStart, vDistance);
626 strStatus.Format("Distance x: %.1f y: %.1f z: %.1f", vDistance[0], vDistance[1], vDistance[2]);
627 g_pParentWnd->SetStatusText(3, strStatus);
630 // dragging only a part of the selection
633 // this is fairly crappy way to deal with curvepoint and area selection
634 // but it touches the smallest amount of code this way
636 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)
639 if (g_qeglobals.d_select_mode == sel_area || g_qeglobals.d_select_mode == sel_areatall)
641 VectorAdd(g_qeglobals.d_vAreaBR, move, g_qeglobals.d_vAreaBR);
644 //curve point selection
645 if (g_qeglobals.d_select_mode == sel_curvepoint)
647 Patch_UpdateSelected(move);
651 if (g_qeglobals.d_select_mode == sel_vertex && g_PrefsDlg.m_bVertexSplit)
653 if(g_qeglobals.d_num_move_points) {
655 for (b = selected_brushes.next; b != &selected_brushes; b = b->next)
657 success &= Brush_MoveVertex(b, g_qeglobals.d_move_points[0], move, end, true);
660 VectorCopy(end, g_qeglobals.d_move_points[0]);
664 //all other selection types
665 for (i=0 ; i<g_qeglobals.d_num_move_points ; i++)
666 VectorAdd (g_qeglobals.d_move_points[i], move, g_qeglobals.d_move_points[i]);
667 for (b = selected_brushes.next; b != &selected_brushes; b = b->next)
670 for(face_t *f = b->brush_faces; !bMoved && f!=NULL; f=f->next)
671 for(int p=0; !bMoved && p<3; p++)
672 for (i=0 ; !bMoved && i<g_qeglobals.d_num_move_points ; i++)
673 if(f->planepts[p] == g_qeglobals.d_move_points[i])
675 if(!bMoved) continue;
677 VectorCopy(b->maxs, vTemp);
678 VectorSubtract(vTemp, b->mins, vTemp);
679 Brush_Build(b,true,true,false,false); // don't filter
680 for (i=0 ; i<3 ; i++)
682 if (b->mins[i] > b->maxs[i]
683 || b->maxs[i] - b->mins[i] > g_MaxBrushSize)
684 break; // dragged backwards or fucked up
690 VectorCopy(b->maxs, vTemp2);
691 VectorSubtract(vTemp2, b->mins, vTemp2);
692 VectorSubtract(vTemp2, vTemp, vTemp2);
693 //if (!Patch_DragScale(b->nPatchID, vTemp2, move))
694 if (!Patch_DragScale(b->pPatch, vTemp2, move))
701 // if any of the brushes were crushed out of existance
702 // calcel the entire move
703 if (b != &selected_brushes)
705 Sys_Printf ("Brush dragged backwards, move canceled\n");
706 for (i=0 ; i<g_qeglobals.d_num_move_points ; i++)
707 VectorSubtract (g_qeglobals.d_move_points[i], move, g_qeglobals.d_move_points[i]);
709 for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
710 Brush_Build(b,true,true,false,false); // don't filter
716 // reset face originals from vertex edit mode
717 // this is dirty, but unfortunately necessary because Brush_Build
718 // can remove windings
719 for (b = selected_brushes.next; b != &selected_brushes; b = b->next)
721 Brush_ResetFaceOriginals(b);
724 // if there are lots of brushes selected, just translate instead
725 // of rebuilding the brushes
726 // NOTE: this is not actually done, but would be a good idea
737 void Drag_MouseMoved (int x, int y, int buttons)
750 // clear along one axis
751 if (buttons & MK_SHIFT && (g_PrefsDlg.m_bALTEdge && g_qeglobals.d_select_mode != sel_areatall))
754 if (abs(x-pressx) > abs(y-pressy))
760 if (g_qeglobals.d_select_mode == sel_area && g_nPatchClickedView == W_CAMERA)
762 camera_t *m_pCamera = g_pParentWnd->GetCamWnd()->Camera();
765 if( y > m_pCamera->height ) y = m_pCamera->height - 1; else if( y < 0 ) y = 0;
766 if( x > m_pCamera->width ) x = m_pCamera->width - 1; else if( x < 0 ) x = 0;
768 VectorSet (move, x - pressx, y - pressy, 0);
771 for (i=0 ; i<3 ; i++)
773 move[i] = drag_xvec[i]*(x - pressx) + drag_yvec[i]*(y - pressy);
774 if (!g_PrefsDlg.m_bNoClamp)
776 move[i] = floor(move[i]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize;
781 VectorSubtract (move, pressdelta, delta);
782 VectorCopy (move, pressdelta);
784 MoveSelection (delta);
792 void Drag_MouseUp (int nButtons)
794 Sys_Status ("Drag completed.", 0);
796 if (g_qeglobals.d_select_mode == sel_area)
798 Patch_SelectAreaPoints(nButtons & MK_CONTROL); // adds to selection and/or deselects selected points if ctrl is held
799 g_qeglobals.d_select_mode = sel_curvepoint;
800 Sys_UpdateWindows (W_ALL);
803 if (g_qeglobals.d_select_mode == sel_areatall)
807 int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0;
808 int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2;
811 mins[nDim1] = MIN( g_qeglobals.d_vAreaTL[nDim1], g_qeglobals.d_vAreaBR[nDim1] );
812 mins[nDim2] = MIN( g_qeglobals.d_vAreaTL[nDim2], g_qeglobals.d_vAreaBR[nDim2] );
813 maxs[nDim1] = MAX( g_qeglobals.d_vAreaTL[nDim1], g_qeglobals.d_vAreaBR[nDim1] );
814 maxs[nDim2] = MAX( g_qeglobals.d_vAreaTL[nDim2], g_qeglobals.d_vAreaBR[nDim2] );
816 // deselect current selection
817 if( !(nButtons & (MK_CONTROL|MK_SHIFT)) )
820 // select new selection
821 Select_RealCompleteTall( mins, maxs );
823 Sys_UpdateWindows (W_ALL);
826 if (g_qeglobals.d_select_translate[0] || g_qeglobals.d_select_translate[1] || g_qeglobals.d_select_translate[2])
828 Select_Move (g_qeglobals.d_select_translate);
829 VectorCopy (vec3_origin, g_qeglobals.d_select_translate);
830 Sys_UpdateWindows (W_CAMERA);
833 /* note: added cleanup here, since an edge drag will leave selected vertices
834 in g_qeglobals.d_num_move_points
836 if ( g_qeglobals.d_select_mode != sel_vertex &&
837 g_qeglobals.d_select_mode != sel_curvepoint &&
838 g_qeglobals.d_select_mode != sel_edge)
839 g_qeglobals.d_num_move_points = 0;
841 g_pParentWnd->SetStatusText(3, "");
842 Undo_EndBrushList(&selected_brushes);
844 UpdateSurfaceDialog();