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 "CreateSimpleBrushToolController3D.h"
21 
22 #include "PreferenceManager.h"
23 #include "Preferences.h"
24 #include "Model/Brush.h"
25 #include "Model/BrushFace.h"
26 #include "Model/BrushGeometry.h"
27 #include "Model/HitAdapter.h"
28 #include "Model/HitQuery.h"
29 #include "Model/PickResult.h"
30 #include "Renderer/Camera.h"
31 #include "Renderer/RenderService.h"
32 #include "View/CreateSimpleBrushTool.h"
33 #include "View/Grid.h"
34 #include "View/InputState.h"
35 #include "View/MapDocument.h"
36 
37 #include <cassert>
38 
39 namespace TrenchBroom {
40     namespace View {
CreateSimpleBrushToolController3D(CreateSimpleBrushTool * tool,MapDocumentWPtr document)41         CreateSimpleBrushToolController3D::CreateSimpleBrushToolController3D(CreateSimpleBrushTool* tool, MapDocumentWPtr document) :
42         m_tool(tool),
43         m_document(document) {
44             assert(tool != NULL);
45         }
46 
doGetTool()47         Tool* CreateSimpleBrushToolController3D::doGetTool() {
48             return m_tool;
49         }
50 
doModifierKeyChange(const InputState & inputState)51         void CreateSimpleBrushToolController3D::doModifierKeyChange(const InputState& inputState) {
52             if (thisToolDragging()) {
53                 if (inputState.modifierKeys() == ModifierKeys::MKAlt) {
54                     setRestricter(inputState, new LineDragRestricter(Line3(curPoint(), Vec3::PosZ)), true);
55                 } else {
56                     setRestricter(inputState, new PlaneDragRestricter(horizontalDragPlane(curPoint())), true);
57                 }
58             }
59         }
60 
doStartDrag(const InputState & inputState)61         RestrictedDragPolicy::DragInfo CreateSimpleBrushToolController3D::doStartDrag(const InputState& inputState) {
62             if (!inputState.mouseButtonsPressed(MouseButtons::MBLeft))
63                 return DragInfo();
64             if (!inputState.modifierKeysPressed(ModifierKeys::MKNone))
65                 return DragInfo();
66 
67             MapDocumentSPtr document = lock(m_document);
68             if (document->hasSelection())
69                 return DragInfo();
70 
71             const Model::PickResult& pickResult = inputState.pickResult();
72             const Model::Hit& hit = pickResult.query().pickable().type(Model::Brush::BrushHit).occluded().first();
73             if (hit.isMatch())
74                 m_initialPoint = hit.hitPoint();
75             else
76                 m_initialPoint = inputState.defaultPointUnderMouse();
77 
78             updateBounds(m_initialPoint);
79             refreshViews();
80 
81 
82             const Plane3 plane = Plane3(m_initialPoint, Vec3::PosZ);
83             return DragInfo(new PlaneDragRestricter(plane), new NoDragSnapper(), m_initialPoint);
84         }
85 
doDrag(const InputState & inputState,const Vec3 & lastPoint,const Vec3 & curPoint)86         RestrictedDragPolicy::DragResult CreateSimpleBrushToolController3D::doDrag(const InputState& inputState, const Vec3& lastPoint, const Vec3& curPoint) {
87             updateBounds(curPoint);
88             refreshViews();
89             return DR_Continue;
90         }
91 
doEndDrag(const InputState & inputState)92         void CreateSimpleBrushToolController3D::doEndDrag(const InputState& inputState) {
93             m_tool->createBrush();
94         }
95 
doCancelDrag()96         void CreateSimpleBrushToolController3D::doCancelDrag() {
97             m_tool->cancel();
98         }
99 
doSetRenderOptions(const InputState & inputState,Renderer::RenderContext & renderContext) const100         void CreateSimpleBrushToolController3D::doSetRenderOptions(const InputState& inputState, Renderer::RenderContext& renderContext) const {}
101 
doRender(const InputState & inputState,Renderer::RenderContext & renderContext,Renderer::RenderBatch & renderBatch)102         void CreateSimpleBrushToolController3D::doRender(const InputState& inputState, Renderer::RenderContext& renderContext, Renderer::RenderBatch& renderBatch) {
103             m_tool->render(renderContext, renderBatch);
104         }
105 
doCancel()106         bool CreateSimpleBrushToolController3D::doCancel() {
107             return false;
108         }
109 
updateBounds(const Vec3 & point)110         void CreateSimpleBrushToolController3D::updateBounds(const Vec3& point) {
111             BBox3 bounds;
112             bounds.min = min(m_initialPoint, point);
113             bounds.max = max(m_initialPoint, point);
114 
115             MapDocumentSPtr document = lock(m_document);
116             const Grid& grid = document->grid();
117 
118             // prevent flickering due to very small rounding errors
119             bounds.min.correct();
120             bounds.max.correct();
121 
122             bounds.min = grid.snapDown(bounds.min);
123             bounds.max = grid.snapUp(bounds.max);
124 
125             for (size_t i = 0; i < 3; i++)
126                 if (bounds.max[i] <= bounds.min[i])
127                     bounds.max[i] = bounds.min[i] + grid.actualSize();
128 
129             m_tool->update(bounds);
130         }
131     }
132 }
133