| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include <QMetaType> |
| | #include <QUuid> |
| |
|
| |
|
| |
|
| | #include <App/Application.h> |
| | #include <Gui/MetaTypes.h> |
| |
|
| | #include "Materials.h" |
| |
|
| | #include "MaterialLibrary.h" |
| | #include "MaterialManager.h" |
| | #include "ModelManager.h" |
| | #include "ModelUuids.h" |
| |
|
| |
|
| | using namespace Materials; |
| |
|
| | |
| |
|
| | TYPESYSTEM_SOURCE(Materials::MaterialProperty, Materials::ModelProperty) |
| |
|
| | MaterialProperty::MaterialProperty() |
| | { |
| | _valuePtr = std::make_shared<MaterialValue>(MaterialValue::None); |
| | } |
| |
|
| | MaterialProperty::MaterialProperty(const ModelProperty& other, QString modelUUID) |
| | : ModelProperty(other) |
| | , _modelUUID(modelUUID) |
| | , _valuePtr(nullptr) |
| | { |
| | setType(getPropertyType()); |
| | auto columns = other.getColumns(); |
| | for (auto& it : columns) { |
| | MaterialProperty prop(it, modelUUID); |
| | addColumn(prop); |
| | } |
| | } |
| |
|
| | void MaterialProperty::copyValuePtr(const std::shared_ptr<MaterialValue>& value) |
| | { |
| | if (value->getType() == MaterialValue::Array2D) { |
| | _valuePtr = |
| | std::make_shared<Array2D>(*(std::static_pointer_cast<Array2D>(value))); |
| | } |
| | else if (value->getType() == MaterialValue::Array3D) { |
| | _valuePtr = |
| | std::make_shared<Array3D>(*(std::static_pointer_cast<Array3D>(value))); |
| | } |
| | else { |
| | _valuePtr = std::make_shared<MaterialValue>(*value); |
| | } |
| | } |
| |
|
| | MaterialProperty::MaterialProperty(const MaterialProperty& other) |
| | : ModelProperty(other) |
| | , _modelUUID(other._modelUUID) |
| | { |
| | copyValuePtr(other._valuePtr); |
| |
|
| | for (auto& it : other._columns) { |
| | _columns.push_back(it); |
| | } |
| | } |
| |
|
| | MaterialProperty::MaterialProperty(const std::shared_ptr<MaterialProperty>& other) |
| | : MaterialProperty(*other) |
| | {} |
| |
|
| | void MaterialProperty::setModelUUID(const QString& uuid) |
| | { |
| | _modelUUID = uuid; |
| | } |
| |
|
| | QVariant MaterialProperty::getValue() |
| | { |
| | return _valuePtr->getValue(); |
| | } |
| |
|
| | QVariant MaterialProperty::getValue() const |
| | { |
| | return _valuePtr->getValue(); |
| | } |
| |
|
| | std::shared_ptr<MaterialValue> MaterialProperty::getMaterialValue() |
| | { |
| | return _valuePtr; |
| | } |
| |
|
| | std::shared_ptr<MaterialValue> MaterialProperty::getMaterialValue() const |
| | { |
| | return _valuePtr; |
| | } |
| |
|
| | QString MaterialProperty::getString() const |
| | { |
| | |
| | |
| | if (isNull()) { |
| | return {}; |
| | } |
| | if (getType() == MaterialValue::Quantity) { |
| | auto quantity = getValue().value<Base::Quantity>(); |
| | return QString::fromStdString(quantity.getUserString()); |
| | } |
| | if (getType() == MaterialValue::Float) { |
| | auto value = getValue(); |
| | if (value.isNull()) { |
| | return {}; |
| | } |
| | return QString(QStringLiteral("%L1")).arg(value.toFloat(), 0, 'g', MaterialValue::PRECISION); |
| | } |
| | return getValue().toString(); |
| | } |
| |
|
| | QString MaterialProperty::getYAMLString() const |
| | { |
| | return _valuePtr->getYAMLString(); |
| | } |
| |
|
| | Base::Color MaterialProperty::getColor() const |
| | { |
| | auto colorString = getValue().toString(); |
| | std::stringstream stream(colorString.toStdString()); |
| |
|
| | char c; |
| | stream >> c; |
| | float red; |
| | stream >> red; |
| | stream >> c; |
| | float green; |
| | stream >> green; |
| | stream >> c; |
| | float blue; |
| | stream >> blue; |
| | stream >> c; |
| | float alpha = 1.0; |
| | if (c == ',') { |
| | stream >> alpha; |
| | } |
| |
|
| | Base::Color color(red, green, blue, alpha); |
| | return color; |
| | } |
| |
|
| |
|
| | QString MaterialProperty::getDictionaryString() const |
| | { |
| | |
| | |
| | if (isNull()) { |
| | return {}; |
| | } |
| | if (getType() == MaterialValue::Quantity) { |
| | auto quantity = getValue().value<Base::Quantity>(); |
| | auto string = QString(QStringLiteral("%1 %2")) |
| | .arg(quantity.getValue(), 0, 'g', MaterialValue::PRECISION) |
| | .arg(QString::fromStdString(quantity.getUnit().getString())); |
| | return string; |
| | } |
| | if (getType() == MaterialValue::Float) { |
| | auto value = getValue(); |
| | if (value.isNull()) { |
| | return {}; |
| | } |
| | return QString(QStringLiteral("%1")).arg(value.toFloat(), 0, 'g', MaterialValue::PRECISION); |
| | } |
| | return getValue().toString(); |
| | } |
| |
|
| | void MaterialProperty::setPropertyType(const QString& type) |
| | { |
| | ModelProperty::setPropertyType(type); |
| | setType(type); |
| | } |
| |
|
| | void MaterialProperty::setType(const QString& type) |
| | { |
| | auto mappedType = MaterialValue::mapType(type); |
| | if (mappedType == MaterialValue::None) { |
| | throw UnknownValueType(); |
| | } |
| | if (mappedType == MaterialValue::Array2D) { |
| | auto arrayPtr = std::make_shared<Array2D>(); |
| | arrayPtr->setColumns(columns()); |
| | _valuePtr = arrayPtr; |
| | } |
| | else if (mappedType == MaterialValue::Array3D) { |
| | auto arrayPtr = std::make_shared<Array3D>(); |
| | |
| | arrayPtr->setColumns(columns() - 1); |
| | _valuePtr = arrayPtr; |
| | } |
| | else { |
| | _valuePtr = std::make_shared<MaterialValue>(mappedType); |
| | } |
| | } |
| |
|
| | MaterialProperty& MaterialProperty::getColumn(int column) |
| | { |
| | try { |
| | return _columns.at(column); |
| | } |
| | catch (std::out_of_range const&) { |
| | throw InvalidIndex(); |
| | } |
| | } |
| |
|
| | const MaterialProperty& MaterialProperty::getColumn(int column) const |
| | { |
| | try { |
| | return _columns.at(column); |
| | } |
| | catch (std::out_of_range const&) { |
| | throw InvalidIndex(); |
| | } |
| | } |
| |
|
| | MaterialValue::ValueType MaterialProperty::getColumnType(int column) const |
| | { |
| | try { |
| | return _columns.at(column).getType(); |
| | } |
| | catch (std::out_of_range const&) { |
| | throw InvalidIndex(); |
| | } |
| | } |
| |
|
| | QString MaterialProperty::getColumnUnits(int column) const |
| | { |
| | try { |
| | return _columns.at(column).getUnits(); |
| | } |
| | catch (std::out_of_range const&) { |
| | throw InvalidIndex(); |
| | } |
| | } |
| |
|
| | QVariant MaterialProperty::getColumnNull(int column) const |
| | { |
| | MaterialValue::ValueType valueType = getColumnType(column); |
| |
|
| | switch (valueType) { |
| | case MaterialValue::Quantity: { |
| | Base::Quantity quant = Base::Quantity(0, getColumnUnits(column).toStdString()); |
| | return QVariant::fromValue(quant); |
| | } |
| |
|
| | case MaterialValue::Float: |
| | case MaterialValue::Integer: |
| | return 0; |
| |
|
| | default: |
| | break; |
| | } |
| |
|
| | return QString(); |
| | } |
| |
|
| | void MaterialProperty::setValue(const QVariant& value) |
| | { |
| | if (_valuePtr->getType() == MaterialValue::Quantity && value.canConvert<Base::Quantity>()) { |
| | |
| | auto quantity = value.value<Base::Quantity>(); |
| | if (quantity.isValid()) { |
| | setQuantity(quantity); |
| | } |
| | else { |
| | |
| | setValue(QStringLiteral("0")); |
| | } |
| | } |
| | else { |
| | _valuePtr->setValue(value); |
| | } |
| | } |
| |
|
| | void MaterialProperty::setValue(const QString& value) |
| | { |
| | if (_valuePtr->getType() == MaterialValue::Boolean) { |
| | setBoolean(value); |
| | } |
| | else if (_valuePtr->getType() == MaterialValue::Integer) { |
| | setInt(value); |
| | } |
| | else if (_valuePtr->getType() == MaterialValue::Float) { |
| | setFloat(value); |
| | } |
| | else if (_valuePtr->getType() == MaterialValue::URL) { |
| | setURL(value); |
| | } |
| | else if (_valuePtr->getType() == MaterialValue::Array2D |
| | || _valuePtr->getType() == MaterialValue::Array3D) { |
| | |
| | } |
| | else if (_valuePtr->getType() == MaterialValue::Quantity) { |
| | try { |
| | setQuantity(Base::Quantity::parse(value.toStdString())); |
| | } |
| | catch (const Base::ParserError& e) { |
| | Base::Console().log("MaterialProperty::setValue Error '%s' - '%s'\n", |
| | e.what(), |
| | value.toStdString().c_str()); |
| | |
| | setString(value); |
| | } |
| | } |
| | else { |
| | setString(value); |
| | } |
| | } |
| |
|
| | void MaterialProperty::setValue(const std::shared_ptr<MaterialValue>& value) |
| | { |
| | _valuePtr = value; |
| | } |
| |
|
| | void MaterialProperty::setString(const QString& value) |
| | { |
| | _valuePtr->setValue(QVariant(value)); |
| | } |
| |
|
| | void MaterialProperty::setString(const std::string& value) |
| | { |
| | _valuePtr->setValue(QVariant(QString::fromStdString(value))); |
| | } |
| |
|
| | void MaterialProperty::setBoolean(bool value) |
| | { |
| | _valuePtr->setValue(QVariant(value)); |
| | } |
| |
|
| | void MaterialProperty::setBoolean(int value) |
| | { |
| | _valuePtr->setValue(QVariant(value != 0)); |
| | } |
| |
|
| | void MaterialProperty::setBoolean(const QString& value) |
| | { |
| | bool boolean = false; |
| | std::string val = value.toStdString(); |
| | if ((val == "true") || (val == "True")) { |
| | boolean = true; |
| | } |
| | else if ((val == "false") || (val == "False")) { |
| | boolean = false; |
| | } |
| | else { |
| | boolean = (std::stoi(val) != 0); |
| | } |
| |
|
| | setBoolean(boolean); |
| | } |
| |
|
| | void MaterialProperty::setInt(int value) |
| | { |
| | _valuePtr->setValue(QVariant(value)); |
| | } |
| |
|
| | void MaterialProperty::setInt(const QString& value) |
| | { |
| | _valuePtr->setValue(value.toInt()); |
| | } |
| |
|
| | void MaterialProperty::setFloat(double value) |
| | { |
| | _valuePtr->setValue(QVariant(value)); |
| | } |
| |
|
| | void MaterialProperty::setFloat(const QString& value) |
| | { |
| | _valuePtr->setValue(QVariant(value.toFloat())); |
| | } |
| |
|
| | void MaterialProperty::setQuantity(const Base::Quantity& value) |
| | { |
| | auto quantity = value; |
| | if (quantity.isDimensionless()) { |
| | |
| | |
| | |
| | |
| | quantity = Base::Quantity::parse(quantity.getUserString() + getUnits().toStdString()); |
| | } |
| | else { |
| | auto propertyUnit = Base::Quantity::parse(getUnits().toStdString()).getUnit(); |
| | auto units = quantity.getUnit(); |
| | if (propertyUnit != units) { |
| | throw Base::ValueError("Incompatible material units"); |
| | } |
| | } |
| | quantity.setFormat(MaterialValue::getQuantityFormat()); |
| | _valuePtr->setValue(QVariant(QVariant::fromValue(quantity))); |
| | } |
| |
|
| | void MaterialProperty::setQuantity(double value, const QString& units) |
| | { |
| | setQuantity(Base::Quantity(value, units.toStdString())); |
| | } |
| |
|
| | void MaterialProperty::setQuantity(const QString& value) |
| | { |
| | setQuantity(Base::Quantity::parse(value.toStdString())); |
| | } |
| |
|
| | void MaterialProperty::setList(const QList<QVariant>& value) |
| | { |
| | _valuePtr->setList(value); |
| | } |
| |
|
| | void MaterialProperty::setURL(const QString& value) |
| | { |
| | _valuePtr->setValue(QVariant(value)); |
| | } |
| |
|
| | void MaterialProperty::setColor(const Base::Color& value) |
| | { |
| | std::stringstream ss; |
| | ss << "(" << value.r << ", " << value.g << ", " << value.b << ", " << value.a << ")"; |
| | _valuePtr->setValue(QVariant(QString::fromStdString(ss.str()))); |
| | } |
| |
|
| | MaterialProperty& MaterialProperty::operator=(const MaterialProperty& other) |
| | { |
| | if (this == &other) { |
| | return *this; |
| | } |
| |
|
| | ModelProperty::operator=(other); |
| |
|
| | _modelUUID = other._modelUUID; |
| | copyValuePtr(other._valuePtr); |
| |
|
| | _columns.clear(); |
| | for (auto& it : other._columns) { |
| | _columns.push_back(it); |
| | } |
| |
|
| | return *this; |
| | } |
| |
|
| | bool MaterialProperty::operator==(const MaterialProperty& other) const |
| | { |
| | if (this == &other) { |
| | return true; |
| | } |
| |
|
| | if (ModelProperty::operator==(other)) { |
| | return (*_valuePtr == *other._valuePtr); |
| | } |
| | return false; |
| | } |
| |
|
| | void MaterialProperty::validate(const MaterialProperty& other) const { |
| | _valuePtr->validate(*other._valuePtr); |
| |
|
| | if (_columns.size() != other._columns.size()) { |
| | throw InvalidProperty("Model property column counts don't match"); |
| | } |
| | for (size_t i = 0; i < _columns.size(); i++) { |
| | _columns[i].validate(other._columns[i]); |
| | } |
| | } |
| |
|
| | TYPESYSTEM_SOURCE(Materials::Material, Base::BaseClass) |
| |
|
| | Material::Material() |
| | : _dereferenced(false) |
| | , _oldFormat(false) |
| | , _editState(ModelEdit_None) |
| | { |
| | |
| | newUuid(); |
| | } |
| |
|
| | Material::Material(const std::shared_ptr<MaterialLibrary>& library, |
| | const QString& directory, |
| | const QString& uuid, |
| | const QString& name) |
| | : _library(library) |
| | , _uuid(uuid) |
| | , _name(name) |
| | , _dereferenced(false) |
| | , _oldFormat(false) |
| | , _editState(ModelEdit_None) |
| | { |
| | setDirectory(directory); |
| | } |
| |
|
| | Material::Material(const Material& other) |
| | : _library(other._library) |
| | , _directory(other._directory) |
| | , _filename(other._filename) |
| | , _uuid(other._uuid) |
| | , _name(other._name) |
| | , _author(other._author) |
| | , _license(other._license) |
| | , _parentUuid(other._parentUuid) |
| | , _description(other._description) |
| | , _url(other._url) |
| | , _reference(other._reference) |
| | , _dereferenced(other._dereferenced) |
| | , _oldFormat(other._oldFormat) |
| | , _editState(other._editState) |
| | { |
| | for (auto& it : other._tags) { |
| | _tags.insert(it); |
| | } |
| | for (auto& it : other._physicalUuids) { |
| | _physicalUuids.insert(it); |
| | } |
| | for (auto& it : other._appearanceUuids) { |
| | _appearanceUuids.insert(it); |
| | } |
| | for (auto& it : other._allUuids) { |
| | _allUuids.insert(it); |
| | } |
| | for (auto& it : other._physical) { |
| | MaterialProperty prop(it.second); |
| | _physical[it.first] = std::make_shared<MaterialProperty>(prop); |
| | } |
| | for (auto& it : other._appearance) { |
| | MaterialProperty prop(it.second); |
| | _appearance[it.first] = std::make_shared<MaterialProperty>(prop); |
| | } |
| | for (auto& it : other._legacy) { |
| | _legacy[it.first] = it.second; |
| | } |
| | } |
| |
|
| | QString Material::getDirectory() const |
| | { |
| | return _directory; |
| | } |
| |
|
| | void Material::setDirectory(const QString& directory) |
| | { |
| | _directory = directory; |
| | } |
| |
|
| | QString Material::getFilename() const |
| | { |
| | return _filename; |
| | } |
| |
|
| | void Material::setFilename(const QString& filename) |
| | { |
| | _filename = filename; |
| | } |
| |
|
| | QString Material::getFilePath() const |
| | { |
| | return QDir(_directory + QStringLiteral("/") + _filename).absolutePath(); |
| | } |
| |
|
| | QString Material::getAuthorAndLicense() const |
| | { |
| | QString authorAndLicense; |
| |
|
| | |
| | if (!_author.isNull()) { |
| | authorAndLicense = _author; |
| | if (!_license.isNull()) { |
| | authorAndLicense += QStringLiteral(" ") + _license; |
| | } |
| | } |
| | else if (!_license.isNull()) { |
| | authorAndLicense = _license; |
| | } |
| |
|
| | return _license; |
| | } |
| |
|
| | void Material::addModel(const QString& uuid) |
| | { |
| | for (const auto& modelUUID : std::as_const(_allUuids)) { |
| | if (modelUUID == uuid) { |
| | return; |
| | } |
| | } |
| |
|
| | _allUuids << uuid; |
| |
|
| | auto& manager = ModelManager::getManager(); |
| |
|
| | try { |
| | auto model = manager.getModel(uuid); |
| | auto inheritance = model->getInheritance(); |
| | for (auto& inherits : inheritance) { |
| | addModel(inherits); |
| | } |
| | } |
| | catch (ModelNotFound const&) { |
| | } |
| | } |
| |
|
| | void Material::clearModels() |
| | { |
| | _physicalUuids.clear(); |
| | _appearanceUuids.clear(); |
| | _allUuids.clear(); |
| | _physical.clear(); |
| | _appearance.clear(); |
| | } |
| |
|
| | void Material::clearInherited() |
| | { |
| | _allUuids.clear(); |
| |
|
| | |
| | for (auto& uuid : _physicalUuids) { |
| | _allUuids << uuid; |
| | } |
| | for (auto& uuid : _appearanceUuids) { |
| | _allUuids << uuid; |
| | } |
| | } |
| |
|
| | void Material::setName(const QString& name) |
| | { |
| | _name = name; |
| | setEditStateExtend(); |
| | } |
| |
|
| | void Material::setAuthor(const QString& author) |
| | { |
| | _author = author; |
| | setEditStateExtend(); |
| | } |
| |
|
| | void Material::setLicense(const QString& license) |
| | { |
| | _license = license; |
| | setEditStateExtend(); |
| | } |
| |
|
| | void Material::setParentUUID(const QString& uuid) |
| | { |
| | _parentUuid = uuid; |
| | setEditStateExtend(); |
| | } |
| |
|
| | void Material::setDescription(const QString& description) |
| | { |
| | _description = description; |
| | setEditStateExtend(); |
| | } |
| |
|
| | void Material::setURL(const QString& url) |
| | { |
| | _url = url; |
| | setEditStateExtend(); |
| | } |
| |
|
| | void Material::setReference(const QString& reference) |
| | { |
| | _reference = reference; |
| | setEditStateExtend(); |
| | } |
| |
|
| | void Material::setEditState(ModelEdit newState) |
| | { |
| | if (newState == ModelEdit_Extend) { |
| | if (_editState != ModelEdit_Alter) { |
| | _editState = newState; |
| | } |
| | } |
| | else if (newState == ModelEdit_Alter) { |
| | _editState = newState; |
| | } |
| | } |
| |
|
| | void Material::removeUUID(QSet<QString>& uuidList, const QString& uuid) |
| | { |
| | uuidList.remove(uuid); |
| | } |
| |
|
| | void Material::addTag(const QString& tag) |
| | { |
| | auto trimmed = tag.trimmed(); |
| | if (!trimmed.isEmpty()) { |
| | _tags.insert(trimmed); |
| | } |
| | } |
| |
|
| | void Material::removeTag(const QString& tag) |
| | { |
| | _tags.remove(tag); |
| | } |
| |
|
| | void Material::addPhysical(const QString& uuid) |
| | { |
| | if (hasPhysicalModel(uuid)) { |
| | return; |
| | } |
| |
|
| | auto& manager = ModelManager::getManager(); |
| |
|
| | try { |
| | auto model = manager.getModel(uuid); |
| |
|
| | auto& inheritance = model->getInheritance(); |
| | for (auto& it : inheritance) { |
| | |
| | |
| | removeUUID(_physicalUuids, it); |
| | } |
| |
|
| | _physicalUuids.insert(uuid); |
| | addModel(uuid); |
| | setEditStateExtend(); |
| |
|
| | for (auto& it : *model) { |
| | QString propertyName = it.first; |
| | if (!hasPhysicalProperty(propertyName)) { |
| | ModelProperty property = static_cast<ModelProperty>(it.second); |
| |
|
| | try { |
| | _physical[propertyName] = std::make_shared<MaterialProperty>(property, uuid); |
| | } |
| | catch (const UnknownValueType&) { |
| | Base::Console().error("Property '%s' has unknown type '%s'. Ignoring\n", |
| | property.getName().toStdString().c_str(), |
| | property.getPropertyType().toStdString().c_str()); |
| | } |
| | } |
| | } |
| | } |
| | catch (ModelNotFound const&) { |
| | } |
| | } |
| |
|
| | void Material::removePhysical(const QString& uuid) |
| | { |
| | if (!hasPhysicalModel(uuid)) { |
| | return; |
| | } |
| |
|
| | |
| | if (isInherited(uuid)) { |
| | return; |
| | } |
| |
|
| | auto& manager = ModelManager::getManager(); |
| |
|
| | try { |
| | auto model = manager.getModel(uuid); |
| |
|
| | auto& inheritance = model->getInheritance(); |
| | for (auto& it : inheritance) { |
| | removeUUID(_physicalUuids, it); |
| | removeUUID(_allUuids, it); |
| | } |
| | removeUUID(_physicalUuids, uuid); |
| | removeUUID(_allUuids, uuid); |
| |
|
| | for (auto& it : *model) { |
| | _physical.erase(it.first); |
| | } |
| |
|
| | setEditStateAlter(); |
| | } |
| | catch (ModelNotFound const&) { |
| | Base::Console().log("Physical model not found '%s'\n", uuid.toStdString().c_str()); |
| | } |
| | } |
| |
|
| | void Material::addAppearance(const QString& uuid) |
| | { |
| | if (hasAppearanceModel(uuid)) { |
| | return; |
| | } |
| |
|
| | auto& manager = ModelManager::getManager(); |
| |
|
| | try { |
| | auto model = manager.getModel(uuid); |
| |
|
| | auto& inheritance = model->getInheritance(); |
| | for (auto& it : inheritance) { |
| | |
| | |
| | removeUUID(_appearanceUuids, it); |
| | } |
| |
|
| | _appearanceUuids.insert(uuid); |
| | addModel(uuid); |
| | setEditStateExtend(); |
| |
|
| | for (auto& it : *model) { |
| | QString propertyName = it.first; |
| | if (!hasAppearanceProperty(propertyName)) { |
| | ModelProperty property = static_cast<ModelProperty>(it.second); |
| |
|
| | _appearance[propertyName] = std::make_shared<MaterialProperty>(property, uuid); |
| | } |
| | } |
| | } |
| | catch (ModelNotFound const&) { |
| | Base::Console().log("Appearance model not found '%s'\n", uuid.toStdString().c_str()); |
| | } |
| | } |
| |
|
| | void Material::removeAppearance(const QString& uuid) |
| | { |
| | if (!hasAppearanceModel(uuid)) { |
| | return; |
| | } |
| |
|
| | |
| | if (isInherited(uuid)) { |
| | return; |
| | } |
| |
|
| | auto& manager = ModelManager::getManager(); |
| |
|
| | try { |
| | auto model = manager.getModel(uuid); |
| |
|
| | auto& inheritance = model->getInheritance(); |
| | for (auto& it : inheritance) { |
| | removeUUID(_appearanceUuids, it); |
| | removeUUID(_allUuids, it); |
| | } |
| | removeUUID(_appearanceUuids, uuid); |
| | removeUUID(_allUuids, uuid); |
| |
|
| | for (auto& it : *model) { |
| | _appearance.erase(it.first); |
| | } |
| |
|
| | setEditStateAlter(); |
| | } |
| | catch (ModelNotFound const&) { |
| | } |
| | } |
| |
|
| | void Material::setPropertyEditState(const QString& name) |
| | { |
| | try { |
| | if (hasPhysicalProperty(name)) { |
| | setPhysicalEditState(name); |
| | } |
| | else if (hasAppearanceProperty(name)) { |
| | setAppearanceEditState(name); |
| | } |
| | } |
| | catch (const PropertyNotFound&) { |
| | } |
| | } |
| |
|
| | void Material::setPhysicalEditState(const QString& name) |
| | { |
| | if (getPhysicalProperty(name)->isNull()) { |
| | setEditStateExtend(); |
| | } |
| | else { |
| | setEditStateAlter(); |
| | } |
| | } |
| |
|
| | void Material::setAppearanceEditState(const QString& name) |
| | { |
| | try { |
| | if (getAppearanceProperty(name)->isNull()) { |
| | setEditStateExtend(); |
| | } |
| | else { |
| | setEditStateAlter(); |
| | } |
| | } |
| | catch (const PropertyNotFound&) { |
| | } |
| | } |
| |
|
| | void Material::setPhysicalValue(const QString& name, const QString& value) |
| | { |
| | setPhysicalEditState(name); |
| |
|
| | if (hasPhysicalProperty(name)) { |
| | _physical[name]->setValue(value); |
| | } |
| | } |
| |
|
| | void Material::setPhysicalValue(const QString& name, int value) |
| | { |
| | setPhysicalEditState(name); |
| |
|
| | if (hasPhysicalProperty(name)) { |
| | _physical[name]->setInt(value); |
| | } |
| | } |
| |
|
| | void Material::setPhysicalValue(const QString& name, double value) |
| | { |
| | setPhysicalEditState(name); |
| |
|
| | if (hasPhysicalProperty(name)) { |
| | _physical[name]->setFloat(value); |
| | } |
| | } |
| |
|
| | void Material::setPhysicalValue(const QString& name, const Base::Quantity& value) |
| | { |
| | setPhysicalEditState(name); |
| |
|
| | if (hasPhysicalProperty(name)) { |
| | _physical[name]->setQuantity(value); |
| | } |
| | } |
| |
|
| | void Material::setPhysicalValue(const QString& name, const std::shared_ptr<MaterialValue>& value) |
| | { |
| | setPhysicalEditState(name); |
| |
|
| | if (hasPhysicalProperty(name)) { |
| | _physical[name]->setValue(value); |
| | } |
| | } |
| |
|
| | void Material::setPhysicalValue(const QString& name, const std::shared_ptr<QList<QVariant>>& value) |
| | { |
| | setPhysicalEditState(name); |
| |
|
| | if (hasPhysicalProperty(name)) { |
| | _physical[name]->setList(*value); |
| | } |
| | } |
| |
|
| | void Material::setPhysicalValue(const QString& name, const QVariant& value) |
| | { |
| | setPhysicalEditState(name); |
| |
|
| | if (hasPhysicalProperty(name)) { |
| | _physical[name]->setValue(value); |
| | } |
| | } |
| |
|
| | void Material::setAppearanceValue(const QString& name, const QString& value) |
| | { |
| | setAppearanceEditState(name); |
| |
|
| | if (hasAppearanceProperty(name)) { |
| | _appearance[name]->setValue(value); |
| | } |
| | } |
| |
|
| | void Material::setAppearanceValue(const QString& name, const std::shared_ptr<MaterialValue>& value) |
| | { |
| | setAppearanceEditState(name); |
| |
|
| | if (hasAppearanceProperty(name)) { |
| | _appearance[name]->setValue(value); |
| | } |
| | } |
| |
|
| | void Material::setAppearanceValue(const QString& name, |
| | const std::shared_ptr<QList<QVariant>>& value) |
| | { |
| | setAppearanceEditState(name); |
| |
|
| | if (hasAppearanceProperty(name)) { |
| | _appearance[name]->setList(*value); |
| | } |
| | } |
| |
|
| | void Material::setAppearanceValue(const QString& name, const QVariant& value) |
| | { |
| | setAppearanceEditState(name); |
| |
|
| | if (hasAppearanceProperty(name)) { |
| | _appearance[name]->setValue(value); |
| | } |
| | } |
| |
|
| | void Material::setValue(const QString& name, const QString& value) |
| | { |
| | if (hasPhysicalProperty(name)) { |
| | setPhysicalValue(name, value); |
| | } |
| | else if (hasAppearanceProperty(name)) { |
| | setAppearanceValue(name, value); |
| | } |
| | else { |
| | throw PropertyNotFound(); |
| | } |
| | } |
| |
|
| | void Material::setValue(const QString& name, const QVariant& value) |
| | { |
| | if (hasPhysicalProperty(name)) { |
| | setPhysicalValue(name, value); |
| | } |
| | else if (hasAppearanceProperty(name)) { |
| | setAppearanceValue(name, value); |
| | } |
| | else { |
| | throw PropertyNotFound(); |
| | } |
| | } |
| |
|
| | void Material::setValue(const QString& name, const std::shared_ptr<MaterialValue>& value) |
| | { |
| | if (hasPhysicalProperty(name)) { |
| | setPhysicalValue(name, value); |
| | } |
| | else if (hasAppearanceProperty(name)) { |
| | setAppearanceValue(name, value); |
| | } |
| | else { |
| | throw PropertyNotFound(); |
| | } |
| | } |
| |
|
| | void Material::setLegacyValue(const QString& name, const QString& value) |
| | { |
| | setEditStateAlter(); |
| |
|
| | _legacy[name] = value; |
| | } |
| |
|
| | std::shared_ptr<MaterialProperty> Material::getPhysicalProperty(const QString& name) |
| | { |
| | try { |
| | return _physical.at(name); |
| | } |
| | catch (std::out_of_range const&) { |
| | throw PropertyNotFound(); |
| | } |
| | } |
| |
|
| | std::shared_ptr<MaterialProperty> Material::getPhysicalProperty(const QString& name) const |
| | { |
| | try { |
| | return _physical.at(name); |
| | } |
| | catch (std::out_of_range const&) { |
| | throw PropertyNotFound(); |
| | } |
| | } |
| |
|
| | std::shared_ptr<MaterialProperty> Material::getAppearanceProperty(const QString& name) |
| | { |
| | try { |
| | return _appearance.at(name); |
| | } |
| | catch (std::out_of_range const&) { |
| | throw PropertyNotFound(); |
| | } |
| | } |
| |
|
| | std::shared_ptr<MaterialProperty> Material::getAppearanceProperty(const QString& name) const |
| | { |
| | try { |
| | return _appearance.at(name); |
| | } |
| | catch (std::out_of_range const&) { |
| | throw PropertyNotFound(); |
| | } |
| | } |
| |
|
| | std::shared_ptr<MaterialProperty> Material::getProperty(const QString& name) |
| | { |
| | if (hasPhysicalProperty(name)) { |
| | return getPhysicalProperty(name); |
| | } |
| | if (hasAppearanceProperty(name)) { |
| | return getAppearanceProperty(name); |
| | } |
| | throw PropertyNotFound(); |
| | } |
| |
|
| | std::shared_ptr<MaterialProperty> Material::getProperty(const QString& name) const |
| | { |
| | if (hasPhysicalProperty(name)) { |
| | return getPhysicalProperty(name); |
| | } |
| | if (hasAppearanceProperty(name)) { |
| | return getAppearanceProperty(name); |
| | } |
| | throw PropertyNotFound(); |
| | } |
| |
|
| | QVariant |
| | Material::getValue(const std::map<QString, std::shared_ptr<MaterialProperty>>& propertyList, |
| | const QString& name) |
| | { |
| | try { |
| | return propertyList.at(name)->getValue(); |
| | } |
| | catch (std::out_of_range const&) { |
| | throw PropertyNotFound(); |
| | } |
| | } |
| |
|
| | QString |
| | Material::getValueString(const std::map<QString, std::shared_ptr<MaterialProperty>>& propertyList, |
| | const QString& name) |
| | { |
| | try { |
| | const auto& property = propertyList.at(name); |
| | if (property->isNull()) { |
| | return {}; |
| | } |
| | if (property->getType() == MaterialValue::Quantity) { |
| | auto value = property->getValue(); |
| | if (value.isNull()) { |
| | return {}; |
| | } |
| | return QString::fromStdString(value.value<Base::Quantity>().getUserString()); |
| | } |
| | if (property->getType() == MaterialValue::Float) { |
| | auto value = property->getValue(); |
| | if (value.isNull()) { |
| | return {}; |
| | } |
| | return QString(QStringLiteral("%L1")) |
| | .arg(value.toFloat(), 0, 'g', MaterialValue::PRECISION); |
| | } |
| | return property->getValue().toString(); |
| | } |
| | catch (std::out_of_range const&) { |
| | throw PropertyNotFound(); |
| | } |
| | } |
| |
|
| | QVariant Material::getPhysicalValue(const QString& name) const |
| | { |
| | return getValue(_physical, name); |
| | } |
| |
|
| | Base::Quantity Material::getPhysicalQuantity(const QString& name) const |
| | { |
| | return getValue(_physical, name).value<Base::Quantity>(); |
| | } |
| |
|
| | QString Material::getPhysicalValueString(const QString& name) const |
| | { |
| | return getValueString(_physical, name); |
| | } |
| |
|
| | QVariant Material::getAppearanceValue(const QString& name) const |
| | { |
| | return getValue(_appearance, name); |
| | } |
| |
|
| | Base::Quantity Material::getAppearanceQuantity(const QString& name) const |
| | { |
| | return getValue(_appearance, name).value<Base::Quantity>(); |
| | } |
| |
|
| | QString Material::getAppearanceValueString(const QString& name) const |
| | { |
| | return getValueString(_appearance, name); |
| | } |
| |
|
| | bool Material::hasPhysicalProperty(const QString& name) const |
| | { |
| | return _physical.find(name) != _physical.end(); |
| | } |
| |
|
| | bool Material::hasAppearanceProperty(const QString& name) const |
| | { |
| | return _appearance.find(name) != _appearance.end(); |
| | } |
| |
|
| | bool Material::hasNonLegacyProperty(const QString& name) const |
| | { |
| | if (hasPhysicalProperty(name) || hasAppearanceProperty(name)) { |
| | return true; |
| | } |
| | return false; |
| | } |
| |
|
| | bool Material::hasLegacyProperties() const |
| | { |
| | return !_legacy.empty(); |
| | } |
| |
|
| | bool Material::hasPhysicalProperties() const |
| | { |
| | return !_physicalUuids.isEmpty(); |
| | } |
| |
|
| | bool Material::hasAppearanceProperties() const |
| | { |
| | return !_appearanceUuids.isEmpty(); |
| | } |
| |
|
| | bool Material::isInherited(const QString& uuid) const |
| | { |
| | if (_physicalUuids.contains(uuid)) { |
| | return false; |
| | } |
| | if (_appearanceUuids.contains(uuid)) { |
| | return false; |
| | } |
| |
|
| | return _allUuids.contains(uuid); |
| | } |
| |
|
| | bool Material::hasModel(const QString& uuid) const |
| | { |
| | return _allUuids.contains(uuid); |
| | } |
| |
|
| | bool Material::hasPhysicalModel(const QString& uuid) const |
| | { |
| | if (!hasModel(uuid)) { |
| | return false; |
| | } |
| |
|
| | auto& manager = ModelManager::getManager(); |
| |
|
| | try { |
| | auto model = manager.getModel(uuid); |
| | if (model->getType() == Model::ModelType_Physical) { |
| | return true; |
| | } |
| | } |
| | catch (ModelNotFound const&) { |
| | } |
| |
|
| | return false; |
| | } |
| |
|
| | bool Material::hasAppearanceModel(const QString& uuid) const |
| | { |
| | if (!hasModel(uuid)) { |
| | return false; |
| | } |
| |
|
| | auto& manager = ModelManager::getManager(); |
| |
|
| | try { |
| | auto model = manager.getModel(uuid); |
| | if (model->getType() == Model::ModelType_Appearance) { |
| | return true; |
| | } |
| | } |
| | catch (ModelNotFound const&) { |
| | } |
| |
|
| | return false; |
| | } |
| |
|
| | bool Material::isPhysicalModelComplete(const QString& uuid) const |
| | { |
| | if (!hasPhysicalModel(uuid)) { |
| | return false; |
| | } |
| |
|
| | auto& manager = ModelManager::getManager(); |
| |
|
| | try { |
| | auto model = manager.getModel(uuid); |
| | for (auto& it : *model) { |
| | QString propertyName = it.first; |
| | auto property = getPhysicalProperty(propertyName); |
| |
|
| | if (property->isNull()) { |
| | return false; |
| | } |
| | } |
| | } |
| | catch (ModelNotFound const&) { |
| | return false; |
| | } |
| |
|
| | return true; |
| | } |
| |
|
| | bool Material::isAppearanceModelComplete(const QString& uuid) const |
| | { |
| | if (!hasAppearanceModel(uuid)) { |
| | return false; |
| | } |
| |
|
| | auto& manager = ModelManager::getManager(); |
| |
|
| | try { |
| | auto model = manager.getModel(uuid); |
| | for (auto& it : *model) { |
| | QString propertyName = it.first; |
| | auto property = getAppearanceProperty(propertyName); |
| |
|
| | if (property->isNull()) { |
| | return false; |
| | } |
| | } |
| | } |
| | catch (ModelNotFound const&) { |
| | return false; |
| | } |
| |
|
| | return true; |
| | } |
| |
|
| | void Material::saveGeneral(QTextStream& stream) const |
| | { |
| | stream << "General:\n"; |
| | stream << " UUID: \"" << _uuid << "\"\n"; |
| | stream << " Name: \"" << MaterialValue::escapeString(_name) << "\"\n"; |
| | if (!_author.isEmpty()) { |
| | stream << " Author: \"" << MaterialValue::escapeString(_author) << "\"\n"; |
| | } |
| | if (!_license.isEmpty()) { |
| | stream << " License: \"" << MaterialValue::escapeString(_license) << "\"\n"; |
| | } |
| | if (!_description.isEmpty()) { |
| | stream << " Description: \"" << MaterialValue::escapeString(_description) << "\"\n"; |
| | } |
| | if (!_url.isEmpty()) { |
| | stream << " SourceURL: \"" << MaterialValue::escapeString(_url) << "\"\n"; |
| | } |
| | if (!_reference.isEmpty()) { |
| | stream << " ReferenceSource: \"" << MaterialValue::escapeString(_reference) << "\"\n"; |
| | } |
| | if (!_tags.isEmpty()) { |
| | stream << " Tags:\n"; |
| | for (auto tag : _tags) { |
| | stream << " - \"" << tag << "\"\n"; |
| | } |
| | } |
| | } |
| |
|
| | void Material::saveInherits(QTextStream& stream) const |
| | { |
| | if (!_parentUuid.isEmpty()) { |
| | try { |
| | auto material = MaterialManager::getManager().getMaterial(_parentUuid); |
| |
|
| | stream << "Inherits:\n"; |
| | stream << " " << material->getName() << ":\n"; |
| | stream << " UUID: \"" << _parentUuid << "\"\n"; |
| | } |
| | catch (const MaterialNotFound&) { |
| | } |
| | } |
| | } |
| |
|
| | bool Material::modelChanged(const Material& parent, |
| | const Model& model) const |
| | { |
| | for (auto& it : model) { |
| | QString propertyName = it.first; |
| | auto property = getPhysicalProperty(propertyName); |
| | try { |
| | auto parentProperty = parent.getPhysicalProperty(propertyName); |
| |
|
| | if (*property != *parentProperty) { |
| | return true; |
| | } |
| | } |
| | catch (const PropertyNotFound&) { |
| | return true; |
| | } |
| | } |
| |
|
| | return false; |
| | } |
| |
|
| | bool Material::modelAppearanceChanged(const Material& parent, |
| | const Model& model) const |
| | { |
| | for (auto& it : model) { |
| | QString propertyName = it.first; |
| | auto property = getAppearanceProperty(propertyName); |
| | try { |
| | auto parentProperty = parent.getAppearanceProperty(propertyName); |
| |
|
| | if (*property != *parentProperty) { |
| | return true; |
| | } |
| | } |
| | catch (const PropertyNotFound&) { |
| | return true; |
| | } |
| | } |
| |
|
| | return false; |
| | } |
| |
|
| | void Material::saveModels(QTextStream& stream, bool saveInherited) const |
| | { |
| | if (_physical.empty()) { |
| | return; |
| | } |
| |
|
| | auto& modelManager = ModelManager::getManager(); |
| | auto& materialManager = MaterialManager::getManager(); |
| |
|
| | bool inherited = saveInherited && (_parentUuid.size() > 0); |
| | std::shared_ptr<Material> parent; |
| | if (inherited) { |
| | try { |
| | parent = materialManager.getMaterial(_parentUuid); |
| | } |
| | catch (const MaterialNotFound&) { |
| | inherited = false; |
| | } |
| | } |
| |
|
| | bool headerPrinted = false; |
| | for (auto& itm : _physicalUuids) { |
| | auto model = modelManager.getModel(itm); |
| | if (!inherited || modelChanged(*parent, *model)) { |
| | if (!headerPrinted) { |
| | stream << "Models:\n"; |
| | headerPrinted = true; |
| | } |
| | stream << " " << MaterialValue::escapeString(model->getName()) << ":\n"; |
| | stream << " UUID: \"" << model->getUUID() << "\"\n"; |
| | for (const auto& it : *model) { |
| | QString propertyName = it.first; |
| | std::shared_ptr<MaterialProperty> property = getPhysicalProperty(propertyName); |
| | std::shared_ptr<MaterialProperty> parentProperty; |
| | try { |
| | if (inherited) { |
| | parentProperty = parent->getPhysicalProperty(propertyName); |
| | } |
| | } |
| | catch (const PropertyNotFound&) { |
| | Base::Console().log("Material::saveModels Property not found '%s'\n", |
| | propertyName.toStdString().c_str()); |
| | } |
| |
|
| | if (!inherited || !parentProperty || (*property != *parentProperty)) { |
| | if (!property->isNull()) { |
| | stream << " " << *property << "\n"; |
| | } |
| | } |
| | } |
| | } |
| | } |
| | } |
| |
|
| | void Material::saveAppearanceModels(QTextStream& stream, bool saveInherited) const |
| | { |
| | if (_appearance.empty()) { |
| | return; |
| | } |
| |
|
| | auto& modelManager = ModelManager::getManager(); |
| | auto& materialManager = MaterialManager::getManager(); |
| |
|
| | bool inherited = saveInherited && (_parentUuid.size() > 0); |
| | std::shared_ptr<Material> parent; |
| | if (inherited) { |
| | try { |
| | parent = materialManager.getMaterial(_parentUuid); |
| | } |
| | catch (const MaterialNotFound&) { |
| | inherited = false; |
| | } |
| | } |
| |
|
| | bool headerPrinted = false; |
| | for (auto& itm : _appearanceUuids) { |
| | auto model = modelManager.getModel(itm); |
| | if (!inherited || modelAppearanceChanged(*parent, *model)) { |
| | if (!headerPrinted) { |
| | stream << "AppearanceModels:\n"; |
| | headerPrinted = true; |
| | } |
| | stream << " " << MaterialValue::escapeString(model->getName()) << ":\n"; |
| | stream << " UUID: \"" << model->getUUID() << "\"\n"; |
| | for (const auto& it : *model) { |
| | QString propertyName = it.first; |
| | std::shared_ptr<MaterialProperty> property = getAppearanceProperty(propertyName); |
| | std::shared_ptr<MaterialProperty> parentProperty; |
| | try { |
| | if (inherited) { |
| | parentProperty = parent->getAppearanceProperty(propertyName); |
| | } |
| | } |
| | catch (const PropertyNotFound&) { |
| | } |
| |
|
| | if (!inherited || !parentProperty || (*property != *parentProperty)) { |
| | if (!property->isNull()) { |
| | stream << " " << *property << "\n"; |
| | } |
| | } |
| | } |
| | } |
| | } |
| | } |
| |
|
| | void Material::newUuid() |
| | { |
| | _uuid = QUuid::createUuid().toString(QUuid::WithoutBraces); |
| | } |
| |
|
| | QString Material::getModelByName(const QString& name) const |
| | { |
| | auto& manager = ModelManager::getManager(); |
| |
|
| | for (auto& it : _allUuids) { |
| | try { |
| | auto model = manager.getModel(it); |
| | if (model->getName() == name) { |
| | return it; |
| | } |
| | } |
| | catch (ModelNotFound const&) { |
| | } |
| | } |
| |
|
| | return {}; |
| | } |
| |
|
| | void Material::save(QTextStream& stream, bool overwrite, bool saveAsCopy, bool saveInherited) |
| | { |
| | if (saveInherited && !saveAsCopy) { |
| | |
| | |
| | if (MaterialManager::getManager().exists(_uuid) && !overwrite) { |
| | |
| | setParentUUID(_uuid); |
| | } |
| | } |
| |
|
| | |
| | if (_parentUuid == _uuid) { |
| | _parentUuid = QString(); |
| | } |
| |
|
| | if (saveAsCopy) { |
| | |
| | if (_parentUuid.isEmpty()) { |
| | saveInherited = false; |
| | } |
| | else { |
| | saveInherited = true; |
| | } |
| | } |
| | else { |
| | if (!overwrite) { |
| | |
| | |
| | newUuid(); |
| | } |
| | } |
| |
|
| | stream << "---\n"; |
| | stream << "# File created by " << QString::fromStdString(App::Application::Config()["ExeName"]) |
| | << " " << QString::fromStdString(App::Application::Config()["ExeVersion"]) |
| | << " Revision: " << QString::fromStdString(App::Application::Config()["BuildRevision"]) |
| | << "\n"; |
| | saveGeneral(stream); |
| | if (saveInherited) { |
| | saveInherits(stream); |
| | } |
| | saveModels(stream, saveInherited); |
| | saveAppearanceModels(stream, saveInherited); |
| |
|
| | setOldFormat(false); |
| | } |
| |
|
| | Material& Material::operator=(const Material& other) |
| | { |
| | if (this == &other) { |
| | return *this; |
| | } |
| |
|
| | _library = other._library; |
| | _directory = other._directory; |
| | _filename = other._filename; |
| | _uuid = other._uuid; |
| | _name = other._name; |
| | _author = other._author; |
| | _license = other._license; |
| | _parentUuid = other._parentUuid; |
| | _description = other._description; |
| | _url = other._url; |
| | _reference = other._reference; |
| | _dereferenced = other._dereferenced; |
| | _oldFormat = other._oldFormat; |
| | _editState = other._editState; |
| |
|
| | _tags.clear(); |
| | for (auto& it : other._tags) { |
| | _tags.insert(it); |
| | } |
| | _physicalUuids.clear(); |
| | for (auto& it : other._physicalUuids) { |
| | _physicalUuids.insert(it); |
| | } |
| | _appearanceUuids.clear(); |
| | for (auto& it : other._appearanceUuids) { |
| | _appearanceUuids.insert(it); |
| | } |
| | _allUuids.clear(); |
| | for (auto& it : other._allUuids) { |
| | _allUuids.insert(it); |
| | } |
| |
|
| | |
| | _physical.clear(); |
| | for (auto& it : other._physical) { |
| | MaterialProperty prop(it.second); |
| | _physical[it.first] = std::make_shared<MaterialProperty>(prop); |
| | } |
| | _appearance.clear(); |
| | for (auto& it : other._appearance) { |
| | MaterialProperty prop(it.second); |
| | _appearance[it.first] = std::make_shared<MaterialProperty>(prop); |
| | } |
| | _legacy.clear(); |
| | for (auto& it : other._legacy) { |
| | _legacy[it.first] = it.second; |
| | } |
| |
|
| | return *this; |
| | } |
| |
|
| | Material& Material::operator=(const App::Material& other) |
| | { |
| | if (!hasAppearanceModel(ModelUUIDs::ModelUUID_Rendering_Basic)) { |
| | addAppearance(ModelUUIDs::ModelUUID_Rendering_Basic); |
| | } |
| |
|
| | getAppearanceProperty(QStringLiteral("AmbientColor"))->setColor(other.ambientColor); |
| | getAppearanceProperty(QStringLiteral("DiffuseColor"))->setColor(other.diffuseColor); |
| | getAppearanceProperty(QStringLiteral("SpecularColor"))->setColor(other.specularColor); |
| | getAppearanceProperty(QStringLiteral("EmissiveColor"))->setColor(other.emissiveColor); |
| | getAppearanceProperty(QStringLiteral("Shininess"))->setFloat(other.shininess); |
| | getAppearanceProperty(QStringLiteral("Transparency"))->setFloat(other.transparency); |
| |
|
| | if (!other.image.empty() || !other.imagePath.empty()) { |
| | if (!hasAppearanceModel(ModelUUIDs::ModelUUID_Rendering_Texture)) { |
| | addAppearance(ModelUUIDs::ModelUUID_Rendering_Texture); |
| | } |
| |
|
| | getAppearanceProperty(QStringLiteral("TextureImage"))->setString(other.image); |
| | getAppearanceProperty(QStringLiteral("TexturePath"))->setString(other.imagePath); |
| | } |
| |
|
| | return *this; |
| | } |
| |
|
| | |
| | |
| | |
| | QStringList Material::normalizeModels(const QStringList& models) |
| | { |
| | QStringList normalized; |
| |
|
| | auto& manager = ModelManager::getManager(); |
| |
|
| | for (auto& uuid : models) { |
| | auto model = manager.getModel(uuid); |
| |
|
| | bool found = false; |
| | for (auto& childUuid : models) { |
| | if (uuid != childUuid) { |
| | auto childModel = manager.getModel(childUuid); |
| | if (childModel->inherits(childUuid)) { |
| | |
| | found = true; |
| | break; |
| | } |
| | } |
| | } |
| | if (!found) { |
| | normalized << uuid; |
| | } |
| | } |
| |
|
| | return normalized; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | void Material::updateInheritance([[maybe_unused]] const QString& parent) |
| | {} |
| |
|
| | |
| | |
| | |
| | |
| | QStringList Material::inheritedMissingModels(const Material& parent) const |
| | { |
| | QStringList missing; |
| | for (auto& uuid : parent._allUuids) { |
| | if (!hasModel(uuid)) { |
| | missing << uuid; |
| | } |
| | } |
| |
|
| | return normalizeModels(missing); |
| | } |
| |
|
| | |
| | |
| | |
| | QStringList Material::inheritedAddedModels(const Material& parent) const |
| | { |
| | QStringList added; |
| | for (auto& uuid : _allUuids) { |
| | if (!parent.hasModel(uuid)) { |
| | added << uuid; |
| | } |
| | } |
| |
|
| | return normalizeModels(added); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | void Material::inheritedPropertyDiff([[maybe_unused]] const QString& parent) |
| | {} |
| |
|
| | |
| | |
| | |
| | |
| | App::Material Material::getMaterialAppearance() const |
| | { |
| | App::Material material(App::Material::DEFAULT); |
| |
|
| | bool custom = false; |
| | if (hasAppearanceProperty(QStringLiteral("AmbientColor"))) { |
| | material.ambientColor = getAppearanceProperty(QStringLiteral("AmbientColor"))->getColor(); |
| | custom = true; |
| | } |
| | if (hasAppearanceProperty(QStringLiteral("DiffuseColor"))) { |
| | material.diffuseColor = getAppearanceProperty(QStringLiteral("DiffuseColor"))->getColor(); |
| | custom = true; |
| | } |
| | if (hasAppearanceProperty(QStringLiteral("SpecularColor"))) { |
| | material.specularColor = getAppearanceProperty(QStringLiteral("SpecularColor"))->getColor(); |
| | custom = true; |
| | } |
| | if (hasAppearanceProperty(QStringLiteral("EmissiveColor"))) { |
| | material.emissiveColor = getAppearanceProperty(QStringLiteral("EmissiveColor"))->getColor(); |
| | custom = true; |
| | } |
| | if (hasAppearanceProperty(QStringLiteral("Shininess"))) { |
| | material.shininess = getAppearanceProperty(QStringLiteral("Shininess"))->getFloat(); |
| | custom = true; |
| | } |
| | if (hasAppearanceProperty(QStringLiteral("Transparency"))) { |
| | material.transparency = getAppearanceProperty(QStringLiteral("Transparency"))->getFloat(); |
| | custom = true; |
| | } |
| | if (hasAppearanceProperty(QStringLiteral("TextureImage"))) { |
| | auto property = getAppearanceProperty(QStringLiteral("TextureImage")); |
| | if (!property->isNull()) { |
| | Base::Console().log("Has 'TextureImage'\n"); |
| | material.image = property->getString().toStdString(); |
| | } |
| |
|
| | custom = true; |
| | } |
| | else if (hasAppearanceProperty(QStringLiteral("TexturePath"))) { |
| | auto property = getAppearanceProperty(QStringLiteral("TexturePath")); |
| | if (!property->isNull()) { |
| | Base::Console().log("Has 'TexturePath'\n"); |
| | material.imagePath = property->getString().toStdString(); |
| | } |
| |
|
| | custom = true; |
| | } |
| |
|
| | if (custom) { |
| | material.setType(App::Material::USER_DEFINED); |
| | material.uuid = getUUID().toStdString(); |
| | } |
| |
|
| | return material; |
| | } |
| |
|
| | void Material::validate(Material& other) const |
| | { |
| |
|
| | try { |
| | _library->validate(*other._library); |
| | } |
| | catch (const InvalidLibrary& e) { |
| | throw InvalidMaterial(e.what()); |
| | } |
| |
|
| | if (_directory != other._directory) { |
| | throw InvalidMaterial("Model directories don't match"); |
| | } |
| | if (!other._filename.isEmpty()) { |
| | throw InvalidMaterial("Remote filename is not empty"); |
| | } |
| | if (_uuid != other._uuid) { |
| | throw InvalidMaterial("Model UUIDs don't match"); |
| | } |
| | if (_name != other._name) { |
| | throw InvalidMaterial("Model names don't match"); |
| | } |
| | if (_author != other._author) { |
| | throw InvalidMaterial("Model authors don't match"); |
| | } |
| | if (_license != other._license) { |
| | throw InvalidMaterial("Model licenses don't match"); |
| | } |
| | if (_parentUuid != other._parentUuid) { |
| | throw InvalidMaterial("Model parents don't match"); |
| | } |
| | if (_description != other._description) { |
| | throw InvalidMaterial("Model descriptions don't match"); |
| | } |
| | if (_url != other._url) { |
| | throw InvalidMaterial("Model URLs don't match"); |
| | } |
| | if (_reference != other._reference) { |
| | throw InvalidMaterial("Model references don't match"); |
| | } |
| |
|
| | if (_tags.size() != other._tags.size()) { |
| | Base::Console().log("Local tags count %d\n", _tags.size()); |
| | Base::Console().log("Remote tags count %d\n", other._tags.size()); |
| | throw InvalidMaterial("Material tags counts don't match"); |
| | } |
| | if (!other._tags.contains(_tags)) { |
| | throw InvalidMaterial("Material tags don't match"); |
| | } |
| |
|
| | if (_physicalUuids.size() != other._physicalUuids.size()) { |
| | Base::Console().log("Local physical model count %d\n", _physicalUuids.size()); |
| | Base::Console().log("Remote physical model count %d\n", other._physicalUuids.size()); |
| | throw InvalidMaterial("Material physical model counts don't match"); |
| | } |
| | if (!other._physicalUuids.contains(_physicalUuids)) { |
| | throw InvalidMaterial("Material physical models don't match"); |
| | } |
| |
|
| | if (_physicalUuids.size() != other._physicalUuids.size()) { |
| | Base::Console().log("Local appearance model count %d\n", _physicalUuids.size()); |
| | Base::Console().log("Remote appearance model count %d\n", other._physicalUuids.size()); |
| | throw InvalidMaterial("Material appearance model counts don't match"); |
| | } |
| | if (!other._physicalUuids.contains(_physicalUuids)) { |
| | throw InvalidMaterial("Material appearance models don't match"); |
| | } |
| |
|
| | if (_allUuids.size() != other._allUuids.size()) { |
| | Base::Console().log("Local model count %d\n", _allUuids.size()); |
| | Base::Console().log("Remote model count %d\n", other._allUuids.size()); |
| | throw InvalidMaterial("Material model counts don't match"); |
| | } |
| | if (!other._allUuids.contains(_allUuids)) { |
| | throw InvalidMaterial("Material models don't match"); |
| | } |
| |
|
| | |
| | if (_physical.size() != other._physical.size()) { |
| | throw InvalidMaterial("Material physical property counts don't match"); |
| | } |
| | for (auto& property : _physical) { |
| | auto& remote = other._physical[property.first]; |
| | property.second->validate(*remote); |
| | } |
| |
|
| | if (_appearance.size() != other._appearance.size()) { |
| | throw InvalidMaterial("Material appearance property counts don't match"); |
| | } |
| | for (auto& property : _appearance) { |
| | auto& remote = other._appearance[property.first]; |
| | property.second->validate(*remote); |
| | } |
| | } |
| |
|