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 "UVOffsetTool.h" 21 22 #include "Model/BrushFace.h" 23 #include "Model/BrushGeometry.h" 24 #include "Model/ChangeBrushFaceAttributesRequest.h" 25 #include "View/InputState.h" 26 #include "View/MapDocument.h" 27 #include "View/UVView.h" 28 29 #include <cassert> 30 31 namespace TrenchBroom { 32 namespace View { UVOffsetTool(MapDocumentWPtr document,const UVViewHelper & helper)33 UVOffsetTool::UVOffsetTool(MapDocumentWPtr document, const UVViewHelper& helper) : 34 ToolControllerBase(), 35 Tool(true), 36 m_document(document), 37 m_helper(helper) {} 38 doGetTool()39 Tool* UVOffsetTool::doGetTool() { 40 return this; 41 } 42 doStartMouseDrag(const InputState & inputState)43 bool UVOffsetTool::doStartMouseDrag(const InputState& inputState) { 44 assert(m_helper.valid()); 45 46 if (!inputState.modifierKeysPressed(ModifierKeys::MKNone) || 47 !inputState.mouseButtonsPressed(MouseButtons::MBLeft)) 48 return false; 49 50 m_lastPoint = computeHitPoint(inputState.pickRay()); 51 52 MapDocumentSPtr document = lock(m_document); 53 document->beginTransaction("Move Texture"); 54 return true; 55 } 56 doMouseDrag(const InputState & inputState)57 bool UVOffsetTool::doMouseDrag(const InputState& inputState) { 58 assert(m_helper.valid()); 59 60 const Vec2f curPoint = computeHitPoint(inputState.pickRay()); 61 const Vec2f delta = curPoint - m_lastPoint; 62 const Vec2f snapped = snapDelta(delta); 63 64 const Model::BrushFace* face = m_helper.face(); 65 const Vec2f corrected = (face->offset() - snapped).corrected(4, 0.0f); 66 67 if (corrected == face->offset()) 68 return true; 69 70 Model::ChangeBrushFaceAttributesRequest request; 71 request.setOffset(corrected); 72 73 MapDocumentSPtr document = lock(m_document); 74 document->setFaceAttributes(request); 75 76 m_lastPoint += snapped; 77 return true; 78 } 79 doEndMouseDrag(const InputState & inputState)80 void UVOffsetTool::doEndMouseDrag(const InputState& inputState) { 81 MapDocumentSPtr document = lock(m_document); 82 document->commitTransaction(); 83 } 84 doCancelMouseDrag()85 void UVOffsetTool::doCancelMouseDrag() { 86 MapDocumentSPtr document = lock(m_document); 87 document->cancelTransaction(); 88 } 89 computeHitPoint(const Ray3 & ray) const90 Vec2f UVOffsetTool::computeHitPoint(const Ray3& ray) const { 91 const Model::BrushFace* face = m_helper.face(); 92 const Plane3& boundary = face->boundary(); 93 const FloatType distance = boundary.intersectWithRay(ray); 94 const Vec3 hitPoint = ray.pointAtDistance(distance); 95 96 const Mat4x4 transform = face->toTexCoordSystemMatrix(Vec2f::Null, face->scale(), true); 97 return Vec2f(transform * hitPoint); 98 } 99 snapDelta(const Vec2f & delta) const100 Vec2f UVOffsetTool::snapDelta(const Vec2f& delta) const { 101 const Model::BrushFace* face = m_helper.face(); 102 assert(face != NULL); 103 104 const Assets::Texture* texture = face->texture(); 105 if (texture == NULL) 106 return delta.rounded(); 107 108 const Mat4x4 transform = face->toTexCoordSystemMatrix(face->offset() - delta, face->scale(), true); 109 110 Vec2f distance = Vec2f::Max; 111 const Model::BrushFace::VertexList vertices = face->vertices(); 112 Model::BrushFace::VertexList::const_iterator it, end; 113 for (it = vertices.begin(), end = vertices.end(); it != end; ++it) { 114 const Model::BrushVertex* vertex = *it; 115 const Vec2f temp = m_helper.computeDistanceFromTextureGrid(transform * vertex->position()); 116 distance = absMin(distance, temp); 117 } 118 119 return m_helper.snapDelta(delta, -distance); 120 } 121 doCancel()122 bool UVOffsetTool::doCancel() { 123 return false; 124 } 125 } 126 } 127