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 "CameraTool3D.h"
21 
22 #include "Preferences.h"
23 #include "PreferenceManager.h"
24 #include "Model/Brush.h"
25 #include "Model/Entity.h"
26 #include "Model/Group.h"
27 #include "Model/Hit.h"
28 #include "Model/HitAdapter.h"
29 #include "Model/HitQuery.h"
30 #include "Model/PickResult.h"
31 #include "View/InputState.h"
32 #include "View/MapDocument.h"
33 #include "Renderer/PerspectiveCamera.h"
34 
35 #include <iostream>
36 
37 namespace TrenchBroom {
38     namespace View {
CameraTool3D(MapDocumentWPtr document,Renderer::PerspectiveCamera & camera)39         CameraTool3D::CameraTool3D(MapDocumentWPtr document, Renderer::PerspectiveCamera& camera) :
40         ToolControllerBase(),
41         Tool(true),
42         m_document(document),
43         m_camera(camera),
44         m_orbit(false) {}
45 
fly(int dx,int dy,const bool forward,const bool backward,const bool left,const bool right,const unsigned int time)46         void CameraTool3D::fly(int dx, int dy, const bool forward, const bool backward, const bool left, const bool right, const unsigned int time) {
47 
48             static const float speed = 256.0f / 1000.0f; // 64 units per second
49             const float dist  = speed * time;
50 
51             Vec3 delta;
52             if (forward)
53                 delta += m_camera.direction() * dist;
54             if (backward)
55                 delta -= m_camera.direction() * dist;
56             if (left)
57                 delta -= m_camera.right() * dist;
58             if (right)
59                 delta += m_camera.right() * dist;
60             m_camera.moveBy(delta);
61 
62             const float hAngle = static_cast<float>(dx) * lookSpeedH();
63             const float vAngle = static_cast<float>(dy) * lookSpeedV();
64             m_camera.rotate(hAngle, vAngle);
65         }
66 
doGetTool()67         Tool* CameraTool3D::doGetTool() {
68             return this;
69         }
70 
doMouseScroll(const InputState & inputState)71         void CameraTool3D::doMouseScroll(const InputState& inputState) {
72             const float factor = pref(Preferences::CameraMouseWheelInvert) ? -1.0f : 1.0f;;
73             if (m_orbit) {
74                 const Plane3f orbitPlane(m_orbitCenter, m_camera.direction());
75                 const float maxDistance = std::max(orbitPlane.intersectWithRay(m_camera.viewRay()) - 32.0f, 0.0f);
76                 const float distance = std::min(factor * inputState.scrollY() * moveSpeed(false), maxDistance);
77                 m_camera.moveBy(distance * m_camera.direction());
78             } else if (move(inputState)) {
79                 const Vec3f moveDirection = pref(Preferences::CameraMoveInCursorDir) ? Vec3f(inputState.pickRay().direction) : m_camera.direction();
80                 const float distance = inputState.scrollY() * moveSpeed(false);
81                 m_camera.moveBy(factor * distance * moveDirection);
82             }
83         }
84 
doStartMouseDrag(const InputState & inputState)85         bool CameraTool3D::doStartMouseDrag(const InputState& inputState) {
86             if (orbit(inputState)) {
87                 const Model::Hit& hit = inputState.pickResult().query().pickable().type(Model::Brush::BrushHit | Model::Entity::EntityHit | Model::Group::GroupHit).occluded().minDistance(3.0).first();
88                 if (hit.isMatch())
89                     m_orbitCenter = hit.hitPoint();
90                 else
91                     m_orbitCenter = inputState.camera().defaultPoint(inputState.pickRay());
92                 m_orbit = true;
93                 return true;
94             } else if (look(inputState)) {
95                 return true;
96             } else if (pan(inputState)) {
97                 return true;
98             }
99             return false;
100         }
101 
doMouseDrag(const InputState & inputState)102         bool CameraTool3D::doMouseDrag(const InputState& inputState) {
103             if (m_orbit) {
104                 const float hAngle = inputState.mouseDX() * lookSpeedH();
105                 const float vAngle = inputState.mouseDY() * lookSpeedV();
106                 m_camera.orbit(m_orbitCenter, hAngle, vAngle);
107                 return true;
108             } else if (look(inputState)) {
109                 const float hAngle = inputState.mouseDX() * lookSpeedH();
110                 const float vAngle = inputState.mouseDY() * lookSpeedV();
111                 m_camera.rotate(hAngle, vAngle);
112                 return true;
113             } else if (pan(inputState)) {
114                 const bool altMove = pref(Preferences::CameraEnableAltMove);
115                 Vec3f delta;
116                 if (altMove && inputState.modifierKeysPressed(ModifierKeys::MKAlt)) {
117                     delta += inputState.mouseDX() * panSpeedH() * m_camera.right();
118                     delta += inputState.mouseDY() * -moveSpeed(altMove) * m_camera.direction();
119                 } else {
120                     delta += inputState.mouseDX() * panSpeedH() * m_camera.right();
121                     delta += inputState.mouseDY() * panSpeedV() * m_camera.up();
122                 }
123                 m_camera.moveBy(delta);
124                 return true;
125             }
126             return false;
127         }
128 
doEndMouseDrag(const InputState & inputState)129         void CameraTool3D::doEndMouseDrag(const InputState& inputState) {
130             m_orbit = false;
131         }
132 
doCancelMouseDrag()133         void CameraTool3D::doCancelMouseDrag() {
134             m_orbit = false;
135         }
136 
move(const InputState & inputState) const137         bool CameraTool3D::move(const InputState& inputState) const {
138             return ((inputState.mouseButtonsPressed(MouseButtons::MBNone) ||
139                      inputState.mouseButtonsPressed(MouseButtons::MBRight)) &&
140                     inputState.checkModifierKeys(MK_No, MK_No, MK_No));
141         }
142 
look(const InputState & inputState) const143         bool CameraTool3D::look(const InputState& inputState) const {
144             return (inputState.mouseButtonsPressed(MouseButtons::MBRight) &&
145                     inputState.modifierKeysPressed(ModifierKeys::MKNone));
146         }
147 
pan(const InputState & inputState) const148         bool CameraTool3D::pan(const InputState& inputState) const {
149             return (inputState.mouseButtonsPressed(MouseButtons::MBMiddle) &&
150                     (inputState.modifierKeysPressed(ModifierKeys::MKNone) ||
151                      inputState.modifierKeysPressed(ModifierKeys::MKAlt)));
152         }
153 
orbit(const InputState & inputState) const154         bool CameraTool3D::orbit(const InputState& inputState) const {
155             return (inputState.mouseButtonsPressed(MouseButtons::MBRight) &&
156                     inputState.modifierKeysPressed(ModifierKeys::MKAlt));
157         }
158 
lookSpeedH() const159         float CameraTool3D::lookSpeedH() const {
160             float speed = pref(Preferences::CameraLookSpeed) / -50.0f;
161             if (pref(Preferences::CameraLookInvertH))
162                 speed *= -1.0f;
163             return speed;
164         }
165 
lookSpeedV() const166         float CameraTool3D::lookSpeedV() const {
167             float speed = pref(Preferences::CameraLookSpeed) / -50.0f;
168             if (pref(Preferences::CameraLookInvertV))
169                 speed *= -1.0f;
170             return speed;
171         }
172 
panSpeedH() const173         float CameraTool3D::panSpeedH() const {
174             float speed = pref(Preferences::CameraPanSpeed);
175             if (pref(Preferences::CameraPanInvertH))
176                 speed *= -1.0f;
177             return speed;
178         }
179 
panSpeedV() const180         float CameraTool3D::panSpeedV() const {
181             float speed = pref(Preferences::CameraPanSpeed);
182             if (pref(Preferences::CameraPanInvertV))
183                 speed *= -1.0f;
184             return speed;
185         }
186 
moveSpeed(const bool altMode) const187         float CameraTool3D::moveSpeed(const bool altMode) const {
188             float speed = pref(Preferences::CameraMoveSpeed) * 20.0f;
189             // if (slow)
190                 // speed /= 10.0f;
191             if (altMode && pref(Preferences::CameraAltMoveInvert))
192                 speed *= -1.0f;
193             return speed;
194         }
195 
doCancel()196         bool CameraTool3D::doCancel() {
197             return false;
198         }
199     }
200 }
201