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 "EntityBrowserView.h" 21 22 #include "Preferences.h" 23 #include "Logger.h" 24 #include "Assets/EntityDefinition.h" 25 #include "Assets/EntityDefinitionManager.h" 26 #include "Assets/EntityModel.h" 27 #include "Assets/EntityModelManager.h" 28 #include "Assets/ModelDefinition.h" 29 #include "Renderer/GL.h" 30 #include "Renderer/FontDescriptor.h" 31 #include "Renderer/FontManager.h" 32 #include "Renderer/ShaderManager.h" 33 #include "Renderer/Shaders.h" 34 #include "Renderer/TextureFont.h" 35 #include "Renderer/Transformation.h" 36 #include "Renderer/TexturedIndexRangeRenderer.h" 37 #include "Renderer/Vertex.h" 38 #include "Renderer/VertexArray.h" 39 #include "View/MapFrame.h" 40 #include "View/ViewUtils.h" 41 #include "View/wxUtils.h" 42 43 #include <map> 44 45 namespace TrenchBroom { 46 namespace View { EntityCellData(Assets::PointEntityDefinition * i_entityDefinition,EntityRenderer * i_modelRenderer,const Renderer::FontDescriptor & i_fontDescriptor,const BBox3f & i_bounds)47 EntityCellData::EntityCellData(Assets::PointEntityDefinition* i_entityDefinition, EntityRenderer* i_modelRenderer, const Renderer::FontDescriptor& i_fontDescriptor, const BBox3f& i_bounds) : 48 entityDefinition(i_entityDefinition), 49 modelRenderer(i_modelRenderer), 50 fontDescriptor(i_fontDescriptor), 51 bounds(i_bounds) {} 52 EntityBrowserView(wxWindow * parent,wxScrollBar * scrollBar,GLContextManager & contextManager,Assets::EntityDefinitionManager & entityDefinitionManager,Assets::EntityModelManager & entityModelManager,Logger & logger)53 EntityBrowserView::EntityBrowserView(wxWindow* parent, 54 wxScrollBar* scrollBar, 55 GLContextManager& contextManager, 56 Assets::EntityDefinitionManager& entityDefinitionManager, 57 Assets::EntityModelManager& entityModelManager, 58 Logger& logger) : 59 CellView(parent, contextManager, buildAttribs(), scrollBar), 60 m_entityDefinitionManager(entityDefinitionManager), 61 m_entityModelManager(entityModelManager), 62 m_logger(logger), 63 m_group(false), 64 m_hideUnused(false), 65 m_sortOrder(Assets::EntityDefinition::Name) { 66 const Quatf hRotation = Quatf(Vec3f::PosZ, Math::radians(-30.0f)); 67 const Quatf vRotation = Quatf(Vec3f::PosY, Math::radians(20.0f)); 68 m_rotation = vRotation * hRotation; 69 } 70 ~EntityBrowserView()71 EntityBrowserView::~EntityBrowserView() { 72 clear(); 73 } 74 setSortOrder(const Assets::EntityDefinition::SortOrder sortOrder)75 void EntityBrowserView::setSortOrder(const Assets::EntityDefinition::SortOrder sortOrder) { 76 if (sortOrder == m_sortOrder) 77 return; 78 m_sortOrder = sortOrder; 79 reload(); 80 Refresh(); 81 } 82 setGroup(const bool group)83 void EntityBrowserView::setGroup(const bool group) { 84 if (group == m_group) 85 return; 86 m_group = group; 87 reload(); 88 Refresh(); 89 } 90 setHideUnused(const bool hideUnused)91 void EntityBrowserView::setHideUnused(const bool hideUnused) { 92 if (hideUnused == m_hideUnused) 93 return; 94 m_hideUnused = hideUnused; 95 reload(); 96 Refresh(); 97 } 98 setFilterText(const String & filterText)99 void EntityBrowserView::setFilterText(const String& filterText) { 100 if (filterText == m_filterText) 101 return; 102 m_filterText = filterText; 103 reload(); 104 Refresh(); 105 } 106 doInitLayout(Layout & layout)107 void EntityBrowserView::doInitLayout(Layout& layout) { 108 layout.setOuterMargin(5.0f); 109 layout.setGroupMargin(5.0f); 110 layout.setRowMargin(5.0f); 111 layout.setCellMargin(5.0f); 112 layout.setCellWidth(93.0f, 93.0f); 113 layout.setCellHeight(64.0f, 128.0f); 114 layout.setMaxUpScale(1.5f); 115 } 116 doReloadLayout(Layout & layout)117 void EntityBrowserView::doReloadLayout(Layout& layout) { 118 const IO::Path& fontPath = pref(Preferences::RendererFontPath()); 119 int fontSize = pref(Preferences::BrowserFontSize); 120 assert(fontSize > 0); 121 122 const Renderer::FontDescriptor font(fontPath, static_cast<size_t>(fontSize)); 123 124 if (m_group) { 125 const Assets::EntityDefinitionGroup::List& groups = m_entityDefinitionManager.groups(); 126 Assets::EntityDefinitionGroup::List::const_iterator groupIt, groupEnd; 127 128 for (groupIt = groups.begin(), groupEnd = groups.end(); groupIt != groupEnd; ++groupIt) { 129 const Assets::EntityDefinitionGroup& group = *groupIt; 130 const Assets::EntityDefinitionList& definitions = group.definitions(Assets::EntityDefinition::Type_PointEntity, m_sortOrder); 131 132 if (!definitions.empty()) { 133 const String displayName = group.displayName(); 134 layout.addGroup(displayName, fontSize + 2.0f); 135 136 Assets::EntityDefinitionList::const_iterator defIt, defEnd; 137 for (defIt = definitions.begin(), defEnd = definitions.end(); defIt != defEnd; ++defIt) { 138 Assets::PointEntityDefinition* definition = static_cast<Assets::PointEntityDefinition*>(*defIt); 139 addEntityToLayout(layout, definition, font); 140 } 141 } 142 } 143 } else { 144 const Assets::EntityDefinitionList& definitions = m_entityDefinitionManager.definitions(Assets::EntityDefinition::Type_PointEntity, m_sortOrder); 145 Assets::EntityDefinitionList::const_iterator it, end; 146 for (it = definitions.begin(), end = definitions.end(); it != end; ++it) { 147 Assets::PointEntityDefinition* definition = static_cast<Assets::PointEntityDefinition*>(*it); 148 addEntityToLayout(layout, definition, font); 149 } 150 } 151 } 152 dndEnabled()153 bool EntityBrowserView::dndEnabled() { 154 return true; 155 } 156 dndWillStart()157 void EntityBrowserView::dndWillStart() { 158 MapFrame* mapFrame = findMapFrame(this); 159 assert(mapFrame != NULL); 160 mapFrame->setToolBoxDropTarget(); 161 } 162 dndDidEnd()163 void EntityBrowserView::dndDidEnd() { 164 MapFrame* mapFrame = findMapFrame(this); 165 assert(mapFrame != NULL); 166 mapFrame->clearDropTarget(); 167 } 168 dndData(const Layout::Group::Row::Cell & cell)169 wxString EntityBrowserView::dndData(const Layout::Group::Row::Cell& cell) { 170 static const String prefix("entity:"); 171 const String name = cell.item().entityDefinition->name(); 172 return wxString(prefix + name); 173 } 174 addEntityToLayout(Layout & layout,Assets::PointEntityDefinition * definition,const Renderer::FontDescriptor & font)175 void EntityBrowserView::addEntityToLayout(Layout& layout, Assets::PointEntityDefinition* definition, const Renderer::FontDescriptor& font) { 176 if ((!m_hideUnused || definition->usageCount() > 0) && 177 (m_filterText.empty() || StringUtils::containsCaseInsensitive(definition->name(), m_filterText))) { 178 179 const float maxCellWidth = layout.maxCellWidth(); 180 const Renderer::FontDescriptor actualFont = fontManager().selectFontSize(font, definition->name(), maxCellWidth, 5); 181 const Vec2f actualSize = fontManager().font(actualFont).measure(definition->name()); 182 183 const Assets::ModelSpecification spec = definition->defaultModel(); 184 Assets::EntityModel* model = safeGetModel(m_entityModelManager, spec, m_logger); 185 EntityRenderer* modelRenderer = NULL; 186 187 BBox3f rotatedBounds; 188 if (model != NULL) { 189 const Vec3f center = model->bounds(spec.skinIndex, spec.frameIndex).center(); 190 const Mat4x4f transformation = translationMatrix(center) * rotationMatrix(m_rotation) * translationMatrix(-center); 191 rotatedBounds = model->transformedBounds(spec.skinIndex, spec.frameIndex, transformation); 192 modelRenderer = m_entityModelManager.renderer(spec); 193 } else { 194 rotatedBounds = BBox3f(definition->bounds()); 195 const Vec3f center = rotatedBounds.center(); 196 rotatedBounds = rotateBBox(rotatedBounds, m_rotation, center); 197 } 198 199 const Vec3f size = rotatedBounds.size(); 200 layout.addItem(EntityCellData(definition, modelRenderer, actualFont, rotatedBounds), 201 size.y(), 202 size.z(), 203 actualSize.x(), 204 font.size() + 2.0f); 205 } 206 } 207 doClear()208 void EntityBrowserView::doClear() {} 209 doRender(Layout & layout,const float y,const float height)210 void EntityBrowserView::doRender(Layout& layout, const float y, const float height) { 211 const float viewLeft = static_cast<float>(GetClientRect().GetLeft()); 212 const float viewTop = static_cast<float>(GetClientRect().GetBottom()); 213 const float viewRight = static_cast<float>(GetClientRect().GetRight()); 214 const float viewBottom = static_cast<float>(GetClientRect().GetTop()); 215 216 const Mat4x4f projection = orthoMatrix(-1024.0f, 1024.0f, viewLeft, viewTop, viewRight, viewBottom); 217 const Mat4x4f view = viewMatrix(Vec3f::NegX, Vec3f::PosZ) * translationMatrix(Vec3f(256.0f, 0.0f, 0.0f)); 218 Renderer::Transformation transformation(projection, view); 219 220 renderBounds(layout, y, height); 221 renderModels(layout, y, height, transformation); 222 renderNames(layout, y, height, projection); 223 } 224 doShouldRenderFocusIndicator() const225 bool EntityBrowserView::doShouldRenderFocusIndicator() const { 226 return false; 227 } 228 229 template <typename Vertex> 230 struct CollectBoundsVertices { 231 const Mat4x4f& transformation; 232 const Color& color; 233 typename Vertex::List& vertices; 234 CollectBoundsVerticesTrenchBroom::View::CollectBoundsVertices235 CollectBoundsVertices(const Mat4x4f& i_transformation, const Color& i_color, typename Vertex::List& i_vertices) : 236 transformation(i_transformation), 237 color(i_color), 238 vertices(i_vertices) {} 239 operator ()TrenchBroom::View::CollectBoundsVertices240 void operator()(const Vec3f& v1, const Vec3f& v2) { 241 vertices.push_back(Vertex(transformation * v1, color)); 242 vertices.push_back(Vertex(transformation * v2, color)); 243 } 244 }; 245 renderBounds(Layout & layout,const float y,const float height)246 void EntityBrowserView::renderBounds(Layout& layout, const float y, const float height) { 247 typedef Renderer::VertexSpecs::P3C4::Vertex BoundsVertex; 248 BoundsVertex::List vertices; 249 250 for (size_t i = 0; i < layout.size(); ++i) { 251 const Layout::Group& group = layout[i]; 252 if (group.intersectsY(y, height)) { 253 for (size_t j = 0; j < group.size(); ++j) { 254 const Layout::Group::Row& row = group[j]; 255 if (row.intersectsY(y, height)) { 256 for (size_t k = 0; k < row.size(); ++k) { 257 const Layout::Group::Row::Cell& cell = row[k]; 258 Assets::PointEntityDefinition* definition = cell.item().entityDefinition; 259 EntityRenderer* modelRenderer = cell.item().modelRenderer; 260 261 if (modelRenderer == NULL) { 262 const Mat4x4f itemTrans = itemTransformation(cell, y, height); 263 const Color& color = definition->color(); 264 CollectBoundsVertices<BoundsVertex> collect(itemTrans, color, vertices); 265 eachBBoxEdge(definition->bounds(), collect); 266 } 267 } 268 } 269 } 270 } 271 } 272 273 Renderer::ActiveShader shader(shaderManager(), Renderer::Shaders::VaryingPCShader); 274 Renderer::VertexArray vertexArray = Renderer::VertexArray::swap(vertices); 275 276 Renderer::ActivateVbo activate(vertexVbo()); 277 vertexArray.prepare(vertexVbo()); 278 vertexArray.render(GL_LINES); 279 } 280 renderModels(Layout & layout,const float y,const float height,Renderer::Transformation & transformation)281 void EntityBrowserView::renderModels(Layout& layout, const float y, const float height, Renderer::Transformation& transformation) { 282 Renderer::ActiveShader shader(shaderManager(), Renderer::Shaders::EntityModelShader); 283 shader.set("ApplyTinting", false); 284 shader.set("Brightness", pref(Preferences::Brightness)); 285 shader.set("GrayScale", false); 286 287 glAssert(glFrontFace(GL_CW)); 288 289 Renderer::ActivateVbo activate(vertexVbo()); 290 m_entityModelManager.prepare(vertexVbo()); 291 292 for (size_t i = 0; i < layout.size(); ++i) { 293 const Layout::Group& group = layout[i]; 294 if (group.intersectsY(y, height)) { 295 for (size_t j = 0; j < group.size(); ++j) { 296 const Layout::Group::Row& row = group[j]; 297 if (row.intersectsY(y, height)) { 298 for (size_t k = 0; k < row.size(); ++k) { 299 const Layout::Group::Row::Cell& cell = row[k]; 300 EntityRenderer* modelRenderer = cell.item().modelRenderer; 301 302 if (modelRenderer != NULL) { 303 const Mat4x4f itemTrans = itemTransformation(cell, y, height); 304 Renderer::MultiplyModelMatrix multMatrix(transformation, itemTrans); 305 modelRenderer->render(); 306 } 307 } 308 } 309 } 310 } 311 } 312 } 313 renderNames(Layout & layout,const float y,const float height,const Mat4x4f & projection)314 void EntityBrowserView::renderNames(Layout& layout, const float y, const float height, const Mat4x4f& projection) { 315 Renderer::Transformation transformation = Renderer::Transformation(projection, viewMatrix(Vec3f::NegZ, Vec3f::PosY) * translationMatrix(Vec3f(0.0f, 0.0f, -1.0f))); 316 317 Renderer::ActivateVbo activate(vertexVbo()); 318 319 glAssert(glDisable(GL_DEPTH_TEST)); 320 glAssert(glFrontFace(GL_CCW)); 321 renderGroupTitleBackgrounds(layout, y, height); 322 renderStrings(layout, y, height); 323 glAssert(glFrontFace(GL_CW)); 324 } 325 renderGroupTitleBackgrounds(Layout & layout,const float y,const float height)326 void EntityBrowserView::renderGroupTitleBackgrounds(Layout& layout, const float y, const float height) { 327 typedef Renderer::VertexSpecs::P2::Vertex Vertex; 328 Vertex::List vertices; 329 330 for (size_t i = 0; i < layout.size(); ++i) { 331 const Layout::Group& group = layout[i]; 332 if (group.intersectsY(y, height)) { 333 const LayoutBounds titleBounds = layout.titleBoundsForVisibleRect(group, y, height); 334 vertices.push_back(Vertex(Vec2f(titleBounds.left(), height - (titleBounds.top() - y)))); 335 vertices.push_back(Vertex(Vec2f(titleBounds.left(), height - (titleBounds.bottom() - y)))); 336 vertices.push_back(Vertex(Vec2f(titleBounds.right(), height - (titleBounds.bottom() - y)))); 337 vertices.push_back(Vertex(Vec2f(titleBounds.right(), height - (titleBounds.top() - y)))); 338 } 339 } 340 341 Renderer::VertexArray vertexArray = Renderer::VertexArray::swap(vertices); 342 Renderer::ActiveShader shader(shaderManager(), Renderer::Shaders::BrowserGroupShader); 343 shader.set("Color", pref(Preferences::BrowserGroupBackgroundColor)); 344 345 Renderer::ActivateVbo activate(vertexVbo()); 346 vertexArray.prepare(vertexVbo()); 347 vertexArray.render(GL_QUADS); 348 } 349 renderStrings(Layout & layout,const float y,const float height)350 void EntityBrowserView::renderStrings(Layout& layout, const float y, const float height) { 351 typedef std::map<Renderer::FontDescriptor, Renderer::VertexArray> StringRendererMap; 352 StringRendererMap stringRenderers; 353 354 { // create and upload all vertex arrays 355 Renderer::ActivateVbo activate(vertexVbo()); 356 357 const StringMap stringVertices = collectStringVertices(layout, y, height); 358 StringMap::const_iterator it, end; 359 for (it = stringVertices.begin(), end = stringVertices.end(); it != end; ++it) { 360 const Renderer::FontDescriptor& descriptor = it->first; 361 const TextVertex::List& vertices = it->second; 362 stringRenderers[descriptor] = Renderer::VertexArray::ref(vertices); 363 stringRenderers[descriptor].prepare(vertexVbo()); 364 } 365 } 366 367 Renderer::ActiveShader shader(shaderManager(), Renderer::Shaders::ColoredTextShader); 368 shader.set("Texture", 0); 369 370 StringRendererMap::iterator it, end; 371 for (it = stringRenderers.begin(), end = stringRenderers.end(); it != end; ++it) { 372 const Renderer::FontDescriptor& descriptor = it->first; 373 Renderer::VertexArray& vertexArray = it->second; 374 375 Renderer::TextureFont& font = fontManager().font(descriptor); 376 font.activate(); 377 vertexArray.render(GL_QUADS); 378 font.deactivate(); 379 } 380 } 381 collectStringVertices(Layout & layout,const float y,const float height)382 EntityBrowserView::StringMap EntityBrowserView::collectStringVertices(Layout& layout, const float y, const float height) { 383 Renderer::FontDescriptor defaultDescriptor(pref(Preferences::RendererFontPath()), 384 static_cast<size_t>(pref(Preferences::BrowserFontSize))); 385 386 const Color::List textColor(1, pref(Preferences::BrowserTextColor)); 387 388 StringMap stringVertices; 389 for (size_t i = 0; i < layout.size(); ++i) { 390 const Layout::Group& group = layout[i]; 391 if (group.intersectsY(y, height)) { 392 const String& title = group.item(); 393 if (!title.empty()) { 394 const LayoutBounds titleBounds = layout.titleBoundsForVisibleRect(group, y, height); 395 const Vec2f offset(titleBounds.left() + 2.0f, height - (titleBounds.top() - y) - titleBounds.height()); 396 397 Renderer::TextureFont& font = fontManager().font(defaultDescriptor); 398 const Vec2f::List quads = font.quads(title, false, offset); 399 const TextVertex::List titleVertices = TextVertex::fromLists(quads, quads, textColor, quads.size() / 2, 0, 2, 1, 2, 0, 0); 400 VectorUtils::append(stringVertices[defaultDescriptor], titleVertices); 401 } 402 403 for (size_t j = 0; j < group.size(); ++j) { 404 const Layout::Group::Row& row = group[j]; 405 if (row.intersectsY(y, height)) { 406 for (unsigned int k = 0; k < row.size(); k++) { 407 const Layout::Group::Row::Cell& cell = row[k]; 408 const LayoutBounds titleBounds = cell.titleBounds(); 409 const Vec2f offset(titleBounds.left(), height - (titleBounds.top() - y) - titleBounds.height()); 410 411 Renderer::TextureFont& font = fontManager().font(cell.item().fontDescriptor); 412 const Vec2f::List quads = font.quads(cell.item().entityDefinition->name(), false, offset); 413 const TextVertex::List titleVertices = TextVertex::fromLists(quads, quads, textColor, quads.size() / 2, 0, 2, 1, 2, 0, 0); 414 VectorUtils::append(stringVertices[cell.item().fontDescriptor], titleVertices); 415 } 416 } 417 } 418 } 419 } 420 421 return stringVertices; 422 } 423 itemTransformation(const Layout::Group::Row::Cell & cell,const float y,const float height) const424 Mat4x4f EntityBrowserView::itemTransformation(const Layout::Group::Row::Cell& cell, const float y, const float height) const { 425 Assets::PointEntityDefinition* definition = cell.item().entityDefinition; 426 427 const Vec3f offset = Vec3f(0.0f, cell.itemBounds().left(), height - (cell.itemBounds().bottom() - y)); 428 const float scaling = cell.scale(); 429 const BBox3f& rotatedBounds = cell.item().bounds; 430 const Vec3f rotationOffset = Vec3f(0.0f, -rotatedBounds.min.y(), -rotatedBounds.min.z()); 431 const Vec3f center = definition->bounds().center(); 432 433 return (translationMatrix(offset) * 434 scalingMatrix<4>(scaling) * 435 translationMatrix(rotationOffset) * 436 translationMatrix(center) * 437 rotationMatrix(m_rotation) * 438 translationMatrix(-center)); 439 } 440 tooltip(const Layout::Group::Row::Cell & cell)441 wxString EntityBrowserView::tooltip(const Layout::Group::Row::Cell& cell) { 442 return cell.item().entityDefinition->name(); 443 } 444 } 445 } 446