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 "MapView3D.h" 21 #include "Logger.h" 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/Entity.h" 28 #include "Model/HitAdapter.h" 29 #include "Model/HitQuery.h" 30 #include "Model/PickResult.h" 31 #include "Model/PointFile.h" 32 #include "Renderer/BoundsGuideRenderer.h" 33 #include "Renderer/Compass3D.h" 34 #include "Renderer/MapRenderer.h" 35 #include "Renderer/RenderBatch.h" 36 #include "Renderer/RenderContext.h" 37 #include "Renderer/SelectionBoundsRenderer.h" 38 #include "View/ActionManager.h" 39 #include "View/Animation.h" 40 #include "View/CameraAnimation.h" 41 #include "View/CameraTool3D.h" 42 #include "View/ClipToolController.h" 43 #include "View/CommandIds.h" 44 #include "View/CreateComplexBrushToolController3D.h" 45 #include "View/CreateEntityToolController.h" 46 #include "View/CreateSimpleBrushToolController3D.h" 47 #include "View/FlashSelectionAnimation.h" 48 #include "View/FlyModeHelper.h" 49 #include "View/GLContextManager.h" 50 #include "View/Grid.h" 51 #include "View/InputState.h" 52 #include "View/MapDocument.h" 53 #include "View/MapViewToolBox.h" 54 #include "View/MoveObjectsToolController.h" 55 #include "View/ResizeBrushesToolController.h" 56 #include "View/RotateObjectsToolController.h" 57 #include "View/SelectionTool.h" 58 #include "View/SetBrushFaceAttributesTool.h" 59 #include "View/VertexTool.h" 60 #include "View/VertexToolController.h" 61 #include "View/wxUtils.h" 62 63 namespace TrenchBroom { 64 namespace View { MapView3D(wxWindow * parent,Logger * logger,MapDocumentWPtr document,MapViewToolBox & toolBox,Renderer::MapRenderer & renderer,GLContextManager & contextManager)65 MapView3D::MapView3D(wxWindow* parent, Logger* logger, MapDocumentWPtr document, MapViewToolBox& toolBox, Renderer::MapRenderer& renderer, GLContextManager& contextManager) : 66 MapViewBase(parent, logger, document, toolBox, renderer, contextManager), 67 m_flyModeHelper(new FlyModeHelper(this, m_camera)) { 68 bindEvents(); 69 bindObservers(); 70 initializeCamera(); 71 initializeToolChain(toolBox); 72 setCompass(new Renderer::Compass3D()); 73 } 74 ~MapView3D()75 MapView3D::~MapView3D() { 76 m_flyModeHelper->Delete(); 77 unbindObservers(); 78 } 79 initializeCamera()80 void MapView3D::initializeCamera() { 81 m_camera.moveTo(Vec3f(-80.0f, -128.0f, 96.0f)); 82 m_camera.lookAt(Vec3::Null, Vec3::PosZ); 83 } 84 initializeToolChain(MapViewToolBox & toolBox)85 void MapView3D::initializeToolChain(MapViewToolBox& toolBox) { 86 addTool(new CameraTool3D(m_document, m_camera)); 87 addTool(new MoveObjectsToolController(toolBox.moveObjectsTool())); 88 addTool(new RotateObjectsToolController3D(toolBox.rotateObjectsTool())); 89 addTool(new ResizeBrushesToolController3D(toolBox.resizeBrushesTool())); 90 addTool(new CreateComplexBrushToolController3D(toolBox.createComplexBrushTool())); 91 addTool(new ClipToolController3D(toolBox.clipTool())); 92 addTool(new VertexToolController(toolBox.vertexTool())); 93 addTool(new CreateEntityToolController3D(toolBox.createEntityTool())); 94 addTool(new SetBrushFaceAttributesTool(m_document)); 95 addTool(new SelectionTool(m_document)); 96 addTool(new CreateSimpleBrushToolController3D(toolBox.createSimpleBrushTool(), m_document)); 97 } 98 cameraFlyModeActive() const99 bool MapView3D::cameraFlyModeActive() const { 100 return m_flyModeHelper->enabled(); 101 } 102 toggleCameraFlyMode()103 void MapView3D::toggleCameraFlyMode() { 104 if (!cameraFlyModeActive()) { 105 m_toolBox.disable(); 106 m_flyModeHelper->enable(); 107 } else { 108 m_flyModeHelper->disable(); 109 m_toolBox.enable(); 110 } 111 updateAcceleratorTable(); 112 Refresh(); 113 } 114 bindObservers()115 void MapView3D::bindObservers() { 116 m_camera.cameraDidChangeNotifier.addObserver(this, &MapView3D::cameraDidChange); 117 } 118 unbindObservers()119 void MapView3D::unbindObservers() { 120 m_camera.cameraDidChangeNotifier.removeObserver(this, &MapView3D::cameraDidChange); 121 } 122 cameraDidChange(const Renderer::Camera * camera)123 void MapView3D::cameraDidChange(const Renderer::Camera* camera) { 124 Refresh(); 125 } 126 bindEvents()127 void MapView3D::bindEvents() { 128 Bind(wxEVT_KEY_DOWN, &MapView3D::OnKeyDown, this); 129 Bind(wxEVT_KEY_UP, &MapView3D::OnKeyUp, this); 130 Bind(wxEVT_MOTION, &MapView3D::OnMouseMotion, this); 131 132 Bind(wxEVT_KILL_FOCUS, &MapView3D::OnKillFocus, this); 133 134 Bind(wxEVT_MENU, &MapView3D::OnPerformCreateBrush, this, CommandIds::Actions::PerformCreateBrush); 135 136 Bind(wxEVT_MENU, &MapView3D::OnMoveTexturesUp, this, CommandIds::Actions::MoveTexturesUp); 137 Bind(wxEVT_MENU, &MapView3D::OnMoveTexturesDown, this, CommandIds::Actions::MoveTexturesDown); 138 Bind(wxEVT_MENU, &MapView3D::OnMoveTexturesLeft, this, CommandIds::Actions::MoveTexturesLeft); 139 Bind(wxEVT_MENU, &MapView3D::OnMoveTexturesRight, this, CommandIds::Actions::MoveTexturesRight); 140 141 Bind(wxEVT_MENU, &MapView3D::OnRotateTexturesCW, this, CommandIds::Actions::RotateTexturesCW); 142 Bind(wxEVT_MENU, &MapView3D::OnRotateTexturesCCW, this, CommandIds::Actions::RotateTexturesCCW); 143 144 Bind(wxEVT_MENU, &MapView3D::OnToggleFlyMode, this, CommandIds::Actions::ToggleFlyMode); 145 146 wxFrame* frame = findFrame(this); 147 frame->Bind(wxEVT_ACTIVATE, &MapView3D::OnActivateFrame, this); 148 } 149 OnKeyDown(wxKeyEvent & event)150 void MapView3D::OnKeyDown(wxKeyEvent& event) { 151 if (IsBeingDeleted()) return; 152 153 if (!m_flyModeHelper->keyDown(event)) 154 event.Skip(); 155 } 156 OnKeyUp(wxKeyEvent & event)157 void MapView3D::OnKeyUp(wxKeyEvent& event) { 158 if (IsBeingDeleted()) return; 159 160 if (!m_flyModeHelper->keyUp(event)) 161 event.Skip(); 162 } 163 OnMouseMotion(wxMouseEvent & event)164 void MapView3D::OnMouseMotion(wxMouseEvent& event) { 165 if (IsBeingDeleted()) return; 166 167 m_flyModeHelper->motion(event); 168 event.Skip(); 169 } 170 OnPerformCreateBrush(wxCommandEvent & event)171 void MapView3D::OnPerformCreateBrush(wxCommandEvent& event) { 172 if (IsBeingDeleted()) return; 173 174 if (m_toolBox.createComplexBrushToolActive()) 175 m_toolBox.performCreateComplexBrush(); 176 } 177 OnMoveTexturesUp(wxCommandEvent & event)178 void MapView3D::OnMoveTexturesUp(wxCommandEvent& event) { 179 if (IsBeingDeleted()) return; 180 181 moveTextures(Vec2f(0.0f, moveTextureDistance())); 182 } 183 OnMoveTexturesDown(wxCommandEvent & event)184 void MapView3D::OnMoveTexturesDown(wxCommandEvent& event) { 185 if (IsBeingDeleted()) return; 186 187 moveTextures(Vec2f(0.0f, -moveTextureDistance())); 188 } 189 OnMoveTexturesLeft(wxCommandEvent & event)190 void MapView3D::OnMoveTexturesLeft(wxCommandEvent& event) { 191 if (IsBeingDeleted()) return; 192 193 moveTextures(Vec2f(-moveTextureDistance(), 0.0f)); 194 } 195 OnMoveTexturesRight(wxCommandEvent & event)196 void MapView3D::OnMoveTexturesRight(wxCommandEvent& event) { 197 if (IsBeingDeleted()) return; 198 199 moveTextures(Vec2f(moveTextureDistance(), 0.0f)); 200 } 201 OnRotateTexturesCW(wxCommandEvent & event)202 void MapView3D::OnRotateTexturesCW(wxCommandEvent& event) { 203 if (IsBeingDeleted()) return; 204 205 rotateTextures(rotateTextureAngle(true)); 206 } 207 OnRotateTexturesCCW(wxCommandEvent & event)208 void MapView3D::OnRotateTexturesCCW(wxCommandEvent& event) { 209 if (IsBeingDeleted()) return; 210 211 rotateTextures(rotateTextureAngle(false)); 212 } 213 moveTextureDistance() const214 float MapView3D::moveTextureDistance() const { 215 const Grid& grid = lock(m_document)->grid(); 216 const float gridSize = static_cast<float>(grid.actualSize()); 217 218 const wxMouseState mouseState = wxGetMouseState(); 219 switch (mouseState.GetModifiers()) { 220 case wxMOD_CMD: 221 return 1.0f; 222 case wxMOD_SHIFT: 223 return 2.0f * gridSize; 224 default: 225 return gridSize; 226 } 227 } 228 moveTextures(const Vec2f & offset)229 void MapView3D::moveTextures(const Vec2f& offset) { 230 MapDocumentSPtr document = lock(m_document); 231 if (document->hasSelectedBrushFaces()) 232 document->moveTextures(m_camera.up(), m_camera.right(), offset); 233 } 234 rotateTextureAngle(const bool clockwise) const235 float MapView3D::rotateTextureAngle(const bool clockwise) const { 236 const Grid& grid = lock(m_document)->grid(); 237 const float gridAngle = static_cast<float>(Math::degrees(grid.angle())); 238 float angle = 0.0f; 239 240 const wxMouseState mouseState = wxGetMouseState(); 241 switch (mouseState.GetModifiers()) { 242 case wxMOD_CMD: 243 angle = 1.0f; 244 break; 245 case wxMOD_SHIFT: 246 angle = 90.0f; 247 break; 248 default: 249 angle = gridAngle; 250 break; 251 } 252 253 return clockwise ? angle : -angle; 254 } 255 rotateTextures(const float angle)256 void MapView3D::rotateTextures(const float angle) { 257 MapDocumentSPtr document = lock(m_document); 258 if (document->hasSelectedBrushFaces()) 259 document->rotateTextures(angle); 260 } 261 OnToggleFlyMode(wxCommandEvent & event)262 void MapView3D::OnToggleFlyMode(wxCommandEvent& event) { 263 if (IsBeingDeleted()) return; 264 265 toggleCameraFlyMode(); 266 } 267 OnKillFocus(wxFocusEvent & event)268 void MapView3D::OnKillFocus(wxFocusEvent& event) { 269 if (IsBeingDeleted()) return; 270 271 if (cameraFlyModeActive()) 272 toggleCameraFlyMode(); 273 event.Skip(); 274 } 275 OnActivateFrame(wxActivateEvent & event)276 void MapView3D::OnActivateFrame(wxActivateEvent& event) { 277 if (IsBeingDeleted()) return; 278 279 if (cameraFlyModeActive()) 280 toggleCameraFlyMode(); 281 event.Skip(); 282 } 283 doGetPickRequest(const int x,const int y) const284 PickRequest MapView3D::doGetPickRequest(const int x, const int y) const { 285 return PickRequest(Ray3(m_camera.pickRay(x, y)), m_camera); 286 } 287 doPick(const Ray3 & pickRay) const288 Model::PickResult MapView3D::doPick(const Ray3& pickRay) const { 289 MapDocumentSPtr document = lock(m_document); 290 const Model::EditorContext& editorContext = document->editorContext(); 291 Model::PickResult pickResult = Model::PickResult::byDistance(editorContext); 292 293 document->pick(pickRay, pickResult); 294 return pickResult; 295 } 296 doUpdateViewport(const int x,const int y,const int width,const int height)297 void MapView3D::doUpdateViewport(const int x, const int y, const int width, const int height) { 298 m_camera.setViewport(Renderer::Camera::Viewport(x, y, width, height)); 299 } 300 doGetPasteObjectsDelta(const BBox3 & bounds,const BBox3 & referenceBounds) const301 Vec3 MapView3D::doGetPasteObjectsDelta(const BBox3& bounds, const BBox3& referenceBounds) const { 302 MapDocumentSPtr document = lock(m_document); 303 const Grid& grid = document->grid(); 304 305 const wxMouseState mouseState = wxGetMouseState(); 306 const wxPoint clientCoords = ScreenToClient(mouseState.GetPosition()); 307 308 if (HitTest(clientCoords) == wxHT_WINDOW_INSIDE) { 309 const Ray3f pickRay = m_camera.pickRay(clientCoords.x, clientCoords.y); 310 311 const Model::EditorContext& editorContext = document->editorContext(); 312 Model::PickResult pickResult = Model::PickResult::byDistance(editorContext); 313 314 document->pick(Ray3(pickRay), pickResult); 315 const Model::Hit& hit = pickResult.query().pickable().type(Model::Brush::BrushHit).first(); 316 317 if (hit.isMatch()) { 318 const Model::BrushFace* face = Model::hitToFace(hit); 319 const Plane3 dragPlane = alignedOrthogonalDragPlane(hit.hitPoint(), face->boundary().normal); 320 return grid.moveDeltaForBounds(dragPlane, bounds, document->worldBounds(), pickRay, hit.hitPoint()); 321 } else { 322 const Vec3 point = m_camera.defaultPoint(pickRay); 323 const Plane3 dragPlane = alignedOrthogonalDragPlane(point, -Vec3(m_camera.direction())); 324 return grid.moveDeltaForBounds(dragPlane, bounds, document->worldBounds(), pickRay, point); 325 } 326 } else { 327 const Vec3 oldMin = bounds.min; 328 const Vec3 oldCenter = bounds.center(); 329 const Vec3 newCenter = m_camera.defaultPoint(); 330 const Vec3 newMin = oldMin + (newCenter - oldCenter); 331 return grid.snap(newMin); 332 } 333 } 334 doCanSelectTall()335 bool MapView3D::doCanSelectTall() { 336 return false; 337 } 338 doSelectTall()339 void MapView3D::doSelectTall() {} 340 doFocusCameraOnSelection(const bool animate)341 void MapView3D::doFocusCameraOnSelection(const bool animate) { 342 MapDocumentSPtr document = lock(m_document); 343 const Model::NodeList& nodes = document->selectedNodes().nodes(); 344 if (!nodes.empty()) { 345 const Vec3 newPosition = focusCameraOnObjectsPosition(nodes); 346 moveCameraToPosition(newPosition, animate); 347 } 348 } 349 350 class MapView3D::ComputeCameraCenterPositionVisitor : public Model::ConstNodeVisitor { 351 private: 352 const Vec3 m_cameraPosition; 353 const Vec3 m_cameraDirection; 354 FloatType m_minDist; 355 Vec3 m_center; 356 size_t m_count; 357 public: ComputeCameraCenterPositionVisitor(const Vec3 & cameraPosition,const Vec3 & cameraDirection)358 ComputeCameraCenterPositionVisitor(const Vec3& cameraPosition, const Vec3& cameraDirection) : 359 m_cameraPosition(cameraPosition), 360 m_cameraDirection(cameraDirection), 361 m_minDist(std::numeric_limits<FloatType>::max()), 362 m_count(0) {} 363 position() const364 Vec3 position() const { 365 return m_center / static_cast<FloatType>(m_count); 366 } 367 private: doVisit(const Model::World * world)368 void doVisit(const Model::World* world) {} doVisit(const Model::Layer * layer)369 void doVisit(const Model::Layer* layer) {} doVisit(const Model::Group * group)370 void doVisit(const Model::Group* group) {} 371 doVisit(const Model::Entity * entity)372 void doVisit(const Model::Entity* entity) { 373 if (!entity->hasChildren()) { 374 const Vec3::List vertices = bBoxVertices(entity->bounds()); 375 for (size_t i = 0; i < vertices.size(); ++i) 376 addPoint(vertices[i]); 377 } 378 } 379 doVisit(const Model::Brush * brush)380 void doVisit(const Model::Brush* brush) { 381 const Model::Brush::VertexList vertices = brush->vertices(); 382 Model::Brush::VertexList::const_iterator it, end; 383 for (it = vertices.begin(), end = vertices.end(); it != end; ++it) 384 addPoint((*it)->position()); 385 } 386 addPoint(const Vec3 & point)387 void addPoint(const Vec3& point) { 388 const Vec3 toPosition = point - m_cameraPosition; 389 m_minDist = std::min(m_minDist, toPosition.dot(m_cameraDirection)); 390 m_center += point; 391 ++m_count; 392 } 393 }; 394 395 class MapView3D::ComputeCameraCenterOffsetVisitor : public Model::ConstNodeVisitor { 396 private: 397 const Vec3f m_cameraPosition; 398 const Vec3f m_cameraDirection; 399 Plane3f m_frustumPlanes[4]; 400 float m_offset; 401 public: ComputeCameraCenterOffsetVisitor(const Vec3f & cameraPosition,const Vec3f & cameraDirection,const Plane3f frustumPlanes[4])402 ComputeCameraCenterOffsetVisitor(const Vec3f& cameraPosition, const Vec3f& cameraDirection, const Plane3f frustumPlanes[4]) : 403 m_cameraPosition(cameraPosition), 404 m_cameraDirection(cameraDirection), 405 m_offset(std::numeric_limits<float>::min()) { 406 for (size_t i = 0; i < 4; ++i) 407 m_frustumPlanes[i] = frustumPlanes[i]; 408 } 409 offset() const410 float offset() const { 411 return m_offset; 412 } 413 private: doVisit(const Model::World * world)414 void doVisit(const Model::World* world) {} doVisit(const Model::Layer * layer)415 void doVisit(const Model::Layer* layer) {} doVisit(const Model::Group * group)416 void doVisit(const Model::Group* group) {} 417 doVisit(const Model::Entity * entity)418 void doVisit(const Model::Entity* entity) { 419 if (!entity->hasChildren()) { 420 const Vec3::List vertices = bBoxVertices(entity->bounds()); 421 for (size_t i = 0; i < vertices.size(); ++i) { 422 for (size_t j = 0; j < 4; ++j) 423 addPoint(vertices[i], m_frustumPlanes[j]); 424 } 425 } 426 } 427 doVisit(const Model::Brush * brush)428 void doVisit(const Model::Brush* brush) { 429 const Model::Brush::VertexList vertices = brush->vertices(); 430 Model::Brush::VertexList::const_iterator it, end; 431 for (it = vertices.begin(), end = vertices.end(); it != end; ++it) { 432 const Model::BrushVertex* vertex = *it; 433 for (size_t j = 0; j < 4; ++j) 434 addPoint(vertex->position(), m_frustumPlanes[j]); 435 } 436 } 437 addPoint(const Vec3f point,const Plane3f & plane)438 void addPoint(const Vec3f point, const Plane3f& plane) { 439 const Ray3f ray(m_cameraPosition, -m_cameraDirection); 440 const Plane3f newPlane(point + 64.0f * plane.normal, plane.normal); 441 const float dist = newPlane.intersectWithRay(ray); 442 if (!Math::isnan(dist) && dist > 0.0f) 443 m_offset = std::max(m_offset, dist); 444 } 445 }; 446 focusCameraOnObjectsPosition(const Model::NodeList & nodes)447 Vec3f MapView3D::focusCameraOnObjectsPosition(const Model::NodeList& nodes) { 448 ComputeCameraCenterPositionVisitor center(m_camera.position(), m_camera.direction()); 449 Model::Node::acceptAndRecurse(nodes.begin(), nodes.end(), center); 450 451 const Vec3 newPosition = center.position(); 452 453 // act as if the camera were there already: 454 const Vec3f oldPosition = m_camera.position(); 455 m_camera.moveTo(Vec3f(newPosition)); 456 457 Plane3f frustumPlanes[4]; 458 m_camera.frustumPlanes(frustumPlanes[0], frustumPlanes[1], frustumPlanes[2], frustumPlanes[3]); 459 460 ComputeCameraCenterOffsetVisitor offset(m_camera.position(), m_camera.direction(), frustumPlanes); 461 Model::Node::acceptAndRecurse(nodes.begin(), nodes.end(), offset); 462 463 // jump back 464 m_camera.moveTo(oldPosition); 465 return newPosition - m_camera.direction() * offset.offset(); 466 } 467 doMoveCameraToPosition(const Vec3 & position,const bool animate)468 void MapView3D::doMoveCameraToPosition(const Vec3& position, const bool animate) { 469 if (animate) 470 animateCamera(position, m_camera.direction(), m_camera.up()); 471 else 472 m_camera.moveTo(position); 473 } 474 animateCamera(const Vec3f & position,const Vec3f & direction,const Vec3f & up,const wxLongLong duration)475 void MapView3D::animateCamera(const Vec3f& position, const Vec3f& direction, const Vec3f& up, const wxLongLong duration) { 476 CameraAnimation* animation = new CameraAnimation(m_camera, position, direction, up, duration); 477 m_animationManager->runAnimation(animation, true); 478 } 479 doMoveCameraToCurrentTracePoint()480 void MapView3D::doMoveCameraToCurrentTracePoint() { 481 MapDocumentSPtr document = lock(m_document); 482 483 assert(document->isPointFileLoaded()); 484 Model::PointFile* pointFile = document->pointFile(); 485 assert(pointFile->hasNextPoint()); 486 487 const Vec3f position = pointFile->currentPoint() + Vec3f(0.0f, 0.0f, 16.0f); 488 const Vec3f direction = pointFile->currentDirection(); 489 animateCamera(position, direction, Vec3f::PosZ); 490 } 491 doGetMoveDirection(const Math::Direction direction) const492 Vec3 MapView3D::doGetMoveDirection(const Math::Direction direction) const { 493 switch (direction) { 494 case Math::Direction_Forward: { 495 Vec3 dir = m_camera.direction().firstAxis(); 496 if (dir.z() < 0.0) 497 dir = m_camera.up().firstAxis(); 498 else if (dir.z() > 0.0) 499 dir = -m_camera.up().firstAxis(); 500 return dir; 501 } 502 case Math::Direction_Backward: 503 return -doGetMoveDirection(Math::Direction_Forward); 504 case Math::Direction_Left: 505 return -doGetMoveDirection(Math::Direction_Right); 506 case Math::Direction_Right: { 507 Vec3 dir = m_camera.right().firstAxis(); 508 if (dir == doGetMoveDirection(Math::Direction_Forward)) 509 dir = crossed(dir, Vec3::PosZ); 510 return dir; 511 } 512 case Math::Direction_Up: 513 return Vec3::PosZ; 514 case Math::Direction_Down: 515 return Vec3::NegZ; 516 switchDefault() 517 } 518 } 519 doComputePointEntityPosition(const BBox3 & bounds) const520 Vec3 MapView3D::doComputePointEntityPosition(const BBox3& bounds) const { 521 MapDocumentSPtr document = lock(m_document); 522 523 Vec3 delta; 524 View::Grid& grid = document->grid(); 525 526 const BBox3& worldBounds = document->worldBounds(); 527 528 const Model::Hit& hit = pickResult().query().pickable().type(Model::Brush::BrushHit).occluded().first(); 529 if (hit.isMatch()) { 530 const Model::BrushFace* face = Model::hitToFace(hit); 531 return grid.moveDeltaForBounds(face->boundary(), bounds, worldBounds, pickRay(), hit.hitPoint()); 532 } else { 533 const Vec3 newPosition = Renderer::Camera::defaultPoint(pickRay()); 534 const Vec3 defCenter = bounds.center(); 535 return grid.moveDeltaForPoint(defCenter, worldBounds, newPosition - defCenter); 536 } 537 } 538 doGetActionContext() const539 ActionContext MapView3D::doGetActionContext() const { 540 if (cameraFlyModeActive()) 541 return ActionContext_FlyMode; 542 return ActionContext_Default; 543 } 544 doCreateAccelerationTable(ActionContext context) const545 wxAcceleratorTable MapView3D::doCreateAccelerationTable(ActionContext context) const { 546 ActionManager& actionManager = ActionManager::instance(); 547 return actionManager.createViewAcceleratorTable(context, ActionView_Map3D); 548 } 549 doCancel()550 bool MapView3D::doCancel() { 551 if (cameraFlyModeActive()) { 552 toggleCameraFlyMode(); 553 return true; 554 } 555 return false; 556 } 557 doCreateRenderContext()558 Renderer::RenderContext MapView3D::doCreateRenderContext() { 559 return Renderer::RenderContext(Renderer::RenderContext::RenderMode_3D, m_camera, fontManager(), shaderManager()); 560 } 561 doRenderGrid(Renderer::RenderContext & renderContext,Renderer::RenderBatch & renderBatch)562 void MapView3D::doRenderGrid(Renderer::RenderContext& renderContext, Renderer::RenderBatch& renderBatch) {} 563 doRenderMap(Renderer::MapRenderer & renderer,Renderer::RenderContext & renderContext,Renderer::RenderBatch & renderBatch)564 void MapView3D::doRenderMap(Renderer::MapRenderer& renderer, Renderer::RenderContext& renderContext, Renderer::RenderBatch& renderBatch) { 565 renderer.render(renderContext, renderBatch); 566 567 MapDocumentSPtr document = lock(m_document); 568 if (renderContext.showSelectionGuide() && document->hasSelectedNodes()) { 569 const BBox3& bounds = document->selectionBounds(); 570 Renderer::SelectionBoundsRenderer boundsRenderer(bounds); 571 boundsRenderer.render(renderContext, renderBatch); 572 573 Renderer::BoundsGuideRenderer* guideRenderer = new Renderer::BoundsGuideRenderer(m_document); 574 guideRenderer->setColor(pref(Preferences::SelectionBoundsColor)); 575 guideRenderer->setBounds(bounds); 576 renderBatch.addOneShot(guideRenderer); 577 } 578 } 579 doRenderTools(MapViewToolBox & toolBox,Renderer::RenderContext & renderContext,Renderer::RenderBatch & renderBatch)580 void MapView3D::doRenderTools(MapViewToolBox& toolBox, Renderer::RenderContext& renderContext, Renderer::RenderBatch& renderBatch) { 581 renderTools(renderContext, renderBatch); 582 } 583 doLinkCamera(CameraLinkHelper & helper)584 void MapView3D::doLinkCamera(CameraLinkHelper& helper) {} 585 } 586 } 587