| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include <random> |
| |
|
| |
|
| | #include <QDirIterator> |
| | #include <QMutex> |
| | #include <QMutexLocker> |
| |
|
| | #include <App/Application.h> |
| | #include <App/Material.h> |
| |
|
| | #include "Exceptions.h" |
| | #include "MaterialConfigLoader.h" |
| | #include "MaterialLoader.h" |
| | #include "MaterialManager.h" |
| | #if defined(BUILD_MATERIAL_EXTERNAL) |
| | #include "MaterialManagerExternal.h" |
| | #endif |
| | #include "MaterialManagerLocal.h" |
| | #include "ModelManager.h" |
| | #include "ModelUuids.h" |
| |
|
| | #include <Base/Tools.h> |
| |
|
| |
|
| | using namespace Materials; |
| |
|
| | |
| |
|
| | TYPESYSTEM_SOURCE(Materials::MaterialManager, Base::BaseClass) |
| |
|
| | QMutex MaterialManager::_mutex; |
| | bool MaterialManager::_useExternal = false; |
| | MaterialManager* MaterialManager::_manager = nullptr; |
| | std::unique_ptr<MaterialManagerLocal> MaterialManager::_localManager; |
| | #if defined(BUILD_MATERIAL_EXTERNAL) |
| | std::unique_ptr<MaterialManagerExternal> MaterialManager::_externalManager; |
| | #endif |
| |
|
| | MaterialManager::MaterialManager() |
| | { |
| | #if defined(BUILD_MATERIAL_EXTERNAL) |
| | _hGrp = App::GetApplication().GetParameterGroupByPath( |
| | "User parameter:BaseApp/Preferences/Mod/Material/ExternalInterface"); |
| | _useExternal = _hGrp->GetBool("UseExternal", false); |
| | _hGrp->Attach(this); |
| | #else |
| | _useExternal = false; |
| | #endif |
| | } |
| |
|
| | MaterialManager::~MaterialManager() |
| | { |
| | #if defined(BUILD_MATERIAL_EXTERNAL) |
| | _hGrp->Detach(this); |
| | #endif |
| | } |
| |
|
| | MaterialManager& MaterialManager::getManager() |
| | { |
| | if (!_manager) { |
| | initManagers(); |
| | } |
| | return *_manager; |
| | } |
| |
|
| | void MaterialManager::initManagers() |
| | { |
| | QMutexLocker locker(&_mutex); |
| |
|
| | if (!_manager) { |
| | |
| | _manager = new MaterialManager(); |
| | } |
| | if (!_localManager) { |
| | _localManager = std::make_unique<MaterialManagerLocal>(); |
| | } |
| |
|
| | #if defined(BUILD_MATERIAL_EXTERNAL) |
| | if (!_externalManager) { |
| | _externalManager = std::make_unique<MaterialManagerExternal>(); |
| | } |
| | #endif |
| | } |
| |
|
| | void MaterialManager::OnChange(ParameterGrp::SubjectType& rCaller, ParameterGrp::MessageType Reason) |
| | { |
| | const ParameterGrp& rGrp = static_cast<ParameterGrp&>(rCaller); |
| | if (strcmp(Reason, "UseExternal") == 0) { |
| | Base::Console().log("Use external changed\n"); |
| | _useExternal = rGrp.GetBool("UseExternal", false); |
| | |
| | } |
| | } |
| |
|
| | void MaterialManager::cleanup() |
| | { |
| | if (_localManager) { |
| | _localManager->cleanup(); |
| | } |
| | #if defined(BUILD_MATERIAL_EXTERNAL) |
| | if (_externalManager) { |
| | _externalManager->cleanup(); |
| | } |
| | #endif |
| | } |
| |
|
| | void MaterialManager::refresh() |
| | { |
| | _localManager->refresh(); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| |
|
| | std::shared_ptr<App::Material> MaterialManager::defaultAppearance() |
| | { |
| | ParameterGrp::handle hGrp = |
| | App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); |
| |
|
| | auto getColor = [hGrp](const char* parameter, Base::Color& color) { |
| | uint32_t packed = color.getPackedRGB(); |
| | packed = hGrp->GetUnsigned(parameter, packed); |
| | color.setPackedRGB(packed); |
| | color.a = 1.0; |
| | }; |
| | auto intRandom = [](int min, int max) -> int { |
| | static std::mt19937 generator; |
| | std::uniform_int_distribution<int> distribution(min, max); |
| | return distribution(generator); |
| | }; |
| |
|
| | App::Material mat(App::Material::DEFAULT); |
| | bool randomColor = hGrp->GetBool("RandomColor", false); |
| |
|
| | if (randomColor) { |
| | float red = static_cast<float>(intRandom(0, 255)) / 255.0F; |
| | float green = static_cast<float>(intRandom(0, 255)) / 255.0F; |
| | float blue = static_cast<float>(intRandom(0, 255)) / 255.0F; |
| | mat.diffuseColor = Base::Color(red, green, blue, 1.0); |
| | } |
| | else { |
| | getColor("DefaultShapeColor", mat.diffuseColor); |
| | } |
| |
|
| | getColor("DefaultAmbientColor", mat.ambientColor); |
| | getColor("DefaultEmissiveColor", mat.emissiveColor); |
| | getColor("DefaultSpecularColor", mat.specularColor); |
| |
|
| | long initialTransparency = hGrp->GetInt("DefaultShapeTransparency", 0); |
| | long initialShininess = hGrp->GetInt("DefaultShapeShininess", 90); |
| | mat.shininess = Base::fromPercent(initialShininess); |
| | mat.transparency = Base::fromPercent(initialTransparency); |
| |
|
| | return std::make_shared<App::Material>(mat); |
| | } |
| |
|
| | std::shared_ptr<Material> MaterialManager::defaultMaterial() |
| | { |
| | MaterialManager manager; |
| |
|
| | auto mat = defaultAppearance(); |
| | auto material = getManager().getMaterial(defaultMaterialUUID()); |
| | if (!material) { |
| | material = getManager().getMaterial(QStringLiteral("7f9fd73b-50c9-41d8-b7b2-575a030c1eeb")); |
| | } |
| | if (material->hasAppearanceModel(ModelUUIDs::ModelUUID_Rendering_Basic)) { |
| | material->getAppearanceProperty(QStringLiteral("DiffuseColor")) |
| | ->setColor(mat->diffuseColor); |
| | material->getAppearanceProperty(QStringLiteral("AmbientColor")) |
| | ->setColor(mat->ambientColor); |
| | material->getAppearanceProperty(QStringLiteral("EmissiveColor")) |
| | ->setColor(mat->emissiveColor); |
| | material->getAppearanceProperty(QStringLiteral("SpecularColor")) |
| | ->setColor(mat->specularColor); |
| | material->getAppearanceProperty(QStringLiteral("Transparency")) |
| | ->setFloat(mat->transparency); |
| | material->getAppearanceProperty(QStringLiteral("Shininess")) |
| | ->setFloat(mat->shininess); |
| | } |
| |
|
| | return material; |
| | } |
| |
|
| | QString MaterialManager::defaultMaterialUUID() |
| | { |
| | |
| | auto param = App::GetApplication().GetParameterGroupByPath( |
| | "User parameter:BaseApp/Preferences/Mod/Material"); |
| | auto uuid = param->GetASCII("DefaultMaterial", "7f9fd73b-50c9-41d8-b7b2-575a030c1eeb"); |
| | return QString::fromStdString(uuid); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| |
|
| | std::shared_ptr<std::list<std::shared_ptr<MaterialLibrary>>> MaterialManager::getLibraries() |
| | { |
| | |
| | auto libMap = std::map<QString, std::shared_ptr<MaterialLibrary>>(); |
| | #if defined(BUILD_MATERIAL_EXTERNAL) |
| | if (_useExternal) { |
| | auto remoteLibraries = _externalManager->getLibraries(); |
| | for (auto& remote : *remoteLibraries) { |
| | libMap.try_emplace(remote->getName(), remote); |
| | } |
| | } |
| | #endif |
| | auto localLibraries = _localManager->getLibraries(); |
| | for (auto& local : *localLibraries) { |
| | libMap.try_emplace(local->getName(), local); |
| | } |
| |
|
| | |
| | auto libraries = std::make_shared<std::list<std::shared_ptr<MaterialLibrary>>>(); |
| | for (auto libEntry : libMap) { |
| | libraries->push_back(libEntry.second); |
| | } |
| |
|
| | return libraries; |
| | } |
| |
|
| | std::shared_ptr<std::list<std::shared_ptr<MaterialLibrary>>> |
| | MaterialManager::getLocalLibraries() |
| | { |
| | return _localManager->getLibraries(); |
| | } |
| |
|
| | std::shared_ptr<MaterialLibrary> MaterialManager::getLibrary(const QString& name) const |
| | { |
| | #if defined(BUILD_MATERIAL_EXTERNAL) |
| | if (_useExternal) { |
| | try |
| | { |
| | auto lib = _externalManager->getLibrary(name); |
| | if (lib) { |
| | return lib; |
| | } |
| | } |
| | catch (const LibraryNotFound& e) { |
| | } |
| | } |
| | #endif |
| | |
| | return _localManager->getLibrary(name); |
| | } |
| |
|
| | void MaterialManager::createLibrary([[maybe_unused]] const QString& libraryName, |
| | [[maybe_unused]] const QString& iconPath, |
| | [[maybe_unused]] bool readOnly) |
| | { |
| | #if defined(BUILD_MATERIAL_EXTERNAL) |
| | if (_useExternal) { |
| | auto icon = Materials::Library::getIcon(iconPath); |
| | _externalManager->createLibrary(libraryName, icon, readOnly); |
| | return; |
| | } |
| | #endif |
| | throw CreationError("Local library requires a path"); |
| | } |
| |
|
| | void MaterialManager::createLocalLibrary(const QString& libraryName, |
| | const QString& directory, |
| | const QString& iconPath, |
| | bool readOnly) |
| | { |
| | _localManager->createLibrary(libraryName, directory, iconPath, readOnly); |
| | } |
| |
|
| | void MaterialManager::renameLibrary(const QString& libraryName, const QString& newName) |
| | { |
| | auto library = getLibrary(libraryName); |
| | if (library) { |
| | #if defined(BUILD_MATERIAL_EXTERNAL) |
| | if (!library->isLocal()) { |
| | if (_useExternal) { |
| | _externalManager->renameLibrary(libraryName, newName); |
| | return; |
| | } |
| |
|
| | throw Materials::RenameError(); |
| | } |
| | #endif |
| | _localManager->renameLibrary(libraryName, newName); |
| | } |
| | } |
| |
|
| | void MaterialManager::changeIcon(const QString& libraryName, const QString& iconPath) |
| | { |
| | auto icon = Materials::Library::getIcon(iconPath); |
| | _localManager->changeIcon(libraryName, icon); |
| | } |
| |
|
| | void MaterialManager::removeLibrary(const QString& libraryName) |
| | { |
| | _localManager->removeLibrary(libraryName); |
| | } |
| |
|
| | std::shared_ptr<std::vector<LibraryObject>> |
| | MaterialManager::libraryMaterials(const QString& libraryName, [[maybe_unused]] bool local) |
| | { |
| | #if defined(BUILD_MATERIAL_EXTERNAL) |
| | if (_useExternal && !local) { |
| | try { |
| | auto materials = _externalManager->libraryMaterials(libraryName); |
| | if (materials) { |
| | return materials; |
| | } |
| | } |
| | catch (const LibraryNotFound& e) { |
| | } |
| | } |
| | #endif |
| | return _localManager->libraryMaterials(libraryName); |
| | } |
| |
|
| | std::shared_ptr<std::vector<LibraryObject>> |
| | MaterialManager::libraryMaterials(const QString& libraryName, |
| | const MaterialFilter& filter, |
| | const MaterialFilterOptions& options, |
| | [[maybe_unused]] bool local) |
| | { |
| | #if defined(BUILD_MATERIAL_EXTERNAL) |
| | if (_useExternal && !local) { |
| | try { |
| | auto materials = _externalManager->libraryMaterials(libraryName, filter, options); |
| | if (materials) { |
| | return materials; |
| | } |
| | } |
| | catch (const LibraryNotFound& e) { |
| | } |
| | } |
| | #endif |
| | return _localManager->libraryMaterials(libraryName, filter, options); |
| | } |
| |
|
| | #if defined(BUILD_MATERIAL_EXTERNAL) |
| | bool MaterialManager::isLocalLibrary(const QString& libraryName) |
| | { |
| | if (_useExternal) { |
| | try { |
| | auto lib = _externalManager->getLibrary(libraryName); |
| | if (lib) { |
| | return false; |
| | } |
| | } |
| | catch (const LibraryNotFound& e) { |
| | } |
| | } |
| | return true; |
| | } |
| | #else |
| | bool MaterialManager::isLocalLibrary(const QString& ) |
| | { |
| | return true; |
| | } |
| | #endif |
| |
|
| | |
| | |
| | |
| | |
| | |
| |
|
| | std::shared_ptr<std::list<QString>> |
| | MaterialManager::getMaterialFolders(const std::shared_ptr<MaterialLibrary>& library) const |
| | { |
| | if (library->isLocal()) { |
| | auto materialLibrary = |
| | reinterpret_cast<const std::shared_ptr<Materials::MaterialLibraryLocal>&>(library); |
| |
|
| | return _localManager->getMaterialFolders(materialLibrary); |
| | } |
| |
|
| | return std::make_shared<std::list<QString>>(); |
| | } |
| |
|
| | void MaterialManager::createFolder(const std::shared_ptr<MaterialLibrary>& library, |
| | const QString& path) |
| | { |
| | if (library->isLocal()) { |
| | auto materialLibrary = |
| | reinterpret_cast<const std::shared_ptr<Materials::MaterialLibraryLocal>&>(library); |
| |
|
| | _localManager->createFolder(materialLibrary, path); |
| | } |
| | #if defined(BUILD_MATERIAL_EXTERNAL) |
| | else if (_useExternal) { |
| | _externalManager->createFolder(*library, path); |
| | } |
| | else { |
| | throw Materials::CreationError("External materials are not enabled"); |
| | } |
| | #endif |
| | } |
| |
|
| | void MaterialManager::renameFolder(const std::shared_ptr<MaterialLibrary>& library, |
| | const QString& oldPath, |
| | const QString& newPath) |
| | { |
| | if (library->isLocal()) { |
| | auto materialLibrary = |
| | reinterpret_cast<const std::shared_ptr<Materials::MaterialLibraryLocal>&>(library); |
| |
|
| | _localManager->renameFolder(materialLibrary, oldPath, newPath); |
| | } |
| | #if defined(BUILD_MATERIAL_EXTERNAL) |
| | else if (_useExternal) { |
| | _externalManager->renameFolder(*library, oldPath, newPath); |
| | } |
| | else { |
| | throw Materials::RenameError("External materials are not enabled"); |
| | } |
| | #endif |
| | } |
| |
|
| | void MaterialManager::deleteRecursive(const std::shared_ptr<MaterialLibrary>& library, |
| | const QString& path) |
| | { |
| | if (library->isLocal()) { |
| | auto materialLibrary = |
| | reinterpret_cast<const std::shared_ptr<Materials::MaterialLibraryLocal>&>(library); |
| |
|
| | _localManager->deleteRecursive(materialLibrary, path); |
| | } |
| | #if defined(BUILD_MATERIAL_EXTERNAL) |
| | else if (_useExternal) { |
| | _externalManager->deleteRecursive(*library, path); |
| | } |
| | else { |
| | throw Materials::DeleteError("External materials are not enabled"); |
| | } |
| | #endif |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| |
|
| | std::shared_ptr<std::map<QString, std::shared_ptr<MaterialTreeNode>>> |
| | MaterialManager::getMaterialTree(const MaterialLibrary& library, |
| | const Materials::MaterialFilter& filter) const |
| | { |
| | MaterialFilterOptions options; |
| | return library.getMaterialTree(filter, options); |
| | } |
| |
|
| | std::shared_ptr<std::map<QString, std::shared_ptr<MaterialTreeNode>>> |
| | MaterialManager::getMaterialTree(const MaterialLibrary& library, |
| | const Materials::MaterialFilter& filter, |
| | const MaterialFilterOptions& options) const |
| | { |
| | return library.getMaterialTree(filter, options); |
| | } |
| |
|
| | std::shared_ptr<std::map<QString, std::shared_ptr<MaterialTreeNode>>> |
| | MaterialManager::getMaterialTree(const MaterialLibrary& library) const |
| | { |
| | Materials::MaterialFilter filter; |
| | MaterialFilterOptions options; |
| | return library.getMaterialTree(filter, options); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| |
|
| | std::shared_ptr<std::map<QString, std::shared_ptr<Material>>> |
| | MaterialManager::getLocalMaterials() const |
| | { |
| | return _localManager->getLocalMaterials(); |
| | } |
| |
|
| | std::shared_ptr<Material> MaterialManager::getMaterial(const QString& uuid) const |
| | { |
| | #if defined(BUILD_MATERIAL_EXTERNAL) |
| | if (_useExternal) { |
| | auto material = _externalManager->getMaterial(uuid); |
| | if (material) { |
| | return material; |
| | } |
| | } |
| | #endif |
| | |
| | return _localManager->getMaterial(uuid); |
| | } |
| |
|
| | std::shared_ptr<Material> MaterialManager::getMaterial(const App::Material& material) |
| | { |
| | MaterialManager manager; |
| |
|
| | return manager.getMaterial(QString::fromStdString(material.uuid)); |
| | } |
| |
|
| | std::shared_ptr<Material> MaterialManager::getMaterialByPath(const QString& path) const |
| | { |
| | return _localManager->getMaterialByPath(path); |
| | } |
| |
|
| | std::shared_ptr<Material> MaterialManager::getMaterialByPath(const QString& path, |
| | const QString& lib) const |
| | { |
| | return _localManager->getMaterialByPath(path, lib); |
| | } |
| |
|
| | std::shared_ptr<Material> |
| | MaterialManager::getParent(const std::shared_ptr<Material>& material) const |
| | { |
| | if (material->getParentUUID().isEmpty()) { |
| | throw MaterialNotFound(); |
| | } |
| |
|
| | return getMaterial(material->getParentUUID()); |
| | } |
| |
|
| | bool MaterialManager::exists(const QString& uuid) const |
| | { |
| | return _localManager->exists(uuid); |
| | } |
| |
|
| | bool MaterialManager::exists(const MaterialLibrary& library, |
| | const QString& uuid) const |
| | { |
| | if (library.isLocal()) { |
| | return _localManager->exists(library, uuid); |
| | } |
| | return false; |
| | } |
| |
|
| | void MaterialManager::remove(const QString& uuid) const |
| | { |
| | _localManager->remove(uuid); |
| | } |
| |
|
| | void MaterialManager::saveMaterial(const std::shared_ptr<MaterialLibrary>& library, |
| | const std::shared_ptr<Material>& material, |
| | const QString& path, |
| | bool overwrite, |
| | bool saveAsCopy, |
| | bool saveInherited) const |
| | { |
| | auto materialLibrary = |
| | reinterpret_cast<const std::shared_ptr<Materials::MaterialLibraryLocal>&>(library); |
| | _localManager |
| | ->saveMaterial(materialLibrary, material, path, overwrite, saveAsCopy, saveInherited); |
| | } |
| |
|
| | bool MaterialManager::isMaterial(const fs::path& p) const |
| | { |
| | return _localManager->isMaterial(p); |
| | } |
| |
|
| | bool MaterialManager::isMaterial(const QFileInfo& file) const |
| | { |
| | return _localManager->isMaterial(file); |
| | } |
| |
|
| | std::shared_ptr<std::map<QString, std::shared_ptr<Material>>> |
| | MaterialManager::materialsWithModel(const QString& uuid) const |
| | { |
| | return _localManager->materialsWithModel(uuid); |
| | } |
| |
|
| | std::shared_ptr<std::map<QString, std::shared_ptr<Material>>> |
| | MaterialManager::materialsWithModelComplete(const QString& uuid) const |
| | { |
| | return _localManager->materialsWithModelComplete(uuid); |
| | } |
| |
|
| | void MaterialManager::dereference() const |
| | { |
| | _localManager->dereference(); |
| | } |
| |
|
| | void MaterialManager::dereference(std::shared_ptr<Material> material) const |
| | { |
| | _localManager->dereference(material); |
| | } |
| |
|
| | #if defined(BUILD_MATERIAL_EXTERNAL) |
| | void MaterialManager::migrateToExternal(const std::shared_ptr<Materials::MaterialLibrary>& library) |
| | { |
| | try { |
| | _externalManager->createLibrary(library->getName(), |
| | library->getIcon(), |
| | library->isReadOnly()); |
| | } |
| | catch (const CreationError&) { |
| | } |
| | catch (const ConnectionError&) { |
| | } |
| |
|
| | auto materials = _localManager->libraryMaterials(library->getName()); |
| | for (auto& it : *materials) { |
| | auto uuid = it.getUUID(); |
| | auto path = it.getPath(); |
| | auto name = it.getName(); |
| | Base::Console().log("\t('%s', '%s', '%s')\n", |
| | uuid.toStdString().c_str(), |
| | path.toStdString().c_str(), |
| | name.toStdString().c_str()); |
| |
|
| | auto material = _localManager->getMaterial(uuid); |
| | if (!material->isOldFormat()) { |
| | _externalManager->migrateMaterial(library->getName(), path, *material); |
| | } |
| | } |
| | } |
| |
|
| | void MaterialManager::validateMigration(const std::shared_ptr<Materials::MaterialLibrary>& library) |
| | { |
| | auto materials = _localManager->libraryMaterials(library->getName()); |
| | _externalManager->resetCache(); |
| | for (auto& it : *materials) { |
| | auto uuid = it.getUUID(); |
| | auto path = it.getPath(); |
| | auto name = it.getName(); |
| | Base::Console().log("\t('%s', '%s', '%s')\n", |
| | uuid.toStdString().c_str(), |
| | path.toStdString().c_str(), |
| | name.toStdString().c_str()); |
| |
|
| | auto material = _localManager->getMaterial(uuid); |
| | if (!material->isOldFormat()) { |
| | auto externalMaterial = _externalManager->getMaterial(uuid); |
| | material->validate(*externalMaterial); |
| | } |
| | } |
| | } |
| |
|
| | |
| | double MaterialManager::materialHitRate() |
| | { |
| | initManagers(); |
| | return _externalManager->materialHitRate(); |
| | } |
| | #endif |
| |
|