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 "CreateEntityTool.h" 21 22 #include "PreferenceManager.h" 23 #include "Preferences.h" 24 #include "Assets/EntityDefinition.h" 25 #include "Assets/EntityDefinitionManager.h" 26 #include "Assets/EntityModelManager.h" 27 #include "Assets/ModelDefinition.h" 28 #include "Model/Brush.h" 29 #include "Model/BrushFace.h" 30 #include "Model/Entity.h" 31 #include "Model/HitAdapter.h" 32 #include "Model/Hit.h" 33 #include "Model/HitQuery.h" 34 #include "Model/Layer.h" 35 #include "Model/PickResult.h" 36 #include "Model/World.h" 37 #include "Renderer/Camera.h" 38 #include "View/Grid.h" 39 #include "View/MapDocument.h" 40 41 #include <cassert> 42 43 namespace TrenchBroom { 44 namespace View { CreateEntityTool(MapDocumentWPtr document)45 CreateEntityTool::CreateEntityTool(MapDocumentWPtr document) : 46 Tool(true), 47 m_document(document), 48 m_entity(NULL) {} 49 createEntity(const String & classname)50 bool CreateEntityTool::createEntity(const String& classname) { 51 MapDocumentSPtr document = lock(m_document); 52 const Assets::EntityDefinitionManager& definitionManager = document->entityDefinitionManager(); 53 Assets::EntityDefinition* definition = definitionManager.definition(classname); 54 if (definition == NULL) 55 return false; 56 57 if (definition->type() != Assets::EntityDefinition::Type_PointEntity) 58 return false; 59 60 const Model::World* world = document->world(); 61 m_entity = world->createEntity(); 62 m_entity->addOrUpdateAttribute(Model::AttributeNames::Classname, definition->name()); 63 64 m_referenceBounds = document->referenceBounds(); 65 66 document->beginTransaction("Create '" + definition->name() + "'"); 67 document->deselectAll(); 68 document->addNode(m_entity, document->currentParent()); 69 document->select(m_entity); 70 71 return true; 72 } 73 removeEntity()74 void CreateEntityTool::removeEntity() { 75 assert(m_entity != NULL); 76 MapDocumentSPtr document = lock(m_document); 77 document->cancelTransaction(); 78 m_entity = NULL; 79 } 80 commitEntity()81 void CreateEntityTool::commitEntity() { 82 assert(m_entity != NULL); 83 MapDocumentSPtr document = lock(m_document); 84 document->commitTransaction(); 85 m_entity = NULL; 86 } 87 updateEntityPosition2D(const Ray3 & pickRay)88 void CreateEntityTool::updateEntityPosition2D(const Ray3& pickRay) { 89 assert(m_entity != NULL); 90 91 MapDocumentSPtr document = lock(m_document); 92 93 const Vec3 toMin = m_referenceBounds.min - pickRay.origin; 94 const Vec3 toMax = m_referenceBounds.max - pickRay.origin; 95 const Vec3 anchor = toMin.dot(pickRay.direction) > toMax.dot(pickRay.direction) ? m_referenceBounds.min : m_referenceBounds.max; 96 const Plane3 dragPlane(anchor, -pickRay.direction); 97 98 const FloatType distance = dragPlane.intersectWithRay(pickRay); 99 if (Math::isnan(distance)) 100 return; 101 102 const Vec3 hitPoint = pickRay.pointAtDistance(distance); 103 104 const Grid& grid = document->grid(); 105 const Vec3 delta = grid.moveDeltaForBounds(dragPlane, m_entity->bounds(), document->worldBounds(), pickRay, hitPoint); 106 107 if (delta.null()) 108 return; 109 110 document->translateObjects(delta); 111 } 112 updateEntityPosition3D(const Ray3 & pickRay,const Model::PickResult & pickResult)113 void CreateEntityTool::updateEntityPosition3D(const Ray3& pickRay, const Model::PickResult& pickResult) { 114 assert(m_entity != NULL); 115 116 MapDocumentSPtr document = lock(m_document); 117 118 Vec3 delta; 119 const Grid& grid = document->grid(); 120 const Model::Hit& hit = pickResult.query().pickable().type(Model::Brush::BrushHit).occluded().first(); 121 if (hit.isMatch()) { 122 const Model::BrushFace* face = Model::hitToFace(hit); 123 const Plane3 dragPlane = alignedOrthogonalDragPlane(hit.hitPoint(), face->boundary().normal); 124 delta = grid.moveDeltaForBounds(dragPlane, m_entity->bounds(), document->worldBounds(), pickRay, hit.hitPoint()); 125 } else { 126 const Vec3 newPosition = pickRay.pointAtDistance(Renderer::Camera::DefaultPointDistance); 127 const Vec3 center = m_entity->bounds().center(); 128 delta = grid.moveDeltaForPoint(center, document->worldBounds(), newPosition - center); 129 } 130 131 if (delta.null()) 132 return; 133 134 document->translateObjects(delta); 135 } 136 } 137 } 138