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 "TextureManager.h" 21 22 #include "Exceptions.h" 23 #include "CollectionUtils.h" 24 #include "Logger.h" 25 #include "Assets/Texture.h" 26 #include "Assets/TextureCollection.h" 27 #include "Assets/TextureCollectionSpec.h" 28 #include "IO/TextureLoader.h" 29 30 namespace TrenchBroom { 31 namespace Assets { 32 class CompareByName { 33 public: CompareByName()34 CompareByName() {} operator ()(const Texture * left,const Texture * right) const35 bool operator() (const Texture* left, const Texture* right) const { 36 return left->name() < right->name(); 37 } 38 }; 39 40 class CompareByUsage { 41 public: operator ()(const Texture * left,const Texture * right) const42 bool operator() (const Texture* left, const Texture* right) const { 43 if (left->usageCount() == right->usageCount()) 44 return left->name() < right->name(); 45 return left->usageCount() > right->usageCount(); 46 } 47 }; 48 TextureManager(Logger * logger,int minFilter,int magFilter)49 TextureManager::TextureManager(Logger* logger, int minFilter, int magFilter) : 50 m_logger(logger), 51 m_loader(NULL), 52 m_minFilter(minFilter), 53 m_magFilter(magFilter), 54 m_resetTextureMode(false) {} 55 ~TextureManager()56 TextureManager::~TextureManager() { 57 clear(); 58 } 59 setBuiltinTextureCollections(const IO::Path::List & paths)60 void TextureManager::setBuiltinTextureCollections(const IO::Path::List& paths) { 61 clearBuiltinTextureCollections(); 62 63 TextureCollectionList newCollections; 64 TextureCollectionMap newCollectionsByName; 65 66 try { 67 IO::Path::List::const_iterator it, end; 68 for (it = paths.begin(), end = paths.end(); it != end; ++it) { 69 const IO::Path& path = *it; 70 const TextureCollectionSpec spec(path.suffix(2).asString(), path); 71 addTextureCollection(spec, newCollections, newCollectionsByName); 72 } 73 74 using std::swap; 75 std::swap(m_builtinCollections, newCollections); 76 std::swap(m_builtinCollectionsByName, newCollectionsByName); 77 78 updateTextures(); 79 } catch (...) { 80 updateTextures(); 81 VectorUtils::deleteAll(newCollections); 82 throw; 83 } 84 } 85 addExternalTextureCollection(const TextureCollectionSpec & spec)86 void TextureManager::addExternalTextureCollection(const TextureCollectionSpec& spec) { 87 try { 88 addTextureCollection(spec, m_externalCollections, m_externalCollectionsByName); 89 updateTextures(); 90 } catch (...) { 91 TextureCollection* dummy = new TextureCollection(spec.name()); 92 m_externalCollections.push_back(dummy); 93 m_externalCollectionsByName[spec.name()] = dummy; 94 updateTextures(); 95 96 throw; 97 } 98 } 99 removeExternalTextureCollection(const String & name)100 void TextureManager::removeExternalTextureCollection(const String& name) { 101 removeTextureCollection(name, m_externalCollections, m_externalCollectionsByName); 102 updateTextures(); 103 } 104 moveExternalTextureCollectionUp(const String & name)105 void TextureManager::moveExternalTextureCollectionUp(const String& name) { 106 TextureCollectionMap::iterator it = m_externalCollectionsByName.find(name); 107 if (it == m_externalCollectionsByName.end()) 108 throw AssetException("Unknown external texture collection: '" + name + "'"); 109 110 TextureCollection* collection = it->second; 111 const size_t index = VectorUtils::indexOf(m_externalCollections, collection); 112 if (index == 0) 113 throw AssetException("Could not move texture collection"); 114 115 using std::swap; 116 swap(m_externalCollections[index-1], m_externalCollections[index]); 117 updateTextures(); 118 } 119 moveExternalTextureCollectionDown(const String & name)120 void TextureManager::moveExternalTextureCollectionDown(const String& name) { 121 TextureCollectionMap::iterator it = m_externalCollectionsByName.find(name); 122 if (it == m_externalCollectionsByName.end()) 123 throw AssetException("Unknown external texture collection: '" + name + "'"); 124 125 TextureCollection* collection = it->second; 126 const size_t index = VectorUtils::indexOf(m_externalCollections, collection); 127 if (index == m_externalCollections.size() - 1) 128 throw AssetException("Could not move texture collection"); 129 130 using std::swap; 131 swap(m_externalCollections[index+1], m_externalCollections[index]); 132 updateTextures(); 133 } 134 clear()135 void TextureManager::clear() { 136 VectorUtils::clearAndDelete(m_builtinCollections); 137 VectorUtils::clearAndDelete(m_externalCollections); 138 MapUtils::clearAndDelete(m_toRemove); 139 140 m_toPrepare.clear(); 141 m_builtinCollectionsByName.clear(); 142 m_externalCollectionsByName.clear(); 143 m_allCollections.clear(); 144 m_texturesByName.clear(); 145 146 for (size_t i = 0; i < 2; ++i) { 147 m_sortedTextures[i].clear(); 148 m_sortedGroups[i].clear(); 149 } 150 151 if (m_logger != NULL) 152 m_logger->debug("Cleared texture collections"); 153 } 154 setTextureMode(const int minFilter,const int magFilter)155 void TextureManager::setTextureMode(const int minFilter, const int magFilter) { 156 m_minFilter = minFilter; 157 m_magFilter = magFilter; 158 m_resetTextureMode = true; 159 } 160 setLoader(const IO::TextureLoader * loader)161 void TextureManager::setLoader(const IO::TextureLoader* loader) { 162 clear(); 163 m_loader = loader; 164 updateTextures(); 165 } 166 commitChanges()167 void TextureManager::commitChanges() { 168 resetTextureMode(); 169 prepare(); 170 MapUtils::clearAndDelete(m_toRemove); 171 } 172 texture(const String & name) const173 Texture* TextureManager::texture(const String& name) const { 174 TextureMap::const_iterator it = m_texturesByName.find(StringUtils::toLower(name)); 175 if (it == m_texturesByName.end()) 176 return NULL; 177 return it->second; 178 } 179 textures(const SortOrder sortOrder) const180 const TextureList& TextureManager::textures(const SortOrder sortOrder) const { 181 return m_sortedTextures[sortOrder]; 182 } 183 groups(const SortOrder sortOrder) const184 const TextureManager::GroupList& TextureManager::groups(const SortOrder sortOrder) const { 185 return m_sortedGroups[sortOrder]; 186 } 187 collections() const188 const TextureCollectionList& TextureManager::collections() const { 189 return m_allCollections; 190 } 191 externalCollectionNames() const192 const StringList TextureManager::externalCollectionNames() const { 193 StringList names; 194 names.reserve(m_externalCollections.size()); 195 196 TextureCollectionList::const_iterator it, end; 197 for (it = m_externalCollections.begin(), end = m_externalCollections.end(); it != end; ++it) { 198 const TextureCollection* collection = *it; 199 names.push_back(collection->name()); 200 } 201 202 return names; 203 } 204 addTextureCollection(const TextureCollectionSpec & spec,TextureCollectionList & collections,TextureCollectionMap & collectionsByName)205 void TextureManager::addTextureCollection(const TextureCollectionSpec& spec, TextureCollectionList& collections, TextureCollectionMap& collectionsByName) { 206 207 const String& name = spec.name(); 208 if (collectionsByName.find(spec.name()) == collectionsByName.end()) { 209 TextureCollection* collection = loadTextureCollection(spec); 210 collections.push_back(collection); 211 collectionsByName.insert(std::make_pair(name, collection)); 212 213 m_toPrepare.insert(TextureCollectionMapEntry(name, collection)); 214 m_toRemove.erase(name); 215 216 if (m_logger != NULL) 217 m_logger->debug("Added texture collection %s", name.c_str()); 218 } 219 } 220 removeTextureCollection(const String & name,TextureCollectionList & collections,TextureCollectionMap & collectionsByName)221 void TextureManager::removeTextureCollection(const String& name, TextureCollectionList& collections, TextureCollectionMap& collectionsByName) { 222 TextureCollectionMap::iterator it = collectionsByName.find(name); 223 if (it == collectionsByName.end()) 224 throw AssetException("Unknown external texture collection: '" + name + "'"); 225 226 TextureCollection* collection = it->second; 227 VectorUtils::erase(collections, collection); 228 229 collectionsByName.erase(it); 230 m_toPrepare.erase(name); 231 m_toRemove.insert(TextureCollectionMapEntry(name, collection)); 232 233 if (m_logger != NULL) 234 m_logger->debug("Removed texture collection '%s'", name.c_str()); 235 } 236 loadTextureCollection(const TextureCollectionSpec & spec) const237 TextureCollection* TextureManager::loadTextureCollection(const TextureCollectionSpec& spec) const { 238 assert(m_loader != NULL); 239 return m_loader->loadTextureCollection(spec); 240 } 241 resetTextureMode()242 void TextureManager::resetTextureMode() { 243 if (m_resetTextureMode) { 244 TextureCollectionList::const_iterator it, end; 245 for (it = m_allCollections.begin(), end = m_allCollections.end(); it != end; ++it) { 246 TextureCollection* collection = *it; 247 collection->setTextureMode(m_minFilter, m_magFilter); 248 } 249 m_resetTextureMode = false; 250 } 251 } 252 prepare()253 void TextureManager::prepare() { 254 TextureCollectionMap::const_iterator it, end; 255 for (it = m_toPrepare.begin(), end = m_toPrepare.end(); it != end; ++it) { 256 TextureCollection* collection = it->second; 257 collection->prepare(m_minFilter, m_magFilter); 258 } 259 m_toPrepare.clear(); 260 } 261 clearBuiltinTextureCollections()262 void TextureManager::clearBuiltinTextureCollections() { 263 m_toRemove.insert(m_builtinCollectionsByName.begin(), m_builtinCollectionsByName.end()); 264 m_builtinCollections.clear(); 265 m_builtinCollectionsByName.clear(); 266 267 if (m_logger != NULL) 268 m_logger->debug("Cleared builtin texture collections"); 269 } 270 clearExternalTextureCollections()271 void TextureManager::clearExternalTextureCollections() { 272 m_toRemove.insert(m_externalCollectionsByName.begin(), m_externalCollectionsByName.end()); 273 m_externalCollections.clear(); 274 m_externalCollectionsByName.clear(); 275 276 if (m_logger != NULL) 277 m_logger->debug("Cleared builtin texture collections"); 278 } 279 updateTextures()280 void TextureManager::updateTextures() { 281 m_allCollections = VectorUtils::concatenate(m_builtinCollections, m_externalCollections); 282 m_texturesByName.clear(); 283 m_sortedGroups[SortOrder_Name].clear(); 284 m_sortedGroups[SortOrder_Usage].clear(); 285 286 TextureCollectionList::iterator cIt, cEnd; 287 for (cIt = m_allCollections.begin(), cEnd = m_allCollections.end(); cIt != cEnd; ++cIt) { 288 TextureCollection* collection = *cIt; 289 const TextureList textures = collection->textures(); 290 291 TextureList::const_iterator tIt, tEnd; 292 for (tIt = textures.begin(), tEnd = textures.end(); tIt != tEnd; ++tIt) { 293 Texture* texture = *tIt; 294 const String key = StringUtils::toLower(texture->name()); 295 texture->setOverridden(false); 296 297 TextureMap::iterator mIt = m_texturesByName.find(key); 298 if (mIt != m_texturesByName.end()) { 299 mIt->second->setOverridden(true); 300 mIt->second = texture; 301 } else { 302 m_texturesByName.insert(std::make_pair(key, texture)); 303 } 304 } 305 306 const Group group = std::make_pair(collection, textures); 307 m_sortedGroups[SortOrder_Name].push_back(group); 308 m_sortedGroups[SortOrder_Usage].push_back(group); 309 std::sort(m_sortedGroups[SortOrder_Name].back().second.begin(), 310 m_sortedGroups[SortOrder_Name].back().second.end(), 311 CompareByName()); 312 std::sort(m_sortedGroups[SortOrder_Usage].back().second.begin(), 313 m_sortedGroups[SortOrder_Usage].back().second.end(), 314 CompareByUsage()); 315 } 316 317 m_sortedTextures[SortOrder_Name] = m_sortedTextures[SortOrder_Usage] = textureList(); 318 std::sort(m_sortedTextures[SortOrder_Name].begin(), m_sortedTextures[SortOrder_Name].end(), CompareByName()); 319 std::sort(m_sortedTextures[SortOrder_Usage].begin(), m_sortedTextures[SortOrder_Usage].end(), CompareByUsage()); 320 } 321 textureList() const322 TextureList TextureManager::textureList() const { 323 TextureList result; 324 TextureCollectionList::const_iterator cIt, cEnd; 325 for (cIt = m_allCollections.begin(), cEnd = m_allCollections.end(); cIt != cEnd; ++cIt) { 326 const TextureCollection* collection = *cIt; 327 const TextureList textures = collection->textures(); 328 329 TextureList::const_iterator tIt, tEnd; 330 for (tIt = textures.begin(), tEnd = textures.end(); tIt != tEnd; ++tIt) { 331 Texture* texture = *tIt; 332 result.push_back(texture); 333 } 334 } 335 336 return result; 337 } 338 } 339 } 340