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 "RotateObjectsHandle.h" 21 22 #include "Macros.h" 23 #include "PreferenceManager.h" 24 #include "Preferences.h" 25 #include "Renderer/Camera.h" 26 #include "Renderer/Circle.h" 27 #include "Renderer/Renderable.h" 28 #include "Renderer/RenderBatch.h" 29 #include "Renderer/RenderContext.h" 30 #include "Renderer/RenderService.h" 31 #include "Renderer/RenderUtils.h" 32 #include "Renderer/Shaders.h" 33 #include "Renderer/ShaderManager.h" 34 #include "Renderer/Transformation.h" 35 #include "Renderer/VertexArray.h" 36 #include "View/InputState.h" 37 38 #include <cassert> 39 40 namespace TrenchBroom { 41 namespace View { 42 const Model::Hit::HitType RotateObjectsHandle::HandleHit = Model::Hit::freeHitType(); 43 position() const44 const Vec3& RotateObjectsHandle::position() const { 45 return m_position; 46 } 47 setPosition(const Vec3 & position)48 void RotateObjectsHandle::setPosition(const Vec3& position) { 49 m_position = position; 50 } 51 pick2D(const Ray3 & pickRay,const Renderer::Camera & camera) const52 Model::Hit RotateObjectsHandle::pick2D(const Ray3& pickRay, const Renderer::Camera& camera) const { 53 Vec3 xAxis, yAxis, zAxis; 54 computeAxes(pickRay.origin, xAxis, yAxis, zAxis); 55 56 Model::Hit hit = pickPointHandle(pickRay, camera, m_position, HitArea_Center); 57 switch (camera.direction().firstComponent()) { 58 case Math::Axis::AX: 59 hit = selectHit(hit, pickPointHandle(pickRay, camera, getPointHandlePosition(yAxis), HitArea_YAxis)); 60 break; 61 case Math::Axis::AY: 62 hit = selectHit(hit, pickPointHandle(pickRay, camera, getPointHandlePosition(xAxis), HitArea_XAxis)); 63 break; 64 case Math::Axis::AZ: 65 default: 66 hit = selectHit(hit, pickPointHandle(pickRay, camera, getPointHandlePosition(xAxis), HitArea_XAxis)); 67 break; 68 } 69 return hit; 70 } 71 pick3D(const Ray3 & pickRay,const Renderer::Camera & camera) const72 Model::Hit RotateObjectsHandle::pick3D(const Ray3& pickRay, const Renderer::Camera& camera) const { 73 Vec3 xAxis, yAxis, zAxis; 74 computeAxes(pickRay.origin, xAxis, yAxis, zAxis); 75 76 Model::Hit hit = pickPointHandle(pickRay, camera, m_position, HitArea_Center); 77 hit = selectHit(hit, pickPointHandle(pickRay, camera, getPointHandlePosition(xAxis), HitArea_XAxis)); 78 hit = selectHit(hit, pickPointHandle(pickRay, camera, getPointHandlePosition(yAxis), HitArea_YAxis)); 79 hit = selectHit(hit, pickPointHandle(pickRay, camera, getPointHandlePosition(zAxis), HitArea_ZAxis)); 80 return hit; 81 } 82 pointHandlePosition(const HitArea area,const Vec3 & cameraPos) const83 Vec3 RotateObjectsHandle::pointHandlePosition(const HitArea area, const Vec3& cameraPos) const { 84 Vec3 xAxis, yAxis, zAxis; 85 computeAxes(cameraPos, xAxis, yAxis, zAxis); 86 switch (area) { 87 case HitArea_XAxis: 88 return getPointHandlePosition(xAxis); 89 case HitArea_YAxis: 90 return getPointHandlePosition(yAxis); 91 case HitArea_ZAxis: 92 return getPointHandlePosition(zAxis); 93 case HitArea_None: 94 case HitArea_Center: 95 return m_position; 96 switchDefault() 97 } 98 } 99 handleRadius() const100 FloatType RotateObjectsHandle::handleRadius() const { 101 return pref(Preferences::RotateHandleRadius); 102 } 103 pointHandleAxis(const HitArea area,const Vec3 & cameraPos) const104 Vec3 RotateObjectsHandle::pointHandleAxis(const HitArea area, const Vec3& cameraPos) const { 105 Vec3 xAxis, yAxis, zAxis; 106 computeAxes(cameraPos, xAxis, yAxis, zAxis); 107 switch (area) { 108 case HitArea_XAxis: 109 return xAxis; 110 case HitArea_YAxis: 111 return yAxis; 112 case HitArea_ZAxis: 113 return zAxis; 114 case HitArea_None: 115 case HitArea_Center: 116 return Vec3::PosZ; 117 switchDefault() 118 } 119 } 120 rotationAxis(const HitArea area) const121 Vec3 RotateObjectsHandle::rotationAxis(const HitArea area) const { 122 switch (area) { 123 case HitArea_XAxis: 124 return Vec3::PosZ; 125 case HitArea_YAxis: 126 return Vec3::PosX; 127 case HitArea_ZAxis: 128 return Vec3::PosY; 129 case HitArea_None: 130 case HitArea_Center: 131 return Vec3::PosZ; 132 switchDefault() 133 } 134 } 135 renderHandle2D(Renderer::RenderContext & renderContext,Renderer::RenderBatch & renderBatch)136 void RotateObjectsHandle::renderHandle2D(Renderer::RenderContext& renderContext, Renderer::RenderBatch& renderBatch) { 137 const Renderer::Camera& camera = renderContext.camera(); 138 const float radius = static_cast<float>(pref(Preferences::RotateHandleRadius)); 139 140 Renderer::RenderService renderService(renderContext, renderBatch); 141 renderService.setShowOccludedObjects(); 142 143 renderService.setForegroundColor(pref(Preferences::axisColor(camera.direction().firstComponent()))); 144 renderService.renderCircle(m_position, camera.direction().firstComponent(), 64, radius); 145 146 renderService.setForegroundColor(pref(Preferences::HandleColor)); 147 renderService.renderPointHandle(m_position); 148 renderService.renderPointHandle(m_position + radius * camera.right()); 149 } 150 renderHandle3D(Renderer::RenderContext & renderContext,Renderer::RenderBatch & renderBatch)151 void RotateObjectsHandle::renderHandle3D(Renderer::RenderContext& renderContext, Renderer::RenderBatch& renderBatch) { 152 const float radius = static_cast<float>(pref(Preferences::RotateHandleRadius)); 153 154 Vec3f xAxis, yAxis, zAxis; 155 computeAxes(renderContext.camera().position(), xAxis, yAxis, zAxis); 156 157 Renderer::RenderService renderService(renderContext, renderBatch); 158 renderService.setShowOccludedObjects(); 159 160 renderService.renderCoordinateSystem(BBox3f(radius).translated(m_position)); 161 162 renderService.setForegroundColor(pref(Preferences::XAxisColor)); 163 renderService.renderCircle(m_position, Math::Axis::AX, 64, radius, zAxis, yAxis); 164 renderService.setForegroundColor(pref(Preferences::YAxisColor)); 165 renderService.renderCircle(m_position, Math::Axis::AY, 64, radius, xAxis, zAxis); 166 renderService.setForegroundColor(pref(Preferences::ZAxisColor)); 167 renderService.renderCircle(m_position, Math::Axis::AZ, 64, radius, xAxis, yAxis); 168 169 /* 170 renderService.renderCircle(m_position, Math::Axis::AX, 8, radius, 171 Quatf(Vec3f::PosX, Math::radians(+15.0f)) * yAxis, 172 Quatf(Vec3f::PosX, Math::radians(-15.0f)) * yAxis); 173 renderService.renderCircle(m_position, Math::Axis::AY, 8, radius, 174 Quatf(Vec3f::PosY, Math::radians(+15.0f)) * zAxis, 175 Quatf(Vec3f::PosY, Math::radians(-15.0f)) * zAxis); 176 renderService.renderCircle(m_position, Math::Axis::AZ, 8, radius, 177 Quatf(Vec3f::PosZ, Math::radians(+15.0f)) * xAxis, 178 Quatf(Vec3f::PosZ, Math::radians(-15.0f)) * xAxis); 179 180 */ 181 renderService.setForegroundColor(pref(Preferences::HandleColor)); 182 renderService.renderPointHandle(m_position); 183 184 renderService.setForegroundColor(pref(Preferences::ZAxisColor)); 185 renderService.renderPointHandle(m_position + radius * xAxis); 186 187 renderService.setForegroundColor(pref(Preferences::XAxisColor)); 188 renderService.renderPointHandle(m_position + radius * yAxis); 189 190 renderService.setForegroundColor(pref(Preferences::YAxisColor)); 191 renderService.renderPointHandle(m_position + radius * zAxis); 192 193 } 194 renderHighlight2D(Renderer::RenderContext & renderContext,Renderer::RenderBatch & renderBatch,const HitArea area)195 void RotateObjectsHandle::renderHighlight2D(Renderer::RenderContext& renderContext, Renderer::RenderBatch& renderBatch, const HitArea area) { 196 const float radius = static_cast<float>(pref(Preferences::RotateHandleRadius)); 197 const Renderer::Camera& camera = renderContext.camera(); 198 199 Renderer::RenderService renderService(renderContext, renderBatch); 200 renderService.setForegroundColor(pref(Preferences::SelectedHandleColor)); 201 renderService.setShowOccludedObjects(); 202 203 switch (area) { 204 case RotateObjectsHandle::HitArea_Center: 205 renderService.renderPointHandleHighlight(m_position); 206 break; 207 case RotateObjectsHandle::HitArea_XAxis: 208 case RotateObjectsHandle::HitArea_YAxis: 209 case RotateObjectsHandle::HitArea_ZAxis: 210 renderService.renderPointHandleHighlight(m_position + radius * camera.right()); 211 break; 212 case RotateObjectsHandle::HitArea_None: 213 break; 214 switchDefault() 215 }; 216 } 217 renderHighlight3D(Renderer::RenderContext & renderContext,Renderer::RenderBatch & renderBatch,const HitArea area)218 void RotateObjectsHandle::renderHighlight3D(Renderer::RenderContext& renderContext, Renderer::RenderBatch& renderBatch, const HitArea area) { 219 const float radius = static_cast<float>(pref(Preferences::RotateHandleRadius)); 220 Vec3f xAxis, yAxis, zAxis; 221 computeAxes(renderContext.camera().position(), xAxis, yAxis, zAxis); 222 223 Renderer::RenderService renderService(renderContext, renderBatch); 224 renderService.setForegroundColor(pref(Preferences::SelectedHandleColor)); 225 renderService.setShowOccludedObjects(); 226 227 switch (area) { 228 case RotateObjectsHandle::HitArea_Center: 229 renderService.renderPointHandleHighlight(m_position); 230 renderService.setForegroundColor(pref(Preferences::InfoOverlayTextColor)); 231 renderService.setBackgroundColor(pref(Preferences::InfoOverlayBackgroundColor)); 232 renderService.renderString(m_position.asString(), m_position); 233 break; 234 case RotateObjectsHandle::HitArea_XAxis: 235 renderService.renderPointHandleHighlight(m_position + radius * xAxis); 236 break; 237 case RotateObjectsHandle::HitArea_YAxis: 238 renderService.renderPointHandleHighlight(m_position + radius * yAxis); 239 break; 240 case RotateObjectsHandle::HitArea_ZAxis: 241 renderService.renderPointHandleHighlight(m_position + radius * zAxis); 242 break; 243 case RotateObjectsHandle::HitArea_None: 244 break; 245 switchDefault() 246 }; 247 } 248 249 /* 250 void RotateObjectsHandle::renderAngle(Renderer::RenderContext& renderContext, const HitArea handle, const FloatType angle) { 251 252 PreferenceManager& prefs = PreferenceManager::instance(); 253 const float handleRadius = static_cast<float>(prefs.get(Preferences::RotateHandleRadius)); 254 const Color& pointHandleColor = prefs.get(Preferences::RotateHandleColor); 255 256 const Vec3f rotationAxis(getRotationAxis(handle)); 257 const Vec3f startAxis(getPointHandleAxis(handle)); 258 const Vec3f endAxis(Quat3(rotationAxis, angle) * startAxis); 259 260 Renderer::SetVboState setVboState(m_vbo); 261 setVboState.active(); 262 263 glAssert(glDisable(GL_DEPTH_TEST)); 264 { 265 glAssert(glDisable(GL_CULL_FACE)); 266 glAssert(glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)); 267 Renderer::MultiplyModelMatrix translation(renderContext.transformation(), translationMatrix(m_position)); 268 Renderer::ActiveShader shader(renderContext.shaderManager(), Renderer::Shaders::VaryingPUniformCShader); 269 shader.set("Color", getAngleIndicatorColor(handle)); 270 271 Renderer::Circle circle(handleRadius, 24, true, rotationAxis.firstComponent(), startAxis, endAxis); 272 273 setVboState.mapped(); 274 circle.prepare(m_vbo); 275 276 setVboState.active(); 277 circle.render(); 278 279 glAssert(glPolygonMode(GL_FRONT, GL_FILL)); 280 glAssert(glEnable(GL_CULL_FACE)); 281 } 282 283 m_pointHandleRenderer.setColor(pointHandleColor); 284 m_pointHandleRenderer.renderSingleHandle(renderContext, m_position); 285 m_pointHandleRenderer.renderSingleHandle(renderContext, getPointHandlePosition(handle)); 286 287 glAssert(glEnable(GL_DEPTH_TEST)); 288 } 289 */ 290 pickPointHandle(const Ray3 & pickRay,const Renderer::Camera & camera,const Vec3 & position,const HitArea area) const291 Model::Hit RotateObjectsHandle::pickPointHandle(const Ray3& pickRay, const Renderer::Camera& camera, const Vec3& position, const HitArea area) const { 292 const FloatType distance = camera.pickPointHandle(pickRay, position, pref(Preferences::HandleRadius)); 293 if (Math::isnan(distance)) 294 return Model::Hit::NoHit; 295 return Model::Hit(HandleHit, distance, pickRay.pointAtDistance(distance), area); 296 } 297 selectHit(const Model::Hit & closest,const Model::Hit & hit) const298 Model::Hit RotateObjectsHandle::selectHit(const Model::Hit& closest, const Model::Hit& hit) const { 299 if (!closest.isMatch()) 300 return hit; 301 if (hit.isMatch()) { 302 if (hit.distance() < closest.distance()) 303 return hit; 304 } 305 return closest; 306 } 307 getPointHandlePosition(const Vec3 & axis) const308 Vec3 RotateObjectsHandle::getPointHandlePosition(const Vec3& axis) const { 309 PreferenceManager& prefs = PreferenceManager::instance(); 310 return m_position + axis * prefs.get(Preferences::RotateHandleRadius); 311 } 312 getAngleIndicatorColor(const HitArea area) const313 Color RotateObjectsHandle::getAngleIndicatorColor(const HitArea area) const { 314 PreferenceManager& prefs = PreferenceManager::instance(); 315 switch (area) { 316 case HitArea_XAxis: 317 return Color(prefs.get(Preferences::ZAxisColor), 0.5f); 318 case HitArea_YAxis: 319 return Color(prefs.get(Preferences::XAxisColor), 0.5f); 320 case HitArea_ZAxis: 321 return Color(prefs.get(Preferences::YAxisColor), 0.5f); 322 case HitArea_Center: 323 case HitArea_None: 324 return Color(1.0f, 1.0f, 1.0f, 1.0f); 325 switchDefault() 326 }; 327 } 328 } 329 } 330