2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
\r
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
\r
5 This file is part of GtkRadiant.
\r
7 GtkRadiant is free software; you can redistribute it and/or modify
\r
8 it under the terms of the GNU General Public License as published by
\r
9 the Free Software Foundation; either version 2 of the License, or
\r
10 (at your option) any later version.
\r
12 GtkRadiant is distributed in the hope that it will be useful,
\r
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
15 GNU General Public License for more details.
\r
17 You should have received a copy of the GNU General Public License
\r
18 along with GtkRadiant; if not, write to the Free Software
\r
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
\r
27 drag either multiple brushes, or select plane points from
\r
32 extern int g_nPatchClickedView;
\r
38 //static int buttonstate;
\r
40 static vec3_t pressdelta;
\r
41 static vec3_t vPressStart;
\r
42 //static int buttonx, buttony;
\r
45 //int num_move_points;
\r
46 //float *move_points[1024];
\r
50 qboolean drag_first;
\r
53 void AxializeVector (vec3_t v)
\r
66 for (i=0 ; i<3 ; i++)
\r
68 if (a[0] > a[1] && a[0] > a[2])
\r
70 else if (a[1] > a[0] && a[1] > a[2])
\r
76 VectorCopy (vec3_origin, v);
\r
89 extern void SelectCurvePointByRay (vec3_t org, vec3_t dir, int buttons);
\r
91 void Drag_Setup (int x, int y, int buttons,
\r
92 vec3_t xaxis, vec3_t yaxis,
\r
93 vec3_t origin, vec3_t dir)
\r
100 VectorCopy (vec3_origin, pressdelta);
\r
104 // snap to nearest axis for camwindow drags
\r
105 VectorCopy (xaxis, drag_xvec);
\r
106 AxializeVector (drag_xvec);
\r
107 VectorCopy (yaxis, drag_yvec);
\r
108 AxializeVector (drag_yvec);
\r
110 if (g_qeglobals.d_select_mode == sel_curvepoint)
\r
112 SelectCurvePointByRay (origin, dir, buttons);
\r
114 if(g_qeglobals.d_select_mode == sel_area)
\r
118 if(g_nPatchClickedView == W_CAMERA ) {
\r
119 VectorSet( g_qeglobals.d_vAreaTL, x, y, 0 );
\r
120 VectorSet( g_qeglobals.d_vAreaBR, x, y, 0 );
\r
123 else if (g_qeglobals.d_num_move_points) // don't add an undo if there are no points selected
\r
126 Sys_UpdateWindows(W_ALL);
\r
127 Undo_Start("drag curve point");
\r
128 Undo_AddBrushList(&selected_brushes);
\r
134 g_qeglobals.d_num_move_points = 0;
\r
137 if (g_qeglobals.d_select_mode == sel_areatall)
\r
139 VectorCopy(origin, g_qeglobals.d_vAreaTL);
\r
140 VectorCopy(origin, g_qeglobals.d_vAreaBR);
\r
142 Sys_UpdateWindows(W_ALL);
\r
148 if (selected_brushes.next == &selected_brushes)
\r
150 //in this case a new brush is created when the dragging
\r
151 //takes place in the XYWnd, An useless undo is created
\r
152 //when the dragging takes place in the CamWnd
\r
153 Undo_Start("create brush");
\r
155 Sys_Status("No selection to drag", 0);
\r
159 if (g_qeglobals.d_select_mode == sel_vertex)
\r
161 SelectVertexByRay (origin, dir);
\r
162 if (g_qeglobals.d_num_move_points)
\r
165 Undo_Start("drag vertex");
\r
166 Undo_AddBrushList(&selected_brushes);
\r
167 // Need an update here for highlighting selected vertices
\r
168 Sys_UpdateWindows(W_XY | W_CAMERA);
\r
173 if (g_qeglobals.d_select_mode == sel_edge)
\r
175 SelectEdgeByRay (origin, dir);
\r
176 if (g_qeglobals.d_num_move_points)
\r
179 Undo_Start("drag edge");
\r
180 Undo_AddBrushList(&selected_brushes);
\r
186 // check for direct hit first
\r
188 t = Test_Ray (origin, dir, true);
\r
193 Undo_Start("drag selection");
\r
194 Undo_AddBrushList(&selected_brushes);
\r
196 if (buttons == (MK_LBUTTON|MK_CONTROL) )
\r
198 Sys_Printf ("Shear dragging face\n");
\r
199 Brush_SelectFaceForDragging (t.brush, t.face, true);
\r
201 else if (buttons == (MK_LBUTTON|MK_CONTROL|MK_SHIFT) )
\r
203 Sys_Printf ("Sticky dragging brush\n");
\r
204 for (f=t.brush->brush_faces ; f ; f=f->next)
\r
205 Brush_SelectFaceForDragging (t.brush, f, false);
\r
208 Sys_Printf ("Dragging entire selection\n");
\r
213 if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge)
\r
217 // check for side hit
\r
219 // multiple brushes selected?
\r
220 if (selected_brushes.next->next != &selected_brushes)
\r
222 // yes, special handling
\r
223 bool bOK = (g_PrefsDlg.m_bALTEdge) ? Sys_AltDown() : true;
\r
226 for (brush_t* pBrush = selected_brushes.next ; pBrush != &selected_brushes ; pBrush = pBrush->next)
\r
228 if (buttons & MK_CONTROL)
\r
229 Brush_SideSelect (pBrush, origin, dir, true);
\r
231 Brush_SideSelect (pBrush, origin, dir, false);
\r
236 Sys_Printf ("press ALT to drag multiple edges\n");
\r
242 // single select.. trying to drag fixed entities handle themselves and just move
\r
243 if (buttons & MK_CONTROL)
\r
244 Brush_SideSelect (selected_brushes.next, origin, dir, true);
\r
246 Brush_SideSelect (selected_brushes.next, origin, dir, false);
\r
249 Sys_Printf ("Side stretch\n");
\r
252 Undo_Start("side stretch");
\r
253 Undo_AddBrushList(&selected_brushes);
\r
258 void UpdateTarget(vec3_t origin, vec3_t dir)
\r
265 t = Test_Ray (origin, dir, 0);
\r
270 pe = t.brush->owner;
\r
275 // is this the first?
\r
276 if (peLink != NULL)
\r
279 // Get the target id from out current target
\r
280 // if there is no id, make one
\r
282 i = IntForKey(pe, "target");
\r
285 i = GetUniqueTargetId(1);
\r
286 sprintf(sz, "%d", i);
\r
288 SetKeyValue(pe, "target", sz);
\r
291 // set the target # into our src
\r
293 sprintf(sz, "%d", i);
\r
294 SetKeyValue(peLink, "targetname", sz);
\r
296 Sys_UpdateWindows(W_ENTITY);
\r
300 // promote the target to the src
\r
309 //++timo test three button mouse and three button emulation here ?
\r
312 void Drag_Begin (int x, int y, int buttons,
\r
313 vec3_t xaxis, vec3_t yaxis,
\r
314 vec3_t origin, vec3_t dir, bool sf_camera)
\r
321 VectorCopy (vec3_origin, pressdelta);
\r
322 VectorCopy (vec3_origin, vPressStart);
\r
327 altdown = Sys_AltDown();
\r
329 // shift-LBUTTON = select entire brush
\r
330 // shift-alt-LBUTTON = drill select
\r
331 if (buttons == (MK_LBUTTON | MK_SHIFT) && g_qeglobals.d_select_mode != sel_curvepoint)
\r
333 nFlag = altdown ? SF_CYCLE : 0;
\r
335 nFlag |= SF_CAMERA;
\r
337 nFlag |= SF_ENTITIES_FIRST;
\r
338 Select_Ray(origin, dir, nFlag);
\r
342 // (shift-)alt-LBUTTON = area select completely tall
\r
344 ( g_PrefsDlg.m_bALTEdge ? buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT) : (buttons == MK_LBUTTON || buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT)) ) &&
\r
345 altdown && g_qeglobals.d_select_mode != sel_curvepoint)
\r
347 if (g_pParentWnd->ActiveXY()->AreaSelectOK())
\r
349 g_qeglobals.d_select_mode = sel_areatall;
\r
351 Drag_Setup (x, y, buttons, xaxis, yaxis, origin, dir);
\r
356 // ctrl-alt-LBUTTON = multiple brush select without selecting whole entities
\r
357 if (buttons == (MK_LBUTTON | MK_CONTROL) && altdown && g_qeglobals.d_select_mode != sel_curvepoint)
\r
361 nFlag |= SF_CAMERA;
\r
363 nFlag |= SF_ENTITIES_FIRST;
\r
364 Select_Ray (origin, dir, nFlag);
\r
365 UpdateSurfaceDialog();
\r
370 // ctrl-shift LBUTTON = select single face
\r
371 if (sf_camera && buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT) && g_qeglobals.d_select_mode != sel_curvepoint)
\r
376 for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
\r
381 for (face_t* pFace = b->brush_faces; pFace; pFace = pFace->next)
\r
383 g_ptrSelectedFaces.Add(pFace);
\r
384 g_ptrSelectedFaceBrushes.Add(b);
\r
388 for (b = selected_brushes.next; b != &selected_brushes; )
\r
392 Brush_RemoveFromList (pb);
\r
393 Brush_AddToList (pb, &active_brushes);
\r
397 Select_Deselect (true);
\r
399 Select_Ray (origin, dir, (SF_SINGLEFACE|SF_CAMERA));
\r
404 // LBUTTON + all other modifiers = manipulate selection
\r
405 if (buttons & MK_LBUTTON)
\r
407 Drag_Setup (x, y, buttons, xaxis, yaxis, origin, dir);
\r
411 int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON;
\r
412 // middle button = grab texture
\r
413 if (buttons == nMouseButton)
\r
415 t = Test_Ray (origin, dir, false);
\r
418 UpdateWorkzone_ForBrush( t.brush );
\r
419 // use a local brushprimit_texdef fitted to a default 2x2 texture
\r
420 brushprimit_texdef_t bp_local;
\r
421 ConvertTexMatWithQTexture( &t.face->brushprimit_texdef, t.face->d_texture, &bp_local, NULL );
\r
422 Texture_SetTexture ( &t.face->texdef, &bp_local, false, NULL);
\r
423 UpdateSurfaceDialog();
\r
424 UpdatePatchInspector();
\r
427 Sys_Printf ("Did not select a texture\n");
\r
431 // ctrl-middle button = set entire brush to texture
\r
432 if (buttons == (nMouseButton|MK_CONTROL) )
\r
434 t = Test_Ray (origin, dir, false);
\r
437 if (t.brush->brush_faces->texdef.GetName()[0] == '(')
\r
438 Sys_Printf ("Can't change an entity texture\n");
\r
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 ) );
\r
442 Sys_UpdateWindows (W_ALL);
\r
446 Sys_Printf ("Didn't hit a btrush\n");
\r
450 // ctrl-shift-middle button = set single face to texture
\r
451 if (buttons == (nMouseButton|MK_SHIFT|MK_CONTROL) )
\r
453 t = Test_Ray (origin, dir, false);
\r
456 if (t.brush->brush_faces->texdef.GetName()[0] == '(')
\r
457 Sys_Printf ("Can't change an entity texture\n");
\r
460 SetFaceTexdef (t.face, &g_qeglobals.d_texturewin.texdef, &g_qeglobals.d_texturewin.brushprimit_texdef);
\r
461 Brush_Build( t.brush );
\r
463 Sys_UpdateWindows (W_ALL);
\r
467 Sys_Printf ("Didn't hit a btrush\n");
\r
471 if (buttons == (nMouseButton | MK_SHIFT))
\r
473 Sys_Printf("Set brush face texture info\n");
\r
474 t = Test_Ray (origin, dir, false);
\r
477 if (t.brush->brush_faces->texdef.GetName()[0] == '(')
\r
479 if (t.brush->owner->eclass->nShowFlags & ECLASS_LIGHT)
\r
482 qtexture_t* pTex = g_qeglobals.d_texturewin.pShader->getTexture();
\r
486 VectorCopy(pTex->color, vColor);
\r
488 float fLargest = 0.0f;
\r
489 for (int i = 0; i < 3; i++)
\r
491 if (vColor[i] > fLargest)
\r
492 fLargest = vColor[i];
\r
495 if (fLargest == 0.0f)
\r
497 vColor[0] = vColor[1] = vColor[2] = 1.0f;
\r
501 float fScale = 1.0f / fLargest;
\r
502 for (int i = 0; i < 3; i++)
\r
504 vColor[i] *= fScale;
\r
507 strBuff.Format("%f %f %f",pTex->color[0], pTex->color[1], pTex->color[2]);
\r
508 SetKeyValue(t.brush->owner, "_color", strBuff.GetBuffer());
\r
509 Sys_UpdateWindows (W_ALL);
\r
514 Sys_Printf ("Can't select an entity brush face\n");
\r
519 // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=425
\r
520 Face_SetShader(t.face, g_qeglobals.d_texturewin.texdef.GetName());
\r
521 Brush_Build(t.brush);
\r
523 Sys_UpdateWindows (W_ALL);
\r
527 Sys_Printf ("Didn't hit a brush\n");
\r
539 void MoveSelection (vec3_t move)
\r
544 vec3_t vTemp, vTemp2, end;
\r
546 if (!move[0] && !move[1] && !move[2])
\r
551 if (!(g_qeglobals.d_select_mode == sel_area || g_qeglobals.d_select_mode == sel_areatall))
\r
553 move[0] = (g_nScaleHow & SCALE_X) ? 0 : move[0];
\r
554 move[1] = (g_nScaleHow & SCALE_Y) ? 0 : move[1];
\r
555 move[2] = (g_nScaleHow & SCALE_Z) ? 0 : move[2];
\r
558 if (g_pParentWnd->ActiveXY()->RotateMode() || g_bPatchBendMode)
\r
560 float fDeg = -move[2];
\r
561 float fAdj = move[2];
\r
563 if (g_pParentWnd->ActiveXY()->GetViewType() == XY)
\r
570 if (g_pParentWnd->ActiveXY()->GetViewType() == XZ)
\r
579 g_pParentWnd->ActiveXY()->Rotation()[nAxis] += fAdj;
\r
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]);
\r
581 g_pParentWnd->SetStatusText(2, strStatus);
\r
583 if (g_bPatchBendMode)
\r
585 Patch_SelectBendNormal();
\r
586 Select_RotateAxis(nAxis, fDeg*2, false, true);
\r
587 Patch_SelectBendAxis();
\r
588 Select_RotateAxis(nAxis, fDeg, false, true);
\r
592 Select_RotateAxis(nAxis, fDeg, false, true);
\r
597 if (g_pParentWnd->ActiveXY()->ScaleMode())
\r
600 v[0] = v[1] = v[2] = 1.0f;
\r
615 Select_Scale((g_nScaleHow & SCALE_X) ? 1.0f : v[0],
\r
616 (g_nScaleHow & SCALE_Y) ? 1.0f : v[1],
\r
617 (g_nScaleHow & SCALE_Z) ? 1.0f : v[2]);
\r
618 // is that really necessary???
\r
619 Sys_UpdateWindows (W_ALL);
\r
625 VectorSubtract(pressdelta, vPressStart, vDistance);
\r
626 strStatus.Format("Distance x: %.1f y: %.1f z: %.1f", vDistance[0], vDistance[1], vDistance[2]);
\r
627 g_pParentWnd->SetStatusText(3, strStatus);
\r
630 // dragging only a part of the selection
\r
633 // this is fairly crappy way to deal with curvepoint and area selection
\r
634 // but it touches the smallest amount of code this way
\r
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)
\r
639 if (g_qeglobals.d_select_mode == sel_area || g_qeglobals.d_select_mode == sel_areatall)
\r
641 VectorAdd(g_qeglobals.d_vAreaBR, move, g_qeglobals.d_vAreaBR);
\r
644 //curve point selection
\r
645 if (g_qeglobals.d_select_mode == sel_curvepoint)
\r
647 Patch_UpdateSelected(move);
\r
651 if (g_qeglobals.d_select_mode == sel_vertex && g_PrefsDlg.m_bVertexSplit)
\r
653 if(g_qeglobals.d_num_move_points) {
\r
655 for (b = selected_brushes.next; b != &selected_brushes; b = b->next)
\r
657 success &= Brush_MoveVertex(b, g_qeglobals.d_move_points[0], move, end, true);
\r
660 VectorCopy(end, g_qeglobals.d_move_points[0]);
\r
664 //all other selection types
\r
665 for (i=0 ; i<g_qeglobals.d_num_move_points ; i++)
\r
666 VectorAdd (g_qeglobals.d_move_points[i], move, g_qeglobals.d_move_points[i]);
\r
667 for (b = selected_brushes.next; b != &selected_brushes; b = b->next)
\r
669 bool bMoved = false;
\r
670 for(face_t *f = b->brush_faces; !bMoved && f!=NULL; f=f->next)
\r
671 for(int p=0; !bMoved && p<3; p++)
\r
672 for (i=0 ; !bMoved && i<g_qeglobals.d_num_move_points ; i++)
\r
673 if(f->planepts[p] == g_qeglobals.d_move_points[i])
\r
675 if(!bMoved) continue;
\r
677 VectorCopy(b->maxs, vTemp);
\r
678 VectorSubtract(vTemp, b->mins, vTemp);
\r
679 Brush_Build(b,true,true,false,false); // don't filter
\r
680 for (i=0 ; i<3 ; i++)
\r
682 if (b->mins[i] > b->maxs[i]
\r
683 || b->maxs[i] - b->mins[i] > g_MaxBrushSize)
\r
684 break; // dragged backwards or fucked up
\r
690 VectorCopy(b->maxs, vTemp2);
\r
691 VectorSubtract(vTemp2, b->mins, vTemp2);
\r
692 VectorSubtract(vTemp2, vTemp, vTemp2);
\r
693 //if (!Patch_DragScale(b->nPatchID, vTemp2, move))
\r
694 if (!Patch_DragScale(b->pPatch, vTemp2, move))
\r
701 // if any of the brushes were crushed out of existance
\r
702 // calcel the entire move
\r
703 if (b != &selected_brushes)
\r
705 Sys_Printf ("Brush dragged backwards, move canceled\n");
\r
706 for (i=0 ; i<g_qeglobals.d_num_move_points ; i++)
\r
707 VectorSubtract (g_qeglobals.d_move_points[i], move, g_qeglobals.d_move_points[i]);
\r
709 for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
\r
710 Brush_Build(b,true,true,false,false); // don't filter
\r
716 // reset face originals from vertex edit mode
\r
717 // this is dirty, but unfortunately necessary because Brush_Build
\r
718 // can remove windings
\r
719 for (b = selected_brushes.next; b != &selected_brushes; b = b->next)
\r
721 Brush_ResetFaceOriginals(b);
\r
724 // if there are lots of brushes selected, just translate instead
\r
725 // of rebuilding the brushes
\r
726 // NOTE: this is not actually done, but would be a good idea
\r
728 Select_Move (move);
\r
737 void Drag_MouseMoved (int x, int y, int buttons)
\r
739 vec3_t move, delta;
\r
750 // clear along one axis
\r
751 if (buttons & MK_SHIFT && (g_PrefsDlg.m_bALTEdge && g_qeglobals.d_select_mode != sel_areatall))
\r
753 drag_first = false;
\r
754 if (abs(x-pressx) > abs(y-pressy))
\r
760 if (g_qeglobals.d_select_mode == sel_area && g_nPatchClickedView == W_CAMERA)
\r
762 camera_t *m_pCamera = g_pParentWnd->GetCamWnd()->Camera();
\r
765 if( y > m_pCamera->height ) y = m_pCamera->height - 1; else if( y < 0 ) y = 0;
\r
766 if( x > m_pCamera->width ) x = m_pCamera->width - 1; else if( x < 0 ) x = 0;
\r
768 VectorSet (move, x - pressx, y - pressy, 0);
\r
771 for (i=0 ; i<3 ; i++)
\r
773 move[i] = drag_xvec[i]*(x - pressx) + drag_yvec[i]*(y - pressy);
\r
774 if (!g_PrefsDlg.m_bNoClamp)
\r
776 move[i] = floor(move[i]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize;
\r
781 VectorSubtract (move, pressdelta, delta);
\r
782 VectorCopy (move, pressdelta);
\r
784 MoveSelection (delta);
\r
792 void Drag_MouseUp (int nButtons)
\r
794 Sys_Status ("Drag completed.", 0);
\r
796 if (g_qeglobals.d_select_mode == sel_area)
\r
798 Patch_SelectAreaPoints(nButtons & MK_CONTROL); // adds to selection and/or deselects selected points if ctrl is held
\r
799 g_qeglobals.d_select_mode = sel_curvepoint;
\r
800 Sys_UpdateWindows (W_ALL);
\r
803 if (g_qeglobals.d_select_mode == sel_areatall)
\r
807 int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0;
\r
808 int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2;
\r
810 // get our rectangle
\r
811 mins[nDim1] = MIN( g_qeglobals.d_vAreaTL[nDim1], g_qeglobals.d_vAreaBR[nDim1] );
\r
812 mins[nDim2] = MIN( g_qeglobals.d_vAreaTL[nDim2], g_qeglobals.d_vAreaBR[nDim2] );
\r
813 maxs[nDim1] = MAX( g_qeglobals.d_vAreaTL[nDim1], g_qeglobals.d_vAreaBR[nDim1] );
\r
814 maxs[nDim2] = MAX( g_qeglobals.d_vAreaTL[nDim2], g_qeglobals.d_vAreaBR[nDim2] );
\r
816 // deselect current selection
\r
817 if( !(nButtons & (MK_CONTROL|MK_SHIFT)) )
\r
820 // select new selection
\r
821 Select_RealCompleteTall( mins, maxs );
\r
823 Sys_UpdateWindows (W_ALL);
\r
826 if (g_qeglobals.d_select_translate[0] || g_qeglobals.d_select_translate[1] || g_qeglobals.d_select_translate[2])
\r
828 Select_Move (g_qeglobals.d_select_translate);
\r
829 VectorCopy (vec3_origin, g_qeglobals.d_select_translate);
\r
830 Sys_UpdateWindows (W_CAMERA);
\r
833 /* note: added cleanup here, since an edge drag will leave selected vertices
\r
834 in g_qeglobals.d_num_move_points
\r
836 if ( g_qeglobals.d_select_mode != sel_vertex &&
\r
837 g_qeglobals.d_select_mode != sel_curvepoint &&
\r
838 g_qeglobals.d_select_mode != sel_edge)
\r
839 g_qeglobals.d_num_move_points = 0;
\r
841 g_pParentWnd->SetStatusText(3, "");
\r
842 Undo_EndBrushList(&selected_brushes);
\r
844 UpdateSurfaceDialog();
\r