1 /*
2  Copyright (C) 2010-2014 Kristian Duske
3 
4  This file is part of TrenchBroom.
5 
6  TrenchBroom is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  TrenchBroom is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with TrenchBroom. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "ResizeBrushesToolController.h"
21 
22 #include "PreferenceManager.h"
23 #include "Preferences.h"
24 #include "Reference.h"
25 #include "Model/BrushFace.h"
26 #include "Model/BrushGeometry.h"
27 #include "Model/HitQuery.h"
28 #include "Model/PickResult.h"
29 #include "Renderer/RenderContext.h"
30 #include "Renderer/VertexArray.h"
31 #include "Renderer/VertexSpec.h"
32 #include "View/InputState.h"
33 #include "View/ResizeBrushesTool.h"
34 
35 #include <cassert>
36 
37 namespace TrenchBroom {
38     namespace View {
ResizeBrushesToolController(ResizeBrushesTool * tool)39         ResizeBrushesToolController::ResizeBrushesToolController(ResizeBrushesTool* tool) :
40         m_tool(tool) {
41             assert(m_tool != NULL);
42         }
43 
~ResizeBrushesToolController()44         ResizeBrushesToolController::~ResizeBrushesToolController() {}
45 
doGetTool()46         Tool* ResizeBrushesToolController::doGetTool() {
47             return m_tool;
48         }
49 
doPick(const InputState & inputState,Model::PickResult & pickResult)50         void ResizeBrushesToolController::doPick(const InputState& inputState, Model::PickResult& pickResult) {
51             if (handleInput(inputState)) {
52                 const Model::Hit hit = doPick(inputState.pickRay(), pickResult);
53                 if (hit.isMatch())
54                     pickResult.addHit(hit);
55             }
56         }
57 
doModifierKeyChange(const InputState & inputState)58         void ResizeBrushesToolController::doModifierKeyChange(const InputState& inputState) {
59             updateDragFaces(inputState);
60         }
61 
doMouseMove(const InputState & inputState)62         void ResizeBrushesToolController::doMouseMove(const InputState& inputState) {
63             if (handleInput(inputState))
64                 updateDragFaces(inputState);
65         }
66 
doStartMouseDrag(const InputState & inputState)67         bool ResizeBrushesToolController::doStartMouseDrag(const InputState& inputState) {
68             if (!handleInput(inputState))
69                 return false;
70             const bool split = inputState.modifierKeysDown(ModifierKeys::MKCtrlCmd);
71             if (m_tool->beginResize(inputState.pickResult(), split)) {
72                 updateDragFaces(inputState);
73                 return true;
74             }
75             return false;
76         }
77 
doMouseDrag(const InputState & inputState)78         bool ResizeBrushesToolController::doMouseDrag(const InputState& inputState) {
79             return m_tool->resize(inputState.pickRay(), inputState.camera());
80         }
81 
doEndMouseDrag(const InputState & inputState)82         void ResizeBrushesToolController::doEndMouseDrag(const InputState& inputState) {
83             m_tool->commitResize();
84         }
85 
doCancelMouseDrag()86         void ResizeBrushesToolController::doCancelMouseDrag() {
87             m_tool->cancelResize();
88         }
89 
doSetRenderOptions(const InputState & inputState,Renderer::RenderContext & renderContext) const90         void ResizeBrushesToolController::doSetRenderOptions(const InputState& inputState, Renderer::RenderContext& renderContext) const {
91             if (thisToolDragging())
92                 renderContext.setForceShowSelectionGuide();
93             // TODO: force rendering of all other map views if the input applies and the tool has drag faces
94         }
95 
doRender(const InputState & inputState,Renderer::RenderContext & renderContext,Renderer::RenderBatch & renderBatch)96         void ResizeBrushesToolController::doRender(const InputState& inputState, Renderer::RenderContext& renderContext, Renderer::RenderBatch& renderBatch) {
97             if (m_tool->hasDragFaces()) {
98                 Renderer::DirectEdgeRenderer edgeRenderer = buildEdgeRenderer();
99                 edgeRenderer.renderOnTop(renderBatch, pref(Preferences::ResizeHandleColor));
100             }
101         }
102 
buildEdgeRenderer()103         Renderer::DirectEdgeRenderer ResizeBrushesToolController::buildEdgeRenderer() {
104             typedef Renderer::VertexSpecs::P3::Vertex Vertex;
105             Vertex::List vertices;
106 
107             const Model::BrushFaceList& dragFaces = m_tool->dragFaces();
108             Model::BrushFaceList::const_iterator faceIt, faceEnd;
109             Model::BrushFace::EdgeList::const_iterator edgeIt, edgeEnd;
110             for (faceIt = dragFaces.begin(), faceEnd = dragFaces.end(); faceIt != faceEnd; ++faceIt) {
111                 const Model::BrushFace* face = *faceIt;
112                 const Model::BrushFace::EdgeList edges = face->edges();
113                 for (edgeIt = edges.begin(), edgeEnd = edges.end(); edgeIt != edgeEnd; ++edgeIt) {
114                     const Model::BrushEdge* edge = *edgeIt;
115                     vertices.push_back(Vertex(edge->firstVertex()->position()));
116                     vertices.push_back(Vertex(edge->secondVertex()->position()));
117                 }
118             }
119 
120             return Renderer::DirectEdgeRenderer(Renderer::VertexArray::swap(vertices), GL_LINES);
121         }
122 
doCancel()123         bool ResizeBrushesToolController::doCancel() {
124             return false;
125         }
126 
updateDragFaces(const InputState & inputState)127         void ResizeBrushesToolController::updateDragFaces(const InputState& inputState) {
128             if (!anyToolDragging(inputState))
129                 m_tool->updateDragFaces(inputState.pickResult());
130         }
131 
handleInput(const InputState & inputState) const132         bool ResizeBrushesToolController::handleInput(const InputState& inputState) const {
133             return ((inputState.modifierKeysPressed(ModifierKeys::MKShift) ||
134                      inputState.modifierKeysPressed(ModifierKeys::MKShift | ModifierKeys::MKCtrlCmd)) &&
135                     m_tool->applies());
136         }
137 
ResizeBrushesToolController2D(ResizeBrushesTool * tool)138         ResizeBrushesToolController2D::ResizeBrushesToolController2D(ResizeBrushesTool* tool) :
139         ResizeBrushesToolController(tool) {}
140 
doPick(const Ray3 & pickRay,const Model::PickResult & pickResult)141         Model::Hit ResizeBrushesToolController2D::doPick(const Ray3& pickRay, const Model::PickResult& pickResult) {
142             return m_tool->pick2D(pickRay, pickResult);
143         }
144 
ResizeBrushesToolController3D(ResizeBrushesTool * tool)145         ResizeBrushesToolController3D::ResizeBrushesToolController3D(ResizeBrushesTool* tool) :
146         ResizeBrushesToolController(tool) {}
147 
doPick(const Ray3 & pickRay,const Model::PickResult & pickResult)148         Model::Hit ResizeBrushesToolController3D::doPick(const Ray3& pickRay, const Model::PickResult& pickResult) {
149             return m_tool->pick3D(pickRay, pickResult);
150         }
151     }
152 }
153