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