2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
26 ===========================================================================
29 #include "../../idlib/precompiled.h"
35 /* drag either multiple brushes, or select plane points from a single brush. */
36 bool g_moveOnly = false;
41 static int buttonstate;
43 static idVec3 pressdelta;
44 static idVec3 vPressStart;
45 static int buttonx, buttony;
47 // int num_move_points; float *move_points[1024];
57 static void AxializeVector( idVec3 &v ) {
74 for (i = 0; i < 3; i++) {
75 a[i] = idMath::Fabs(v[i]);
78 if (a[0] > a[1] && a[0] > a[2]) {
81 else if (a[1] > a[0] && a[1] > a[2]) {
89 VectorCopy(vec3_origin, v);
98 extern bool UpdateActiveDragPoint(const idVec3 &move);
99 extern void SetActiveDrag(CDragPoint *p);
106 static void Drag_Setup( int x, int y, int buttons,
107 const idVec3 &xaxis, const idVec3 &yaxis, const idVec3 &origin, const idVec3 &dir ) {
113 VectorCopy(vec3_origin, pressdelta);
117 VectorCopy(xaxis, drag_xvec);
118 AxializeVector(drag_xvec);
119 VectorCopy(yaxis, drag_yvec);
120 AxializeVector(drag_yvec);
122 if (g_qeglobals.d_select_mode == sel_addpoint) {
123 if (g_qeglobals.selectObject) {
124 g_qeglobals.selectObject->addPoint(origin);
127 g_qeglobals.d_select_mode = sel_brush;
133 if (g_qeglobals.d_select_mode == sel_editpoint) {
135 g_Inspectors->entityDlg.SelectCurvePointByRay( origin, dir, buttons );
137 if ( g_qeglobals.d_num_move_points ) {
141 Sys_UpdateWindows(W_ALL);
146 if (g_qeglobals.d_select_mode == sel_curvepoint) {
147 SelectCurvePointByRay(origin, dir, buttons);
149 if (g_qeglobals.d_num_move_points || g_qeglobals.d_select_mode == sel_area) {
153 Sys_UpdateWindows(W_ALL);
155 Undo_Start("drag curve point");
156 Undo_AddBrushList(&selected_brushes);
161 g_qeglobals.d_num_move_points = 0;
164 if (selected_brushes.next == &selected_brushes) {
166 // in this case a new brush is created when the dragging takes place in the XYWnd,
167 // An useless undo is created when the dragging takes place in the CamWnd
169 Undo_Start("create brush");
171 Sys_Status("No selection to drag\n", 0);
175 if (g_qeglobals.d_select_mode == sel_vertex) {
177 if ( radiant_entityMode.GetBool() ) {
181 SelectVertexByRay(origin, dir);
182 if (g_qeglobals.d_num_move_points) {
184 Undo_Start("drag vertex");
185 Undo_AddBrushList(&selected_brushes);
190 if (g_qeglobals.d_select_mode == sel_edge) {
192 if ( radiant_entityMode.GetBool() ) {
196 SelectEdgeByRay(origin, dir);
197 if (g_qeglobals.d_num_move_points) {
199 Undo_Start("drag edge");
200 Undo_AddBrushList(&selected_brushes);
205 // check for direct hit first
206 t = Test_Ray(origin, dir, true);
207 SetActiveDrag(t.point);
218 Undo_Start("drag selection");
219 Undo_AddBrushList(&selected_brushes);
221 if (buttons == (MK_LBUTTON | MK_CONTROL)) {
222 Sys_Status("Shear dragging face\n");
223 Brush_SelectFaceForDragging(t.brush, t.face, true);
225 else if (buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT)) {
226 Sys_Status("Sticky dragging brush\n");
227 for (f = t.brush->brush_faces; f; f = f->next) {
228 Brush_SelectFaceForDragging(t.brush, f, false);
232 Sys_Status("Dragging entire selection\n");
238 if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge) {
242 if ( radiant_entityMode.GetBool() ) {
246 // check for side hit multiple brushes selected?
247 if (selected_brushes.next->next != &selected_brushes) {
248 // yes, special handling
249 bool bOK = ( g_PrefsDlg.m_bALTEdge ) ? ( ::GetAsyncKeyState( VK_MENU ) != 0 ) : true;
251 for (brush_t * pBrush = selected_brushes.next; pBrush != &selected_brushes; pBrush = pBrush->next) {
252 if (buttons & MK_CONTROL) {
253 Brush_SideSelect(pBrush, origin, dir, true);
256 Brush_SideSelect(pBrush, origin, dir, false);
261 Sys_Status("press ALT to drag multiple edges\n");
266 // single select.. trying to drag fixed entities handle themselves and just move
267 if (buttons & MK_CONTROL) {
268 Brush_SideSelect(selected_brushes.next, origin, dir, true);
271 Brush_SideSelect(selected_brushes.next, origin, dir, false);
275 Sys_Status("Side stretch\n");
278 Undo_Start("side stretch");
279 Undo_AddBrushList(&selected_brushes);
282 extern void Face_GetScale_BrushPrimit(face_t *face, float *s, float *t, float *rot);
289 void Drag_Begin( int x, int y, int buttons,
290 const idVec3 &xaxis, const idVec3 &yaxis, const idVec3 &origin, const idVec3 &dir ) {
294 VectorCopy(vec3_origin, pressdelta);
295 VectorCopy(vec3_origin, vPressStart);
299 // shift LBUTTON = select entire brush
300 if (buttons == (MK_LBUTTON | MK_SHIFT) && g_qeglobals.d_select_mode != sel_curvepoint) {
301 int nFlag = ( ::GetAsyncKeyState( VK_MENU ) != 0 ) ? SF_CYCLE : 0;
302 if (dir[0] == 0 || dir[1] == 0 || dir[2] == 0) { // extremely low chance of this happening from camera
303 Select_Ray(origin, dir, nFlag | SF_ENTITIES_FIRST); // hack for XY
306 Select_Ray(origin, dir, nFlag);
312 // ctrl-shift LBUTTON = select single face
313 if (buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT) && g_qeglobals.d_select_mode != sel_curvepoint) {
314 if ( radiant_entityMode.GetBool() ) {
319 //Select_Deselect( ( ::GetAsyncKeyState( VK_MENU ) == 0 ) );
320 Select_Ray(origin, dir, SF_SINGLEFACE);
324 // LBUTTON + all other modifiers = manipulate selection
325 if (buttons & MK_LBUTTON) {
326 Drag_Setup(x, y, buttons, xaxis, yaxis, origin, dir);
330 if ( radiant_entityMode.GetBool() ) {
334 int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON;
336 // middle button = grab texture
337 if (buttons == nMouseButton) {
338 t = Test_Ray(origin, dir, false);
340 g_qeglobals.d_new_brush_bottom = t.brush->mins;
341 g_qeglobals.d_new_brush_top = t.brush->maxs;
343 // use a local brushprimit_texdef fitted to a default 2x2 texture
344 brushprimit_texdef_t bp_local;
345 if (t.brush && t.brush->pPatch) {
347 memset(&bp_local.coords, 0, sizeof(bp_local.coords));
348 bp_local.coords[0][0] = 1.0f;
349 bp_local.coords[1][1] = 1.0f;
350 localtd.SetName(t.brush->pPatch->d_texture->GetName());
351 Texture_SetTexture(&localtd, &bp_local, false, true);
352 Select_CopyPatchTextureCoords ( t.brush->pPatch );
354 Select_ProjectFaceOntoPatch( t.face );
355 ConvertTexMatWithQTexture(&t.face->brushprimit_texdef, t.face->d_texture, &bp_local, NULL);
356 Texture_SetTexture(&t.face->texdef, &bp_local, false, true);
358 UpdateSurfaceDialog();
359 UpdatePatchInspector();
360 UpdateLightInspector();
363 Sys_Status("Did not select a texture\n");
369 // ctrl-middle button = set entire brush to texture
370 if (buttons == (nMouseButton | MK_CONTROL)) {
371 t = Test_Ray(origin, dir, false);
373 if (t.brush->brush_faces->texdef.name[0] == '(') {
374 Sys_Status("Can't change an entity texture\n");
380 &g_qeglobals.d_texturewin.texdef,
381 &g_qeglobals.d_texturewin.brushprimit_texdef,
384 Sys_UpdateWindows(W_ALL);
388 Sys_Status("Didn't hit a btrush\n");
394 // ctrl-shift-middle button = set single face to texture
395 if (buttons == (nMouseButton | MK_SHIFT | MK_CONTROL)) {
396 t = Test_Ray(origin, dir, false);
398 if (t.brush->brush_faces->texdef.name[0] == '(') {
399 Sys_Status("Can't change an entity texture\n");
406 &g_qeglobals.d_texturewin.texdef,
407 &g_qeglobals.d_texturewin.brushprimit_texdef
409 Brush_Build(t.brush);
410 Sys_UpdateWindows(W_ALL);
414 Sys_Status("Didn't hit a btrush\n");
420 if (buttons == (nMouseButton | MK_SHIFT)) {
421 Sys_Status("Set brush face texture info\n");
422 t = Test_Ray(origin, dir, false);
423 if (t.brush && !t.brush->owner->eclass->fixedsize) {
425 if (t.brush->brush_faces->texdef.name[0] == '(') {
426 if (t.brush->owner->eclass->nShowFlags & ECLASS_LIGHT) {
428 idMaterial *pTex = declManager->FindMaterial(g_qeglobals.d_texturewin.texdef.name);
430 idVec3 vColor = pTex->getColor();
432 float fLargest = 0.0f;
433 for (int i = 0; i < 3; i++) {
434 if (vColor[i] > fLargest) {
435 fLargest = vColor[i];
439 if (fLargest == 0.0f) {
440 vColor[0] = vColor[1] = vColor[2] = 1.0f;
443 float fScale = 1.0f / fLargest;
444 for (int i = 0; i < 3; i++) {
449 strBuff.Format("%f %f %f", pTex->getColor().x, pTex->getColor().y, pTex->getColor().z);
450 SetKeyValue(t.brush->owner, "_color", strBuff.GetBuffer(0));
451 Sys_UpdateWindows(W_ALL);
455 Sys_Status("Can't select an entity brush face\n");
461 // strcpy(t.face->texdef.name,g_qeglobals.d_texturewin.texdef.name);
462 t.face->texdef.SetName(g_qeglobals.d_texturewin.texdef.name);
463 Brush_Build(t.brush);
464 Sys_UpdateWindows(W_ALL);
468 Sys_Status("Didn't hit a brush\n");
476 void Brush_GetBounds(brush_t *b, idVec3 &mins, idVec3 &maxs) {
479 for (i = 0; i < 3; i++) {
484 for (i = 0; i < 3; i++) {
485 if (b->mins[i] < mins[i]) {
486 mins[i] = b->mins[i];
489 if (b->maxs[i] > maxs[i]) {
490 maxs[i] = b->maxs[i];
501 static void MoveSelection( const idVec3 &orgMove ) {
505 idVec3 vTemp, vTemp2, end, move;
509 if (!move[0] && !move[1] && !move[2]) {
513 move[0] = (g_nScaleHow & SCALE_X) ? 0 : move[0];
514 move[1] = (g_nScaleHow & SCALE_Y) ? 0 : move[1];
515 move[2] = (g_nScaleHow & SCALE_Z) ? 0 : move[2];
517 if (g_pParentWnd->ActiveXY()->RotateMode() || g_bPatchBendMode) {
518 float fDeg = -move[2];
519 float fAdj = move[2];
521 if (g_pParentWnd->ActiveXY()->GetViewType() == XY) {
526 else if (g_pParentWnd->ActiveXY()->GetViewType() == XZ) {
532 g_pParentWnd->ActiveXY()->Rotation()[g_qeglobals.rotateAxis] += fAdj;
535 "%s x:: %.1f y:: %.1f z:: %.1f",
536 (g_bPatchBendMode) ? "Bend angle" : "Rotation",
537 g_pParentWnd->ActiveXY()->Rotation()[0],
538 g_pParentWnd->ActiveXY()->Rotation()[1],
539 g_pParentWnd->ActiveXY()->Rotation()[2]
541 g_pParentWnd->SetStatusText(2, strStatus);
543 if (g_bPatchBendMode) {
544 Patch_SelectBendNormal();
545 Select_RotateAxis(axis, fDeg * 2, false, true);
546 Patch_SelectBendAxis();
547 Select_RotateAxis(axis, fDeg, false, true);
550 Select_RotateAxis(g_qeglobals.rotateAxis, fDeg, false, true);
556 if (g_pParentWnd->ActiveXY()->ScaleMode()) {
558 v[0] = v[1] = v[2] = 1.0f;
559 for (int i = 0; i < 3; i++) {
560 if ( move[i] > 0.0f ) {
562 } else if ( move[i] < 0.0f ) {
567 Select_Scale(v.x, v.y, v.z);
568 Sys_UpdateWindows(W_ALL);
573 VectorSubtract(pressdelta, vPressStart, vDistance);
574 strStatus.Format("Distance x: %.3f y: %.3f z: %.3f", vDistance[0], vDistance[1], vDistance[2]);
575 g_pParentWnd->SetStatusText(3, strStatus);
577 // dragging only a part of the selection
578 if (UpdateActiveDragPoint(move)) {
579 UpdateLightInspector();
584 // this is fairly crappy way to deal with curvepoint and area selection but it
585 // touches the smallest amount of code this way
587 if (g_qeglobals.d_num_move_points || g_qeglobals.d_num_move_planes || g_qeglobals.d_select_mode == sel_area) {
589 if (g_qeglobals.d_select_mode == sel_area) {
590 VectorAdd(g_qeglobals.d_vAreaBR, move, g_qeglobals.d_vAreaBR);
594 // curve point selection
595 if (g_qeglobals.d_select_mode == sel_curvepoint) {
596 Patch_UpdateSelected(move);
601 if (g_qeglobals.d_select_mode == sel_vertex) {
603 for (b = selected_brushes.next; b != &selected_brushes; b = b->next) {
604 success &= Brush_MoveVertex(selected_brushes.next, *g_qeglobals.d_move_points[0], move, end, true);
608 VectorCopy(end, *g_qeglobals.d_move_points[0]);
612 // all other selection types
613 for (i = 0; i < g_qeglobals.d_num_move_points; i++) {
614 VectorAdd(*g_qeglobals.d_move_points[i], move, *g_qeglobals.d_move_points[i]);
617 if ( g_qeglobals.d_select_mode == sel_editpoint ) {
618 g_Inspectors->entityDlg.UpdateEntityCurve();
622 // VectorScale(move, .5, move); for (i=0 ; i<g_qeglobals.d_num_move_points2 ; i++)
623 // VectorAdd (g_qeglobals.d_move_points2[i], move, g_qeglobals.d_move_points2[i]);
625 for (b = selected_brushes.next; b != &selected_brushes; b = b->next) {
626 VectorCopy(b->maxs, vTemp);
627 VectorSubtract(vTemp, b->mins, vTemp);
629 for (i = 0; i < 3; i++) {
632 b->mins[i] > b->maxs[i] ||
633 b->maxs[i] - b->mins[i] > MAX_WORLD_SIZE ||
634 b->maxs[i] - b->mins[i] == 0.0f
636 break; // dragged backwards or messed up
645 VectorCopy(b->maxs, vTemp2);
646 VectorSubtract(vTemp2, b->mins, vTemp2);
647 VectorSubtract(vTemp2, vTemp, vTemp2);
649 // if (!Patch_DragScale(b->nPatchID, vTemp2, move))
650 if (!Patch_DragScale(b->pPatch, vTemp2, move)) {
657 // if any of the brushes were crushed out of existance calcel the entire move
658 if (b != &selected_brushes) {
659 Sys_Status("Brush dragged backwards, move canceled\n");
660 for (i = 0; i < g_qeglobals.d_num_move_points; i++) {
661 VectorSubtract(*g_qeglobals.d_move_points[i], move, *g_qeglobals.d_move_points[i]);
664 for (b = selected_brushes.next; b != &selected_brushes; b = b->next) {
671 // reset face originals from vertex edit mode this is dirty, but unfortunately
672 // necessary because Brush_Build can remove windings
674 for (b = selected_brushes.next; b != &selected_brushes; b = b->next) {
675 Brush_ResetFaceOriginals(b);
687 void Drag_MouseMoved(int x, int y, int buttons) {
691 if (!buttons || !drag_ok) {
696 // clear along one axis
697 if (buttons & MK_SHIFT) {
699 if (abs(x - pressx) > abs(y - pressy)) {
707 for (i = 0; i < 3; i++) {
708 move[i] = drag_xvec[i] * (x - pressx) + drag_yvec[i] * (y - pressy);
709 if (!g_PrefsDlg.m_bNoClamp) {
710 move[i] = floor(move[i] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
714 VectorSubtract(move, pressdelta, delta);
715 VectorCopy(move, pressdelta);
717 if (buttons & MK_CONTROL && g_pParentWnd->ActiveXY()->RotateMode()) {
718 for (i = 0; i < 3; i++) {
730 MoveSelection(delta);
738 void Drag_MouseUp(int nButtons) {
739 Sys_Status("drag completed.", 0);
741 if (g_qeglobals.d_select_mode == sel_area) {
742 Patch_SelectAreaPoints();
743 g_qeglobals.d_select_mode = sel_curvepoint;
744 Sys_UpdateWindows(W_ALL);
747 if (g_qeglobals.d_select_translate[0] || g_qeglobals.d_select_translate[1] || g_qeglobals.d_select_translate[2]) {
748 Select_Move(g_qeglobals.d_select_translate);
749 VectorCopy(vec3_origin, g_qeglobals.d_select_translate);
750 Sys_UpdateWindows(W_CAMERA);
753 g_pParentWnd->SetStatusText(3, "");
756 if (g_pParentWnd->GetCamera()->UpdateRenderEntities()) {
757 Sys_UpdateWindows(W_CAMERA);
761 Undo_EndBrushList(&selected_brushes);