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 "TextureBrowserView.h" 21 22 #include "Renderer/GL.h" 23 #include "PreferenceManager.h" 24 #include "Preferences.h" 25 #include "Assets/Texture.h" 26 #include "Assets/TextureCollection.h" 27 #include "Renderer/FontManager.h" 28 #include "Renderer/Shaders.h" 29 #include "Renderer/ShaderManager.h" 30 #include "Renderer/TextureFont.h" 31 #include "Renderer/VertexArray.h" 32 #include "View/TextureSelectedCommand.h" 33 34 namespace TrenchBroom { 35 namespace View { TextureCellData(Assets::Texture * i_texture,const Renderer::FontDescriptor & i_fontDescriptor)36 TextureCellData::TextureCellData(Assets::Texture* i_texture, const Renderer::FontDescriptor& i_fontDescriptor) : 37 texture(i_texture), 38 fontDescriptor(i_fontDescriptor) {} 39 TextureBrowserView(wxWindow * parent,wxScrollBar * scrollBar,GLContextManager & contextManager,Assets::TextureManager & textureManager)40 TextureBrowserView::TextureBrowserView(wxWindow* parent, 41 wxScrollBar* scrollBar, 42 GLContextManager& contextManager, 43 Assets::TextureManager& textureManager) : 44 CellView(parent, contextManager, buildAttribs(), scrollBar), 45 m_textureManager(textureManager), 46 m_group(false), 47 m_hideUnused(false), 48 m_sortOrder(Assets::TextureManager::SortOrder_Name), 49 m_selectedTexture(NULL) {} 50 ~TextureBrowserView()51 TextureBrowserView::~TextureBrowserView() { 52 clear(); 53 } 54 setSortOrder(const Assets::TextureManager::SortOrder sortOrder)55 void TextureBrowserView::setSortOrder(const Assets::TextureManager::SortOrder sortOrder) { 56 if (sortOrder == m_sortOrder) 57 return; 58 m_sortOrder = sortOrder; 59 reload(); 60 Refresh(); 61 } 62 setGroup(const bool group)63 void TextureBrowserView::setGroup(const bool group) { 64 if (group == m_group) 65 return; 66 m_group = group; 67 reload(); 68 Refresh(); 69 } 70 setHideUnused(const bool hideUnused)71 void TextureBrowserView::setHideUnused(const bool hideUnused) { 72 if (hideUnused == m_hideUnused) 73 return; 74 m_hideUnused = hideUnused; 75 reload(); 76 Refresh(); 77 } 78 setFilterText(const String & filterText)79 void TextureBrowserView::setFilterText(const String& filterText) { 80 if (filterText == m_filterText) 81 return; 82 m_filterText = filterText; 83 reload(); 84 Refresh(); 85 } 86 selectedTexture() const87 Assets::Texture* TextureBrowserView::selectedTexture() const { 88 return m_selectedTexture; 89 } 90 setSelectedTexture(Assets::Texture * selectedTexture)91 void TextureBrowserView::setSelectedTexture(Assets::Texture* selectedTexture) { 92 if (m_selectedTexture == selectedTexture) 93 return; 94 m_selectedTexture = selectedTexture; 95 Refresh(); 96 } 97 doInitLayout(Layout & layout)98 void TextureBrowserView::doInitLayout(Layout& layout) { 99 const float scaleFactor = pref(Preferences::TextureBrowserIconSize); 100 101 layout.setOuterMargin(5.0f); 102 layout.setGroupMargin(5.0f); 103 layout.setRowMargin(5.0f); 104 layout.setCellMargin(5.0f); 105 layout.setTitleMargin(2.0f); 106 layout.setCellWidth(scaleFactor * 64.0f, scaleFactor * 64.0f); 107 layout.setCellHeight(scaleFactor * 64.0f, scaleFactor * 128.0f); 108 } 109 doReloadLayout(Layout & layout)110 void TextureBrowserView::doReloadLayout(Layout& layout) { 111 const IO::Path& fontPath = pref(Preferences::RendererFontPath()); 112 int fontSize = pref(Preferences::BrowserFontSize); 113 assert(fontSize > 0); 114 115 const Renderer::FontDescriptor font(fontPath, static_cast<size_t>(fontSize)); 116 117 if (m_group) { 118 const Assets::TextureManager::GroupList& groups = m_textureManager.groups(m_sortOrder); 119 Assets::TextureManager::GroupList::const_iterator gIt, gEnd; 120 for (gIt = groups.begin(), gEnd = groups.end(); gIt != gEnd; ++gIt) { 121 const Assets::TextureCollection* collection = gIt->first; 122 const Assets::TextureList& textures = gIt->second; 123 const IO::Path collectionPath(collection->name()); 124 125 layout.addGroup(collectionPath.lastComponent().asString(), fontSize + 2.0f); 126 127 Assets::TextureList::const_iterator tIt, tEnd; 128 for (tIt = textures.begin(), tEnd = textures.end(); tIt != tEnd; ++tIt) { 129 Assets::Texture* texture = *tIt; 130 addTextureToLayout(layout, texture, font); 131 } 132 } 133 } else { 134 const Assets::TextureList& textures = m_textureManager.textures(m_sortOrder); 135 Assets::TextureList::const_iterator it, end; 136 for (it = textures.begin(), end = textures.end(); it != end; ++it) { 137 Assets::Texture* texture = *it; 138 addTextureToLayout(layout, texture, font); 139 } 140 } 141 } 142 addTextureToLayout(Layout & layout,Assets::Texture * texture,const Renderer::FontDescriptor & font)143 void TextureBrowserView::addTextureToLayout(Layout& layout, Assets::Texture* texture, const Renderer::FontDescriptor& font) { 144 if ((!m_hideUnused || texture->usageCount() > 0) && 145 (m_filterText.empty() || StringUtils::containsCaseInsensitive(texture->name(), m_filterText))) { 146 const float maxCellWidth = layout.maxCellWidth(); 147 const Renderer::FontDescriptor actualFont = fontManager().selectFontSize(font, texture->name(), maxCellWidth, 5); 148 const Vec2f actualSize = fontManager().font(actualFont).measure(texture->name()); 149 150 const float scaleFactor = pref(Preferences::TextureBrowserIconSize); 151 const size_t scaledTextureWidth = static_cast<size_t>(Math::round(scaleFactor * static_cast<float>(texture->width()))); 152 const size_t scaledTextureHeight = static_cast<size_t>(Math::round(scaleFactor * static_cast<float>(texture->height()))); 153 154 layout.addItem(TextureCellData(texture, actualFont), 155 scaledTextureWidth, 156 scaledTextureHeight, 157 actualSize.x(), 158 font.size() + 2.0f); 159 } 160 } 161 doClear()162 void TextureBrowserView::doClear() {} 163 doRender(Layout & layout,const float y,const float height)164 void TextureBrowserView::doRender(Layout& layout, const float y, const float height) { 165 m_textureManager.commitChanges(); 166 167 const float viewLeft = static_cast<float>(GetClientRect().GetLeft()); 168 const float viewTop = static_cast<float>(GetClientRect().GetBottom()); 169 const float viewRight = static_cast<float>(GetClientRect().GetRight()); 170 const float viewBottom = static_cast<float>(GetClientRect().GetTop()); 171 172 const Mat4x4f projection = orthoMatrix(-1.0f, 1.0f, viewLeft, viewTop, viewRight, viewBottom); 173 const Mat4x4f view = viewMatrix(Vec3f::NegZ, Vec3f::PosY) * translationMatrix(Vec3f(0.0f, 0.0f, 0.1f)); 174 const Renderer::Transformation transformation(projection, view); 175 176 Renderer::ActivateVbo activate(vertexVbo()); 177 178 glAssert(glDisable(GL_DEPTH_TEST)); 179 glAssert(glFrontFace(GL_CCW)); 180 181 renderBounds(layout, y, height); 182 renderTextures(layout, y, height); 183 renderNames(layout, y, height); 184 } 185 doShouldRenderFocusIndicator() const186 bool TextureBrowserView::doShouldRenderFocusIndicator() const { 187 return false; 188 } 189 renderBounds(Layout & layout,const float y,const float height)190 void TextureBrowserView::renderBounds(Layout& layout, const float y, const float height) { 191 typedef Renderer::VertexSpecs::P2C4::Vertex BoundsVertex; 192 BoundsVertex::List vertices; 193 194 for (size_t i = 0; i < layout.size(); ++i) { 195 const Layout::Group& group = layout[i]; 196 if (group.intersectsY(y, height)) { 197 for (size_t j = 0; j < group.size(); ++j) { 198 const Layout::Group::Row& row = group[j]; 199 if (row.intersectsY(y, height)) { 200 for (size_t k = 0; k < row.size(); ++k) { 201 const Layout::Group::Row::Cell& cell = row[k]; 202 const LayoutBounds& bounds = cell.itemBounds(); 203 const Assets::Texture* texture = cell.item().texture; 204 const Color& color = textureColor(*texture); 205 vertices.push_back(BoundsVertex(Vec2f(bounds.left() - 2.0f, height - (bounds.top() - 2.0f - y)), color)); 206 vertices.push_back(BoundsVertex(Vec2f(bounds.left() - 2.0f, height - (bounds.bottom() + 2.0f - y)), color)); 207 vertices.push_back(BoundsVertex(Vec2f(bounds.right() + 2.0f, height - (bounds.bottom() + 2.0f - y)), color)); 208 vertices.push_back(BoundsVertex(Vec2f(bounds.right() + 2.0f, height - (bounds.top() - 2.0f - y)), color)); 209 } 210 } 211 } 212 } 213 } 214 215 Renderer::VertexArray vertexArray = Renderer::VertexArray::swap(vertices); 216 Renderer::ActiveShader shader(shaderManager(), Renderer::Shaders::TextureBrowserBorderShader); 217 218 Renderer::ActivateVbo activate(vertexVbo()); 219 vertexArray.prepare(vertexVbo()); 220 vertexArray.render(GL_QUADS); 221 } 222 textureColor(const Assets::Texture & texture) const223 const Color& TextureBrowserView::textureColor(const Assets::Texture& texture) const { 224 if (&texture == m_selectedTexture) 225 return pref(Preferences::TextureBrowserSelectedColor); 226 if (texture.usageCount() > 0) 227 return pref(Preferences::TextureBrowserUsedColor); 228 return pref(Preferences::TextureBrowserDefaultColor); 229 } 230 renderTextures(Layout & layout,const float y,const float height)231 void TextureBrowserView::renderTextures(Layout& layout, const float y, const float height) { 232 typedef Renderer::VertexSpecs::P2T2::Vertex TextureVertex; 233 TextureVertex::List vertices(4); 234 235 Renderer::ActiveShader shader(shaderManager(), Renderer::Shaders::TextureBrowserShader); 236 shader.set("ApplyTinting", false); 237 shader.set("Texture", 0); 238 shader.set("Brightness", pref(Preferences::Brightness)); 239 240 size_t num = 0; 241 242 Renderer::ActivateVbo activate(vertexVbo()); 243 244 for (size_t i = 0; i < layout.size(); ++i) { 245 const Layout::Group& group = layout[i]; 246 if (group.intersectsY(y, height)) { 247 for (size_t j = 0; j < group.size(); ++j) { 248 const Layout::Group::Row& row = group[j]; 249 if (row.intersectsY(y, height)) { 250 for (size_t k = 0; k < row.size(); ++k) { 251 const Layout::Group::Row::Cell& cell = row[k]; 252 const LayoutBounds& bounds = cell.itemBounds(); 253 const Assets::Texture* texture = cell.item().texture; 254 255 vertices[0] = TextureVertex(Vec2f(bounds.left(), height - (bounds.top() - y)), Vec2f(0.0f, 0.0f)); 256 vertices[1] = TextureVertex(Vec2f(bounds.left(), height - (bounds.bottom() - y)), Vec2f(0.0f, 1.0f)); 257 vertices[2] = TextureVertex(Vec2f(bounds.right(), height - (bounds.bottom() - y)), Vec2f(1.0f, 1.0f)); 258 vertices[3] = TextureVertex(Vec2f(bounds.right(), height - (bounds.top() - y)), Vec2f(1.0f, 0.0f)); 259 260 Renderer::VertexArray vertexArray = Renderer::VertexArray::copy(vertices); 261 262 shader.set("GrayScale", texture->overridden()); 263 texture->activate(); 264 265 vertexArray.prepare(vertexVbo()); 266 vertexArray.render(GL_QUADS); 267 268 ++num; 269 } 270 } 271 } 272 } 273 } 274 } 275 renderNames(Layout & layout,const float y,const float height)276 void TextureBrowserView::renderNames(Layout& layout, const float y, const float height) { 277 renderGroupTitleBackgrounds(layout, y, height); 278 renderStrings(layout, y, height); 279 } 280 renderGroupTitleBackgrounds(Layout & layout,const float y,const float height)281 void TextureBrowserView::renderGroupTitleBackgrounds(Layout& layout, const float y, const float height) { 282 typedef Renderer::VertexSpecs::P2::Vertex Vertex; 283 Vertex::List vertices; 284 285 for (size_t i = 0; i < layout.size(); ++i) { 286 const Layout::Group& group = layout[i]; 287 if (group.intersectsY(y, height)) { 288 const LayoutBounds titleBounds = layout.titleBoundsForVisibleRect(group, y, height); 289 vertices.push_back(Vertex(Vec2f(titleBounds.left(), height - (titleBounds.top() - y)))); 290 vertices.push_back(Vertex(Vec2f(titleBounds.left(), height - (titleBounds.bottom() - y)))); 291 vertices.push_back(Vertex(Vec2f(titleBounds.right(), height - (titleBounds.bottom() - y)))); 292 vertices.push_back(Vertex(Vec2f(titleBounds.right(), height - (titleBounds.top() - y)))); 293 } 294 } 295 296 Renderer::ActiveShader shader(shaderManager(), Renderer::Shaders::BrowserGroupShader); 297 shader.set("Color", pref(Preferences::BrowserGroupBackgroundColor)); 298 299 Renderer::VertexArray vertexArray = Renderer::VertexArray::swap(vertices); 300 301 Renderer::ActivateVbo activate(vertexVbo()); 302 vertexArray.prepare(vertexVbo()); 303 vertexArray.render(GL_QUADS); 304 } 305 renderStrings(Layout & layout,const float y,const float height)306 void TextureBrowserView::renderStrings(Layout& layout, const float y, const float height) { 307 typedef std::map<Renderer::FontDescriptor, Renderer::VertexArray> StringRendererMap; 308 StringRendererMap stringRenderers; 309 310 Renderer::ActivateVbo activate(vertexVbo()); 311 312 { // create and upload all vertex arrays 313 const StringMap stringVertices = collectStringVertices(layout, y, height); 314 StringMap::const_iterator it, end; 315 for (it = stringVertices.begin(), end = stringVertices.end(); it != end; ++it) { 316 const Renderer::FontDescriptor& descriptor = it->first; 317 const TextVertex::List& vertices = it->second; 318 stringRenderers[descriptor] = Renderer::VertexArray::ref(vertices); 319 stringRenderers[descriptor].prepare(vertexVbo()); 320 } 321 } 322 323 Renderer::ActiveShader shader(shaderManager(), Renderer::Shaders::ColoredTextShader); 324 shader.set("Texture", 0); 325 326 StringRendererMap::iterator it, end; 327 for (it = stringRenderers.begin(), end = stringRenderers.end(); it != end; ++it) { 328 const Renderer::FontDescriptor& descriptor = it->first; 329 Renderer::VertexArray& vertexArray = it->second; 330 331 Renderer::TextureFont& font = fontManager().font(descriptor); 332 font.activate(); 333 vertexArray.render(GL_QUADS); 334 font.deactivate(); 335 } 336 } 337 collectStringVertices(Layout & layout,const float y,const float height)338 TextureBrowserView::StringMap TextureBrowserView::collectStringVertices(Layout& layout, const float y, const float height) { 339 Renderer::FontDescriptor defaultDescriptor(pref(Preferences::RendererFontPath()), 340 static_cast<size_t>(pref(Preferences::BrowserFontSize))); 341 342 const Color::List textColor(1, pref(Preferences::BrowserTextColor)); 343 344 StringMap stringVertices; 345 for (size_t i = 0; i < layout.size(); ++i) { 346 const Layout::Group& group = layout[i]; 347 if (group.intersectsY(y, height)) { 348 const String& title = group.item(); 349 if (!title.empty()) { 350 const LayoutBounds titleBounds = layout.titleBoundsForVisibleRect(group, y, height); 351 const Vec2f offset(titleBounds.left() + 2.0f, height - (titleBounds.top() - y) - titleBounds.height()); 352 353 Renderer::TextureFont& font = fontManager().font(defaultDescriptor); 354 const Vec2f::List quads = font.quads(title, false, offset); 355 const TextVertex::List titleVertices = TextVertex::fromLists(quads, quads, textColor, quads.size() / 2, 0, 2, 1, 2, 0, 0); 356 TextVertex::List& vertices = stringVertices[defaultDescriptor]; 357 vertices.insert(vertices.end(), titleVertices.begin(), titleVertices.end()); 358 } 359 360 for (size_t j = 0; j < group.size(); ++j) { 361 const Layout::Group::Row& row = group[j]; 362 if (row.intersectsY(y, height)) { 363 for (unsigned int k = 0; k < row.size(); k++) { 364 const Layout::Group::Row::Cell& cell = row[k]; 365 const LayoutBounds titleBounds = cell.titleBounds(); 366 const Vec2f offset(titleBounds.left(), height - (titleBounds.top() - y) - titleBounds.height()); 367 368 Renderer::TextureFont& font = fontManager().font(cell.item().fontDescriptor); 369 const Vec2f::List quads = font.quads(cell.item().texture->name(), false, offset); 370 const TextVertex::List titleVertices = TextVertex::fromLists(quads, quads, textColor, quads.size() / 2, 0, 2, 1, 2, 0, 0); 371 TextVertex::List& vertices = stringVertices[cell.item().fontDescriptor]; 372 vertices.insert(vertices.end(), titleVertices.begin(), titleVertices.end()); 373 } 374 } 375 } 376 } 377 } 378 379 return stringVertices; 380 } 381 doLeftClick(Layout & layout,const float x,const float y)382 void TextureBrowserView::doLeftClick(Layout& layout, const float x, const float y) { 383 const Layout::Group::Row::Cell* result = NULL; 384 if (layout.cellAt(x, y, &result)) { 385 if (!result->item().texture->overridden()) { 386 Assets::Texture* texture = result->item().texture; 387 388 TextureSelectedCommand command; 389 command.setTexture(texture); 390 command.SetEventObject(this); 391 command.SetId(GetId()); 392 ProcessEvent(command); 393 394 if (command.IsAllowed()) 395 m_selectedTexture = texture; 396 397 Refresh(); 398 } 399 } 400 } 401 tooltip(const Layout::Group::Row::Cell & cell)402 wxString TextureBrowserView::tooltip(const Layout::Group::Row::Cell& cell) { 403 wxString tooltip; 404 tooltip << cell.item().texture->name() << "\n"; 405 tooltip << cell.item().texture->width() << "x" << cell.item().texture->height(); 406 return tooltip; 407 } 408 } 409 } 410