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 "VertexToolController.h" 21 22 #include "Renderer/Camera.h" 23 #include "Renderer/RenderContext.h" 24 #include "View/InputState.h" 25 #include "View/Lasso.h" 26 #include "View/MapDocument.h" 27 #include "View/VertexTool.h" 28 29 #include <cassert> 30 31 namespace TrenchBroom { 32 namespace View { 33 const FloatType VertexToolController::MaxVertexDistance = 0.25; 34 35 class VertexToolController::VertexPartBase { 36 protected: 37 VertexTool* m_tool; 38 public: VertexPartBase(VertexTool * tool)39 VertexPartBase(VertexTool* tool) : 40 m_tool(tool) { 41 assert(m_tool != NULL); 42 } 43 protected: firstHits(const Model::PickResult & pickResult) const44 Model::Hit::List firstHits(const Model::PickResult& pickResult) const { 45 Model::Hit::List result; 46 Model::BrushSet brushes; 47 48 static const Model::Hit::HitType any = VertexHandleManager::VertexHandleHit | VertexHandleManager::EdgeHandleHit | VertexHandleManager::FaceHandleHit; 49 const Model::Hit& first = pickResult.query().type(any).occluded().first(); 50 if (first.isMatch()) { 51 const Vec3 firstHitPosition = first.target<Vec3>(); 52 53 const Model::Hit::List matches = pickResult.query().type(any).all(); 54 Model::Hit::List::const_iterator hIt, hEnd; 55 for (hIt = matches.begin(), hEnd = matches.end(); hIt != hEnd; ++hIt) { 56 const Model::Hit& hit = *hIt; 57 const Vec3 hitPosition = hit.target<Vec3>(); 58 59 if (hitPosition.distanceTo(firstHitPosition) < MaxVertexDistance) { 60 const bool newBrush = m_tool->handleBrushes(hitPosition, brushes); 61 if (newBrush) 62 result.push_back(hit); 63 } 64 } 65 } 66 67 return result; 68 } 69 }; 70 71 class VertexToolController::SelectVertexPart : public ToolControllerBase<PickingPolicy, NoKeyPolicy, MousePolicy, RestrictedDragPolicy, RenderPolicy, NoDropPolicy>, public VertexPartBase { 72 private: 73 Lasso* m_lasso; 74 public: SelectVertexPart(VertexTool * tool)75 SelectVertexPart(VertexTool* tool) : 76 VertexPartBase(tool), 77 m_lasso(NULL) {} 78 ~SelectVertexPart()79 ~SelectVertexPart() { 80 delete m_lasso; 81 } 82 private: doGetTool()83 Tool* doGetTool() { 84 return m_tool; 85 } 86 doPick(const InputState & inputState,Model::PickResult & pickResult)87 void doPick(const InputState& inputState, Model::PickResult& pickResult) { 88 m_tool->pick(inputState.pickRay(), inputState.camera(), pickResult); 89 } 90 doMouseClick(const InputState & inputState)91 bool doMouseClick(const InputState& inputState) { 92 if (!inputState.mouseButtonsPressed(MouseButtons::MBLeft) || 93 !inputState.checkModifierKeys(MK_DontCare, MK_No, MK_No)) 94 return false; 95 96 const Model::Hit::List hits = firstHits(inputState.pickResult()); 97 if (hits.empty()) 98 return m_tool->deselectAll(); 99 else 100 return m_tool->select(hits, inputState.modifierKeysPressed(ModifierKeys::MKCtrlCmd)); 101 } 102 doStartDrag(const InputState & inputState)103 DragInfo doStartDrag(const InputState& inputState) { 104 if (!inputState.mouseButtonsPressed(MouseButtons::MBLeft) || 105 !inputState.checkModifierKeys(MK_DontCare, MK_No, MK_No)) 106 return DragInfo(); 107 108 const Renderer::Camera& camera = inputState.camera(); 109 const FloatType distance = 64.0f; 110 const Plane3 plane = orthogonalDragPlane(camera.defaultPoint(distance), camera.direction()); 111 const Vec3 initialPoint = inputState.pickRay().pointAtDistance(plane.intersectWithRay(inputState.pickRay())); 112 113 m_lasso = new Lasso(camera, distance, initialPoint); 114 return DragInfo(new PlaneDragRestricter(plane), new NoDragSnapper(), initialPoint); 115 } 116 doDrag(const InputState & inputState,const Vec3 & lastPoint,const Vec3 & curPoint)117 DragResult doDrag(const InputState& inputState, const Vec3& lastPoint, const Vec3& curPoint) { 118 assert(m_lasso != NULL); 119 m_lasso->setPoint(curPoint); 120 return DR_Continue; 121 } 122 doEndDrag(const InputState & inputState)123 void doEndDrag(const InputState& inputState) { 124 assert(m_lasso != NULL); 125 m_tool->select(*m_lasso, inputState.modifierKeysDown(ModifierKeys::MKCtrlCmd)); 126 delete m_lasso; 127 m_lasso = NULL; 128 } 129 doCancelDrag()130 void doCancelDrag() { 131 assert(m_lasso != NULL); 132 delete m_lasso; 133 m_lasso = NULL; 134 } 135 doSetRenderOptions(const InputState & inputState,Renderer::RenderContext & renderContext) const136 void doSetRenderOptions(const InputState& inputState, Renderer::RenderContext& renderContext) const { 137 renderContext.setForceHideSelectionGuide(); 138 } 139 doRender(const InputState & inputState,Renderer::RenderContext & renderContext,Renderer::RenderBatch & renderBatch)140 void doRender(const InputState& inputState, Renderer::RenderContext& renderContext, Renderer::RenderBatch& renderBatch) { 141 m_tool->renderHandles(renderContext, renderBatch); 142 if (m_lasso != NULL) 143 m_lasso->render(renderContext, renderBatch); 144 } 145 doCancel()146 bool doCancel() { 147 return false; 148 } 149 }; 150 151 class VertexToolController::MoveVertexPart : public MoveToolController<NoPickingPolicy, MousePolicy>, public VertexPartBase { 152 public: MoveVertexPart(VertexTool * tool)153 MoveVertexPart(VertexTool* tool) : 154 MoveToolController(tool->grid()), 155 VertexPartBase(tool) {} 156 private: doGetTool()157 Tool* doGetTool() { 158 return m_tool; 159 } 160 doMouseDoubleClick(const InputState & inputState)161 bool doMouseDoubleClick(const InputState& inputState) { 162 if (!inputState.mouseButtonsPressed(MouseButtons::MBLeft) || 163 !inputState.checkModifierKeys(MK_No, MK_No, MK_No)) 164 return false; 165 166 const Model::Hit::List hits = firstHits(inputState.pickResult()); 167 if (hits.empty()) 168 return false; 169 170 const Model::Hit& hit = hits.front(); 171 return m_tool->handleDoubleClicked(hit); 172 } 173 doStartMove(const InputState & inputState)174 MoveInfo doStartMove(const InputState& inputState) { 175 if (!(inputState.mouseButtonsPressed(MouseButtons::MBLeft) && 176 (inputState.modifierKeysPressed(ModifierKeys::MKNone) || 177 inputState.modifierKeysPressed(ModifierKeys::MKAlt)))) 178 return MoveInfo(); 179 180 static const Model::Hit::HitType any = VertexHandleManager::VertexHandleHit | VertexHandleManager::EdgeHandleHit | VertexHandleManager::FaceHandleHit; 181 const Model::Hit& hit = inputState.pickResult().query().type(any).occluded().first(); 182 if (!hit.isMatch()) 183 return MoveInfo(); 184 185 if (!m_tool->beginMove(hit)) 186 return MoveInfo(); 187 188 return MoveInfo(hit.target<Vec3>()); 189 } 190 doMove(const InputState & inputState,const Vec3 & lastPoint,const Vec3 & curPoint)191 DragResult doMove(const InputState& inputState, const Vec3& lastPoint, const Vec3& curPoint) { 192 switch (m_tool->move(curPoint - lastPoint)) { 193 case VertexTool::MR_Continue: 194 return DR_Continue; 195 case VertexTool::MR_Deny: 196 return DR_Deny; 197 case VertexTool::MR_Cancel: 198 return DR_Cancel; 199 switchDefault() 200 } 201 } 202 doEndMove(const InputState & inputState)203 void doEndMove(const InputState& inputState) { 204 m_tool->endMove(); 205 } 206 doCancelMove()207 void doCancelMove() { 208 m_tool->cancelMove(); 209 } 210 doRender(const InputState & inputState,Renderer::RenderContext & renderContext,Renderer::RenderBatch & renderBatch)211 void doRender(const InputState& inputState, Renderer::RenderContext& renderContext, Renderer::RenderBatch& renderBatch) { 212 MoveToolController::doRender(inputState, renderContext, renderBatch); 213 214 if (thisToolDragging()) { 215 m_tool->renderHighlight(renderContext, renderBatch); 216 m_tool->renderGuide(renderContext, renderBatch); 217 } else if (!anyToolDragging(inputState)) { 218 static const Model::Hit::HitType any = VertexHandleManager::VertexHandleHit | VertexHandleManager::EdgeHandleHit | VertexHandleManager::FaceHandleHit; 219 const Model::Hit& hit = inputState.pickResult().query().type(any).occluded().first(); 220 if (hit.isMatch()) { 221 const Vec3 position = hit.target<Vec3>(); 222 m_tool->renderHighlight(renderContext, renderBatch, position); 223 if (!m_tool->handleSelected(position)) { 224 if (hit.type() == VertexHandleManager::EdgeHandleHit) 225 m_tool->renderEdgeHighlight(renderContext, renderBatch, position); 226 else if (hit.type() == VertexHandleManager::FaceHandleHit) 227 m_tool->renderFaceHighlight(renderContext, renderBatch, position); 228 } 229 if (inputState.mouseButtonsPressed(MouseButtons::MBLeft)) 230 m_tool->renderGuide(renderContext, renderBatch, position); 231 } 232 } 233 } 234 doCancel()235 bool doCancel() { 236 return m_tool->cancel(); 237 } 238 }; 239 240 class VertexToolController::SnapVertexPart : public ToolControllerBase<NoPickingPolicy, NoKeyPolicy, MousePolicy, RestrictedDragPolicy, RenderPolicy, NoDropPolicy>, public VertexPartBase { 241 public: SnapVertexPart(VertexTool * tool)242 SnapVertexPart(VertexTool* tool) : 243 VertexPartBase(tool) {} 244 private: doGetTool()245 Tool* doGetTool() { 246 return m_tool; 247 } 248 doMouseClick(const InputState & inputState)249 bool doMouseClick(const InputState& inputState) { 250 if (!inputState.mouseButtonsPressed(MouseButtons::MBLeft) || 251 !inputState.checkModifierKeys(MK_No, MK_Yes, MK_Yes)) 252 return false; 253 254 const Model::Hit& hit = inputState.pickResult().query().type(VertexHandleManager::VertexHandleHit).occluded().first(); 255 if (!hit.isMatch()) 256 return false; 257 258 m_tool->mergeVertices(hit); 259 return true; 260 } 261 262 class VertexDragRestricter : public DragRestricter { 263 private: 264 VertexTool* m_tool; 265 public: VertexDragRestricter(VertexTool * tool)266 VertexDragRestricter(VertexTool* tool) : 267 m_tool(tool) { 268 assert(m_tool != NULL); 269 } 270 private: doComputeHitPoint(const InputState & inputState,Vec3 & point) const271 bool doComputeHitPoint(const InputState& inputState, Vec3& point) const { 272 const Model::Hit& hit = inputState.pickResult().query().type(VertexHandleManager::VertexHandleHit).occluded().first(); 273 if (!hit.isMatch()) 274 return false; 275 const Vec3 position = hit.target<Vec3>(); 276 if (m_tool->handleSelected(position)) 277 return false; 278 point = position; 279 return true; 280 } 281 }; 282 doStartDrag(const InputState & inputState)283 DragInfo doStartDrag(const InputState& inputState) { 284 if (!inputState.mouseButtonsPressed(MouseButtons::MBLeft) || 285 !inputState.checkModifierKeys(MK_No, MK_Yes, MK_Yes)) 286 return DragInfo(); 287 288 const Model::Hit& hit = inputState.pickResult().query().type(VertexHandleManager::VertexHandleHit).occluded().first(); 289 if (!hit.isMatch()) 290 return DragInfo(); 291 292 if (!m_tool->beginMove(hit)) 293 return DragInfo(); 294 295 return DragInfo(new VertexDragRestricter(m_tool), new NoDragSnapper(), hit.target<Vec3>()); 296 } 297 doDrag(const InputState & inputState,const Vec3 & lastPoint,const Vec3 & curPoint)298 DragResult doDrag(const InputState& inputState, const Vec3& lastPoint, const Vec3& curPoint) { 299 switch (m_tool->move(curPoint - lastPoint)) { 300 case VertexTool::MR_Continue: 301 return DR_Continue; 302 case VertexTool::MR_Deny: 303 return DR_Deny; 304 case VertexTool::MR_Cancel: 305 return DR_Cancel; 306 switchDefault() 307 } 308 } 309 doEndDrag(const InputState & inputState)310 void doEndDrag(const InputState& inputState) { 311 m_tool->endMove(); 312 } 313 doCancelDrag()314 void doCancelDrag() { 315 m_tool->cancelMove(); 316 } 317 doRender(const InputState & inputState,Renderer::RenderContext & renderContext,Renderer::RenderBatch & renderBatch)318 void doRender(const InputState& inputState, Renderer::RenderContext& renderContext, Renderer::RenderBatch& renderBatch) { 319 if (thisToolDragging()) { 320 m_tool->renderHighlight(renderContext, renderBatch); 321 m_tool->renderGuide(renderContext, renderBatch); 322 } 323 } 324 doCancel()325 bool doCancel() { 326 return m_tool->cancel(); 327 } 328 }; 329 VertexToolController(VertexTool * tool)330 VertexToolController::VertexToolController(VertexTool* tool) : 331 m_tool(tool) { 332 assert(m_tool != NULL); 333 addController(new MoveVertexPart(tool)); 334 addController(new SnapVertexPart(tool)); 335 addController(new SelectVertexPart(tool)); 336 } 337 ~VertexToolController()338 VertexToolController::~VertexToolController() {} 339 doGetTool()340 Tool* VertexToolController::doGetTool() { 341 return m_tool; 342 } 343 } 344 } 345